summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-01-04 16:35:38 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2017-01-04 17:04:19 +0100
commit5cfd4a5b8e551c23600c93838180487e91698814 (patch)
treed5242d45a034266a35044cca12ebad340dd2a40b
parentbfd5704749cfb8f7faf9f03be49c60f5f2b1cf7d (diff)
downloadrockbox-5cfd4a5b8e551c23600c93838180487e91698814.tar.gz
rockbox-5cfd4a5b8e551c23600c93838180487e91698814.zip
nwztools/upgtools: add more brute force algorithms
Allow to search for hex with upper case and alphanumeric. This is *much* slower of course. Change-Id: I41a2fc63c4b2220c21147b711098ebc37ddb3527
-rw-r--r--utils/nwztools/upgtools/keysig_search.c182
-rw-r--r--utils/nwztools/upgtools/keysig_search.h4
-rw-r--r--utils/nwztools/upgtools/upgtool.c4
3 files changed, 169 insertions, 21 deletions
diff --git a/utils/nwztools/upgtools/keysig_search.c b/utils/nwztools/upgtools/keysig_search.c
index 2740dc1461..51a04bb6f9 100644
--- a/utils/nwztools/upgtools/keysig_search.c
+++ b/utils/nwztools/upgtools/keysig_search.c
@@ -25,6 +25,9 @@
25#include <stdio.h> 25#include <stdio.h>
26#include <stdlib.h> 26#include <stdlib.h>
27#include <pthread.h> 27#include <pthread.h>
28#include <stdbool.h>
29
30#define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0)
28 31
29/** Generic search code */ 32/** Generic search code */
30 33
@@ -164,6 +167,7 @@ static struct
164}g_keysig_search; 167}g_keysig_search;
165 168
166static bool is_hex[256]; 169static bool is_hex[256];
170static bool is_alnum[256];
167static bool is_init = false; 171static bool is_init = false;
168 172
169static void keysig_search_init() 173static void keysig_search_init()
@@ -172,12 +176,21 @@ static void keysig_search_init()
172 is_init = true; 176 is_init = true;
173 memset(is_hex, 0, sizeof(is_hex)); 177 memset(is_hex, 0, sizeof(is_hex));
174 for(int i = '0'; i <= '9'; i++) 178 for(int i = '0'; i <= '9'; i++)
179 {
180 is_alnum[i] = true;
175 is_hex[i] = true; 181 is_hex[i] = true;
182 }
176 for(int i = 'a'; i <= 'f'; i++) 183 for(int i = 'a'; i <= 'f'; i++)
177 is_hex[i] = true; 184 is_hex[i] = true;
185 for(int i = 'A'; i <= 'F'; i++)
186 is_hex[i] = true;
187 for(int i = 'a'; i <= 'z'; i++)
188 is_alnum[i] = true;
189 for(int i = 'A'; i <= 'Z'; i++)
190 is_alnum[i] = true;
178} 191}
179 192
180static inline bool is_full_ascii(uint8_t *arr) 193static bool hex_validate_sig(uint8_t *arr)
181{ 194{
182 for(int i = 0; i < 8; i++) 195 for(int i = 0; i < 8; i++)
183 if(!is_hex[arr[i]]) 196 if(!is_hex[arr[i]])
@@ -185,6 +198,14 @@ static inline bool is_full_ascii(uint8_t *arr)
185 return true; 198 return true;
186} 199}
187 200
201static bool alnum_validate_sig(uint8_t *arr)
202{
203 for(int i = 0; i < 8; i++)
204 if(!is_alnum[arr[i]])
205 return false;
206 return true;
207}
208
188struct upg_header_t 209struct upg_header_t
189{ 210{
190 uint8_t sig[NWZ_SIG_SIZE]; 211 uint8_t sig[NWZ_SIG_SIZE];
@@ -192,11 +213,13 @@ struct upg_header_t
192 uint32_t pad; // make sure structure size is a multiple of 8 213 uint32_t pad; // make sure structure size is a multiple of 8
193} __attribute__((packed)); 214} __attribute__((packed));
194 215
195static bool check_key(uint8_t key[NWZ_KEY_SIZE]) 216typedef bool (*sig_validate_fn_t)(uint8_t *key);
217
218static bool check_key(uint8_t key[NWZ_KEY_SIZE], sig_validate_fn_t validate)
196{ 219{
197 struct upg_header_t hdr; 220 struct upg_header_t hdr;
198 mg_decrypt_fw(g_keysig_search.enc_buf, sizeof(hdr.sig), (void *)&hdr, key); 221 mg_decrypt_fw(g_keysig_search.enc_buf, sizeof(hdr.sig), (void *)&hdr, key);
199 if(is_full_ascii(hdr.sig)) 222 if(validate(hdr.sig))
200 { 223 {
201 /* the signature looks correct, so decrypt the header futher to be sure */ 224 /* the signature looks correct, so decrypt the header futher to be sure */
202 mg_decrypt_fw(g_keysig_search.enc_buf, sizeof(hdr), (void *)&hdr, key); 225 mg_decrypt_fw(g_keysig_search.enc_buf, sizeof(hdr), (void *)&hdr, key);
@@ -220,6 +243,7 @@ static bool check_key(uint8_t key[NWZ_KEY_SIZE])
220struct hex_chunk_t 243struct hex_chunk_t
221{ 244{
222 uint8_t key[NWZ_KEY_SIZE]; /* partially pre-filled key */ 245 uint8_t key[NWZ_KEY_SIZE]; /* partially pre-filled key */
246 bool upper_case; /* allow upper case in letters */
223 int pos; 247 int pos;
224 int rem_letters; 248 int rem_letters;
225 int rem_digits; 249 int rem_digits;
@@ -235,7 +259,7 @@ static bool hex_rec(bool producer, struct hex_chunk_t *ch)
235 } 259 }
236 /* filled the key ? */ 260 /* filled the key ? */
237 if(!producer && ch->pos == NWZ_KEY_SIZE) 261 if(!producer && ch->pos == NWZ_KEY_SIZE)
238 return check_key(ch->key); 262 return check_key(ch->key, hex_validate_sig);
239 /* list next possibilities 263 /* list next possibilities
240 * 264 *
241 * NOTE (42) Since the cipher is DES, the key is actually 56-bit: the least 265 * NOTE (42) Since the cipher is DES, the key is actually 56-bit: the least
@@ -264,6 +288,15 @@ static bool hex_rec(bool producer, struct hex_chunk_t *ch)
264 if(hex_rec(producer, ch)) 288 if(hex_rec(producer, ch))
265 return true; 289 return true;
266 } 290 }
291 if(ch->upper_case)
292 {
293 for(int i = 'A'; i <= 'F'; i += 2)
294 {
295 ch->key[p] = i;
296 if(hex_rec(producer, ch))
297 return true;
298 }
299 }
267 ch->rem_letters++; 300 ch->rem_letters++;
268 } 301 }
269 ch->pos--; 302 ch->pos--;
@@ -283,13 +316,14 @@ static void *hex_worker(void *arg)
283 return NULL; 316 return NULL;
284} 317}
285 318
286static bool hex_producer_list(int nr_digits, int nr_letters) 319static bool hex_producer_list(bool upper_case, int nr_digits, int nr_letters)
287{ 320{
288 struct hex_chunk_t ch; 321 struct hex_chunk_t ch;
289 cprintf(BLUE, " Listing keys with %d letters and %d digits\n", nr_letters, 322 cprintf(BLUE, " Listing keys with %d letters and %d digits\n", nr_letters,
290 nr_digits); 323 nr_digits);
291 memset(ch.key, ' ', 8); 324 memset(ch.key, ' ', 8);
292 ch.pos = 0; 325 ch.pos = 0;
326 ch.upper_case = upper_case;
293 ch.rem_letters = nr_letters; 327 ch.rem_letters = nr_letters;
294 ch.rem_digits = nr_digits; 328 ch.rem_digits = nr_digits;
295 return hex_rec(true, &ch); 329 return hex_rec(true, &ch);
@@ -299,20 +333,107 @@ void *hex_producer(void *arg)
299{ 333{
300 (void) arg; 334 (void) arg;
301 // sorted by probability: 335 // sorted by probability:
302 bool stop = hex_producer_list(5, 3) // 5 digits, 3 letters: 0.281632 336 bool stop = hex_producer_list(false, 5, 3) // 5 digits, 3 letters: 0.281632
303 || hex_producer_list(6, 2) // 6 digits, 2 letters: 0.234693 337 || hex_producer_list(false, 6, 2) // 6 digits, 2 letters: 0.234693
304 || hex_producer_list(4, 4) // 4 digits, 4 letters: 0.211224 338 || hex_producer_list(false, 4, 4) // 4 digits, 4 letters: 0.211224
305 || hex_producer_list(7, 1) // 7 digits, 1 letters: 0.111759 339 || hex_producer_list(false, 7, 1) // 7 digits, 1 letters: 0.111759
306 || hex_producer_list(3, 5) // 3 digits, 5 letters: 0.101388 340 || hex_producer_list(false, 3, 5) // 3 digits, 5 letters: 0.101388
307 || hex_producer_list(2, 6) // 2 digits, 6 letters: 0.030416 341 || hex_producer_list(false, 2, 6) // 2 digits, 6 letters: 0.030416
308 || hex_producer_list(8, 0) // 8 digits, 0 letters: 0.023283 342 || hex_producer_list(false, 8, 0) // 8 digits, 0 letters: 0.023283
309 || hex_producer_list(1, 7) // 1 digits, 7 letters: 0.005214 343 || hex_producer_list(false, 1, 7) // 1 digits, 7 letters: 0.005214
310 || hex_producer_list(0, 8);// 0 digits, 8 letters: 0.000391 344 || hex_producer_list(false, 0, 8);// 0 digits, 8 letters: 0.000391
311 if(!stop) 345 if(!stop)
312 producer_stop(); 346 producer_stop();
313 return NULL; 347 return NULL;
314} 348}
315 349
350void *hex_producer_up(void *arg)
351{
352 (void) arg;
353 // sorted by probability:
354 // TODO sort
355 bool stop = hex_producer_list(true, 5, 3) // 5 digits, 3 letters: 0.281632
356 || hex_producer_list(true, 6, 2) // 6 digits, 2 letters: 0.234693
357 || hex_producer_list(true, 4, 4) // 4 digits, 4 letters: 0.211224
358 || hex_producer_list(true, 7, 1) // 7 digits, 1 letters: 0.111759
359 || hex_producer_list(true, 3, 5) // 3 digits, 5 letters: 0.101388
360 || hex_producer_list(true, 2, 6) // 2 digits, 6 letters: 0.030416
361 || hex_producer_list(true, 8, 0) // 8 digits, 0 letters: 0.023283
362 || hex_producer_list(true, 1, 7) // 1 digits, 7 letters: 0.005214
363 || hex_producer_list(true, 0, 8);// 0 digits, 8 letters: 0.000391
364 if(!stop)
365 producer_stop();
366 return NULL;
367}
368
369/** Alphanumeric search */
370
371struct alnum_chunk_t
372{
373 uint8_t key[NWZ_KEY_SIZE]; /* partially pre-filled key */
374 int pos;
375};
376
377static bool alnum_rec(bool producer, struct alnum_chunk_t *ch)
378{
379 /* we list the first 5 pos in generator, and remaining 3 in workers */
380 if(producer && ch->pos == 4)
381 {
382 printf("yield(%.8s,%d)\n", ch->key, ch->pos);
383 return producer_yield(ch, sizeof(struct alnum_chunk_t));
384 }
385 /* filled the key ? */
386 if(!producer && ch->pos == NWZ_KEY_SIZE)
387 return check_key(ch->key, alnum_validate_sig);
388 /* list next possibilities
389 *
390 * NOTE (42) Since the cipher is DES, the key is actually 56-bit: the least
391 * significant bit of each byte is an (unused) parity bit. We thus only
392 * generate keys where the least significant bit is 0. */
393 int p = ch->pos++;
394 /* NOTE (42) */
395 for(int i = '0'; i <= '9'; i += 2)
396 {
397 ch->key[p] = i;
398 if(alnum_rec(producer, ch))
399 return true;
400 }
401 /* NOTE (42) */
402 for(int i = 'a'; i <= 'z'; i += 2)
403 {
404 ch->key[p] = i;
405 if(alnum_rec(producer, ch))
406 return true;
407 }
408 ch->pos--;
409 return false;
410}
411
412static void *alnum_worker(void *arg)
413{
414 (void) arg;
415 while(true)
416 {
417 struct alnum_chunk_t *ch = consumer_get(NULL);
418 if(ch == NULL)
419 break;
420 alnum_rec(false, ch);
421 }
422 return NULL;
423}
424
425void *alnum_producer(void *arg)
426{
427 (void) arg;
428 struct alnum_chunk_t ch;
429 cprintf(BLUE, " Listing alphanumeric keys\n");
430 memset(ch.key, ' ', 8);
431 ch.pos = 0;
432 if(!alnum_rec(true, &ch))
433 producer_stop();
434 return NULL;
435}
436
316typedef void *(*routine_t)(void *); 437typedef void *(*routine_t)(void *);
317 438
318bool keysig_search(int method, uint8_t *enc_buf, size_t buf_sz, 439bool keysig_search(int method, uint8_t *enc_buf, size_t buf_sz,
@@ -329,11 +450,26 @@ bool keysig_search(int method, uint8_t *enc_buf, size_t buf_sz,
329 /* get methods */ 450 /* get methods */
330 routine_t worker_fn = NULL; 451 routine_t worker_fn = NULL;
331 routine_t producer_fn = NULL; 452 routine_t producer_fn = NULL;
332 if(method == KEYSIG_SEARCH_ASCII_HEX) 453 if(method == KEYSIG_SEARCH_XDIGITS)
333 { 454 {
334 worker_fn = hex_worker; 455 worker_fn = hex_worker;
335 producer_fn = hex_producer; 456 producer_fn = hex_producer;
336 } 457 }
458 else if(method == KEYSIG_SEARCH_XDIGITS_UP)
459 {
460 worker_fn = hex_worker;
461 producer_fn = hex_producer_up;
462 }
463 else if(method == KEYSIG_SEARCH_ALNUM)
464 {
465 worker_fn = alnum_worker;
466 producer_fn = alnum_producer;
467 }
468 else
469 {
470 printf("Invalid method\n");
471 return false;
472 }
337 /* create workers */ 473 /* create workers */
338 pthread_t *worker = malloc(sizeof(pthread_t) * nr_threads); 474 pthread_t *worker = malloc(sizeof(pthread_t) * nr_threads);
339 pthread_t producer; 475 pthread_t producer;
@@ -357,9 +493,19 @@ struct keysig_search_desc_t keysig_search_desc[KEYSIG_SEARCH_LAST] =
357 .name = "none", 493 .name = "none",
358 .comment = "don't use", 494 .comment = "don't use",
359 }, 495 },
360 [KEYSIG_SEARCH_ASCII_HEX] = 496 [KEYSIG_SEARCH_XDIGITS] =
497 {
498 .name = "xdigits",
499 .comment = "Try to find an hexadecimal string keysig"
500 },
501 [KEYSIG_SEARCH_XDIGITS_UP] =
502 {
503 .name = "xdigits-up",
504 .comment = "Try to find an hexadecimal string keysig, including upper case"
505 },
506 [KEYSIG_SEARCH_ALNUM] =
361 { 507 {
362 .name = "ascii-hex", 508 .name = "alnum",
363 .comment = "Try to find an hexadecimal ascii string keysig" 509 .comment = "Try to find an alphanumeric string keysig"
364 }, 510 },
365}; 511};
diff --git a/utils/nwztools/upgtools/keysig_search.h b/utils/nwztools/upgtools/keysig_search.h
index f419e2621c..877da2f89c 100644
--- a/utils/nwztools/upgtools/keysig_search.h
+++ b/utils/nwztools/upgtools/keysig_search.h
@@ -30,7 +30,9 @@ enum keysig_search_method_t
30{ 30{
31 KEYSIG_SEARCH_NONE = 0, 31 KEYSIG_SEARCH_NONE = 0,
32 KEYSIG_SEARCH_FIRST, 32 KEYSIG_SEARCH_FIRST,
33 KEYSIG_SEARCH_ASCII_HEX = KEYSIG_SEARCH_FIRST, 33 KEYSIG_SEARCH_XDIGITS = KEYSIG_SEARCH_FIRST,
34 KEYSIG_SEARCH_XDIGITS_UP,
35 KEYSIG_SEARCH_ALNUM,
34 KEYSIG_SEARCH_LAST 36 KEYSIG_SEARCH_LAST
35}; 37};
36 38
diff --git a/utils/nwztools/upgtools/upgtool.c b/utils/nwztools/upgtools/upgtool.c
index 8f75f93024..833321ec12 100644
--- a/utils/nwztools/upgtools/upgtool.c
+++ b/utils/nwztools/upgtools/upgtool.c
@@ -319,7 +319,7 @@ static int get_key_and_sig(bool is_extract, void *encrypted_hdr)
319 cprintf(GREY, "- select a model with a known KAS\n"); 319 cprintf(GREY, "- select a model with a known KAS\n");
320 cprintf(GREY, "- specify an explicit KAS or key+sig\n"); 320 cprintf(GREY, "- specify an explicit KAS or key+sig\n");
321 if(is_extract) 321 if(is_extract)
322 cprintf(GREY, "- let me try to find the keysig(slow !)\n"); 322 cprintf(GREY, "- let me try to find the keysig by brute force\n");
323 return 1; 323 return 1;
324 } 324 }
325 325
@@ -604,7 +604,7 @@ static void usage(void)
604 printf(" -c/--create\t\tCreate a UPG archive\n"); 604 printf(" -c/--create\t\tCreate a UPG archive\n");
605 printf("keysig search method:\n"); 605 printf("keysig search method:\n");
606 for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++) 606 for(int i = KEYSIG_SEARCH_FIRST; i < KEYSIG_SEARCH_LAST; i++)
607 printf(" %s\t%s\n", keysig_search_desc[i].name, keysig_search_desc[i].comment); 607 printf(" %-10s\t%s\n", keysig_search_desc[i].name, keysig_search_desc[i].comment);
608 exit(1); 608 exit(1);
609} 609}
610 610