1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2012 Amaury Pouly
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
32 #include <openssl/md5.h>
35 #include "keysig_search.h"
38 #define MIN(a,b) ((a) < (b) ? (a) : (b))
42 static char *g_out_prefix
= NULL
;
43 static char *g_in_file
= NULL
;
45 static const char *g_model
= NULL
;
46 static int g_model_index
= -1;
47 static char *g_kas
= NULL
;
48 static char *g_key
= NULL
;
49 static char *g_sig
= NULL
;
51 enum keysig_search_method_t g_keysig_search
= KEYSIG_SEARCH_NONE
;
54 #define let_the_force_flow(x) do { if(!g_force) return x; } while(0)
55 #define continue_the_force(x) if(x) let_the_force_flow(x)
57 #define check_field(v_exp, v_have, str_ok, str_bad) \
58 if((v_exp) != (v_have)) \
59 { cprintf(RED, str_bad); let_the_force_flow(__LINE__); } \
60 else { cprintf(RED, str_ok); }
62 static void print_hex(void *p
, int size
, int unit
)
67 for(int i
= 0; i
< size
; i
+= unit
, p8
++, p16
++, p32
++)
69 if(i
!= 0 && (i
% 16) == 0)
74 printf(" %04x", *p16
);
76 printf(" %08x", *p32
);
80 /* key and signature */
83 char kas
[NWZ_KAS_SIZE
];
86 #define HAS_KAS (1 << 0)
87 #define HAS_KEY (1 << 1)
88 #define HAS_SIG (1 << 2)
89 #define CONFIRMED (1 << 3)
103 }__attribute__((packed
));
110 } __attribute__((packed
));
116 } __attribute__((packed
));
118 struct nwz_model_t g_model_list
[] =
120 { "nwz-e463", HAS_KAS
| HAS_KEY
| HAS_SIG
| CONFIRMED
, {"89d813f8f966efdebd9c9e0ea98156d2"}, "eb4431eb", "4f1d9cac" },
121 { "nwz-a86x", HAS_KEY
| HAS_SIG
, {""}, "c824e4e2", "7c262bb0" },
122 { "nw-a82x", HAS_KEY
| HAS_SIG
, {""}, "4df06482", "07fa0b6e" },
125 static int digit_value(char c
)
127 if(c
>= '0' && c
<= '9') return c
- '0';
128 if(c
>= 'a' && c
<= 'f') return c
- 'a' + 10;
129 if(c
>= 'A' && c
<= 'F') return c
- 'A' + 10;
133 static char hex_digit(unsigned v
)
135 return (v
< 10) ? v
+ '0' : (v
< 16) ? v
- 10 + 'a' : 'x';
138 static int decrypt_keysig(char keysig
[NWZ_KEYSIG_SIZE
])
141 for(int i
= 32; i
< NWZ_KEYSIG_SIZE
; i
++)
143 for(int index
= 0; index
< 16; index
++)
145 int a
= digit_value(keysig
[index
* 2]);
146 int b
= digit_value(keysig
[index
* 2 + 1]);
149 cprintf(GREY
, "Invalid KAS !\n");
152 src
[index
] = a
<< 4 | b
;
154 fwp_setkey("ed295076");
155 fwp_crypt(src
, sizeof(src
), 1);
156 memcpy(keysig
+ 33, src
, 8);
157 memcpy(keysig
+ 42, src
+ 8, 8);
161 static bool upg_notify_keysig(void *user
, uint8_t key
[8], uint8_t sig
[8])
163 memcpy(user
+ 33, key
, 8);
164 memcpy(user
+ 42, sig
, 8);
168 static int do_upg(void *buf
, long size
)
170 struct upg_md5_t
*md5
= buf
;
171 cprintf(BLUE
, "Preliminary\n");
172 cprintf(GREEN
, " MD5: ");
173 for(int i
= 0; i
< 16; i
++)
174 cprintf(YELLOW
, "%02x", md5
->md5
[i
]);
177 uint8_t actual_md5
[MD5_DIGEST_LENGTH
];
181 MD5_Update(&c
, md5
+ 1, size
- sizeof(struct upg_header_t
));
182 MD5_Final(actual_md5
, &c
);
184 check_field(memcmp(actual_md5
, md5
->md5
, 16), 0, "Ok\n", "Mismatch\n");
186 if(g_model_index
== -1 && g_keysig_search
== KEYSIG_SEARCH_NONE
&& g_key
== NULL
&& g_kas
== NULL
)
188 cprintf(GREY
, "A KAS or a keysig is needed to decrypt the firmware\n");
189 cprintf(GREY
, "You have the following options(see hel for more details):\n");
190 cprintf(GREY
, "- select a model with a known KAS\n");
191 cprintf(GREY
, "- specify an explicit KAS or key(+optional sig)\n");
192 cprintf(GREY
, "- let me try to find the keysig(slow !)\n");
196 struct nwz_kas_t kas
;
197 char keysig
[NWZ_KEYSIG_SIZE
];
199 memset(kas
.kas
, '?', NWZ_KAS_SIZE
);
200 memset(keysig
, '?', NWZ_KEYSIG_SIZE
);
201 keysig
[32] = keysig
[41] = keysig
[50] = 0;
205 if(strlen(g_kas
) != NWZ_KAS_SIZE
)
207 cprintf(GREY
, "The specified KAS has wrong length (must be %d hex digits)\n", NWZ_KAS_SIZE
);
210 memcpy(keysig
, g_kas
, NWZ_KAS_SIZE
);
211 decrypt_keysig(keysig
);
218 if(strlen(g_key
) != 8)
220 cprintf(GREY
, "The specified key has wrong length (must be 8 hex digits)\n");
223 if(g_sig
&& strlen(g_sig
) != 8)
225 cprintf(GREY
, "The specified sig has wrong length (must be 8 hex digits)\n");
229 memcpy(keysig
+ 33, g_key
, 8);
231 cprintf(GREY
, "Warning: you have specified a key but no sig, I won't be able to do any checks\n");
233 memcpy(keysig
+ 42, g_sig
, 8);
238 else if(g_model_index
== -1)
240 cprintf(BLUE
, "keysig Search\n");
241 cprintf_field(" Method: ", "%s\n", keysig_search_desc
[g_keysig_search
].name
);
242 bool ok
= keysig_search_desc
[g_keysig_search
].fn((void *)(md5
+ 1), &upg_notify_keysig
, keysig
);
243 cprintf(GREEN
, " Result: ");
244 cprintf(ok
? YELLOW
: RED
, "%s\n", ok
? "Key found" : "No key found");
252 if(g_model_list
[g_model_index
].flags
& HAS_KAS
)
253 g_kas
= g_model_list
[g_model_index
].kas
.kas
;
254 if(g_model_list
[g_model_index
].flags
& HAS_KEY
)
255 g_key
= g_model_list
[g_model_index
].key
;
256 if(g_model_list
[g_model_index
].flags
& HAS_SIG
)
257 g_sig
= g_model_list
[g_model_index
].sig
;
261 memcpy(keysig
, g_kas
, NWZ_KAS_SIZE
);
262 decrypt_keysig(keysig
);
271 memcpy(keysig
+ 33, g_key
, 8);
276 memcpy(keysig
+ 42, g_sig
, 8);
285 fwp_setkey("ed295076");
288 memcpy(kas
.kas
, g_key
, 8);
289 fwp_crypt(kas
.kas
, 8, 0);
290 for(int i
= 0; i
< 8; i
++)
292 g_kas
[2 * i
] = hex_digit((kas
.kas
[i
] >> 4) & 0xf);
293 g_kas
[2 * i
+ 1] = hex_digit(kas
.kas
[i
] & 0xf);
298 memcpy(kas
.kas
+ 8, g_sig
, 8);
299 fwp_crypt(kas
.kas
+ 8, 8, 0);
300 for(int i
= 8; i
< 16; i
++)
302 g_kas
[2 * i
] = hex_digit((kas
.kas
[i
] >> 4) & 0xf);
303 g_kas
[2 * i
+ 1] = hex_digit(kas
.kas
[i
] & 0xf);
308 cprintf(BLUE
, "Keys\n");
309 cprintf_field(" KAS: ", "%."STR(NWZ_KAS_SIZE
)"s\n", g_kas
);
310 cprintf_field(" Key: ", "%s\n", g_key
);
312 cprintf_field(" Sig: ", "%s\n", g_sig
);
314 struct upg_header_t
*hdr
= (void *)(md5
+ 1);
315 int ret
= fwp_read(hdr
, sizeof(struct upg_header_t
), hdr
, (void *)g_key
);
319 cprintf(BLUE
, "Header\n");
320 cprintf_field(" Signature:", " ");
321 for(int i
= 0; i
< 8; i
++)
322 cprintf(YELLOW
, "%c", isprint(hdr
->sig
[i
]) ? hdr
->sig
[i
] : '.');
325 check_field(memcmp(hdr
->sig
, g_sig
, 8), 0, " OK\n", " Mismatch\n");
328 cprintf(RED
, " Can't check\n");
329 cprintf_field(" Files: ", "%d\n", hdr
->nr_files
);
330 cprintf_field(" Unk: ", "0x%x\n", hdr
->unk
);
332 cprintf(BLUE
, "Files\n");
333 struct upg_entry_t
*entry
= (void *)(hdr
+ 1);
334 for(unsigned i
= 0; i
< hdr
->nr_files
; i
++, entry
++)
336 int ret
= fwp_read(entry
, sizeof(struct upg_entry_t
), entry
, (void *)g_key
);
339 cprintf(GREY
, " File");
340 cprintf(RED
, " %d\n", i
);
341 cprintf_field(" Offset: ", "0x%x\n", entry
->offset
);
342 cprintf_field(" Size: ", "0x%x\n", entry
->size
);
346 char *str
= malloc(strlen(g_out_prefix
) + 32);
347 sprintf(str
, "%s/%d.bin", g_out_prefix
, i
);
348 FILE *f
= fopen(str
, "wb");
351 int ret
= fwp_read(buf
+ entry
->offset
, entry
->size
,
352 buf
+ entry
->offset
, (void *)g_key
);
355 fwrite(buf
+ entry
->offset
, 1, entry
->size
, f
);
360 cprintf(GREY
, "Cannot open '%s' for writing\n", str
);
367 static void usage(void)
370 printf("Usage: upgtool [options] firmware\n");
371 printf("Options:\n");
372 printf(" -o <prefix>\t\tSet output prefix\n");
373 printf(" -f/--force\t\tForce to continue on errors\n");
374 printf(" -?/--help\t\tDisplay this message\n");
375 printf(" -d/--debug\t\tDisplay debug messages\n");
376 printf(" -c/--no-color\t\tDisable color output\n");
377 printf(" -m/--model <model>\tSelect model (or ? to list them)\n");
378 printf(" -l/--search <method>\tTry to find the keysig\n");
379 printf(" -a/--kas <kas>\tForce KAS\n");
380 printf(" -k/--key <key>\tForce key\n");
381 printf(" -s/--sig <sig>\tForce sig\n");
382 printf("keysig search method:\n");
383 for(int i
= KEYSIG_SEARCH_FIRST
; i
< KEYSIG_SEARCH_LAST
; i
++)
384 printf(" %s\t%s\n", keysig_search_desc
[i
].name
, keysig_search_desc
[i
].comment
);
388 int main(int argc
, char **argv
)
392 static struct option long_options
[] =
394 {"help", no_argument
, 0, '?'},
395 {"debug", no_argument
, 0, 'd'},
396 {"no-color", no_argument
, 0, 'c'},
397 {"force", no_argument
, 0, 'f'},
398 {"model", required_argument
, 0, 'm'},
399 {"search", required_argument
, 0, 'l'},
400 {"kas", required_argument
, 0, 'a'},
401 {"key", required_argument
, 0, 'k'},
402 {"sig", required_argument
, 0, 's'},
406 int c
= getopt_long(argc
, argv
, "?dcfo:m:l:a:k:s:", long_options
, NULL
);
426 g_out_prefix
= optarg
;
432 g_keysig_search
= KEYSIG_SEARCH_NONE
;
433 for(int i
= KEYSIG_SEARCH_FIRST
; i
< KEYSIG_SEARCH_LAST
; i
++)
434 if(strcmp(keysig_search_desc
[i
].name
, optarg
) == 0)
436 if(g_keysig_search
== KEYSIG_SEARCH_NONE
)
438 cprintf(GREY
, "Unknown keysig search method '%s'\n", optarg
);
456 if(g_model
&& strcmp(g_model
, "?") == 0)
458 cprintf(BLUE
, "Model list:\n");
459 for(unsigned i
= 0; i
< sizeof(g_model_list
) / sizeof(g_model_list
[0]); i
++)
461 cprintf(GREEN
, " %s:", g_model_list
[i
].model
);
462 if(g_model_list
[i
].flags
& HAS_KAS
)
464 cprintf(RED
, " kas=");
465 cprintf(YELLOW
, "%."STR(NWZ_KAS_SIZE
)"s", g_model_list
[i
].kas
.kas
);
467 if(g_model_list
[i
].flags
& HAS_KEY
)
469 cprintf(RED
, " key=");
470 cprintf(YELLOW
, "%.8s", g_model_list
[i
].key
);
472 if(g_model_list
[i
].flags
& HAS_SIG
)
474 cprintf(RED
, " sig=");
475 cprintf(YELLOW
, "%.8s", g_model_list
[i
].sig
);
477 if(g_model_list
[i
].flags
& CONFIRMED
)
478 cprintf(RED
, " confirmed");
480 cprintf(RED
, " guessed");
488 for(unsigned i
= 0; i
< sizeof(g_model_list
) / sizeof(g_model_list
[0]); i
++)
489 if(strcmp(g_model
, g_model_list
[i
].model
) == 0)
491 if(g_model_index
== -1)
492 cprintf(GREY
, "Warning: unknown model %s\n", g_model
);
495 if(argc
- optind
!= 1)
501 g_in_file
= argv
[optind
];
502 FILE *fin
= fopen(g_in_file
, "r");
505 perror("Cannot open boot file");
508 fseek(fin
, 0, SEEK_END
);
509 long size
= ftell(fin
);
510 fseek(fin
, 0, SEEK_SET
);
512 void *buf
= malloc(size
);
515 perror("Cannot allocate memory");
519 if(fread(buf
, size
, 1, fin
) != 1)
521 perror("Cannot read file");
527 int ret
= do_upg(buf
, size
);
530 cprintf(GREY
, "Error: %d", ret
);
532 cprintf(GREY
, " (use --force to force processing)");