From b2c59541b47e98fe69ab973ca4ab2688d70aac23 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Sun, 17 Apr 2011 22:30:09 +0000 Subject: sbtoelf: fix to handle unencrypted files (minor tweak) elftosb: properly generate sb file (encryption not implemented yet) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@29742 a1c6a512-1295-4272-9138-f99709370657 --- utils/sbtools/crc.c | 7 +- utils/sbtools/crypto.h | 1 + utils/sbtools/elftosb.c | 204 +++++++++++++++++++++++++++++++++++++++++++++--- utils/sbtools/sb.h | 8 ++ utils/sbtools/sbtoelf.c | 43 ++++++---- 5 files changed, 234 insertions(+), 29 deletions(-) (limited to 'utils') diff --git a/utils/sbtools/crc.c b/utils/sbtools/crc.c index 8030141567..eaf257ddfe 100644 --- a/utils/sbtools/crc.c +++ b/utils/sbtools/crc.c @@ -70,7 +70,12 @@ static uint32_t crc_table[256] = { uint32_t crc(byte *data, int size) { - uint32_t c = 0xffffffff; + return crc_continue(0xffffffff, data, size); +} + +uint32_t crc_continue(uint32_t previous_crc, byte *data, int size) +{ + uint32_t c = previous_crc; /* normal CRC */ for(int i = 0; i < size; i++) c = crc_table[data[i] ^ (c >> 24)] ^ (c << 8); diff --git a/utils/sbtools/crypto.h b/utils/sbtools/crypto.h index e36900df47..0662ef8587 100644 --- a/utils/sbtools/crypto.h +++ b/utils/sbtools/crypto.h @@ -41,6 +41,7 @@ void cbc_mac( /* crc.c */ uint32_t crc(byte *data, int size); +uint32_t crc_continue(uint32_t previous_crc, byte *data, int size); /* sha1.c */ struct sha_1_params_t diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c index 275f21724d..28717fddd9 100644 --- a/utils/sbtools/elftosb.c +++ b/utils/sbtools/elftosb.c @@ -42,10 +42,23 @@ bool g_debug = false; +#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) + /** * Misc */ +void generate_random_data(void *buf, size_t sz) +{ + static int rand_fd = -1; + if(rand_fd == -1) + rand_fd = open("/dev/urandom", O_RDONLY); + if(rand_fd == -1) + bugp("failed to open /dev/urandom"); + if(read(rand_fd, buf, sz) != (ssize_t)sz) + bugp("failed to read /dev/urandom"); +} + void *xmalloc(size_t s) /* malloc helper, used in elf.c */ { void * r = malloc(s); @@ -316,6 +329,7 @@ static void next_lexem(char **ptr, char *end, struct lexem_t *lexem) #undef ret_simple } +#if 0 static void log_lexem(struct lexem_t *lexem) { switch(lexem->type) @@ -333,6 +347,7 @@ static void log_lexem(struct lexem_t *lexem) default: printf(""); } } +#endif static struct cmd_source_t *find_source_by_id(struct cmd_file_t *cmd_file, const char *id) { @@ -495,6 +510,9 @@ struct sb_inst_t uint32_t pattern; uint32_t addr; // + /* for production use */ + uint32_t padding_size; + uint8_t *padding; }; struct sb_section_t @@ -504,6 +522,7 @@ struct sb_section_t struct sb_inst_t *insts; /* for production use */ uint32_t file_offset; /* in blocks */ + uint32_t sec_size; /* in blocks */ }; struct sb_file_t @@ -637,6 +656,24 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) * Sb file production */ +static void fill_gaps(struct sb_file_t *sb) +{ + for(int i = 0; i < sb->nr_sections; i++) + { + struct sb_section_t *sec = &sb->sections[i]; + for(int j = 0; j < sec->nr_insts; j++) + { + struct sb_inst_t *inst = &sec->insts[j]; + if(inst->inst != SB_INST_LOAD) + continue; + inst->padding_size = ROUND_UP(inst->size, BLOCK_SIZE) - inst->size; + /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */ + inst->padding = xmalloc(15); + generate_random_data(inst->padding, 15); + } + } +} + static void compute_sb_offsets(struct sb_file_t *sb) { sb->image_size = 0; @@ -663,6 +700,7 @@ static void compute_sb_offsets(struct sb_file_t *sb) printf("%s | addr=0x%08x | arg=0x%08x\n", inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, 0); sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; + sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE; } else if(inst->inst == SB_INST_FILL) { @@ -670,6 +708,7 @@ static void compute_sb_offsets(struct sb_file_t *sb) printf("FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n", inst->addr, inst->size, inst->pattern); sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; + sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE; } else if(inst->inst == SB_INST_LOAD) { @@ -677,8 +716,10 @@ static void compute_sb_offsets(struct sb_file_t *sb) printf("LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size); /* load header */ sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; + sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE; /* data + alignment */ - sb->image_size += (inst->size + BLOCK_SIZE - 1) / BLOCK_SIZE; + sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE; + sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE; } } } @@ -686,8 +727,27 @@ static void compute_sb_offsets(struct sb_file_t *sb) sb->image_size += 2; } +static uint64_t generate_timestamp() +{ + struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ + time_t t = time(NULL) - mktime(&tm_base); + return (uint64_t)t * 1000000L; +} + +void generate_version(struct sb_version_t *ver) +{ + ver->major = 0x999; + ver->pad0 = 0; + ver->minor = 0x999; + ver->pad1 = 0; + ver->revision = 0x999; + ver->pad2 = 0; +} + static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) { + struct sha_1_params_t sha_1_params; + sb_hdr->signature[0] = 'S'; sb_hdr->signature[1] = 'T'; sb_hdr->signature[2] = 'M'; @@ -696,6 +756,83 @@ static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) sb_hdr->minor_ver = IMAGE_MINOR_VERSION; sb_hdr->flags = 0; sb_hdr->image_size = sb->image_size; + sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE; + sb_hdr->first_boot_sec_id = sb->sections[0].identifier; + sb_hdr->nr_keys = g_nr_keys; + sb_hdr->nr_sections = sb->nr_sections; + sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE; + sb_hdr->key_dict_off = sb_hdr->header_size + + sb_hdr->sec_hdr_size * sb_hdr->nr_sections; + sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off + + sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE; + generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0)); + generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1)); + sb_hdr->timestamp = generate_timestamp(); + generate_version(&sb_hdr->product_ver); + generate_version(&sb_hdr->component_ver); + sb_hdr->drive_tag = 0; + + sha_1_init(&sha_1_params); + sha_1_update(&sha_1_params, &sb_hdr->signature[0], + sizeof(struct sb_header_t) - sizeof(sb_hdr->sha1_header)); + sha_1_finish(&sha_1_params); + sha_1_output(&sha_1_params, sb_hdr->sha1_header); +} + +static void produce_sb_section_header(struct sb_section_t *sec, + struct sb_section_header_t *sec_hdr) +{ + sec_hdr->identifier = sec->identifier; + sec_hdr->offset = sec->file_offset; + sec_hdr->size = sec->sec_size; + sec_hdr->flags = SECTION_BOOTABLE; +} + +static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) +{ + uint8_t sum = 90; + byte *ptr = (byte *)hdr; + for(int i = 1; i < 16; i++) + sum += ptr[i]; + return sum; +} + +static void produce_section_tag_cmd(struct sb_section_t *sec, + struct sb_instruction_tag_t *tag, bool is_last) +{ + tag->hdr.opcode = SB_INST_TAG; + tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0; + tag->identifier = sec->identifier; + tag->len = sec->sec_size; + tag->flags = SECTION_BOOTABLE; + tag->hdr.checksum = instruction_checksum(&tag->hdr); +} + +void produce_sb_instruction(struct sb_inst_t *inst, + struct sb_instruction_common_t *cmd) +{ + cmd->hdr.flags = 0; + cmd->hdr.opcode = inst->inst; + cmd->addr = inst->addr; + cmd->len = inst->size; + switch(inst->inst) + { + case SB_INST_CALL: + case SB_INST_JUMP: + cmd->len = 0; + cmd->data = 0; + break; + case SB_INST_FILL: + cmd->data = inst->pattern; + break; + case SB_INST_LOAD: + cmd->data = crc_continue(crc(inst->data, inst->size), + inst->padding, inst->padding_size); + break; + default: + break; + } + cmd->hdr.checksum = instruction_checksum(&cmd->hdr); } static void produce_sb_file(struct sb_file_t *sb, const char *filename) @@ -705,25 +842,68 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename) if(fd < 0) bugp("cannot open output file"); + byte real_key[16]; + + fill_gaps(sb); compute_sb_offsets(sb); + generate_random_data(real_key, sizeof(real_key)); + + /* global SHA-1 */ + struct sha_1_params_t file_sha1; + sha_1_init(&file_sha1); + /* produce and write header */ struct sb_header_t sb_hdr; produce_sb_header(sb, &sb_hdr); + sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr)); + write(fd, &sb_hdr, sizeof(sb_hdr)); + + /* produce and write section headers */ + for(int i = 0; i < sb_hdr.nr_sections; i++) + { + struct sb_section_header_t sb_sec_hdr; + produce_sb_section_header(&sb->sections[i], &sb_sec_hdr); + sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr)); + write(fd, &sb_sec_hdr, sizeof(sb_sec_hdr)); + } + /* produce key dictionary */ + /* produce sections data */ + for(int i = 0; i< sb_hdr.nr_sections; i++) + { + /* produce tag command */ + struct sb_instruction_tag_t tag_cmd; + produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections); + sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd)); + write(fd, &tag_cmd, sizeof(tag_cmd)); + /* produce other commands */ + for(int j = 0; j < sb->sections[i].nr_insts; j++) + { + struct sb_inst_t *inst = &sb->sections[i].insts[j]; + /* command */ + struct sb_instruction_common_t cmd; + produce_sb_instruction(inst, &cmd); + sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); + write(fd, &cmd, sizeof(cmd)); + /* data */ + if(inst->inst == SB_INST_LOAD) + { + sha_1_update(&file_sha1, inst->data, inst->size); + write(fd, inst->data, inst->size); + sha_1_update(&file_sha1, inst->padding, inst->padding_size); + write(fd, inst->padding, inst->padding_size); + } + } + } + /* write file SHA-1 */ + byte final_sig[32]; + sha_1_finish(&file_sha1); + sha_1_output(&file_sha1, final_sig); + generate_random_data(final_sig + 20, 12); + write(fd, final_sig, 32); close(fd); } -#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) - -static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) -{ - uint8_t sum = 90; - byte *ptr = (byte *)hdr; - for(int i = 1; i < 16; i++) - sum += ptr[i]; - return sum; -} - int main(int argc, const char **argv) { if(argc != 4) diff --git a/utils/sbtools/sb.h b/utils/sbtools/sb.h index 01ee0e642f..fe9ee3f4db 100644 --- a/utils/sbtools/sb.h +++ b/utils/sbtools/sb.h @@ -99,6 +99,14 @@ struct sb_instruction_header_t uint16_t flags; } __attribute__((packed)); +struct sb_instruction_common_t +{ + struct sb_instruction_header_t hdr; + uint32_t addr; + uint32_t len; + uint32_t data; +} __attribute__((packed)); + struct sb_instruction_load_t { struct sb_instruction_header_t hdr; diff --git a/utils/sbtools/sbtoelf.c b/utils/sbtools/sbtoelf.c index 54daf7bc1f..be719c6a5f 100644 --- a/utils/sbtools/sbtoelf.c +++ b/utils/sbtools/sbtoelf.c @@ -421,6 +421,14 @@ static void extract(unsigned long filesize) printf(" Drive tag = "); color(YELLOW); printf("%x\n", sb_header->drive_tag); + color(GREEN); + printf(" First boot tag offset = "); + color(YELLOW); + printf("%x\n", sb_header->first_boot_tag_off); + color(GREEN); + printf(" First boot section ID = "); + color(YELLOW); + printf("0x%08x\n", sb_header->first_boot_sec_id); /* encryption cbc-mac */ key_array_t keys = NULL; /* array of 16-bytes keys */ @@ -504,7 +512,7 @@ static void extract(unsigned long filesize) int pos = sec_hdr->offset * BLOCK_SIZE; int size = sec_hdr->size * BLOCK_SIZE; int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE); - int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT); + int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; color(GREEN); printf(" Section "); @@ -547,9 +555,7 @@ static void extract(unsigned long filesize) /* advanced raw mode */ color(BLUE); printf("Commands\n"); - uint32_t offset = sizeof(struct sb_header_t) - + sizeof(struct sb_section_header_t) * sb_header->nr_sections - + sizeof(struct sb_key_dictionary_entry_t) * sb_header->nr_keys; + uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE; byte iv[16]; memcpy(iv, g_buf, 16); const char *indent = " "; @@ -597,7 +603,7 @@ static void extract(unsigned long filesize) int pos = offset; int size = tag->len * BLOCK_SIZE; int data_sec = !(tag->flags & SECTION_BOOTABLE); - int encrypted = !(tag->flags & SECTION_CLEARTEXT); + int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; color(GREEN); printf("%sSection ", indent); @@ -653,19 +659,24 @@ static void extract(unsigned long filesize) /* final signature */ color(BLUE); printf("Final signature:\n"); - color(GREEN); - printf(" Encrypted signature:\n"); - color(YELLOW); - byte *encrypted_block = &g_buf[filesize - 32]; - printf(" "); - print_hex(encrypted_block, 16, true); - printf(" "); - print_hex(encrypted_block + 16, 16, true); - /* decrypt it */ byte decrypted_block[32]; - cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0); + if(sb_header->nr_keys > 0) + { + color(GREEN); + printf(" Encrypted SHA-1:\n"); + color(YELLOW); + byte *encrypted_block = &g_buf[filesize - 32]; + printf(" "); + print_hex(encrypted_block, 16, true); + printf(" "); + print_hex(encrypted_block + 16, 16, true); + /* decrypt it */ + cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0); + } + else + memcpy(decrypted_block, &g_buf[filesize - 32], 32); color(GREEN); - printf(" Decrypted SHA-1:\n "); + printf(" File SHA-1:\n "); color(YELLOW); print_hex(decrypted_block, 20, false); /* check it */ -- cgit v1.2.3