summaryrefslogtreecommitdiff
path: root/utils/nwztools/upgtools/upgtool.c
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2016-10-27 23:06:16 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2016-10-27 23:06:16 +0200
commit37f95f67fec2b2460903ffa5255b1beeba1731fd (patch)
tree6a932718139104406ab576ba89065c53f8dd20e7 /utils/nwztools/upgtools/upgtool.c
parent794104dd17a28a2db09ca1ed44ba7dfb18a1f0ca (diff)
downloadrockbox-37f95f67fec2b2460903ffa5255b1beeba1731fd.tar.gz
rockbox-37f95f67fec2b2460903ffa5255b1beeba1731fd.zip
nwztools/upgtools: rewrite keysig brute force search
The new search has two new features: - it takes advantage of the fact that DES keys are only 56-bit long (and not 64) - it is now multithreaded As a proof of concept, I ran it on the A10 series firmware upgrade and was able to find the key in a few seconds using 4 threads. The search is still limited to ascii hex passwords (seems to work on all devices I have tried thus far). Change-Id: Ied080286d2bbdc493a6ceaecaaadba802b429666
Diffstat (limited to 'utils/nwztools/upgtools/upgtool.c')
-rw-r--r--utils/nwztools/upgtools/upgtool.c33
1 files changed, 29 insertions, 4 deletions
diff --git a/utils/nwztools/upgtools/upgtool.c b/utils/nwztools/upgtools/upgtool.c
index 065cede63c..3a8cf6174b 100644
--- a/utils/nwztools/upgtools/upgtool.c
+++ b/utils/nwztools/upgtools/upgtool.c
@@ -47,6 +47,7 @@ static int g_model_index = -1;
47static char *g_kas = NULL; 47static char *g_kas = NULL;
48static char *g_key = NULL; 48static char *g_key = NULL;
49static char *g_sig = NULL; 49static char *g_sig = NULL;
50static int g_nr_threads = 1;
50 51
51enum keysig_search_method_t g_keysig_search = KEYSIG_SEARCH_NONE; 52enum keysig_search_method_t g_keysig_search = KEYSIG_SEARCH_NONE;
52 53
@@ -74,6 +75,18 @@ struct nwz_model_t
74 char *sig; 75 char *sig;
75}; 76};
76 77
78/** Firmware format
79 *
80 * The firmware starts with the MD5 hash of the entire file (except the MD5 hash
81 * itself of course). This is used to check that the file was not corrupted.
82 * The remaining of the file is encrypted (using DES) with the model key. The
83 * encrypted part starts with a header containing the model signature and the
84 * number of files. Since the header is encrypted, decrypting the header with
85 * the key and finding the right signature serves to authenticate the firmware.
86 * The header is followed by N entries (where N is the number of files) giving
87 * the offset, within the file, and size of each file. Note that the files in
88 * the firmware have no name. */
89
77struct upg_md5_t 90struct upg_md5_t
78{ 91{
79 uint8_t md5[16]; 92 uint8_t md5[16];
@@ -81,7 +94,7 @@ struct upg_md5_t
81 94
82struct upg_header_t 95struct upg_header_t
83{ 96{
84 char sig[NWZ_SIG_SIZE]; 97 uint8_t sig[NWZ_SIG_SIZE];
85 uint32_t nr_files; 98 uint32_t nr_files;
86 uint32_t pad; // make sure structure size is a multiple of 8 99 uint32_t pad; // make sure structure size is a multiple of 8
87} __attribute__((packed)); 100} __attribute__((packed));
@@ -166,6 +179,7 @@ struct nwz_model_t g_model_list[] =
166 /* The following keys were obtained by brute forcing firmware upgrades, 179 /* The following keys were obtained by brute forcing firmware upgrades,
167 * someone with a device needs to confirm that they work */ 180 * someone with a device needs to confirm that they work */
168 { "nw-a82x", HAS_KEY | HAS_SIG, "", "4df06482", "07fa0b6e" }, 181 { "nw-a82x", HAS_KEY | HAS_SIG, "", "4df06482", "07fa0b6e" },
182 { "nwz-a1x", HAS_KEY | HAS_SIG, "", "ec2888e2", "f62ced8a" },
169}; 183};
170 184
171static int digit_value(char c) 185static int digit_value(char c)
@@ -286,7 +300,8 @@ static int get_key_and_sig(bool is_extract, void *encrypted_hdr)
286 { 300 {
287 cprintf(BLUE, "keysig Search\n"); 301 cprintf(BLUE, "keysig Search\n");
288 cprintf_field(" Method: ", "%s\n", keysig_search_desc[g_keysig_search].name); 302 cprintf_field(" Method: ", "%s\n", keysig_search_desc[g_keysig_search].name);
289 bool ok = keysig_search_desc[g_keysig_search].fn(encrypted_hdr, &upg_notify_keysig, keysig); 303 bool ok = keysig_search(g_keysig_search, encrypted_hdr, 8,
304 &upg_notify_keysig, keysig, g_nr_threads);
290 cprintf(GREEN, " Result: "); 305 cprintf(GREEN, " Result: ");
291 cprintf(ok ? YELLOW : RED, "%s\n", ok ? "Key found" : "No key found"); 306 cprintf(ok ? YELLOW : RED, "%s\n", ok ? "Key found" : "No key found");
292 if(!ok) 307 if(!ok)
@@ -576,6 +591,7 @@ static void usage(void)
576 printf(" -c/--no-color\t\tDisable color output\n"); 591 printf(" -c/--no-color\t\tDisable color output\n");
577 printf(" -m/--model <model>\tSelect model (or ? to list them)\n"); 592 printf(" -m/--model <model>\tSelect model (or ? to list them)\n");
578 printf(" -l/--search <method>\tTry to find the keysig (implies -e)\n"); 593 printf(" -l/--search <method>\tTry to find the keysig (implies -e)\n");
594 printf(" -t/--threads <nr>\tSpecify number of threads to find the keysig\n");
579 printf(" -a/--kas <kas>\tForce KAS\n"); 595 printf(" -a/--kas <kas>\tForce KAS\n");
580 printf(" -k/--key <key>\tForce key\n"); 596 printf(" -k/--key <key>\tForce key\n");
581 printf(" -s/--sig <sig>\tForce sig\n"); 597 printf(" -s/--sig <sig>\tForce sig\n");
@@ -594,7 +610,7 @@ int main(int argc, char **argv)
594 610
595 if(argc <= 1) 611 if(argc <= 1)
596 usage(); 612 usage();
597 613
598 while(1) 614 while(1)
599 { 615 {
600 static struct option long_options[] = 616 static struct option long_options[] =
@@ -610,10 +626,11 @@ int main(int argc, char **argv)
610 {"sig", required_argument, 0, 's'}, 626 {"sig", required_argument, 0, 's'},
611 {"extract", no_argument, 0, 'e'}, 627 {"extract", no_argument, 0, 'e'},
612 {"create", no_argument, 0 ,'c'}, 628 {"create", no_argument, 0 ,'c'},
629 {"threads", required_argument, 0, 't'},
613 {0, 0, 0, 0} 630 {0, 0, 0, 0}
614 }; 631 };
615 632
616 int c = getopt_long(argc, argv, "?dnfo:m:l:a:k:s:ec", long_options, NULL); 633 int c = getopt_long(argc, argv, "?dnfo:m:l:a:k:s:ect:", long_options, NULL);
617 if(c == -1) 634 if(c == -1)
618 break; 635 break;
619 switch(c) 636 switch(c)
@@ -665,6 +682,14 @@ int main(int argc, char **argv)
665 case 'c': 682 case 'c':
666 create = true; 683 create = true;
667 break; 684 break;
685 case 't':
686 g_nr_threads = strtol(optarg, NULL, 0);
687 if(g_nr_threads < 1 || g_nr_threads > 128)
688 {
689 cprintf(GREY, "Invalid number of threads\n");
690 return 1;
691 }
692 break;
668 default: 693 default:
669 abort(); 694 abort();
670 } 695 }