summaryrefslogtreecommitdiff
path: root/utils/nwztools/upgtools/keysig_search.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/nwztools/upgtools/keysig_search.c')
-rw-r--r--utils/nwztools/upgtools/keysig_search.c108
1 files changed, 73 insertions, 35 deletions
diff --git a/utils/nwztools/upgtools/keysig_search.c b/utils/nwztools/upgtools/keysig_search.c
index 6054ea43ba..7652efa233 100644
--- a/utils/nwztools/upgtools/keysig_search.c
+++ b/utils/nwztools/upgtools/keysig_search.c
@@ -22,8 +22,24 @@
22#include "misc.h" 22#include "misc.h"
23#include "mg.h" 23#include "mg.h"
24#include <string.h> 24#include <string.h>
25#include <stdio.h>
25 26
26#define HEX_MAJ 27/* Key search methods
28 *
29 * This code tries to find the key and signature of a device using an upgrade
30 * file. It more or less relies on brute force and makes the following assumptions.
31 * It assumes the key and the signature are hexadecimal strings (it appears to be
32 * true thus far). The code lists all possible keys and decrypts the first
33 * 8 bytes of the file. If the decrypted signature happens to be an hex string,
34 * the code reports the key and signature as potentially valid. Note that some
35 * key/sig pairs may not be valid but since the likelyhood of decrypting a
36 * random 8-byte sequence using an hex string key and to produce an hex string
37 * is very small, there should be almost no false positive.
38 *
39 * Since the key is supposedly random, the code starts by looking at "balanced"
40 * keys: keys with slightly more digits (0-9) than letters (a-f) and then moving
41 * towards very unbalanced strings (only digits or only letters).
42 */
27 43
28static uint8_t g_cipher[8]; 44static uint8_t g_cipher[8];
29static keysig_notify_fn_t g_notify; 45static keysig_notify_fn_t g_notify;
@@ -31,11 +47,10 @@ static uint8_t g_key[8];
31static void *g_user; 47static void *g_user;
32static bool is_hex[256]; 48static bool is_hex[256];
33static bool is_init = false; 49static bool is_init = false;
34#ifdef HEX_MAJ 50static uint64_t g_tot_count;
35static char hex_digits[] = "02468ABEF"; 51static uint64_t g_cur_count;
36#else 52static int g_last_percent;
37static char hex_digits[] = "02468abef"; 53static int g_last_subpercent;
38#endif
39 54
40static void keysig_search_init() 55static void keysig_search_init()
41{ 56{
@@ -44,11 +59,7 @@ static void keysig_search_init()
44 memset(is_hex, 0, sizeof(is_hex)); 59 memset(is_hex, 0, sizeof(is_hex));
45 for(int i = '0'; i <= '9'; i++) 60 for(int i = '0'; i <= '9'; i++)
46 is_hex[i] = true; 61 is_hex[i] = true;
47#ifdef HEX_MAJ
48 for(int i = 'A'; i <= 'F'; i++)
49#else
50 for(int i = 'a'; i <= 'f'; i++) 62 for(int i = 'a'; i <= 'f'; i++)
51#endif
52 is_hex[i] = true; 63 is_hex[i] = true;
53} 64}
54 65
@@ -63,6 +74,24 @@ static inline bool is_full_ascii(uint8_t *arr)
63static inline bool check_stupid() 74static inline bool check_stupid()
64{ 75{
65 uint8_t res[8]; 76 uint8_t res[8];
77 // display progress
78 g_cur_count++;
79 int percent = (g_cur_count * 100ULL) / g_tot_count;
80 int subpercent = ((g_cur_count * 1000ULL) / g_tot_count) % 10;
81 if(percent != g_last_percent)
82 {
83 cprintf(RED, "%d%%", percent);
84 fflush(stdout);
85 g_last_subpercent = 0;
86 }
87 if(subpercent != g_last_subpercent)
88 {
89 cprintf(WHITE, ".");
90 fflush(stdout);
91 }
92 g_last_percent = percent;
93 g_last_subpercent = subpercent;
94
66 mg_decrypt_fw(g_cipher, 8, res, g_key); 95 mg_decrypt_fw(g_cipher, 8, res, g_key);
67 if(is_full_ascii(res)) 96 if(is_full_ascii(res))
68 return g_notify(g_user, g_key, res); 97 return g_notify(g_user, g_key, res);
@@ -75,7 +104,7 @@ static bool search_stupid_rec(int rem_digit, int rem_letter, int pos)
75 return check_stupid(); 104 return check_stupid();
76 if(rem_digit > 0) 105 if(rem_digit > 0)
77 { 106 {
78 for(int i = '0'; i <= '9'; i += 2) 107 for(int i = '0'; i <= '9'; i++)
79 { 108 {
80 g_key[pos] = i; 109 g_key[pos] = i;
81 if(search_stupid_rec(rem_digit - 1, rem_letter, pos + 1)) 110 if(search_stupid_rec(rem_digit - 1, rem_letter, pos + 1))
@@ -84,11 +113,7 @@ static bool search_stupid_rec(int rem_digit, int rem_letter, int pos)
84 } 113 }
85 if(rem_letter > 0) 114 if(rem_letter > 0)
86 { 115 {
87#ifdef HEX_MAJ 116 for(int i = 'a' - 1; i <= 'f'; i++)
88 for(int i = 'a' - 1; i <= 'f'; i += 2)
89#else
90 for(int i = 'A' - 1; i <= 'F'; i += 2)
91#endif
92 { 117 {
93 g_key[pos] = i; 118 g_key[pos] = i;
94 if(search_stupid_rec(rem_digit, rem_letter - 1, pos + 1)) 119 if(search_stupid_rec(rem_digit, rem_letter - 1, pos + 1))
@@ -100,6 +125,12 @@ static bool search_stupid_rec(int rem_digit, int rem_letter, int pos)
100 125
101static bool search_stupid(int rem_digit, int rem_letter) 126static bool search_stupid(int rem_digit, int rem_letter)
102{ 127{
128 cprintf(WHITE, "\n Looking for keys with ");
129 cprintf(RED, "%d", rem_digit);
130 cprintf(WHITE, " digits and ");
131 cprintf(RED, "%d", rem_letter);
132 cprintf(WHITE, " letters...");
133 fflush(stdout);
103 return search_stupid_rec(rem_digit, rem_letter, 0); 134 return search_stupid_rec(rem_digit, rem_letter, 0);
104} 135}
105 136
@@ -109,28 +140,35 @@ bool keysig_search_ascii_stupid(uint8_t *cipher, keysig_notify_fn_t notify, void
109 memcpy(g_cipher, cipher, 8); 140 memcpy(g_cipher, cipher, 8);
110 g_notify = notify; 141 g_notify = notify;
111 g_user = user; 142 g_user = user;
112#if 1 143 // compute number of possibilities
113 return search_stupid(4, 4) || 144 g_cur_count = 0;
114 search_stupid(3, 5) || search_stupid(5, 3) || 145 g_tot_count = 1;
115 search_stupid(2, 6) || search_stupid(6, 2) || 146 g_last_percent = -1;
116 search_stupid(1, 7) || search_stupid(7, 1) || 147 for(int i = 0; i < 8; i++)
117 search_stupid(0, 8) || search_stupid(8, 0); 148 g_tot_count *= 16ULL;
118#else 149 cprintf(WHITE, " Search space:");
119#define do(i) for(int a##i = 0; a##i < sizeof(hex_digits); a##i++) { g_key[i] = hex_digits[a##i]; 150 cprintf(RED, " %llu", (unsigned long long)g_tot_count);
120#define od() } 151 // sorted by probability:
121 152 bool ret = search_stupid(5, 3) // 5 digits, 3 letters: 0.281632
122 do(0)do(1)do(2)do(3)do(4)do(5)do(6)do(7) 153 || search_stupid(6, 2) // 6 digits, 2 letters: 0.234693
123 if(check_stupid()) return true; 154 || search_stupid(4, 4) // 4 digits, 4 letters: 0.211224
124 od()od()od()od()od()od()od()od() 155 || search_stupid(7, 1) // 7 digits, 1 letters: 0.111759
125#undef do 156 || search_stupid(3, 5) // 3 digits, 5 letters: 0.101388
126#undef od 157 || search_stupid(2, 6) // 2 digits, 6 letters: 0.030416
127 return false; 158 || search_stupid(8, 0) // 8 digits, 0 letters: 0.023283
128#endif 159 || search_stupid(1, 7) // 1 digits, 7 letters: 0.005214
160 || search_stupid(0, 8);// 0 digits, 8 letters: 0.000391
161 cprintf(OFF, "\n");
162 return ret;
129} 163}
130 164
131bool keysig_search_ascii_brute(uint8_t *cipher, keysig_notify_fn_t notify, void *user) 165bool keysig_search_ascii_brute(uint8_t *cipher, keysig_notify_fn_t notify, void *user)
132{ 166{
167 (void) cipher;
168 (void) notify;
169 (void) user;
133 keysig_search_init(); 170 keysig_search_init();
171 cprintf(RED, "Unimplemented\n");
134 return false; 172 return false;
135} 173}
136 174
@@ -144,9 +182,9 @@ struct keysig_search_desc_t keysig_search_desc[KEYSIG_SEARCH_LAST] =
144 }, 182 },
145 [KEYSIG_SEARCH_ASCII_STUPID] = 183 [KEYSIG_SEARCH_ASCII_STUPID] =
146 { 184 {
147 .name = "ascii-stupid", 185 .name = "ascii-hex",
148 .fn = keysig_search_ascii_stupid, 186 .fn = keysig_search_ascii_stupid,
149 .comment = "Try to find a balance ascii key ignoring lsb" 187 .comment = "Try to find an hexadecimal ascii string keysig"
150 }, 188 },
151 [KEYSIG_SEARCH_ASCII_BRUTE] = 189 [KEYSIG_SEARCH_ASCII_BRUTE] =
152 { 190 {