diff options
Diffstat (limited to 'utils/nwztools/upgtools/keysig_search.c')
-rw-r--r-- | utils/nwztools/upgtools/keysig_search.c | 108 |
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 | ||
28 | static uint8_t g_cipher[8]; | 44 | static uint8_t g_cipher[8]; |
29 | static keysig_notify_fn_t g_notify; | 45 | static keysig_notify_fn_t g_notify; |
@@ -31,11 +47,10 @@ static uint8_t g_key[8]; | |||
31 | static void *g_user; | 47 | static void *g_user; |
32 | static bool is_hex[256]; | 48 | static bool is_hex[256]; |
33 | static bool is_init = false; | 49 | static bool is_init = false; |
34 | #ifdef HEX_MAJ | 50 | static uint64_t g_tot_count; |
35 | static char hex_digits[] = "02468ABEF"; | 51 | static uint64_t g_cur_count; |
36 | #else | 52 | static int g_last_percent; |
37 | static char hex_digits[] = "02468abef"; | 53 | static int g_last_subpercent; |
38 | #endif | ||
39 | 54 | ||
40 | static void keysig_search_init() | 55 | static 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) | |||
63 | static inline bool check_stupid() | 74 | static 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 | ||
101 | static bool search_stupid(int rem_digit, int rem_letter) | 126 | static 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 | ||
131 | bool keysig_search_ascii_brute(uint8_t *cipher, keysig_notify_fn_t notify, void *user) | 165 | bool 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 | { |