aboutsummaryrefslogtreecommitdiff
path: root/source/Key.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Key.cpp')
-rw-r--r--source/Key.cpp166
1 files changed, 166 insertions, 0 deletions
diff --git a/source/Key.cpp b/source/Key.cpp
new file mode 100644
index 0000000..31665be
--- /dev/null
+++ b/source/Key.cpp
@@ -0,0 +1,166 @@
1/*
2 * Copyright (c) 2018 shchmue
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "Key.hpp"
18
19#include <algorithm>
20#include <iomanip>
21#include <vector>
22
23#include <mbedtls/aes.h>
24#include <mbedtls/cmac.h>
25
26#include "xxhash64.h"
27
28size_t Key::saved_key_count = 0;
29
30Key::Key(std::string name, u64 xx_hash, byte_vector hash, u8 length, byte_vector key) :
31 key(key),
32 name(name),
33 xx_hash(xx_hash),
34 hash(hash),
35 length(length)
36{
37}
38
39// init with hash only
40Key::Key(std::string name, u64 xx_hash, byte_vector hash, u8 length) :
41 Key(name, xx_hash, hash, length, {})
42{
43}
44
45// init with key only
46Key::Key(std::string name, u8 length, byte_vector key) :
47 Key(name, {}, {}, length, key)
48{
49 is_found = true;
50}
51
52// nameless key
53Key::Key(byte_vector key, u8 length) :
54 Key({}, {}, {}, length, key)
55{
56 is_found = true;
57}
58
59// key to be assigned later
60Key::Key(std::string name, u8 length) :
61 Key(name, {}, {}, length, {})
62{
63}
64
65// declare only
66Key::Key() :
67 Key({}, {}, {}, {}, {})
68{
69}
70
71void Key::save_key(std::ofstream &file) {
72 if (!found())
73 return;
74
75 // format: <keyname> = <hex key> for hactool and similar tools
76 char key_chars[3] = "00";
77 file.write(name.c_str(), name.size());
78 file.write(" = ", 3);
79 for (u8 c : key) {
80 sprintf(key_chars, "%02x", c);
81 file.write(key_chars, 2);
82 }
83 file.write("\n", 1);
84
85 saved_key_count++;
86}
87
88byte_vector Key::aes_decrypt_ctr(const byte_vector &data, byte_vector iv) {
89 byte_vector dest(data.size());
90 if (!found())
91 return dest;
92
93 // used internally
94 size_t nc_off = 0;
95 u8 stream_block[0x10];
96
97 mbedtls_aes_context dec;
98 mbedtls_aes_init(&dec);
99 mbedtls_aes_setkey_enc(&dec, key.data(), length * 8);
100 mbedtls_aes_crypt_ctr(&dec, data.size(), &nc_off, iv.data(), stream_block, data.data(), dest.data());
101 mbedtls_aes_free(&dec);
102
103 return dest;
104}
105
106byte_vector Key::aes_decrypt_ecb(const byte_vector &data) {
107 byte_vector dest(data.size());
108 if (!found())
109 return dest;
110
111 mbedtls_aes_context dec;
112 mbedtls_aes_init(&dec);
113 mbedtls_aes_setkey_dec(&dec, key.data(), length * 8);
114 for (size_t offset = 0; offset < data.size(); offset += 0x10)
115 mbedtls_aes_crypt_ecb(&dec, MBEDTLS_AES_DECRYPT, data.data() + offset, dest.data() + offset);
116 mbedtls_aes_free(&dec);
117
118 return dest;
119}
120
121byte_vector Key::cmac(byte_vector data) {
122 byte_vector dest(data.size());
123 if (!found())
124 return dest;
125
126 mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), key.data(), length * 8, data.data(), data.size(), dest.data());
127
128 return dest;
129}
130
131void Key::find_key(const byte_vector &buffer) {
132 if ((buffer.size() == 0) || (found()))
133 return;
134
135 u8 temp_hash[0x20];
136
137 if (buffer.size() == length) {
138 Common::sha256(buffer.data(), temp_hash, length);
139 if (!std::equal(hash.begin(), hash.end(), temp_hash))
140 return;
141 std::copy(buffer.begin(), buffer.begin() + length, std::back_inserter(key));
142 is_found = true;
143 }
144
145 // hash every length-sized byte chunk in buffer until it matches member hash
146 for (size_t i = 0; i < buffer.size() - length; i++) {
147 if (xx_hash == XXHash64::hash(buffer.data() + i, length, 0)) {
148 // double-check sha256 since xxhash64 isn't as collision-safe
149 Common::sha256(buffer.data() + i, temp_hash, length);
150 if (!std::equal(hash.begin(), hash.end(), temp_hash))
151 continue;
152 std::copy(buffer.begin() + i, buffer.begin() + i + length, std::back_inserter(key));
153 is_found = true;
154 break;
155 }
156 }
157}
158
159 byte_vector Key::generate_kek(Key &master_key, const Key &kek_seed, const Key &key_seed) {
160 Key kek(master_key.aes_decrypt_ecb(kek_seed.key), 0x10);
161 Key srcKek(kek.aes_decrypt_ecb(key), 0x10);
162 if (key_seed.found())
163 return srcKek.aes_decrypt_ecb(key_seed.key);
164 else
165 return srcKek.key;
166} \ No newline at end of file