summaryrefslogtreecommitdiff
path: root/utils/sbtools/sbtoelf.c
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2011-11-01 11:23:43 +0000
committerAmaury Pouly <pamaury@rockbox.org>2011-11-01 11:23:43 +0000
commite36471df9cfb3fa7aaa2216d9b5c79cb775bf9da (patch)
treed8c03ad24a339928a379dd864d235a3f1a02aaad /utils/sbtools/sbtoelf.c
parent591ec0349b424e94eaaaa1c9bf486f769ff34732 (diff)
downloadrockbox-e36471df9cfb3fa7aaa2216d9b5c79cb775bf9da.tar.gz
rockbox-e36471df9cfb3fa7aaa2216d9b5c79cb775bf9da.zip
sbtools: move sb reading from sbtoelf.c to sb.c with a proper interface, fix sb production bug, fix ugly code, add sb dump code and sbtoelf loopback facility
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30881 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/sbtools/sbtoelf.c')
-rw-r--r--utils/sbtools/sbtoelf.c673
1 files changed, 46 insertions, 627 deletions
diff --git a/utils/sbtools/sbtoelf.c b/utils/sbtools/sbtoelf.c
index 24417dc88e..0199ffb4f5 100644
--- a/utils/sbtools/sbtoelf.c
+++ b/utils/sbtools/sbtoelf.c
@@ -56,19 +56,7 @@
56 56
57/* globals */ 57/* globals */
58 58
59uint8_t *g_buf; /* file content */
60char *g_out_prefix; 59char *g_out_prefix;
61bool g_debug;
62bool g_raw_mode;
63
64static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
65{
66 uint8_t sum = 90;
67 byte *ptr = (byte *)hdr;
68 for(int i = 1; i < 16; i++)
69 sum += ptr[i];
70 return sum;
71}
72 60
73static void elf_printf(void *user, bool error, const char *fmt, ...) 61static void elf_printf(void *user, bool error, const char *fmt, ...)
74{ 62{
@@ -104,614 +92,34 @@ static void extract_elf_section(struct elf_params_t *elf, int count, const char
104 fclose(fd); 92 fclose(fd);
105} 93}
106 94
107static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent) 95static void usage(void)
108{
109 char *filename = xmalloc(strlen(g_out_prefix) + strlen(name) + 5);
110 if(g_out_prefix)
111 {
112 sprintf(filename, "%s%s.bin", g_out_prefix, name);
113 FILE *fd = fopen(filename, "wb");
114 if (fd != NULL)
115 {
116 fwrite(buf, size, 1, fd);
117 fclose(fd);
118 }
119 }
120 if(data_sec)
121 return;
122
123 sprintf(filename, "%s%s", g_out_prefix, name);
124
125 /* elf construction */
126 struct elf_params_t elf;
127 elf_init(&elf);
128 int elf_count = 0;
129 /* Pretty print the content */
130 int pos = 0;
131 while(pos < size)
132 {
133 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos];
134 printf("%s", indent);
135 uint8_t checksum = instruction_checksum(hdr);
136 if(checksum != hdr->checksum)
137 {
138 color(GREY);
139 printf("[Bad checksum]");
140 }
141 if(hdr->flags != 0)
142 {
143 color(GREY);
144 printf("[");
145 color(BLUE);
146 printf("f=%x", hdr->flags);
147 color(GREY);
148 printf("] ");
149 }
150 if(hdr->opcode == SB_INST_LOAD)
151 {
152 struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos];
153 color(RED);
154 printf("LOAD");
155 color(OFF);printf(" | ");
156 color(BLUE);
157 printf("addr=0x%08x", load->addr);
158 color(OFF);printf(" | ");
159 color(GREEN);
160 printf("len=0x%08x", load->len);
161 color(OFF);printf(" | ");
162 color(YELLOW);
163 printf("crc=0x%08x", load->crc);
164 /* data is padded to 16-byte boundary with random data and crc'ed with it */
165 uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)],
166 ROUND_UP(load->len, 16));
167 color(RED);
168 if(load->crc == computed_crc)
169 printf(" Ok\n");
170 else
171 printf(" Failed (crc=0x%08x)\n", computed_crc);
172
173 /* elf construction */
174 elf_add_load_section(&elf, load->addr, load->len,
175 &buf[pos + sizeof(struct sb_instruction_load_t)]);
176
177 pos += load->len + sizeof(struct sb_instruction_load_t);
178 }
179 else if(hdr->opcode == SB_INST_FILL)
180 {
181 struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos];
182 color(RED);
183 printf("FILL");
184 color(OFF);printf(" | ");
185 color(BLUE);
186 printf("addr=0x%08x", fill->addr);
187 color(OFF);printf(" | ");
188 color(GREEN);
189 printf("len=0x%08x", fill->len);
190 color(OFF);printf(" | ");
191 color(YELLOW);
192 printf("pattern=0x%08x\n", fill->pattern);
193 color(OFF);
194
195 /* elf construction */
196 elf_add_fill_section(&elf, fill->addr, fill->len, fill->pattern);
197
198 pos += sizeof(struct sb_instruction_fill_t);
199 }
200 else if(hdr->opcode == SB_INST_CALL ||
201 hdr->opcode == SB_INST_JUMP)
202 {
203 int is_call = (hdr->opcode == SB_INST_CALL);
204 struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos];
205 color(RED);
206 if(is_call)
207 printf("CALL");
208 else
209 printf("JUMP");
210 color(OFF);printf(" | ");
211 color(BLUE);
212 printf("addr=0x%08x", call->addr);
213 color(OFF);printf(" | ");
214 color(GREEN);
215 printf("arg=0x%08x\n", call->arg);
216 color(OFF);
217
218 /* elf construction */
219 elf_set_start_addr(&elf, call->addr);
220 extract_elf_section(&elf, elf_count++, filename, indent);
221 elf_release(&elf);
222 elf_init(&elf);
223
224 pos += sizeof(struct sb_instruction_call_t);
225 }
226 else if(hdr->opcode == SB_INST_MODE)
227 {
228 struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr;
229 color(RED);
230 printf("MODE");
231 color(OFF);printf(" | ");
232 color(BLUE);
233 printf("mod=0x%08x\n", mode->mode);
234 color(OFF);
235 pos += sizeof(struct sb_instruction_mode_t);
236 }
237 else if(hdr->opcode == SB_INST_NOP)
238 {
239 color(RED);
240 printf("NOOP\n");
241 pos += sizeof(struct sb_instruction_mode_t);
242 }
243 else
244 {
245 color(RED);
246 printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
247 break;
248 }
249
250 pos = ROUND_UP(pos, BLOCK_SIZE);
251 }
252
253 if(!elf_is_empty(&elf))
254 extract_elf_section(&elf, elf_count++, filename, indent);
255 elf_release(&elf);
256}
257
258static void fill_section_name(char name[5], uint32_t identifier)
259{
260 name[0] = (identifier >> 24) & 0xff;
261 name[1] = (identifier >> 16) & 0xff;
262 name[2] = (identifier >> 8) & 0xff;
263 name[3] = identifier & 0xff;
264 for(int i = 0; i < 4; i++)
265 if(!isprint(name[i]))
266 name[i] = '_';
267 name[4] = 0;
268}
269
270static uint16_t swap16(uint16_t t)
271{
272 return (t << 8) | (t >> 8);
273}
274
275static void fix_version(struct sb_version_t *ver)
276{
277 ver->major = swap16(ver->major);
278 ver->minor = swap16(ver->minor);
279 ver->revision = swap16(ver->revision);
280}
281
282static void extract(unsigned long filesize)
283{
284 struct sha_1_params_t sha_1_params;
285 /* Basic header info */
286 struct sb_header_t *sb_header = (struct sb_header_t *)g_buf;
287
288 if(memcmp(sb_header->signature, "STMP", 4) != 0)
289 bugp("Bad signature");
290 /*
291 if(sb_header->image_size * BLOCK_SIZE > filesize)
292 bugp("File size mismatch");
293 */
294 if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
295 bugp("Bad header size");
296 if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
297 bugp("Bad section header size");
298
299 if(filesize > sb_header->image_size * BLOCK_SIZE)
300 {
301 color(GREY);
302 printf("[Restrict file size from %lu to %d bytes]\n", filesize,
303 sb_header->image_size * BLOCK_SIZE);
304 filesize = sb_header->image_size * BLOCK_SIZE;
305 }
306
307 color(BLUE);
308 printf("Basic info:\n");
309 color(GREEN);
310 printf(" SB version: ");
311 color(YELLOW);
312 printf("%d.%d\n", sb_header->major_ver, sb_header->minor_ver);
313 color(GREEN);
314 printf(" Header SHA-1: ");
315 byte *hdr_sha1 = sb_header->sha1_header;
316 color(YELLOW);
317 print_hex(hdr_sha1, 20, false);
318 /* Check SHA1 sum */
319 byte computed_sha1[20];
320 sha_1_init(&sha_1_params);
321 sha_1_update(&sha_1_params, &sb_header->signature[0],
322 sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header));
323 sha_1_finish(&sha_1_params);
324 sha_1_output(&sha_1_params, computed_sha1);
325 color(RED);
326 if(memcmp(hdr_sha1, computed_sha1, 20) == 0)
327 printf(" Ok\n");
328 else
329 printf(" Failed\n");
330 color(GREEN);
331 printf(" Flags: ");
332 color(YELLOW);
333 printf("%x\n", sb_header->flags);
334 color(GREEN);
335 printf(" Total file size : ");
336 color(YELLOW);
337 printf("%ld\n", filesize);
338
339 /* Sizes and offsets */
340 color(BLUE);
341 printf("Sizes and offsets:\n");
342 color(GREEN);
343 printf(" # of encryption keys = ");
344 color(YELLOW);
345 printf("%d\n", sb_header->nr_keys);
346 color(GREEN);
347 printf(" # of sections = ");
348 color(YELLOW);
349 printf("%d\n", sb_header->nr_sections);
350
351 /* Versions */
352 color(BLUE);
353 printf("Versions\n");
354 color(GREEN);
355
356 printf(" Random 1: ");
357 color(YELLOW);
358 print_hex(sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true);
359 color(GREEN);
360 printf(" Random 2: ");
361 color(YELLOW);
362 print_hex(sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true);
363
364 uint64_t micros = sb_header->timestamp;
365 time_t seconds = (micros / (uint64_t)1000000L);
366 struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
367 seconds += mktime(&tm_base);
368 struct tm *time = gmtime(&seconds);
369 color(GREEN);
370 printf(" Creation date/time = ");
371 color(YELLOW);
372 printf("%s", asctime(time));
373
374 struct sb_version_t product_ver = sb_header->product_ver;
375 fix_version(&product_ver);
376 struct sb_version_t component_ver = sb_header->component_ver;
377 fix_version(&component_ver);
378
379 color(GREEN);
380 printf(" Product version = ");
381 color(YELLOW);
382 printf("%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision);
383 color(GREEN);
384 printf(" Component version = ");
385 color(YELLOW);
386 printf("%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision);
387
388 color(GREEN);
389 printf(" Drive tag = ");
390 color(YELLOW);
391 printf("%x\n", sb_header->drive_tag);
392 color(GREEN);
393 printf(" First boot tag offset = ");
394 color(YELLOW);
395 printf("%x\n", sb_header->first_boot_tag_off);
396 color(GREEN);
397 printf(" First boot section ID = ");
398 color(YELLOW);
399 printf("0x%08x\n", sb_header->first_boot_sec_id);
400
401 /* encryption cbc-mac */
402 byte real_key[16];
403 bool valid_key = false; /* false until a matching key was found */
404 if(sb_header->nr_keys > 0)
405 {
406 if(sb_header->nr_keys > g_nr_keys)
407 {
408 color(GREY);
409 bug("SB file has %d keys but only %d were specified on command line\n",
410 sb_header->nr_keys, g_nr_keys);
411 }
412 color(BLUE);
413 printf("Encryption data\n");
414 for(int i = 0; i < sb_header->nr_keys; i++)
415 {
416 color(RED);
417 printf(" Key %d: ", i);
418 print_key(&g_key_array[i], true);
419 color(GREEN);
420 printf(" CBC-MAC of headers: ");
421
422 uint32_t ofs = sizeof(struct sb_header_t)
423 + sizeof(struct sb_section_header_t) * sb_header->nr_sections
424 + sizeof(struct sb_key_dictionary_entry_t) * i;
425 struct sb_key_dictionary_entry_t *dict_entry =
426 (struct sb_key_dictionary_entry_t *)&g_buf[ofs];
427 /* cbc mac */
428 color(YELLOW);
429 print_hex(dict_entry->hdr_cbc_mac, 16, false);
430 /* check it */
431 byte computed_cbc_mac[16];
432 byte zero[16];
433 memset(zero, 0, 16);
434 crypto_cbc(g_buf, NULL, sb_header->header_size + sb_header->nr_sections,
435 &g_key_array[i], zero, &computed_cbc_mac, 1);
436 color(RED);
437 bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0;
438 if(ok)
439 {
440 valid_key = true;
441 printf(" Ok\n");
442 }
443 else
444 printf(" Failed\n");
445 color(GREEN);
446
447 printf(" Encrypted key : ");
448 color(YELLOW);
449 print_hex(dict_entry->key, 16, true);
450 color(GREEN);
451 /* decrypt */
452 byte decrypted_key[16];
453 byte iv[16];
454 memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
455 crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0);
456 printf(" Decrypted key : ");
457 color(YELLOW);
458 print_hex(decrypted_key, 16, false);
459 /* cross-check or copy */
460 if(valid_key && ok)
461 memcpy(real_key, decrypted_key, 16);
462 else if(valid_key)
463 {
464 if(memcmp(real_key, decrypted_key, 16) == 0)
465 {
466 color(RED);
467 printf(" Cross-Check Ok");
468 }
469 else
470 {
471 color(RED);
472 printf(" Cross-Check Failed");
473 }
474 }
475 printf("\n");
476 }
477 }
478
479 if(getenv("SB_REAL_KEY") != 0)
480 {
481 struct crypto_key_t k;
482 char *env = getenv("SB_REAL_KEY");
483 if(!parse_key(&env, &k) || *env)
484 bug("Invalid SB_REAL_KEY");
485 memcpy(real_key, k.u.key, 16);
486 }
487
488 color(RED);
489 printf(" Summary:\n");
490 color(GREEN);
491 printf(" Real key: ");
492 color(YELLOW);
493 print_hex(real_key, 16, true);
494 color(GREEN);
495 printf(" IV : ");
496 color(YELLOW);
497 print_hex(g_buf, 16, true);
498
499 /* sections */
500 if(!g_raw_mode)
501 {
502 color(BLUE);
503 printf("Sections\n");
504 for(int i = 0; i < sb_header->nr_sections; i++)
505 {
506 uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t);
507 struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&g_buf[ofs];
508
509 char name[5];
510 fill_section_name(name, sec_hdr->identifier);
511 int pos = sec_hdr->offset * BLOCK_SIZE;
512 int size = sec_hdr->size * BLOCK_SIZE;
513 int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE);
514 int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
515
516 color(GREEN);
517 printf(" Section ");
518 color(YELLOW);
519 printf("'%s'\n", name);
520 color(GREEN);
521 printf(" pos = ");
522 color(YELLOW);
523 printf("%8x - %8x\n", pos, pos+size);
524 color(GREEN);
525 printf(" len = ");
526 color(YELLOW);
527 printf("%8x\n", size);
528 color(GREEN);
529 printf(" flags = ");
530 color(YELLOW);
531 printf("%8x", sec_hdr->flags);
532 color(RED);
533 if(data_sec)
534 printf(" Data Section");
535 else
536 printf(" Boot Section");
537 if(encrypted)
538 printf(" (Encrypted)");
539 printf("\n");
540
541 /* save it */
542 byte *sec = xmalloc(size);
543 if(encrypted)
544 cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0);
545 else
546 memcpy(sec, g_buf + pos, size);
547
548 extract_section(data_sec, name, sec, size, " ");
549 free(sec);
550 }
551 }
552 else
553 {
554 /* advanced raw mode */
555 color(BLUE);
556 printf("Commands\n");
557 uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE;
558 byte iv[16];
559 const char *indent = " ";
560 while(true)
561 {
562 /* restart with IV */
563 memcpy(iv, g_buf, 16);
564 byte cmd[BLOCK_SIZE];
565 if(sb_header->nr_keys > 0)
566 cbc_mac(g_buf + offset, cmd, 1, real_key, iv, &iv, 0);
567 else
568 memcpy(cmd, g_buf + offset, BLOCK_SIZE);
569 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd;
570 printf("%s", indent);
571 uint8_t checksum = instruction_checksum(hdr);
572 if(checksum != hdr->checksum)
573 {
574 color(GREY);
575 printf("[Bad checksum']");
576 }
577
578 if(hdr->opcode == SB_INST_NOP)
579 {
580 color(RED);
581 printf("NOOP\n");
582 offset += BLOCK_SIZE;
583 }
584 else if(hdr->opcode == SB_INST_TAG)
585 {
586 struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr;
587 color(RED);
588 printf("BTAG");
589 color(OFF);printf(" | ");
590 color(BLUE);
591 printf("sec=0x%08x", tag->identifier);
592 color(OFF);printf(" | ");
593 color(GREEN);
594 printf("cnt=0x%08x", tag->len);
595 color(OFF);printf(" | ");
596 color(YELLOW);
597 printf("flg=0x%08x", tag->flags);
598 color(OFF);
599 if(tag->hdr.flags & SB_INST_LAST_TAG)
600 {
601 printf(" | ");
602 color(RED);
603 printf(" Last section");
604 color(OFF);
605 }
606 printf("\n");
607 offset += sizeof(struct sb_instruction_tag_t);
608
609 char name[5];
610 fill_section_name(name, tag->identifier);
611 int pos = offset;
612 int size = tag->len * BLOCK_SIZE;
613 int data_sec = !(tag->flags & SECTION_BOOTABLE);
614 int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
615
616 color(GREEN);
617 printf("%sSection ", indent);
618 color(YELLOW);
619 printf("'%s'\n", name);
620 color(GREEN);
621 printf("%s pos = ", indent);
622 color(YELLOW);
623 printf("%8x - %8x\n", pos, pos+size);
624 color(GREEN);
625 printf("%s len = ", indent);
626 color(YELLOW);
627 printf("%8x\n", size);
628 color(GREEN);
629 printf("%s flags = ", indent);
630 color(YELLOW);
631 printf("%8x", tag->flags);
632 color(RED);
633 if(data_sec)
634 printf(" Data Section");
635 else
636 printf(" Boot Section");
637 if(encrypted)
638 printf(" (Encrypted)");
639 printf("\n");
640
641 /* save it */
642 byte *sec = xmalloc(size);
643 if(encrypted)
644 cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0);
645 else
646 memcpy(sec, g_buf + pos, size);
647
648 extract_section(data_sec, name, sec, size, " ");
649 free(sec);
650
651 /* last one ? */
652 if(tag->hdr.flags & SB_INST_LAST_TAG)
653 break;
654 offset += size;
655 }
656 else
657 {
658 color(RED);
659 printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
660 break;
661 }
662 }
663 }
664
665 /* final signature */
666 color(BLUE);
667 printf("Final signature:\n");
668 byte decrypted_block[32];
669 if(sb_header->nr_keys > 0)
670 {
671 color(GREEN);
672 printf(" Encrypted SHA-1:\n");
673 color(YELLOW);
674 byte *encrypted_block = &g_buf[filesize - 32];
675 printf(" ");
676 print_hex(encrypted_block, 16, true);
677 printf(" ");
678 print_hex(encrypted_block + 16, 16, true);
679 /* decrypt it */
680 cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0);
681 }
682 else
683 memcpy(decrypted_block, &g_buf[filesize - 32], 32);
684 color(GREEN);
685 printf(" File SHA-1:\n ");
686 color(YELLOW);
687 print_hex(decrypted_block, 20, false);
688 /* check it */
689 sha_1_init(&sha_1_params);
690 sha_1_update(&sha_1_params, g_buf, filesize - 32);
691 sha_1_finish(&sha_1_params);
692 sha_1_output(&sha_1_params, computed_sha1);
693 color(RED);
694 if(memcmp(decrypted_block, computed_sha1, 20) == 0)
695 printf(" Ok\n");
696 else
697 printf(" Failed\n");
698}
699
700void usage(void)
701{ 96{
702 printf("Usage: sbtoelf [options] sb-file\n"); 97 printf("Usage: sbtoelf [options] sb-file\n");
703 printf("Options:\n"); 98 printf("Options:\n");
704 printf(" -?/--help\tDisplay this message\n"); 99 printf(" -?/--help\tDisplay this message\n");
705 printf(" -o <file>\tSet output prefix\n"); 100 printf(" -o <file>\tSet output prefix\n");
706 printf(" -d/--debug\tEnable debug output\n"); 101 printf(" -d/--debug\tEnable debug output*\n");
707 printf(" -k <file>\tAdd key file\n"); 102 printf(" -k <file>\tAdd key file\n");
708 printf(" -z\t\tAdd zero key\n"); 103 printf(" -z\t\tAdd zero key\n");
709 printf(" -r\t\tUse raw command mode\n"); 104 printf(" -r\t\tUse raw command mode\n");
710 printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n"); 105 printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n");
711 printf(" -n/--no-color\tDisable output colors\n"); 106 printf(" -n/--no-color\tDisable output colors\n");
107 printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n");
108 printf("Options marked with a * are for debug purpose only\n");
712 exit(1); 109 exit(1);
713} 110}
714 111
112static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...)
113{
114 (void) user;
115 (void) error;
116 va_list args;
117 va_start(args, fmt);
118 color(c);
119 vprintf(fmt, args);
120 va_end(args);
121}
122
715static struct crypto_key_t g_zero_key = 123static struct crypto_key_t g_zero_key =
716{ 124{
717 .method = CRYPTO_KEY, 125 .method = CRYPTO_KEY,
@@ -720,6 +128,9 @@ static struct crypto_key_t g_zero_key =
720 128
721int main(int argc, char **argv) 129int main(int argc, char **argv)
722{ 130{
131 bool raw_mode = false;
132 const char *loopback = NULL;
133
723 while(1) 134 while(1)
724 { 135 {
725 static struct option long_options[] = 136 static struct option long_options[] =
@@ -728,16 +139,22 @@ int main(int argc, char **argv)
728 {"debug", no_argument, 0, 'd'}, 139 {"debug", no_argument, 0, 'd'},
729 {"add-key", required_argument, 0, 'a'}, 140 {"add-key", required_argument, 0, 'a'},
730 {"no-color", no_argument, 0, 'n'}, 141 {"no-color", no_argument, 0, 'n'},
142 {"loopback", required_argument, 0, 'l'},
731 {0, 0, 0, 0} 143 {0, 0, 0, 0}
732 }; 144 };
733 145
734 int c = getopt_long(argc, argv, "?do:k:zra:n", long_options, NULL); 146 int c = getopt_long(argc, argv, "?do:k:zra:nl:", long_options, NULL);
735 if(c == -1) 147 if(c == -1)
736 break; 148 break;
737 switch(c) 149 switch(c)
738 { 150 {
739 case -1: 151 case -1:
740 break; 152 break;
153 case 'l':
154 if(loopback)
155 bug("Only one loopback file can be specified !\n");
156 loopback = optarg;
157 break;
741 case 'n': 158 case 'n':
742 enable_color(false); 159 enable_color(false);
743 break; 160 break;
@@ -761,7 +178,7 @@ int main(int argc, char **argv)
761 break; 178 break;
762 } 179 }
763 case 'r': 180 case 'r':
764 g_raw_mode = true; 181 raw_mode = true;
765 break; 182 break;
766 case 'a': 183 case 'a':
767 { 184 {
@@ -788,24 +205,26 @@ int main(int argc, char **argv)
788 return 1; 205 return 1;
789 } 206 }
790 207
791 const char *sb_file = argv[optind]; 208 const char *sb_filename = argv[optind];
792 FILE *fd = fopen(sb_file, "rb");
793 if(fd == NULL)
794 bug("Cannot open input file\n");
795 fseek(fd, 0, SEEK_END);
796 size_t size = ftell(fd);
797 fseek(fd, 0, SEEK_SET);
798
799 g_buf = xmalloc(size);
800 if(fread(g_buf, 1, size, fd) != size) /* load the whole file into memory */
801 bugp("reading firmware");
802
803 fclose(fd);
804
805 extract(size);
806 209
807 color(OFF); 210 struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf);
808 211 if(g_debug)
809 free(g_buf); 212 {
213 color(GREY);
214 printf("[Debug output]\n");
215 sb_dump(file, NULL, sb_printf);
216 }
217 if(loopback)
218 {
219 /* sb_read_file will fill real key and IV but we don't want to override
220 * them when looping back otherwise the output will be inconsistent and
221 * garbage */
222 free(file->real_key);
223 file->real_key = NULL;
224 free(file->crypto_iv);
225 file->crypto_iv = NULL;
226 sb_write_file(file, loopback);
227 }
228
810 return 0; 229 return 0;
811} 230}