diff options
Diffstat (limited to 'source/Key.cpp')
-rw-r--r-- | source/Key.cpp | 166 |
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 | |||
28 | size_t Key::saved_key_count = 0; | ||
29 | |||
30 | Key::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 | ||
40 | Key::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 | ||
46 | Key::Key(std::string name, u8 length, byte_vector key) : | ||
47 | Key(name, {}, {}, length, key) | ||
48 | { | ||
49 | is_found = true; | ||
50 | } | ||
51 | |||
52 | // nameless key | ||
53 | Key::Key(byte_vector key, u8 length) : | ||
54 | Key({}, {}, {}, length, key) | ||
55 | { | ||
56 | is_found = true; | ||
57 | } | ||
58 | |||
59 | // key to be assigned later | ||
60 | Key::Key(std::string name, u8 length) : | ||
61 | Key(name, {}, {}, length, {}) | ||
62 | { | ||
63 | } | ||
64 | |||
65 | // declare only | ||
66 | Key::Key() : | ||
67 | Key({}, {}, {}, {}, {}) | ||
68 | { | ||
69 | } | ||
70 | |||
71 | void 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 | |||
88 | byte_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 | |||
106 | byte_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 | |||
121 | byte_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 | |||
131 | void 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 | ||