diff options
Diffstat (limited to 'utils/nwztools/upgtools/upgtool.c')
-rw-r--r-- | utils/nwztools/upgtools/upgtool.c | 423 |
1 files changed, 187 insertions, 236 deletions
diff --git a/utils/nwztools/upgtools/upgtool.c b/utils/nwztools/upgtools/upgtool.c index fc5cf0fb92..065cede63c 100644 --- a/utils/nwztools/upgtools/upgtool.c +++ b/utils/nwztools/upgtools/upgtool.c | |||
@@ -69,9 +69,9 @@ struct nwz_model_t | |||
69 | { | 69 | { |
70 | const char *model; | 70 | const char *model; |
71 | unsigned flags; | 71 | unsigned flags; |
72 | char kas[NWZ_KAS_SIZE]; /* key and signature */ | 72 | char *kas; |
73 | char key[8]; | 73 | char *key; |
74 | char sig[8]; | 74 | char *sig; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | struct upg_md5_t | 77 | struct upg_md5_t |
@@ -81,7 +81,7 @@ struct upg_md5_t | |||
81 | 81 | ||
82 | struct upg_header_t | 82 | struct upg_header_t |
83 | { | 83 | { |
84 | char sig[8]; | 84 | char sig[NWZ_SIG_SIZE]; |
85 | uint32_t nr_files; | 85 | uint32_t nr_files; |
86 | uint32_t pad; // make sure structure size is a multiple of 8 | 86 | uint32_t pad; // make sure structure size is a multiple of 8 |
87 | } __attribute__((packed)); | 87 | } __attribute__((packed)); |
@@ -92,6 +92,72 @@ struct upg_entry_t | |||
92 | uint32_t size; | 92 | uint32_t size; |
93 | } __attribute__((packed)); | 93 | } __attribute__((packed)); |
94 | 94 | ||
95 | /** KAS / Key / Signature | ||
96 | * | ||
97 | * Since this is all very confusing, we need some terminology and notations: | ||
98 | * - [X, Y, Z] is a sequence of bytes, for example: | ||
99 | * [8, 0x89, 42] | ||
100 | * is a sequence of three bytes. | ||
101 | * - "abcdef" is a string: it is a sequences of bytes where each byte happens to | ||
102 | * be the ASCII encoding of a letter. So for example: | ||
103 | * "abc" = [97, 98, 99] | ||
104 | * because 'a' has ASCII encoding 97 and so one | ||
105 | * - HexString(Seq) refers to the string where each byte of the original sequence | ||
106 | * is represented in hexadecimal by two ASCII characters. For example: | ||
107 | * HexString([8, 0x89, 42]) = "08892a" | ||
108 | * because 8 = 0x08 so it represented by "08" and 42 = 0x2a. Note that the length | ||
109 | * of HexString(Seq) is always exactly twice the length of Seq. | ||
110 | * - DES(Seq,Pass) is the result of encrypting Seq with Pass using the DES cipher. | ||
111 | * Seq must be a sequence of 8 bytes (known as a block) and Pass must be a | ||
112 | * sequence of 8 bytes. The result is also a 8-byte sequence. | ||
113 | * - ECB_DES([Block0, Block1, ..., BlockN], Pass) | ||
114 | * = [DES(Block0,Pass), DES(Block1,Pass), ..., DES(BlockN,Pass)] | ||
115 | * where Blocki is a block (8 byte). | ||
116 | * | ||
117 | * | ||
118 | * A firmware upgrade file is always encrypted using a Key. To authenticate it, | ||
119 | * the upgrade file (before encryption) contains a Sig(nature). The pair (Key,Sig) | ||
120 | * is refered to as KeySig and is specific to each series. For example all | ||
121 | * NWZ-E46x use the same KeySig but the NWZ-E46x and NWZ-A86x use different KeySig. | ||
122 | * In the details, a Key is a sequence of 8 bytes and a Sig is also a sequence | ||
123 | * of 8 bytes. A KeySig is a simply the concatenation of the Key followed by | ||
124 | * the Sig, so it is a sequence of 16 bytes. Probably in an attempt to obfuscate | ||
125 | * things a little further, Sony never provides the KeySig directly but instead | ||
126 | * encrypts it using DES in ECB mode using a hardcoded password and provides | ||
127 | * the hexadecimal string of the result, known as the KAS, which is thus a string | ||
128 | * of 32 ASCII characters. | ||
129 | * Note that since DES works on blocks of 8 bytes and ECB encrypts blocks | ||
130 | * independently, it is the same to encrypt the KeySig as once or encrypt the Key | ||
131 | * and Sig separately. | ||
132 | * | ||
133 | * To summarize: | ||
134 | * Key = [K0, K1, K2, ..., K7] (8 bytes) (model specific) | ||
135 | * Sig = [S0, S1, S2, ..., S7] (8 bytes) (model specific) | ||
136 | * KeySig = [Key, Sig] = [K0, ... K7, S0, ..., S7] (16 bytes) | ||
137 | * FwpPass = "ed295076" (8 bytes) (never changes) | ||
138 | * EncKeySig = ECB_DES(KeySig, FwpPass) = [DES(Key, FwpPass), DES(Sig, FwpPass)] | ||
139 | * KAS = HexString(EncKeySig) (32 characters) | ||
140 | * | ||
141 | * In theory, the Key and Sig can be any 8-byte sequence. In practice, they always | ||
142 | * are strings, probably to make it easier to write them down. In many cases, the | ||
143 | * Key and Sig are even the hexadecimal string of 4-byte sequences but it is | ||
144 | * unclear if this is the result of pure luck, confused engineers, lazyness on | ||
145 | * Sony's part or by design. The following code assumes that Key and Sig are | ||
146 | * strings (though it could easily be fixed to work with anything if this is | ||
147 | * really needed). | ||
148 | * | ||
149 | * | ||
150 | * Here is a real example, from the NWZ-E46x Series: | ||
151 | * Key = "6173819e" (note that this is a string and even a hex string in this case) | ||
152 | * Sig = "30b82e5c" | ||
153 | * KeySig = [Key, Sig] = "6173819e30b82e5c" | ||
154 | * FwpPass = "ed295076" (never changes) | ||
155 | * EncKeySig = ECB_DES(KeySig, FwpPass) | ||
156 | * = [0x8a, 0x01, 0xb6, ..., 0xc5] (16 bytes) | ||
157 | * KAS = HexString(EncKeySig) = "8a01b624bfbfde4a1662a1772220e3c5" | ||
158 | * | ||
159 | */ | ||
160 | |||
95 | struct nwz_model_t g_model_list[] = | 161 | struct nwz_model_t g_model_list[] = |
96 | { | 162 | { |
97 | { "nwz-e45x", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, "8a01b624bfbfde4a1662a1772220e3c5", "6173819e", "30b82e5c"}, | 163 | { "nwz-e45x", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, "8a01b624bfbfde4a1662a1772220e3c5", "6173819e", "30b82e5c"}, |
@@ -99,7 +165,7 @@ struct nwz_model_t g_model_list[] = | |||
99 | { "nwz-a86x", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, "a7c4af6c28b8900a783f307c1ba538c5", "c824e4e2", "7c262bb0" }, | 165 | { "nwz-a86x", HAS_KAS | HAS_KEY | HAS_SIG | CONFIRMED, "a7c4af6c28b8900a783f307c1ba538c5", "c824e4e2", "7c262bb0" }, |
100 | /* The following keys were obtained by brute forcing firmware upgrades, | 166 | /* The following keys were obtained by brute forcing firmware upgrades, |
101 | * someone with a device needs to confirm that they work */ | 167 | * someone with a device needs to confirm that they work */ |
102 | { "nw-a82x", HAS_KEY | HAS_SIG, {""}, "4df06482", "07fa0b6e" }, | 168 | { "nw-a82x", HAS_KEY | HAS_SIG, "", "4df06482", "07fa0b6e" }, |
103 | }; | 169 | }; |
104 | 170 | ||
105 | static int digit_value(char c) | 171 | static int digit_value(char c) |
@@ -115,15 +181,14 @@ static char hex_digit(unsigned v) | |||
115 | return (v < 10) ? v + '0' : (v < 16) ? v - 10 + 'a' : 'x'; | 181 | return (v < 10) ? v + '0' : (v < 16) ? v - 10 + 'a' : 'x'; |
116 | } | 182 | } |
117 | 183 | ||
118 | static int decrypt_keysig(char keysig[NWZ_KEYSIG_SIZE]) | 184 | static int decrypt_keysig(const char kas[NWZ_KAS_SIZE], char key[NWZ_KEY_SIZE], |
185 | char sig[NWZ_SIG_SIZE]) | ||
119 | { | 186 | { |
120 | uint8_t src[16]; | 187 | uint8_t src[NWZ_KAS_SIZE / 2]; |
121 | for(int i = 32; i < NWZ_KEYSIG_SIZE; i++) | 188 | for(int index = 0; index < NWZ_KAS_SIZE / 2; index++) |
122 | keysig[i] = 0; | ||
123 | for(int index = 0; index < 16; index++) | ||
124 | { | 189 | { |
125 | int a = digit_value(keysig[index * 2]); | 190 | int a = digit_value(kas[index * 2]); |
126 | int b = digit_value(keysig[index * 2 + 1]); | 191 | int b = digit_value(kas[index * 2 + 1]); |
127 | if(a < 0 || b < 0) | 192 | if(a < 0 || b < 0) |
128 | { | 193 | { |
129 | cprintf(GREY, "Invalid KAS !\n"); | 194 | cprintf(GREY, "Invalid KAS !\n"); |
@@ -133,166 +198,161 @@ static int decrypt_keysig(char keysig[NWZ_KEYSIG_SIZE]) | |||
133 | } | 198 | } |
134 | fwp_setkey("ed295076"); | 199 | fwp_setkey("ed295076"); |
135 | fwp_crypt(src, sizeof(src), 1); | 200 | fwp_crypt(src, sizeof(src), 1); |
136 | memcpy(keysig + 33, src, 8); | 201 | memcpy(key, src, NWZ_KEY_SIZE); |
137 | memcpy(keysig + 42, src + 8, 8); | 202 | memcpy(sig, src + NWZ_KEY_SIZE, NWZ_SIG_SIZE); |
138 | return 0; | 203 | return 0; |
139 | } | 204 | } |
140 | 205 | ||
141 | static bool upg_notify_keysig(void *user, uint8_t key[8], uint8_t sig[8]) | 206 | static void encrypt_keysig(char kas[NWZ_KEY_SIZE], |
207 | const char key[NWZ_SIG_SIZE], const char sig[NWZ_KAS_SIZE]) | ||
142 | { | 208 | { |
143 | memcpy(user + 33, key, 8); | 209 | uint8_t src[NWZ_KAS_SIZE / 2]; |
144 | memcpy(user + 42, sig, 8); | 210 | fwp_setkey("ed295076"); |
145 | return true; | 211 | memcpy(src, key, NWZ_KEY_SIZE); |
212 | memcpy(src + NWZ_KEY_SIZE, sig, NWZ_SIG_SIZE); | ||
213 | fwp_crypt(src, sizeof(src), 0); | ||
214 | for(int i = 0; i < NWZ_KAS_SIZE / 2; i++) | ||
215 | { | ||
216 | kas[2 * i] = hex_digit((src[i] >> 4) & 0xf); | ||
217 | kas[2 * i + 1] = hex_digit(src[i] & 0xf); | ||
218 | } | ||
146 | } | 219 | } |
147 | 220 | ||
148 | static int do_upg(void *buf, long size) | 221 | /* user needs to be pointer to a NWZ_KEYSIG_SIZE-byte buffer, on success g_key |
222 | * and g_sig are updated to point to the key and sig in the buffer */ | ||
223 | static bool upg_notify_keysig(void *user, uint8_t key[NWZ_KEY_SIZE], | ||
224 | uint8_t sig[NWZ_SIG_SIZE]) | ||
149 | { | 225 | { |
150 | struct upg_md5_t *md5 = buf; | 226 | g_key = user; |
151 | cprintf(BLUE, "Preliminary\n"); | 227 | g_sig = user + NWZ_KEY_SIZE; |
152 | cprintf(GREEN, " MD5: "); | 228 | memcpy(g_key, key, NWZ_KEY_SIZE); |
153 | for(int i = 0; i < 16; i++) | 229 | memcpy(g_sig, sig, NWZ_SIG_SIZE); |
154 | cprintf(YELLOW, "%02x", md5->md5[i]); | 230 | return true; |
155 | printf(" "); | 231 | } |
156 | |||
157 | uint8_t actual_md5[MD5_DIGEST_LENGTH]; | ||
158 | { | ||
159 | MD5_CTX c; | ||
160 | MD5_Init(&c); | ||
161 | MD5_Update(&c, md5 + 1, size - sizeof(struct upg_header_t)); | ||
162 | MD5_Final(actual_md5, &c); | ||
163 | } | ||
164 | check_field(memcmp(actual_md5, md5->md5, 16), 0, "Ok\n", "Mismatch\n"); | ||
165 | 232 | ||
166 | if(g_model_index == -1 && g_keysig_search == KEYSIG_SEARCH_NONE && g_key == NULL && g_kas == NULL) | 233 | static int get_key_and_sig(bool is_extract, void *encrypted_hdr) |
234 | { | ||
235 | static char keysig[NWZ_KEYSIG_SIZE]; | ||
236 | static char kas[NWZ_KAS_SIZE]; | ||
237 | /* database lookup */ | ||
238 | if(g_model_index != -1) | ||
167 | { | 239 | { |
168 | cprintf(GREY, "A KAS or a keysig is needed to decrypt the firmware\n"); | 240 | if(g_model_list[g_model_index].flags & HAS_KAS) |
169 | cprintf(GREY, "You have the following options(see help for more details):\n"); | 241 | g_kas = g_model_list[g_model_index].kas; |
170 | cprintf(GREY, "- select a model with a known KAS\n"); | 242 | if(g_model_list[g_model_index].flags & HAS_KEY) |
171 | cprintf(GREY, "- specify an explicit KAS or key(+optional sig)\n"); | 243 | g_key = g_model_list[g_model_index].key; |
172 | cprintf(GREY, "- let me try to find the keysig(slow !)\n"); | 244 | if(g_model_list[g_model_index].flags & HAS_SIG) |
173 | return 1; | 245 | g_sig = g_model_list[g_model_index].sig; |
174 | } | 246 | } |
175 | 247 | ||
176 | char kas[NWZ_KAS_SIZE]; | 248 | /* always prefer KAS because it contains everything */ |
177 | char keysig[NWZ_KEYSIG_SIZE]; | ||
178 | |||
179 | memset(kas, '?', NWZ_KAS_SIZE); | ||
180 | memset(keysig, '?', NWZ_KEYSIG_SIZE); | ||
181 | keysig[32] = keysig[41] = keysig[50] = 0; | ||
182 | |||
183 | if(g_kas) | 249 | if(g_kas) |
184 | { | 250 | { |
185 | if(strlen(g_kas) != NWZ_KAS_SIZE) | 251 | if(strlen(g_kas) != NWZ_KAS_SIZE) |
186 | { | 252 | { |
187 | cprintf(GREY, "The specified KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE); | 253 | cprintf(GREY, "The KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE); |
188 | return 4; | 254 | return 4; |
189 | } | 255 | } |
190 | memcpy(keysig, g_kas, NWZ_KAS_SIZE); | 256 | g_key = keysig; |
191 | decrypt_keysig(keysig); | 257 | g_sig = keysig + NWZ_KEY_SIZE; |
192 | g_kas = keysig; | 258 | decrypt_keysig(g_kas, g_key, g_sig); |
193 | g_key = keysig + 33; | ||
194 | g_sig = keysig + 42; | ||
195 | } | 259 | } |
196 | else if(g_key) | 260 | /* fall back to key and signature otherwise. The signature is not required |
261 | * when extracting but prevents from checking decryption */ | ||
262 | else if(g_key && (is_extract || g_sig)) | ||
197 | { | 263 | { |
198 | if(strlen(g_key) != 8) | 264 | if(strlen(g_key) != 8) |
199 | { | 265 | { |
200 | cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n"); | 266 | cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n"); |
201 | return 4; | 267 | return 4; |
202 | } | 268 | } |
203 | if(g_sig && strlen(g_sig) != 8) | 269 | |
270 | /* if there is a signature, it must have the correct size */ | ||
271 | if(g_sig) | ||
204 | { | 272 | { |
205 | cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n"); | 273 | if(strlen(g_sig) != 8) |
206 | return 5; | 274 | { |
275 | cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n"); | ||
276 | return 5; | ||
277 | } | ||
207 | } | 278 | } |
208 | |||
209 | memcpy(keysig + 33, g_key, 8); | ||
210 | if(!g_sig) | ||
211 | cprintf(GREY, "Warning: you have specified a key but no sig, I won't be able to do any checks\n"); | ||
212 | else | 279 | else |
213 | memcpy(keysig + 42, g_sig, 8); | 280 | { |
214 | g_key = keysig + 33; | 281 | cprintf(GREY, "Warning: you have specified a key but no sig, I won't be able to do any checks\n"); |
215 | if(g_sig) | 282 | } |
216 | g_sig = keysig + 42; | ||
217 | } | 283 | } |
218 | else if(g_model_index == -1) | 284 | /* for extraction, we offer a brute force search method from the MD5 */ |
285 | else if(is_extract && g_keysig_search != KEYSIG_SEARCH_NONE) | ||
219 | { | 286 | { |
220 | cprintf(BLUE, "keysig Search\n"); | 287 | cprintf(BLUE, "keysig Search\n"); |
221 | cprintf_field(" Method: ", "%s\n", keysig_search_desc[g_keysig_search].name); | 288 | cprintf_field(" Method: ", "%s\n", keysig_search_desc[g_keysig_search].name); |
222 | bool ok = keysig_search_desc[g_keysig_search].fn((void *)(md5 + 1), &upg_notify_keysig, keysig); | 289 | bool ok = keysig_search_desc[g_keysig_search].fn(encrypted_hdr, &upg_notify_keysig, keysig); |
223 | cprintf(GREEN, " Result: "); | 290 | cprintf(GREEN, " Result: "); |
224 | cprintf(ok ? YELLOW : RED, "%s\n", ok ? "Key found" : "No key found"); | 291 | cprintf(ok ? YELLOW : RED, "%s\n", ok ? "Key found" : "No key found"); |
225 | if(!ok) | 292 | if(!ok) |
226 | return 2; | 293 | return 2; |
227 | g_key = keysig + 33; | ||
228 | g_sig = keysig + 42; | ||
229 | } | 294 | } |
230 | else | 295 | else |
231 | { | 296 | { |
232 | if(g_model_list[g_model_index].flags & HAS_KAS) | 297 | cprintf(GREY, "A KAS or a keysig is needed to decrypt the firmware\n"); |
233 | g_kas = g_model_list[g_model_index].kas; | 298 | cprintf(GREY, "You have the following options(see help for more details):\n"); |
234 | if(g_model_list[g_model_index].flags & HAS_KEY) | 299 | cprintf(GREY, "- select a model with a known KAS\n"); |
235 | g_key = g_model_list[g_model_index].key; | 300 | cprintf(GREY, "- specify an explicit KAS or key+sig\n"); |
236 | if(g_model_list[g_model_index].flags & HAS_SIG) | 301 | if(is_extract) |
237 | g_sig = g_model_list[g_model_index].sig; | 302 | cprintf(GREY, "- let me try to find the keysig(slow !)\n"); |
238 | 303 | return 1; | |
239 | if(g_kas) | ||
240 | { | ||
241 | memcpy(keysig, g_kas, NWZ_KAS_SIZE); | ||
242 | decrypt_keysig(keysig); | ||
243 | g_kas = keysig; | ||
244 | g_key = keysig + 33; | ||
245 | g_sig = keysig + 42; | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | if(g_key) | ||
250 | { | ||
251 | memcpy(keysig + 33, g_key, 8); | ||
252 | g_key = keysig + 33; | ||
253 | } | ||
254 | if(g_sig) | ||
255 | { | ||
256 | memcpy(keysig + 42, g_sig, 8); | ||
257 | g_sig = keysig + 42; | ||
258 | } | ||
259 | } | ||
260 | } | 304 | } |
261 | 305 | ||
306 | /* If we only have the key and signature, we can create a "fake" KAS | ||
307 | * that decrypts to the same key and signature. Since it is not unique, | ||
308 | * it will generally not match the "official" one from Sony but will produce | ||
309 | * valid files anyway */ | ||
262 | if(!g_kas) | 310 | if(!g_kas) |
263 | { | 311 | { |
264 | g_kas = keysig; | 312 | if(!g_sig) |
265 | fwp_setkey("ed295076"); | ||
266 | if(g_key) | ||
267 | { | ||
268 | memcpy(kas, g_key, 8); | ||
269 | fwp_crypt(kas, 8, 0); | ||
270 | for(int i = 0; i < 8; i++) | ||
271 | { | ||
272 | g_kas[2 * i] = hex_digit((kas[i] >> 4) & 0xf); | ||
273 | g_kas[2 * i + 1] = hex_digit(kas[i] & 0xf); | ||
274 | } | ||
275 | } | ||
276 | if(g_sig) | ||
277 | { | 313 | { |
278 | memcpy(kas + 8, g_sig, 8); | 314 | /* if we extract and don't have a signature, just use a random |
279 | fwp_crypt(kas + 8, 8, 0); | 315 | * one, we cannot check it anyway */ |
280 | for(int i = 8; i < 16; i++) | 316 | g_sig = keysig; |
281 | { | 317 | memset(g_sig, '?', NWZ_SIG_SIZE); |
282 | g_kas[2 * i] = hex_digit((kas[i] >> 4) & 0xf); | ||
283 | g_kas[2 * i + 1] = hex_digit(kas[i] & 0xf); | ||
284 | } | ||
285 | } | 318 | } |
319 | g_kas = kas; | ||
320 | encrypt_keysig(g_kas, g_key, g_sig); | ||
286 | } | 321 | } |
287 | 322 | ||
288 | cprintf(BLUE, "Keys\n"); | 323 | cprintf(BLUE, "Keys\n"); |
289 | cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas); | 324 | cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas); |
290 | cprintf_field(" Key: ", "%s\n", g_key); | 325 | cprintf_field(" Key: ", "%."STR(NWZ_KEY_SIZE)"s\n", g_key); |
291 | if(g_sig) | 326 | if(g_sig) |
292 | cprintf_field(" Sig: ", "%s\n", g_sig); | 327 | cprintf_field(" Sig: ", "%."STR(NWZ_SIG_SIZE)"s\n", g_sig); |
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int do_upg(void *buf, long size) | ||
333 | { | ||
334 | struct upg_md5_t *md5 = buf; | ||
335 | cprintf(BLUE, "Preliminary\n"); | ||
336 | cprintf(GREEN, " MD5: "); | ||
337 | for(int i = 0; i < 16; i++) | ||
338 | cprintf(YELLOW, "%02x", md5->md5[i]); | ||
339 | printf(" "); | ||
340 | |||
341 | uint8_t actual_md5[MD5_DIGEST_LENGTH]; | ||
342 | { | ||
343 | MD5_CTX c; | ||
344 | MD5_Init(&c); | ||
345 | MD5_Update(&c, md5 + 1, size - sizeof(struct upg_header_t)); | ||
346 | MD5_Final(actual_md5, &c); | ||
347 | } | ||
348 | check_field(memcmp(actual_md5, md5->md5, 16), 0, "Ok\n", "Mismatch\n"); | ||
349 | |||
350 | int ret = get_key_and_sig(true, md5 + 1); | ||
351 | if(ret != 0) | ||
352 | return ret; | ||
293 | 353 | ||
294 | struct upg_header_t *hdr = (void *)(md5 + 1); | 354 | struct upg_header_t *hdr = (void *)(md5 + 1); |
295 | int ret = fwp_read(hdr, sizeof(struct upg_header_t), hdr, (void *)g_key); | 355 | ret = fwp_read(hdr, sizeof(struct upg_header_t), hdr, (void *)g_key); |
296 | if(ret) | 356 | if(ret) |
297 | return ret; | 357 | return ret; |
298 | 358 | ||
@@ -336,7 +396,6 @@ static int do_upg(void *buf, long size) | |||
336 | return ret; | 396 | return ret; |
337 | // but write the *good* amount of data | 397 | // but write the *good* amount of data |
338 | fwrite(buf + entry->offset, 1, entry->size, f); | 398 | fwrite(buf + entry->offset, 1, entry->size, f); |
339 | |||
340 | fclose(f); | 399 | fclose(f); |
341 | } | 400 | } |
342 | else | 401 | else |
@@ -414,118 +473,10 @@ static int create_upg(int argc, char **argv) | |||
414 | printf("You must specify a firmware filename\n"); | 473 | printf("You must specify a firmware filename\n"); |
415 | usage(); | 474 | usage(); |
416 | } | 475 | } |
417 | |||
418 | if(g_model_index == -1 && (g_key == NULL || g_sig == NULL) && g_kas == NULL) | ||
419 | { | ||
420 | cprintf(GREY, "A KAS or a keysig is needed to encrypt the firmware\n"); | ||
421 | cprintf(GREY, "You have the following options(see help for more details):\n"); | ||
422 | cprintf(GREY, "- select a model with a known KAS\n"); | ||
423 | cprintf(GREY, "- specify an explicit KAS or key+sig\n"); | ||
424 | return 1; | ||
425 | } | ||
426 | |||
427 | char kas[NWZ_KAS_SIZE]; | ||
428 | char keysig[NWZ_KEYSIG_SIZE]; | ||
429 | 476 | ||
430 | memset(kas, '?', NWZ_KAS_SIZE); | 477 | int ret = get_key_and_sig(false, NULL); |
431 | memset(keysig, '?', NWZ_KEYSIG_SIZE); | 478 | if(ret != 0) |
432 | keysig[32] = keysig[41] = keysig[50] = 0; | 479 | return ret; |
433 | |||
434 | if(g_kas) | ||
435 | { | ||
436 | if(strlen(g_kas) != NWZ_KAS_SIZE) | ||
437 | { | ||
438 | cprintf(GREY, "The specified KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE); | ||
439 | return 4; | ||
440 | } | ||
441 | memcpy(keysig, g_kas, NWZ_KAS_SIZE); | ||
442 | decrypt_keysig(keysig); | ||
443 | g_kas = keysig; | ||
444 | g_key = keysig + 33; | ||
445 | g_sig = keysig + 42; | ||
446 | } | ||
447 | else if(g_key) | ||
448 | { | ||
449 | if(strlen(g_key) != 8) | ||
450 | { | ||
451 | cprintf(GREY, "The specified key has wrong length (must be 8 hex digits)\n"); | ||
452 | return 4; | ||
453 | } | ||
454 | if(strlen(g_sig) != 8) | ||
455 | { | ||
456 | cprintf(GREY, "The specified sig has wrong length (must be 8 hex digits)\n"); | ||
457 | return 5; | ||
458 | } | ||
459 | |||
460 | memcpy(keysig + 33, g_key, 8); | ||
461 | if(!g_sig) | ||
462 | cprintf(GREY, "Warning: you have specified a key but no sig, I won't be able to do any checks\n"); | ||
463 | else | ||
464 | memcpy(keysig + 42, g_sig, 8); | ||
465 | g_key = keysig + 33; | ||
466 | g_sig = keysig + 42; | ||
467 | } | ||
468 | else if(g_model_index != -1) | ||
469 | { | ||
470 | if(g_model_list[g_model_index].flags & HAS_KAS) | ||
471 | g_kas = g_model_list[g_model_index].kas; | ||
472 | if(g_model_list[g_model_index].flags & HAS_KEY) | ||
473 | g_key = g_model_list[g_model_index].key; | ||
474 | if(g_model_list[g_model_index].flags & HAS_SIG) | ||
475 | g_sig = g_model_list[g_model_index].sig; | ||
476 | |||
477 | if(g_key && g_sig) | ||
478 | { | ||
479 | memcpy(keysig + 33, g_key, 8); | ||
480 | g_key = keysig + 33; | ||
481 | memcpy(keysig + 42, g_sig, 8); | ||
482 | g_sig = keysig + 42; | ||
483 | } | ||
484 | else if(g_kas) | ||
485 | { | ||
486 | memcpy(keysig, g_kas, NWZ_KAS_SIZE); | ||
487 | decrypt_keysig(keysig); | ||
488 | g_kas = keysig; | ||
489 | g_key = keysig + 33; | ||
490 | g_sig = keysig + 42; | ||
491 | } | ||
492 | else | ||
493 | { | ||
494 | printf("Target doesn't have enough information to get key and sig\n"); | ||
495 | return 1; | ||
496 | } | ||
497 | } | ||
498 | else | ||
499 | { | ||
500 | printf("Kill me\n"); | ||
501 | return 1; | ||
502 | } | ||
503 | |||
504 | if(!g_kas) | ||
505 | { | ||
506 | g_kas = keysig; | ||
507 | fwp_setkey("ed295076"); | ||
508 | memcpy(kas, g_key, 8); | ||
509 | fwp_crypt(kas, 8, 0); | ||
510 | for(int i = 0; i < 8; i++) | ||
511 | { | ||
512 | g_kas[2 * i] = hex_digit((kas[i] >> 4) & 0xf); | ||
513 | g_kas[2 * i + 1] = hex_digit(kas[i] & 0xf); | ||
514 | } | ||
515 | memcpy(kas + 8, g_sig, 8); | ||
516 | fwp_crypt(kas + 8, 8, 0); | ||
517 | for(int i = 8; i < 16; i++) | ||
518 | { | ||
519 | g_kas[2 * i] = hex_digit((kas[i] >> 4) & 0xf); | ||
520 | g_kas[2 * i + 1] = hex_digit(kas[i] & 0xf); | ||
521 | } | ||
522 | } | ||
523 | |||
524 | cprintf(BLUE, "Keys\n"); | ||
525 | cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE)"s\n", g_kas); | ||
526 | cprintf_field(" Key: ", "%s\n", g_key); | ||
527 | if(g_sig) | ||
528 | cprintf_field(" Sig: ", "%s\n", g_sig); | ||
529 | 480 | ||
530 | FILE *fout = fopen(argv[0], "wb"); | 481 | FILE *fout = fopen(argv[0], "wb"); |
531 | if(fout == NULL) | 482 | if(fout == NULL) |
@@ -558,8 +509,8 @@ static int create_upg(int argc, char **argv) | |||
558 | memcpy(hdr.sig, g_sig, 8); | 509 | memcpy(hdr.sig, g_sig, 8); |
559 | hdr.nr_files = nr_files; | 510 | hdr.nr_files = nr_files; |
560 | hdr.pad = 0; | 511 | hdr.pad = 0; |
561 | 512 | ||
562 | int ret = fwp_write(&hdr, sizeof(hdr), &hdr, (void *)g_key); | 513 | ret = fwp_write(&hdr, sizeof(hdr), &hdr, (void *)g_key); |
563 | if(ret) | 514 | if(ret) |
564 | return ret; | 515 | return ret; |
565 | MD5_Update(&c, &hdr, sizeof(hdr)); | 516 | MD5_Update(&c, &hdr, sizeof(hdr)); |
@@ -573,7 +524,7 @@ static int create_upg(int argc, char **argv) | |||
573 | entry.offset = offset; | 524 | entry.offset = offset; |
574 | entry.size = filesize(files[i]); | 525 | entry.size = filesize(files[i]); |
575 | offset += ROUND_UP(entry.size, 8); // do it before encryption !! | 526 | offset += ROUND_UP(entry.size, 8); // do it before encryption !! |
576 | 527 | ||
577 | ret = fwp_write(&entry, sizeof(entry), &entry, (void *)g_key); | 528 | ret = fwp_write(&entry, sizeof(entry), &entry, (void *)g_key); |
578 | if(ret) | 529 | if(ret) |
579 | return ret; | 530 | return ret; |