diff options
Diffstat (limited to 'utils/sbtools/sbtoelf.c')
-rw-r--r-- | utils/sbtools/sbtoelf.c | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/utils/sbtools/sbtoelf.c b/utils/sbtools/sbtoelf.c new file mode 100644 index 0000000000..632c4b3eb9 --- /dev/null +++ b/utils/sbtools/sbtoelf.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2010 Bertrik Sikken | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | /* | ||
23 | * .sb file parser and chunk extractor | ||
24 | * | ||
25 | * Based on amsinfo, which is | ||
26 | * Copyright © 2008 Rafaël Carré <rafael.carre@gmail.com> | ||
27 | */ | ||
28 | |||
29 | #define _ISOC99_SOURCE /* snprintf() */ | ||
30 | #include <stdio.h> | ||
31 | #include <sys/types.h> | ||
32 | #include <sys/stat.h> | ||
33 | #include <fcntl.h> | ||
34 | #include <errno.h> | ||
35 | #include <unistd.h> | ||
36 | #include <stdlib.h> | ||
37 | #include <inttypes.h> | ||
38 | #include <string.h> | ||
39 | #include <ctype.h> | ||
40 | #include <time.h> | ||
41 | |||
42 | #include "crypto.h" | ||
43 | #include "elf.h" | ||
44 | #include "sb.h" | ||
45 | |||
46 | #if 1 /* ANSI colors */ | ||
47 | |||
48 | # define color(a) printf("%s",a) | ||
49 | char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' }; | ||
50 | |||
51 | char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' }; | ||
52 | char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' }; | ||
53 | char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' }; | ||
54 | char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' }; | ||
55 | char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; | ||
56 | |||
57 | #else | ||
58 | /* disable colors */ | ||
59 | # define color(a) | ||
60 | #endif | ||
61 | |||
62 | #define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0) | ||
63 | #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0) | ||
64 | |||
65 | /* all blocks are sized as a multiple of 0x1ff */ | ||
66 | #define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) | ||
67 | |||
68 | /* If you find a firmware that breaks the known format ^^ */ | ||
69 | #define assert(a) do { if(!(a)) { fprintf(stderr,"Assertion \"%s\" failed in %s() line %d!\n\nPlease send us your firmware!\n",#a,__func__,__LINE__); exit(1); } } while(0) | ||
70 | |||
71 | /* globals */ | ||
72 | |||
73 | size_t g_sz; /* file size */ | ||
74 | uint8_t *g_buf; /* file content */ | ||
75 | #define PREFIX_SIZE 128 | ||
76 | char out_prefix[PREFIX_SIZE]; | ||
77 | const char *key_file; | ||
78 | |||
79 | void *xmalloc(size_t s) /* malloc helper, used in elf.c */ | ||
80 | { | ||
81 | void * r = malloc(s); | ||
82 | if(!r) bugp("malloc"); | ||
83 | return r; | ||
84 | } | ||
85 | |||
86 | static void print_hex(byte *data, int len, bool newline) | ||
87 | { | ||
88 | for(int i = 0; i < len; i++) | ||
89 | printf("%02X ", data[i]); | ||
90 | if(newline) | ||
91 | printf("\n"); | ||
92 | } | ||
93 | |||
94 | int convxdigit(char digit, byte *val) | ||
95 | { | ||
96 | if(digit >= '0' && digit <= '9') | ||
97 | { | ||
98 | *val = digit - '0'; | ||
99 | return 0; | ||
100 | } | ||
101 | else if(digit >= 'A' && digit <= 'F') | ||
102 | { | ||
103 | *val = digit - 'A' + 10; | ||
104 | return 0; | ||
105 | } | ||
106 | else if(digit >= 'a' && digit <= 'f') | ||
107 | { | ||
108 | *val = digit - 'a' + 10; | ||
109 | return 0; | ||
110 | } | ||
111 | else | ||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | typedef byte (*key_array_t)[16]; | ||
116 | |||
117 | static key_array_t read_keys(int num_keys) | ||
118 | { | ||
119 | int size; | ||
120 | struct stat st; | ||
121 | int fd = open(key_file,O_RDONLY); | ||
122 | if(fd == -1) | ||
123 | bugp("opening key file failed"); | ||
124 | if(fstat(fd,&st) == -1) | ||
125 | bugp("key file stat() failed"); | ||
126 | size = st.st_size; | ||
127 | char *buf = xmalloc(size); | ||
128 | if(read(fd, buf, size) != (ssize_t)size) | ||
129 | bugp("reading key file"); | ||
130 | close(fd); | ||
131 | |||
132 | key_array_t keys = xmalloc(sizeof(byte[16]) * num_keys); | ||
133 | int pos = 0; | ||
134 | for(int i = 0; i < num_keys; i++) | ||
135 | { | ||
136 | /* skip ws */ | ||
137 | while(pos < size && isspace(buf[pos])) | ||
138 | pos++; | ||
139 | /* enough space ? */ | ||
140 | if((pos + 32) > size) | ||
141 | bugp("invalid key file (not enough keys)"); | ||
142 | for(int j = 0; j < 16; j++) | ||
143 | { | ||
144 | byte a, b; | ||
145 | if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b)) | ||
146 | bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n"); | ||
147 | keys[i][j] = (a << 4) | b; | ||
148 | } | ||
149 | pos += 32; | ||
150 | } | ||
151 | free(buf); | ||
152 | |||
153 | return keys; | ||
154 | } | ||
155 | |||
156 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) | ||
157 | |||
158 | static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) | ||
159 | { | ||
160 | uint8_t sum = 90; | ||
161 | byte *ptr = (byte *)hdr; | ||
162 | for(int i = 1; i < 16; i++) | ||
163 | sum += ptr[i]; | ||
164 | return sum; | ||
165 | } | ||
166 | |||
167 | static void elf_write(void *user, uint32_t addr, const void *buf, size_t count) | ||
168 | { | ||
169 | FILE *f = user; | ||
170 | fseek(f, addr, SEEK_SET); | ||
171 | fwrite(buf, count, 1, f); | ||
172 | } | ||
173 | |||
174 | static void extract_elf_section(struct elf_params_t *elf, int count, const char *prefix, | ||
175 | const char *indent) | ||
176 | { | ||
177 | char *filename = xmalloc(strlen(prefix) + 32); | ||
178 | sprintf(filename, "%s.%d.elf", prefix, count); | ||
179 | printf("%swrite %s\n", indent, filename); | ||
180 | |||
181 | FILE *fd = fopen(filename, "wb"); | ||
182 | free(filename); | ||
183 | |||
184 | if(fd == NULL) | ||
185 | return ; | ||
186 | elf_output(elf, elf_write, fd); | ||
187 | fclose(fd); | ||
188 | } | ||
189 | |||
190 | static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent) | ||
191 | { | ||
192 | char filename[PREFIX_SIZE + 32]; | ||
193 | snprintf(filename, sizeof filename, "%s%s.bin", out_prefix, name); | ||
194 | FILE *fd = fopen(filename, "wb"); | ||
195 | if (fd != NULL) { | ||
196 | fwrite(buf, size, 1, fd); | ||
197 | fclose(fd); | ||
198 | } | ||
199 | if(data_sec) | ||
200 | return; | ||
201 | |||
202 | snprintf(filename, sizeof filename, "%s%s", out_prefix, name); | ||
203 | |||
204 | /* elf construction */ | ||
205 | struct elf_params_t elf; | ||
206 | elf_init(&elf); | ||
207 | int elf_count = 0; | ||
208 | /* Pretty print the content */ | ||
209 | int pos = 0; | ||
210 | while(pos < size) | ||
211 | { | ||
212 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos]; | ||
213 | printf("%s", indent); | ||
214 | uint8_t checksum = instruction_checksum(hdr); | ||
215 | if(checksum != hdr->checksum) | ||
216 | { | ||
217 | color(GREY); | ||
218 | printf("[Bad checksum]"); | ||
219 | } | ||
220 | |||
221 | if(hdr->opcode == SB_INST_LOAD) | ||
222 | { | ||
223 | struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos]; | ||
224 | color(RED); | ||
225 | printf("LOAD"); | ||
226 | color(OFF);printf(" | "); | ||
227 | color(BLUE); | ||
228 | printf("addr=0x%08x", load->addr); | ||
229 | color(OFF);printf(" | "); | ||
230 | color(GREEN); | ||
231 | printf("len=0x%08x", load->len); | ||
232 | color(OFF);printf(" | "); | ||
233 | color(YELLOW); | ||
234 | printf("crc=0x%08x", load->crc); | ||
235 | /* data is padded to 16-byte boundary with random data and crc'ed with it */ | ||
236 | uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)], | ||
237 | ROUND_UP(load->len, 16)); | ||
238 | color(RED); | ||
239 | if(load->crc == computed_crc) | ||
240 | printf(" Ok\n"); | ||
241 | else | ||
242 | printf(" Failed (crc=0x%08x)\n", computed_crc); | ||
243 | |||
244 | /* elf construction */ | ||
245 | elf_add_load_section(&elf, load->addr, load->len, | ||
246 | &buf[pos + sizeof(struct sb_instruction_load_t)]); | ||
247 | |||
248 | pos += load->len + sizeof(struct sb_instruction_load_t); | ||
249 | // unsure about rounding | ||
250 | pos = ROUND_UP(pos, 16); | ||
251 | } | ||
252 | else if(hdr->opcode == SB_INST_FILL) | ||
253 | { | ||
254 | struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos]; | ||
255 | color(RED); | ||
256 | printf("FILL"); | ||
257 | color(OFF);printf(" | "); | ||
258 | color(BLUE); | ||
259 | printf("addr=0x%08x", fill->addr); | ||
260 | color(OFF);printf(" | "); | ||
261 | color(GREEN); | ||
262 | printf("len=0x%08x", fill->len); | ||
263 | color(OFF);printf(" | "); | ||
264 | color(YELLOW); | ||
265 | printf("pattern=0x%08x\n", fill->pattern); | ||
266 | color(OFF); | ||
267 | |||
268 | /* elf construction */ | ||
269 | elf_add_fill_section(&elf, fill->addr, fill->len, fill->pattern); | ||
270 | |||
271 | pos += sizeof(struct sb_instruction_fill_t); | ||
272 | // fixme: useless as pos is a multiple of 16 and fill struct is 4-bytes wide ? | ||
273 | pos = ROUND_UP(pos, 16); | ||
274 | } | ||
275 | else if(hdr->opcode == SB_INST_CALL || | ||
276 | hdr->opcode == SB_INST_JUMP) | ||
277 | { | ||
278 | int is_call = (hdr->opcode == SB_INST_CALL); | ||
279 | struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos]; | ||
280 | color(RED); | ||
281 | if(is_call) | ||
282 | printf("CALL"); | ||
283 | else | ||
284 | printf("JUMP"); | ||
285 | color(OFF);printf(" | "); | ||
286 | color(BLUE); | ||
287 | printf("addr=0x%08x", call->addr); | ||
288 | color(OFF);printf(" | "); | ||
289 | color(GREEN); | ||
290 | printf("arg=0x%08x\n", call->arg); | ||
291 | color(OFF); | ||
292 | |||
293 | /* elf construction */ | ||
294 | elf_set_start_addr(&elf, call->addr); | ||
295 | extract_elf_section(&elf, elf_count++, filename, indent); | ||
296 | elf_release(&elf); | ||
297 | elf_init(&elf); | ||
298 | |||
299 | pos += sizeof(struct sb_instruction_call_t); | ||
300 | // fixme: useless as pos is a multiple of 16 and call struct is 4-bytes wide ? | ||
301 | pos = ROUND_UP(pos, 16); | ||
302 | } | ||
303 | else | ||
304 | { | ||
305 | color(RED); | ||
306 | printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos); | ||
307 | break; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | if(!elf_is_empty(&elf)) | ||
312 | extract_elf_section(&elf, elf_count++, filename, indent); | ||
313 | elf_release(&elf); | ||
314 | } | ||
315 | |||
316 | static void extract(unsigned long filesize) | ||
317 | { | ||
318 | struct sha_1_params_t sha_1_params; | ||
319 | /* Basic header info */ | ||
320 | struct sb_header_t *sb_header = (struct sb_header_t *)g_buf; | ||
321 | |||
322 | if(memcmp(sb_header->signature, "STMP", 4) != 0) | ||
323 | bugp("Bad signature"); | ||
324 | if(sb_header->image_size * BLOCK_SIZE != filesize) | ||
325 | bugp("File size mismatch"); | ||
326 | if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t)) | ||
327 | bugp("Bad header size"); | ||
328 | if(sb_header->major_ver != IMAGE_MAJOR_VERSION || | ||
329 | sb_header->minor_ver != IMAGE_MINOR_VERSION) | ||
330 | bugp("Bad file format version"); | ||
331 | if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t)) | ||
332 | bugp("Bad section header size"); | ||
333 | |||
334 | color(BLUE); | ||
335 | printf("Basic info:\n"); | ||
336 | color(GREEN); | ||
337 | printf(" Header SHA-1: "); | ||
338 | byte *hdr_sha1 = sb_header->sha1_header; | ||
339 | color(YELLOW); | ||
340 | print_hex(hdr_sha1, 20, false); | ||
341 | /* Check SHA1 sum */ | ||
342 | byte computed_sha1[20]; | ||
343 | sha_1_init(&sha_1_params); | ||
344 | sha_1_update(&sha_1_params, &sb_header->signature[0], | ||
345 | sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header)); | ||
346 | sha_1_finish(&sha_1_params); | ||
347 | sha_1_output(&sha_1_params, computed_sha1); | ||
348 | color(RED); | ||
349 | if(memcmp(hdr_sha1, computed_sha1, 20) == 0) | ||
350 | printf(" Ok\n"); | ||
351 | else | ||
352 | printf(" Failed\n"); | ||
353 | color(GREEN); | ||
354 | printf(" Flags: "); | ||
355 | color(YELLOW); | ||
356 | printf("%x\n", sb_header->flags); | ||
357 | color(GREEN); | ||
358 | printf(" Total file size : "); | ||
359 | color(YELLOW); | ||
360 | printf("%ld\n", filesize); | ||
361 | |||
362 | /* Sizes and offsets */ | ||
363 | color(BLUE); | ||
364 | printf("Sizes and offsets:\n"); | ||
365 | color(GREEN); | ||
366 | printf(" # of encryption keys = "); | ||
367 | color(YELLOW); | ||
368 | printf("%d\n", sb_header->nr_keys); | ||
369 | color(GREEN); | ||
370 | printf(" # of sections = "); | ||
371 | color(YELLOW); | ||
372 | printf("%d\n", sb_header->nr_sections); | ||
373 | |||
374 | /* Versions */ | ||
375 | color(BLUE); | ||
376 | printf("Versions\n"); | ||
377 | color(GREEN); | ||
378 | |||
379 | printf(" Random 1: "); | ||
380 | color(YELLOW); | ||
381 | print_hex(sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true); | ||
382 | color(GREEN); | ||
383 | printf(" Random 2: "); | ||
384 | color(YELLOW); | ||
385 | print_hex(sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true); | ||
386 | |||
387 | uint64_t micros = sb_header->timestamp; | ||
388 | time_t seconds = (micros / (uint64_t)1000000L); | ||
389 | struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ | ||
390 | seconds += mktime(&tm_base); | ||
391 | struct tm *time = gmtime(&seconds); | ||
392 | color(GREEN); | ||
393 | printf(" Creation date/time = "); | ||
394 | color(YELLOW); | ||
395 | printf("%s", asctime(time)); | ||
396 | |||
397 | color(GREEN); | ||
398 | printf(" Product version = "); | ||
399 | color(YELLOW); | ||
400 | printf("%X.%X.%X\n", sb_header->product_ver.major, | ||
401 | sb_header->product_ver.minor, sb_header->product_ver.revision); | ||
402 | color(GREEN); | ||
403 | printf(" Component version = "); | ||
404 | color(YELLOW); | ||
405 | printf("%X.%X.%X\n", sb_header->component_ver.major, | ||
406 | sb_header->component_ver.minor, sb_header->component_ver.revision); | ||
407 | |||
408 | /* encryption cbc-mac */ | ||
409 | key_array_t keys = NULL; /* array of 16-bytes keys */ | ||
410 | byte real_key[16]; | ||
411 | if(sb_header->nr_keys > 0) | ||
412 | { | ||
413 | keys = read_keys(sb_header->nr_keys); | ||
414 | color(BLUE); | ||
415 | printf("Encryption data\n"); | ||
416 | for(int i = 0; i < sb_header->nr_keys; i++) | ||
417 | { | ||
418 | color(RED); | ||
419 | printf(" Key %d: ", i); | ||
420 | print_hex(keys[i], 16, true); | ||
421 | color(GREEN); | ||
422 | printf(" CBC-MAC of headers: "); | ||
423 | |||
424 | uint32_t ofs = sizeof(struct sb_header_t) | ||
425 | + sizeof(struct sb_section_header_t) * sb_header->nr_sections | ||
426 | + sizeof(struct sb_key_dictionary_entry_t) * i; | ||
427 | struct sb_key_dictionary_entry_t *dict_entry = | ||
428 | (struct sb_key_dictionary_entry_t *)&g_buf[ofs]; | ||
429 | /* cbc mac */ | ||
430 | color(YELLOW); | ||
431 | print_hex(dict_entry->hdr_cbc_mac, 16, false); | ||
432 | /* check it */ | ||
433 | byte computed_cbc_mac[16]; | ||
434 | byte zero[16]; | ||
435 | memset(zero, 0, 16); | ||
436 | cbc_mac(g_buf, NULL, sb_header->header_size + sb_header->nr_sections, | ||
437 | keys[i], zero, &computed_cbc_mac, 1); | ||
438 | color(RED); | ||
439 | if(memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0) | ||
440 | printf(" Ok\n"); | ||
441 | else | ||
442 | printf(" Failed\n"); | ||
443 | color(GREEN); | ||
444 | |||
445 | printf(" Encrypted key : "); | ||
446 | color(YELLOW); | ||
447 | print_hex(dict_entry->key, 16, true); | ||
448 | color(GREEN); | ||
449 | /* decrypt */ | ||
450 | byte decrypted_key[16]; | ||
451 | byte iv[16]; | ||
452 | memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ | ||
453 | cbc_mac(dict_entry->key, decrypted_key, 1, keys[i], iv, NULL, 0); | ||
454 | printf(" Decrypted key : "); | ||
455 | color(YELLOW); | ||
456 | print_hex(decrypted_key, 16, false); | ||
457 | /* cross-check or copy */ | ||
458 | if(i == 0) | ||
459 | memcpy(real_key, decrypted_key, 16); | ||
460 | else if(memcmp(real_key, decrypted_key, 16) == 0) | ||
461 | { | ||
462 | color(RED); | ||
463 | printf(" Cross-Check Ok"); | ||
464 | } | ||
465 | else | ||
466 | { | ||
467 | color(RED); | ||
468 | printf(" Cross-Check Failed"); | ||
469 | } | ||
470 | printf("\n"); | ||
471 | } | ||
472 | } | ||
473 | |||
474 | /* sections */ | ||
475 | color(BLUE); | ||
476 | printf("Sections\n"); | ||
477 | |||
478 | for(int i = 0; i < sb_header->nr_sections; i++) | ||
479 | { | ||
480 | uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t); | ||
481 | struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&g_buf[ofs]; | ||
482 | |||
483 | char name[5]; | ||
484 | name[0] = (sec_hdr->identifier >> 24) & 0xff; | ||
485 | name[1] = (sec_hdr->identifier >> 16) & 0xff; | ||
486 | name[2] = (sec_hdr->identifier >> 8) & 0xff; | ||
487 | name[3] = sec_hdr->identifier & 0xff; | ||
488 | for(int i = 0; i < 4; i++) | ||
489 | if(!isprint(name[i])) | ||
490 | name[i] = '_'; | ||
491 | name[4] = 0; | ||
492 | int pos = sec_hdr->offset * BLOCK_SIZE; | ||
493 | int size = sec_hdr->size * BLOCK_SIZE; | ||
494 | int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE); | ||
495 | int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT); | ||
496 | |||
497 | color(GREEN); | ||
498 | printf(" Chunk "); | ||
499 | color(YELLOW); | ||
500 | printf("'%s'\n", name); | ||
501 | color(GREEN); | ||
502 | printf(" pos = "); | ||
503 | color(YELLOW); | ||
504 | printf("%8x - %8x\n", pos, pos+size); | ||
505 | color(GREEN); | ||
506 | printf(" len = "); | ||
507 | color(YELLOW); | ||
508 | printf("%8x\n", size); | ||
509 | color(GREEN); | ||
510 | printf(" flags = "); | ||
511 | color(YELLOW); | ||
512 | printf("%8x", sec_hdr->flags); | ||
513 | color(RED); | ||
514 | if(data_sec) | ||
515 | printf(" Data Section"); | ||
516 | else | ||
517 | printf(" Boot Section"); | ||
518 | if(encrypted) | ||
519 | printf(" (Encrypted)"); | ||
520 | printf("\n"); | ||
521 | |||
522 | /* save it */ | ||
523 | byte *sec = xmalloc(size); | ||
524 | if(encrypted) | ||
525 | cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0); | ||
526 | else | ||
527 | memcpy(sec, g_buf + pos, size); | ||
528 | |||
529 | extract_section(data_sec, name, sec, size, " "); | ||
530 | free(sec); | ||
531 | } | ||
532 | |||
533 | /* final signature */ | ||
534 | color(BLUE); | ||
535 | printf("Final signature:\n"); | ||
536 | color(GREEN); | ||
537 | printf(" Encrypted signature:\n"); | ||
538 | color(YELLOW); | ||
539 | byte *encrypted_block = &g_buf[filesize - 32]; | ||
540 | printf(" "); | ||
541 | print_hex(encrypted_block, 16, true); | ||
542 | printf(" "); | ||
543 | print_hex(encrypted_block + 16, 16, true); | ||
544 | /* decrypt it */ | ||
545 | byte decrypted_block[32]; | ||
546 | cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0); | ||
547 | color(GREEN); | ||
548 | printf(" Decrypted SHA-1:\n "); | ||
549 | color(YELLOW); | ||
550 | print_hex(decrypted_block, 20, false); | ||
551 | /* check it */ | ||
552 | sha_1_init(&sha_1_params); | ||
553 | sha_1_update(&sha_1_params, g_buf, filesize - 32); | ||
554 | sha_1_finish(&sha_1_params); | ||
555 | sha_1_output(&sha_1_params, computed_sha1); | ||
556 | color(RED); | ||
557 | if(memcmp(decrypted_block, computed_sha1, 20) == 0) | ||
558 | printf(" Ok\n"); | ||
559 | else | ||
560 | printf(" Failed\n"); | ||
561 | } | ||
562 | |||
563 | int main(int argc, const char **argv) | ||
564 | { | ||
565 | int fd; | ||
566 | struct stat st; | ||
567 | if(argc != 3 && argc != 4) | ||
568 | bug("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv); | ||
569 | |||
570 | if(argc == 4) | ||
571 | snprintf(out_prefix, PREFIX_SIZE, "%s", argv[3]); | ||
572 | else | ||
573 | strcpy(out_prefix, ""); | ||
574 | |||
575 | if( (fd = open(argv[1], O_RDONLY)) == -1 ) | ||
576 | bugp("opening firmware failed"); | ||
577 | |||
578 | key_file = argv[2]; | ||
579 | |||
580 | if(fstat(fd, &st) == -1) | ||
581 | bugp("firmware stat() failed"); | ||
582 | g_sz = st.st_size; | ||
583 | |||
584 | g_buf = xmalloc(g_sz); | ||
585 | if(read(fd, g_buf, g_sz) != (ssize_t)g_sz) /* load the whole file into memory */ | ||
586 | bugp("reading firmware"); | ||
587 | |||
588 | close(fd); | ||
589 | |||
590 | extract(st.st_size); | ||
591 | |||
592 | color(OFF); | ||
593 | |||
594 | free(g_buf); | ||
595 | return 0; | ||
596 | } | ||