From 5827937270bac874ae9e04679b3130fef9e306c4 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Sun, 6 Nov 2011 01:49:13 +0000 Subject: sbtools: rename to imxtools, move imx_hid_recovery to imxtools/sbloader, fix tools to correctly handle/free memory, properly return error codes git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30907 a1c6a512-1295-4272-9138-f99709370657 --- utils/imx_hid_recovery/Makefile | 15 - utils/imx_hid_recovery/imx_hid_recovery.c | 174 ----- utils/imxtools/Makefile | 26 + utils/imxtools/README | 32 + utils/imxtools/aes128.c | 284 +++++++ utils/imxtools/crc.c | 83 ++ utils/imxtools/crypto.c | 188 +++++ utils/imxtools/crypto.h | 115 +++ utils/imxtools/dbparser.c | 849 +++++++++++++++++++++ utils/imxtools/dbparser.h | 118 +++ utils/imxtools/elf.c | 575 ++++++++++++++ utils/imxtools/elf.h | 94 +++ utils/imxtools/elftosb.c | 461 +++++++++++ utils/imxtools/fuze+_key_file.txt | 1 + utils/imxtools/misc.c | 248 ++++++ utils/imxtools/misc.h | 59 ++ utils/imxtools/sb.c | 1181 +++++++++++++++++++++++++++++ utils/imxtools/sb.h | 237 ++++++ utils/imxtools/sbloader.c | 174 +++++ utils/imxtools/sbtoelf.c | 302 ++++++++ utils/imxtools/sha1.c | 150 ++++ utils/sbtools/Makefile | 22 - utils/sbtools/README | 32 - utils/sbtools/aes128.c | 284 ------- utils/sbtools/crc.c | 83 -- utils/sbtools/crypto.c | 188 ----- utils/sbtools/crypto.h | 114 --- utils/sbtools/dbparser.c | 785 ------------------- utils/sbtools/dbparser.h | 116 --- utils/sbtools/elf.c | 572 -------------- utils/sbtools/elf.h | 94 --- utils/sbtools/elftosb.c | 449 ----------- utils/sbtools/fuze+_key_file.txt | 1 - utils/sbtools/misc.c | 234 ------ utils/sbtools/misc.h | 57 -- utils/sbtools/sb.c | 1100 --------------------------- utils/sbtools/sb.h | 219 ------ utils/sbtools/sbtoelf.c | 294 ------- utils/sbtools/sha1.c | 150 ---- 39 files changed, 5177 insertions(+), 4983 deletions(-) delete mode 100644 utils/imx_hid_recovery/Makefile delete mode 100644 utils/imx_hid_recovery/imx_hid_recovery.c create mode 100644 utils/imxtools/Makefile create mode 100644 utils/imxtools/README create mode 100644 utils/imxtools/aes128.c create mode 100644 utils/imxtools/crc.c create mode 100644 utils/imxtools/crypto.c create mode 100644 utils/imxtools/crypto.h create mode 100644 utils/imxtools/dbparser.c create mode 100644 utils/imxtools/dbparser.h create mode 100644 utils/imxtools/elf.c create mode 100644 utils/imxtools/elf.h create mode 100644 utils/imxtools/elftosb.c create mode 100644 utils/imxtools/fuze+_key_file.txt create mode 100644 utils/imxtools/misc.c create mode 100644 utils/imxtools/misc.h create mode 100644 utils/imxtools/sb.c create mode 100644 utils/imxtools/sb.h create mode 100644 utils/imxtools/sbloader.c create mode 100644 utils/imxtools/sbtoelf.c create mode 100644 utils/imxtools/sha1.c delete mode 100644 utils/sbtools/Makefile delete mode 100644 utils/sbtools/README delete mode 100644 utils/sbtools/aes128.c delete mode 100644 utils/sbtools/crc.c delete mode 100644 utils/sbtools/crypto.c delete mode 100644 utils/sbtools/crypto.h delete mode 100644 utils/sbtools/dbparser.c delete mode 100644 utils/sbtools/dbparser.h delete mode 100644 utils/sbtools/elf.c delete mode 100644 utils/sbtools/elf.h delete mode 100644 utils/sbtools/elftosb.c delete mode 100644 utils/sbtools/fuze+_key_file.txt delete mode 100644 utils/sbtools/misc.c delete mode 100644 utils/sbtools/misc.h delete mode 100644 utils/sbtools/sb.c delete mode 100644 utils/sbtools/sb.h delete mode 100644 utils/sbtools/sbtoelf.c delete mode 100644 utils/sbtools/sha1.c diff --git a/utils/imx_hid_recovery/Makefile b/utils/imx_hid_recovery/Makefile deleted file mode 100644 index 24d0b8e3d3..0000000000 --- a/utils/imx_hid_recovery/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -CC=gcc -LD=gcc - -all: imx_hid_recovery - -imx_hid_recovery.o: imx_hid_recovery.c - $(CC) -c -Wall -O2 -std=c99 `pkg-config --cflags libusb-1.0` -o $@ $< - -imx_hid_recovery: imx_hid_recovery.o - $(LD) -o $@ $< `pkg-config --libs libusb-1.0` - -clean: - rm -rf imx_hid_recovery.o - - diff --git a/utils/imx_hid_recovery/imx_hid_recovery.c b/utils/imx_hid_recovery/imx_hid_recovery.c deleted file mode 100644 index ba4645f8ab..0000000000 --- a/utils/imx_hid_recovery/imx_hid_recovery.c +++ /dev/null @@ -1,174 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include -#include -#include -#include -#include - -void put32le(uint8_t *buf, uint32_t i) -{ - *buf++ = i & 0xff; - *buf++ = (i >> 8) & 0xff; - *buf++ = (i >> 16) & 0xff; - *buf++ = (i >> 24) & 0xff; -} - -void put32be(uint8_t *buf, uint32_t i) -{ - *buf++ = (i >> 24) & 0xff; - *buf++ = (i >> 16) & 0xff; - *buf++ = (i >> 8) & 0xff; - *buf++ = i & 0xff; -} - -int main(int argc, char **argv) -{ - int ret; - uint8_t msg[0x20]; - uint8_t *p; - FILE *f; - int i, xfer_size, nr_xfers, recv_size; - - if(argc != 3) - { - printf("usage: %s \n", argv[0]); - return 1; - } - - char *end; - xfer_size = strtol(argv[1], &end, 0); - if(end != (argv[1] + strlen(argv[1]))) - { - printf("Invalid transfer size !\n"); - return 1; - } - - libusb_device_handle *dev; - - libusb_init(NULL); - - libusb_set_debug(NULL, 3); - - /* MX23 */ - dev = libusb_open_device_with_vid_pid(NULL, 0x066F, 0x3780); - if(dev == NULL) - /* MX28 */ - dev = libusb_open_device_with_vid_pid(NULL, 0x15A2, 0x004F); - if(dev == NULL) - { - printf("Cannot open device\n"); - return 1; - } - - libusb_detach_kernel_driver(dev, 0); - libusb_detach_kernel_driver(dev, 4); - - libusb_claim_interface (dev, 0); - libusb_claim_interface (dev, 4); - - if (!dev) - { - printf("No dev\n"); - exit(1); - } - - f = fopen(argv[2], "r"); - if(f == NULL) - { - perror("cannot open file"); - return 1; - } - fseek(f, 0, SEEK_END); - size_t size = ftell(f); - fseek(f, 0, SEEK_SET); - - printf("Transfer size: %d\n", xfer_size); - nr_xfers = (size + xfer_size - 1) / xfer_size; - uint8_t *file_buf = malloc(nr_xfers * xfer_size); - memset(file_buf, 0xff, nr_xfers * xfer_size); // pad with 0xff - if(fread(file_buf, size, 1, f) != 1) - { - perror("read error"); - fclose(f); - return 1; - } - fclose(f); - - memset(msg, 0, 0x20); - - p = msg; - - *p++ = 0x01; // Init upload command - *p++ = 'B'; // Signature - *p++ = 'L'; - *p++ = 'T'; - *p++ = 'C'; - put32le(p, 0x1); // I guess version or sub-command - p += 4; - put32le(p, size); // Payload size - - // The second command starts at 0x20 - - p = &msg[0x10]; - - *p++ = 0x02; // Start upload - put32be(p, size); // Payload size, again - - ret = libusb_control_transfer(dev, - LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 0x9, 0x201, 0, - msg, 0x20, 1000); - if(ret < 0) - { - printf("transfer error at init step\n"); - return 1; - } - - uint8_t *xfer_buf = malloc(1 + xfer_size); - - for(i = 0; i < nr_xfers; i++) - { - xfer_buf[0] = 0x2; - memcpy(&xfer_buf[1], &file_buf[i * xfer_size], xfer_size); - - ret = libusb_control_transfer(dev, - LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, - 0x9, 0x202, 0, xfer_buf, xfer_size + 1, 1000); - if(ret < 0) - { - printf("transfer error at send step %d\n", i); - return 1; - } - } - - ret = libusb_interrupt_transfer(dev, 0x81, xfer_buf, xfer_size, &recv_size, - 1000); - if(ret < 0) - { - printf("transfer error at final stage\n"); - return 1; - } - - printf("ret %i\n", ret); - - return 0; -} - diff --git a/utils/imxtools/Makefile b/utils/imxtools/Makefile new file mode 100644 index 0000000000..7a09d86d24 --- /dev/null +++ b/utils/imxtools/Makefile @@ -0,0 +1,26 @@ +DEFINES=-DCRYPTO_LIBUSB +CC=gcc +LD=gcc +CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES) +LDFLAGS=`pkg-config --libs libusb-1.0` +BINS=elftosb sbtoelf sbloader + +all: $(BINS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o + $(LD) -o $@ $^ $(LDFLAGS) + +elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o + $(LD) -o $@ $^ $(LDFLAGS) + +sbloader: sbloader.o + $(LD) -o $@ $^ $(LDFLAGS) + +clean: + rm -fr *.o + +veryclean: + rm -rf $(BINS) diff --git a/utils/imxtools/README b/utils/imxtools/README new file mode 100644 index 0000000000..8bf6fd5f8e --- /dev/null +++ b/utils/imxtools/README @@ -0,0 +1,32 @@ +This file document the format of the command file used by the elftosb tool. +By no way our tools tries to be compatible with Freescale's elftosb2. +However, our format is more subset of the general one. + +The parse supports a limited form of comments: comments starting with // and ending at the end of the line. + +A file first contains the list of sources: + +sources +{ + hw_init = "sdram_init.elf"; + rockbox = "rockbox.elf"; +} + +It can then contain an arbitrary number of section. A section is identified by a number. +Within a section, three commands are supported: "load", "jump" and "call": + +section(0x626f6f74) // hex for 'boot' +{ + load hw_init; + call hw_init; + load rockbox; + jump rockbox; +} + +Finally, both elftosb and sbtoelf tools use key files. A key file is a list of keys. +Each key consist is 128-bit long and is written in hexadecimal: + +00000000000000000000000000000000 + +The parser does not handle blank line and only allows a final newline at the end of the file. +A file is allowed to contain zero (0) keys. diff --git a/utils/imxtools/aes128.c b/utils/imxtools/aes128.c new file mode 100644 index 0000000000..5870813db8 --- /dev/null +++ b/utils/imxtools/aes128.c @@ -0,0 +1,284 @@ +// Simple, thoroughly commented implementation of 128-bit AES / Rijndael using C +// Chris Hulbert - chris.hulbert@gmail.com - http://splinter.com.au/blog +// References: +// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard +// http://en.wikipedia.org/wiki/Rijndael_key_schedule +// http://en.wikipeia.org/wiki/Rijndael_mix_columns +// http://en.wikipedia.org/wiki/Rijndael_S-box +// This code is public domain, or any OSI-approved license, your choice. No warranty. +#include "crypto.h" + +// Here are all the lookup tables for the row shifts, rcon, s-boxes, and galois field multiplications +byte shift_rows_table[] = {0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11}; +byte shift_rows_table_inv[] = {0,13,10,7,4,1,14,11,8,5,2,15,12,9,6,3}; +byte lookup_rcon[]={0x8d,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a}; +byte lookup_sbox[]={0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16}; +byte lookup_sbox_inv[]={0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d}; +byte lookup_g2 []={0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,0x1b,0x19,0x1f,0x1d,0x13,0x11,0x17,0x15,0x0b,0x09,0x0f,0x0d,0x03,0x01,0x07,0x05,0x3b,0x39,0x3f,0x3d,0x33,0x31,0x37,0x35,0x2b,0x29,0x2f,0x2d,0x23,0x21,0x27,0x25,0x5b,0x59,0x5f,0x5d,0x53,0x51,0x57,0x55,0x4b,0x49,0x4f,0x4d,0x43,0x41,0x47,0x45,0x7b,0x79,0x7f,0x7d,0x73,0x71,0x77,0x75,0x6b,0x69,0x6f,0x6d,0x63,0x61,0x67,0x65,0x9b,0x99,0x9f,0x9d,0x93,0x91,0x97,0x95,0x8b,0x89,0x8f,0x8d,0x83,0x81,0x87,0x85,0xbb,0xb9,0xbf,0xbd,0xb3,0xb1,0xb7,0xb5,0xab,0xa9,0xaf,0xad,0xa3,0xa1,0xa7,0xa5,0xdb,0xd9,0xdf,0xdd,0xd3,0xd1,0xd7,0xd5,0xcb,0xc9,0xcf,0xcd,0xc3,0xc1,0xc7,0xc5,0xfb,0xf9,0xff,0xfd,0xf3,0xf1,0xf7,0xf5,0xeb,0xe9,0xef,0xed,0xe3,0xe1,0xe7,0xe5}; +byte lookup_g3 []={0x00,0x03,0x06,0x05,0x0c,0x0f,0x0a,0x09,0x18,0x1b,0x1e,0x1d,0x14,0x17,0x12,0x11,0x30,0x33,0x36,0x35,0x3c,0x3f,0x3a,0x39,0x28,0x2b,0x2e,0x2d,0x24,0x27,0x22,0x21,0x60,0x63,0x66,0x65,0x6c,0x6f,0x6a,0x69,0x78,0x7b,0x7e,0x7d,0x74,0x77,0x72,0x71,0x50,0x53,0x56,0x55,0x5c,0x5f,0x5a,0x59,0x48,0x4b,0x4e,0x4d,0x44,0x47,0x42,0x41,0xc0,0xc3,0xc6,0xc5,0xcc,0xcf,0xca,0xc9,0xd8,0xdb,0xde,0xdd,0xd4,0xd7,0xd2,0xd1,0xf0,0xf3,0xf6,0xf5,0xfc,0xff,0xfa,0xf9,0xe8,0xeb,0xee,0xed,0xe4,0xe7,0xe2,0xe1,0xa0,0xa3,0xa6,0xa5,0xac,0xaf,0xaa,0xa9,0xb8,0xbb,0xbe,0xbd,0xb4,0xb7,0xb2,0xb1,0x90,0x93,0x96,0x95,0x9c,0x9f,0x9a,0x99,0x88,0x8b,0x8e,0x8d,0x84,0x87,0x82,0x81,0x9b,0x98,0x9d,0x9e,0x97,0x94,0x91,0x92,0x83,0x80,0x85,0x86,0x8f,0x8c,0x89,0x8a,0xab,0xa8,0xad,0xae,0xa7,0xa4,0xa1,0xa2,0xb3,0xb0,0xb5,0xb6,0xbf,0xbc,0xb9,0xba,0xfb,0xf8,0xfd,0xfe,0xf7,0xf4,0xf1,0xf2,0xe3,0xe0,0xe5,0xe6,0xef,0xec,0xe9,0xea,0xcb,0xc8,0xcd,0xce,0xc7,0xc4,0xc1,0xc2,0xd3,0xd0,0xd5,0xd6,0xdf,0xdc,0xd9,0xda,0x5b,0x58,0x5d,0x5e,0x57,0x54,0x51,0x52,0x43,0x40,0x45,0x46,0x4f,0x4c,0x49,0x4a,0x6b,0x68,0x6d,0x6e,0x67,0x64,0x61,0x62,0x73,0x70,0x75,0x76,0x7f,0x7c,0x79,0x7a,0x3b,0x38,0x3d,0x3e,0x37,0x34,0x31,0x32,0x23,0x20,0x25,0x26,0x2f,0x2c,0x29,0x2a,0x0b,0x08,0x0d,0x0e,0x07,0x04,0x01,0x02,0x13,0x10,0x15,0x16,0x1f,0x1c,0x19,0x1a}; +byte lookup_g9 []={0x00,0x09,0x12,0x1b,0x24,0x2d,0x36,0x3f,0x48,0x41,0x5a,0x53,0x6c,0x65,0x7e,0x77,0x90,0x99,0x82,0x8b,0xb4,0xbd,0xa6,0xaf,0xd8,0xd1,0xca,0xc3,0xfc,0xf5,0xee,0xe7,0x3b,0x32,0x29,0x20,0x1f,0x16,0x0d,0x04,0x73,0x7a,0x61,0x68,0x57,0x5e,0x45,0x4c,0xab,0xa2,0xb9,0xb0,0x8f,0x86,0x9d,0x94,0xe3,0xea,0xf1,0xf8,0xc7,0xce,0xd5,0xdc,0x76,0x7f,0x64,0x6d,0x52,0x5b,0x40,0x49,0x3e,0x37,0x2c,0x25,0x1a,0x13,0x08,0x01,0xe6,0xef,0xf4,0xfd,0xc2,0xcb,0xd0,0xd9,0xae,0xa7,0xbc,0xb5,0x8a,0x83,0x98,0x91,0x4d,0x44,0x5f,0x56,0x69,0x60,0x7b,0x72,0x05,0x0c,0x17,0x1e,0x21,0x28,0x33,0x3a,0xdd,0xd4,0xcf,0xc6,0xf9,0xf0,0xeb,0xe2,0x95,0x9c,0x87,0x8e,0xb1,0xb8,0xa3,0xaa,0xec,0xe5,0xfe,0xf7,0xc8,0xc1,0xda,0xd3,0xa4,0xad,0xb6,0xbf,0x80,0x89,0x92,0x9b,0x7c,0x75,0x6e,0x67,0x58,0x51,0x4a,0x43,0x34,0x3d,0x26,0x2f,0x10,0x19,0x02,0x0b,0xd7,0xde,0xc5,0xcc,0xf3,0xfa,0xe1,0xe8,0x9f,0x96,0x8d,0x84,0xbb,0xb2,0xa9,0xa0,0x47,0x4e,0x55,0x5c,0x63,0x6a,0x71,0x78,0x0f,0x06,0x1d,0x14,0x2b,0x22,0x39,0x30,0x9a,0x93,0x88,0x81,0xbe,0xb7,0xac,0xa5,0xd2,0xdb,0xc0,0xc9,0xf6,0xff,0xe4,0xed,0x0a,0x03,0x18,0x11,0x2e,0x27,0x3c,0x35,0x42,0x4b,0x50,0x59,0x66,0x6f,0x74,0x7d,0xa1,0xa8,0xb3,0xba,0x85,0x8c,0x97,0x9e,0xe9,0xe0,0xfb,0xf2,0xcd,0xc4,0xdf,0xd6,0x31,0x38,0x23,0x2a,0x15,0x1c,0x07,0x0e,0x79,0x70,0x6b,0x62,0x5d,0x54,0x4f,0x46}; +byte lookup_g11 []={0x00,0x0b,0x16,0x1d,0x2c,0x27,0x3a,0x31,0x58,0x53,0x4e,0x45,0x74,0x7f,0x62,0x69,0xb0,0xbb,0xa6,0xad,0x9c,0x97,0x8a,0x81,0xe8,0xe3,0xfe,0xf5,0xc4,0xcf,0xd2,0xd9,0x7b,0x70,0x6d,0x66,0x57,0x5c,0x41,0x4a,0x23,0x28,0x35,0x3e,0x0f,0x04,0x19,0x12,0xcb,0xc0,0xdd,0xd6,0xe7,0xec,0xf1,0xfa,0x93,0x98,0x85,0x8e,0xbf,0xb4,0xa9,0xa2,0xf6,0xfd,0xe0,0xeb,0xda,0xd1,0xcc,0xc7,0xae,0xa5,0xb8,0xb3,0x82,0x89,0x94,0x9f,0x46,0x4d,0x50,0x5b,0x6a,0x61,0x7c,0x77,0x1e,0x15,0x08,0x03,0x32,0x39,0x24,0x2f,0x8d,0x86,0x9b,0x90,0xa1,0xaa,0xb7,0xbc,0xd5,0xde,0xc3,0xc8,0xf9,0xf2,0xef,0xe4,0x3d,0x36,0x2b,0x20,0x11,0x1a,0x07,0x0c,0x65,0x6e,0x73,0x78,0x49,0x42,0x5f,0x54,0xf7,0xfc,0xe1,0xea,0xdb,0xd0,0xcd,0xc6,0xaf,0xa4,0xb9,0xb2,0x83,0x88,0x95,0x9e,0x47,0x4c,0x51,0x5a,0x6b,0x60,0x7d,0x76,0x1f,0x14,0x09,0x02,0x33,0x38,0x25,0x2e,0x8c,0x87,0x9a,0x91,0xa0,0xab,0xb6,0xbd,0xd4,0xdf,0xc2,0xc9,0xf8,0xf3,0xee,0xe5,0x3c,0x37,0x2a,0x21,0x10,0x1b,0x06,0x0d,0x64,0x6f,0x72,0x79,0x48,0x43,0x5e,0x55,0x01,0x0a,0x17,0x1c,0x2d,0x26,0x3b,0x30,0x59,0x52,0x4f,0x44,0x75,0x7e,0x63,0x68,0xb1,0xba,0xa7,0xac,0x9d,0x96,0x8b,0x80,0xe9,0xe2,0xff,0xf4,0xc5,0xce,0xd3,0xd8,0x7a,0x71,0x6c,0x67,0x56,0x5d,0x40,0x4b,0x22,0x29,0x34,0x3f,0x0e,0x05,0x18,0x13,0xca,0xc1,0xdc,0xd7,0xe6,0xed,0xf0,0xfb,0x92,0x99,0x84,0x8f,0xbe,0xb5,0xa8,0xa3}; +byte lookup_g13 []={0x00,0x0d,0x1a,0x17,0x34,0x39,0x2e,0x23,0x68,0x65,0x72,0x7f,0x5c,0x51,0x46,0x4b,0xd0,0xdd,0xca,0xc7,0xe4,0xe9,0xfe,0xf3,0xb8,0xb5,0xa2,0xaf,0x8c,0x81,0x96,0x9b,0xbb,0xb6,0xa1,0xac,0x8f,0x82,0x95,0x98,0xd3,0xde,0xc9,0xc4,0xe7,0xea,0xfd,0xf0,0x6b,0x66,0x71,0x7c,0x5f,0x52,0x45,0x48,0x03,0x0e,0x19,0x14,0x37,0x3a,0x2d,0x20,0x6d,0x60,0x77,0x7a,0x59,0x54,0x43,0x4e,0x05,0x08,0x1f,0x12,0x31,0x3c,0x2b,0x26,0xbd,0xb0,0xa7,0xaa,0x89,0x84,0x93,0x9e,0xd5,0xd8,0xcf,0xc2,0xe1,0xec,0xfb,0xf6,0xd6,0xdb,0xcc,0xc1,0xe2,0xef,0xf8,0xf5,0xbe,0xb3,0xa4,0xa9,0x8a,0x87,0x90,0x9d,0x06,0x0b,0x1c,0x11,0x32,0x3f,0x28,0x25,0x6e,0x63,0x74,0x79,0x5a,0x57,0x40,0x4d,0xda,0xd7,0xc0,0xcd,0xee,0xe3,0xf4,0xf9,0xb2,0xbf,0xa8,0xa5,0x86,0x8b,0x9c,0x91,0x0a,0x07,0x10,0x1d,0x3e,0x33,0x24,0x29,0x62,0x6f,0x78,0x75,0x56,0x5b,0x4c,0x41,0x61,0x6c,0x7b,0x76,0x55,0x58,0x4f,0x42,0x09,0x04,0x13,0x1e,0x3d,0x30,0x27,0x2a,0xb1,0xbc,0xab,0xa6,0x85,0x88,0x9f,0x92,0xd9,0xd4,0xc3,0xce,0xed,0xe0,0xf7,0xfa,0xb7,0xba,0xad,0xa0,0x83,0x8e,0x99,0x94,0xdf,0xd2,0xc5,0xc8,0xeb,0xe6,0xf1,0xfc,0x67,0x6a,0x7d,0x70,0x53,0x5e,0x49,0x44,0x0f,0x02,0x15,0x18,0x3b,0x36,0x21,0x2c,0x0c,0x01,0x16,0x1b,0x38,0x35,0x22,0x2f,0x64,0x69,0x7e,0x73,0x50,0x5d,0x4a,0x47,0xdc,0xd1,0xc6,0xcb,0xe8,0xe5,0xf2,0xff,0xb4,0xb9,0xae,0xa3,0x80,0x8d,0x9a,0x97}; +byte lookup_g14 []={0x00,0x0e,0x1c,0x12,0x38,0x36,0x24,0x2a,0x70,0x7e,0x6c,0x62,0x48,0x46,0x54,0x5a,0xe0,0xee,0xfc,0xf2,0xd8,0xd6,0xc4,0xca,0x90,0x9e,0x8c,0x82,0xa8,0xa6,0xb4,0xba,0xdb,0xd5,0xc7,0xc9,0xe3,0xed,0xff,0xf1,0xab,0xa5,0xb7,0xb9,0x93,0x9d,0x8f,0x81,0x3b,0x35,0x27,0x29,0x03,0x0d,0x1f,0x11,0x4b,0x45,0x57,0x59,0x73,0x7d,0x6f,0x61,0xad,0xa3,0xb1,0xbf,0x95,0x9b,0x89,0x87,0xdd,0xd3,0xc1,0xcf,0xe5,0xeb,0xf9,0xf7,0x4d,0x43,0x51,0x5f,0x75,0x7b,0x69,0x67,0x3d,0x33,0x21,0x2f,0x05,0x0b,0x19,0x17,0x76,0x78,0x6a,0x64,0x4e,0x40,0x52,0x5c,0x06,0x08,0x1a,0x14,0x3e,0x30,0x22,0x2c,0x96,0x98,0x8a,0x84,0xae,0xa0,0xb2,0xbc,0xe6,0xe8,0xfa,0xf4,0xde,0xd0,0xc2,0xcc,0x41,0x4f,0x5d,0x53,0x79,0x77,0x65,0x6b,0x31,0x3f,0x2d,0x23,0x09,0x07,0x15,0x1b,0xa1,0xaf,0xbd,0xb3,0x99,0x97,0x85,0x8b,0xd1,0xdf,0xcd,0xc3,0xe9,0xe7,0xf5,0xfb,0x9a,0x94,0x86,0x88,0xa2,0xac,0xbe,0xb0,0xea,0xe4,0xf6,0xf8,0xd2,0xdc,0xce,0xc0,0x7a,0x74,0x66,0x68,0x42,0x4c,0x5e,0x50,0x0a,0x04,0x16,0x18,0x32,0x3c,0x2e,0x20,0xec,0xe2,0xf0,0xfe,0xd4,0xda,0xc8,0xc6,0x9c,0x92,0x80,0x8e,0xa4,0xaa,0xb8,0xb6,0x0c,0x02,0x10,0x1e,0x34,0x3a,0x28,0x26,0x7c,0x72,0x60,0x6e,0x44,0x4a,0x58,0x56,0x37,0x39,0x2b,0x25,0x0f,0x01,0x13,0x1d,0x47,0x49,0x5b,0x55,0x7f,0x71,0x63,0x6d,0xd7,0xd9,0xcb,0xc5,0xef,0xe1,0xf3,0xfd,0xa7,0xa9,0xbb,0xb5,0x9f,0x91,0x83,0x8d}; + +// Xor's all elements in a n byte array a by b +void xor_(byte *a, byte *b, int n) { + int i; + for (i=0;i ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "crypto.h" + +/* Table extracted from firmware, don't know if this is regular CRC32 */ + +static uint32_t crc_table[256] = { + 0x0, 0x4C11DB7, 0x9823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, + 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, + 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, + 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, + 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, + 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, + 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0x0BE2B5B58, 0x0BAEA46EF, 0x0B7A96036, + 0x0B3687D81, 0x0AD2F2D84, 0x0A9EE3033, 0x0A4AD16EA, 0x0A06C0B5D, 0x0D4326D90, + 0x0D0F37027, 0x0DDB056FE, 0x0D9714B49, 0x0C7361B4C, 0x0C3F706FB, 0x0CEB42022, + 0x0CA753D95, 0x0F23A8028, 0x0F6FB9D9F, 0x0FBB8BB46, 0x0FF79A6F1, 0x0E13EF6F4, + 0x0E5FFEB43, 0x0E8BCCD9A, 0x0EC7DD02D, 0x34867077, 0x30476DC0, 0x3D044B19, + 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, 0x128E9DCF, + 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x18AEB13, 0x54BF6A4, 0x808D07D, + 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, + 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, + 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, 0x0ACA5C697, + 0x0A864DB20, 0x0A527FDF9, 0x0A1E6E04E, 0x0BFA1B04B, 0x0BB60ADFC, 0x0B6238B25, + 0x0B2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, + 0x9D684044, 0x902B669D, 0x94EA7B2A, 0x0E0B41DE7, 0x0E4750050, 0x0E9362689, + 0x0EDF73B3E, 0x0F3B06B3B, 0x0F771768C, 0x0FA325055, 0x0FEF34DE2, 0x0C6BCF05F, + 0x0C27DEDE8, 0x0CF3ECB31, 0x0CBFFD686, 0x0D5B88683, 0x0D1799B34, 0x0DC3ABDED, + 0x0D8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, + 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, 0x46863638, + 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, + 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, + 0x3B5A6B9B, 0x315D626, 0x7D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, + 0x14D0BD4D, 0x19939B94, 0x1D528623, 0x0F12F560E, 0x0F5EE4BB9, 0x0F8AD6D60, + 0x0FC6C70D7, 0x0E22B20D2, 0x0E6EA3D65, 0x0EBA91BBC, 0x0EF68060B, 0x0D727BBB6, + 0x0D3E6A601, 0x0DEA580D8, 0x0DA649D6F, 0x0C423CD6A, 0x0C0E2D0DD, 0x0CDA1F604, + 0x0C960EBB3, 0x0BD3E8D7E, 0x0B9FF90C9, 0x0B4BCB610, 0x0B07DABA7, 0x0AE3AFBA2, + 0x0AAFBE615, 0x0A7B8C0CC, 0x0A379DD7B, 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, + 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, 0x5D8A9099, + 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, + 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, + 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087, + 0x1CD86D30, 0x29F3D35, 0x65E2082, 0x0B1D065B, 0x0FDC1BEC, 0x3793A651, + 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, + 0x29D4F654, 0x0C5A92679, 0x0C1683BCE, 0x0CC2B1D17, 0x0C8EA00A0, 0x0D6AD50A5, + 0x0D26C4D12, 0x0DF2F6BCB, 0x0DBEE767C, 0x0E3A1CBC1, 0x0E760D676, 0x0EA23F0AF, + 0x0EEE2ED18, 0x0F0A5BD1D, 0x0F464A0AA, 0x0F9278673, 0x0FDE69BC4, 0x89B8FD09, + 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, + 0x97FFAD0C, 0x0AFB010B1, 0x0AB710D06, 0x0A6322BDF, 0x0A2F33668, 0x0BCB4666D, + 0x0B8757BDA, 0x0B5365D03, 0x0B1F740B4 +}; + +uint32_t crc(byte *data, int size) +{ + 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); + return c; +} diff --git a/utils/imxtools/crypto.c b/utils/imxtools/crypto.c new file mode 100644 index 0000000000..d4afc6c816 --- /dev/null +++ b/utils/imxtools/crypto.c @@ -0,0 +1,188 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "crypto.h" +#include +#include +#ifdef CRYPTO_LIBUSB +#include "libusb.h" +#endif +#include "misc.h" + +static enum crypto_method_t cur_method = CRYPTO_NONE; +static byte key[16]; +static uint16_t usb_vid, usb_pid; + +void crypto_setup(enum crypto_method_t method, void *param) +{ + cur_method = method; + switch(method) + { + case CRYPTO_KEY: + memcpy(key, param, sizeof(key)); + break; + case CRYPTO_USBOTP: + { + uint32_t value = *(uint32_t *)param; + usb_vid = value >> 16; + usb_pid = value & 0xffff; + break; + } + default: + break; + } +} + +int crypto_apply( + byte *in_data, /* Input data */ + byte *out_data, /* Output data (or NULL) */ + int nr_blocks, /* Number of blocks (one block=16 bytes) */ + byte iv[16], /* Key */ + byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ + int encrypt) +{ + if(cur_method == CRYPTO_KEY) + { + cbc_mac(in_data, out_data, nr_blocks, key, iv, out_cbc_mac, encrypt); + return CRYPTO_ERROR_SUCCESS; + } + #ifdef CRYPTO_LIBUSB + else if(cur_method == CRYPTO_USBOTP) + { + if(out_cbc_mac && !encrypt) + memcpy(*out_cbc_mac, in_data + 16 * (nr_blocks - 1), 16); + + libusb_device_handle *handle = NULL; + libusb_context *ctx; + /* init library */ + libusb_init(&ctx); + libusb_set_debug(NULL,3); + /* open device */ + handle = libusb_open_device_with_vid_pid(ctx, usb_vid, usb_pid); + if(handle == NULL) + { + printf("usbotp: cannot open device %04x:%04x\n", usb_vid, usb_pid); + return CRYPTO_ERROR_NODEVICE; + } + /* get device pointer */ + libusb_device *mydev = libusb_get_device(handle); + if(g_debug) + printf("usbotp: device found at %d:%d\n", libusb_get_bus_number(mydev), + libusb_get_device_address(mydev)); + int config_id; + /* explore configuration */ + libusb_get_configuration(handle, &config_id); + struct libusb_config_descriptor *config; + libusb_get_active_config_descriptor(mydev, &config); + + if(g_debug) + { + printf("usbotp: configuration: %d\n", config_id); + printf("usbotp: interfaces: %d\n", config->bNumInterfaces); + } + + const struct libusb_endpoint_descriptor *endp = NULL; + int intf, intf_alt; + for(intf = 0; intf < config->bNumInterfaces; intf++) + for(intf_alt = 0; intf_alt < config->interface[intf].num_altsetting; intf_alt++) + for(int ep = 0; ep < config->interface[intf].altsetting[intf_alt].bNumEndpoints; ep++) + { + endp = &config->interface[intf].altsetting[intf_alt].endpoint[ep]; + if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT && + (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) + goto Lfound; + } + libusb_close(handle); + printf("usbotp: No suitable endpoint found\n"); + return CRYPTO_ERROR_BADENDP; + + if(g_debug) + { + printf("usbotp: use interface %d, alt %d\n", intf, intf_alt); + printf("usbotp: use endpoint %d\n", endp->bEndpointAddress); + } + Lfound: + if(libusb_claim_interface(handle, intf) != 0) + { + if(g_debug) + printf("usbotp: claim error\n"); + return CRYPTO_ERROR_CLAIMFAIL; + } + + int buffer_size = 16 + 16 * nr_blocks; + unsigned char *buffer = xmalloc(buffer_size); + memcpy(buffer, iv, 16); + memcpy(buffer + 16, in_data, 16 * nr_blocks); + int ret = libusb_control_transfer(handle, + LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE, + 0xaa, encrypt ? 0xeeee : 0xdddd, 0, buffer, buffer_size, 1000); + if(ret < 0) + { + if(g_debug) + printf("usbotp: control transfer failed: %d\n", ret); + libusb_release_interface(handle, intf); + libusb_close(handle); + return CRYPTO_ERROR_DEVREJECT; + } + + int recv_size; + ret = libusb_interrupt_transfer(handle, endp->bEndpointAddress, buffer, + buffer_size, &recv_size, 1000); + libusb_release_interface(handle, intf); + libusb_close(handle); + + if(ret < 0) + { + if(g_debug) + printf("usbotp: interrupt transfer failed: %d\n", ret); + return CRYPTO_ERROR_DEVSILENT; + } + if(recv_size != buffer_size) + { + if(g_debug) + printf("usbotp: device returned %d bytes, expected %d\n", recv_size, + buffer_size); + return CRYPTO_ERROR_DEVERR; + } + + if(out_data) + memcpy(out_data, buffer + 16, 16 * nr_blocks); + if(out_cbc_mac && encrypt) + memcpy(*out_cbc_mac, buffer + buffer_size - 16, 16); + + return CRYPTO_ERROR_SUCCESS; + } + #endif + else + return CRYPTO_ERROR_BADSETUP; +} + +int crypto_cbc( + byte *in_data, /* Input data */ + byte *out_data, /* Output data (or NULL) */ + int nr_blocks, /* Number of blocks (one block=16 bytes) */ + struct crypto_key_t *key, /* Key */ + byte iv[16], /* IV */ + byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ + int encrypt) +{ + crypto_setup(key->method, (void *)key->u.param); + return crypto_apply(in_data, out_data, nr_blocks, iv, out_cbc_mac, encrypt); +} diff --git a/utils/imxtools/crypto.h b/utils/imxtools/crypto.h new file mode 100644 index 0000000000..452db6a28d --- /dev/null +++ b/utils/imxtools/crypto.h @@ -0,0 +1,115 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __CRYPTO_H__ +#define __CRYPTO_H__ + +#include +#include +#include + +typedef uint8_t byte; + +/* aes128.c */ +void xor_(byte *a, byte *b, int n); +void EncryptAES(byte *msg, byte *key, byte *c); +void DecryptAES(byte *c, byte *key, byte *m); +void Pretty(byte* b,int len,const char* label); +void cbc_mac( + byte *in_data, /* Input data */ + byte *out_data, /* Output data (or NULL) */ + int nr_blocks, /* Number of blocks to encrypt/decrypt (one block=16 bytes) */ + byte key[16], /* Key */ + byte iv[16], /* Initialisation Vector */ + byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ + int encrypt /* 1 to encrypt, 0 to decrypt */ + ); + +/* crypto.c */ +enum crypto_method_t +{ + CRYPTO_NONE, /* disable */ + CRYPTO_KEY, /* key */ + CRYPTO_USBOTP, /* use usbotp device */ +}; + +/* parameter can be: + * - CRYPTO_KEY: array of 16-bytes (the key) + * - CRYPTO_USBOTP: 32-bit integer: vid << 16 | pid */ +void crypto_setup(enum crypto_method_t method, void *param); + +#define CRYPTO_ERROR_SUCCESS 0 +#define CRYPTO_ERROR_BADSETUP -1 /* bad crypto setup */ +#define CRYPTO_ERROR_NODEVICE -2 /* no device with vid:pid */ +#define CRYPTO_ERROR_BADENDP -3 /* device doesn't have the required endpoints */ +#define CRYPTO_ERROR_CLAIMFAIL -4 /* device interface claim error */ +#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */ +#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */ +#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */ +#define CRYPTO_NUM_ERRORS 8 +/* return 0 on success, <0 on error */ +int crypto_apply( + byte *in_data, /* Input data */ + byte *out_data, /* Output data (or NULL) */ + int nr_blocks, /* Number of blocks (one block=16 bytes) */ + byte iv[16], /* IV */ + byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ + int encrypt); + +/* all-in-one function */ +struct crypto_key_t +{ + enum crypto_method_t method; + union + { + byte key[16]; + uint32_t vid_pid; + byte param[0]; + }u; +}; + +int crypto_cbc( + byte *in_data, /* Input data */ + byte *out_data, /* Output data (or NULL) */ + int nr_blocks, /* Number of blocks (one block=16 bytes) */ + struct crypto_key_t *key, /* Key */ + byte iv[16], /* IV */ + byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ + int encrypt); + +/* 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 +{ + uint32_t hash[5]; + uint64_t buffer_nr_bits; + uint32_t w[80]; +}; + +void sha_1_init(struct sha_1_params_t *params); +void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data); +void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size); +void sha_1_finish(struct sha_1_params_t *params); +void sha_1_output(struct sha_1_params_t *params, byte *out); + +#endif /* __CRYPTO_H__ */ diff --git a/utils/imxtools/dbparser.c b/utils/imxtools/dbparser.c new file mode 100644 index 0000000000..b2027e5ad7 --- /dev/null +++ b/utils/imxtools/dbparser.c @@ -0,0 +1,849 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#define _POSIX_C_SOURCE 200809L /* for strdup */ +#include +#include +#include +#include +#include "dbparser.h" +#include "misc.h" + +enum lexem_type_t +{ + LEX_IDENTIFIER, + LEX_LPAREN, + LEX_RPAREN, + LEX_NUMBER, + LEX_STRING, /* double-quoted string */ + LEX_EQUAL, + LEX_SEMICOLON, + LEX_LBRACE, + LEX_RBRACE, + LEX_RANGLE, + LEX_OR, + LEX_LSHIFT, + LEX_COLON, + LEX_LE, + LEX_EOF +}; + +struct lexem_t +{ + enum lexem_type_t type; + /* if str is not NULL, it must be a malloc'd pointer */ + char *str; + uint32_t num; + int line; + const char *file; +}; + +struct context_t +{ + const char *file; + char *begin; + char *end; + char *ptr; + int line; +}; + +#define parse_error(ctx, ...) \ + do { fprintf(stderr, "%s:%d: ", ctx->file, ctx->line); \ + fprintf(stderr, __VA_ARGS__); exit(2); } while(0) + +static void advance(struct context_t *ctx, int nr_chars) +{ + while(nr_chars--) + { + if(*(ctx->ptr++) == '\n') + ctx->line++; + } +} + +static inline bool eof(struct context_t *ctx) +{ + return ctx->ptr == ctx->end; +} + +static inline bool next_valid(struct context_t *ctx, int nr) +{ + return ctx->ptr + nr < ctx->end; +} + +static inline char cur_char(struct context_t *ctx) +{ + return *ctx->ptr; +} + +static inline char next_char(struct context_t *ctx, int nr) +{ + return ctx->ptr[nr]; +} + +static inline void locate_lexem(struct lexem_t *lex, struct context_t *ctx) +{ + lex->file = ctx->file; + lex->line = ctx->line; +} + +static void __parse_string(struct context_t *ctx, void *user, void (*emit_fn)(void *user, char c)) +{ + while(!eof(ctx)) + { + if(cur_char(ctx) == '"') + break; + else if(cur_char(ctx) == '\\') + { + advance(ctx, 1); + if(eof(ctx)) + parse_error(ctx, "Unfinished string\n"); + if(cur_char(ctx) == '\\') emit_fn(user, '\\'); + else if(cur_char(ctx) == '\'') emit_fn(user, '\''); + else if(cur_char(ctx) == '\"') emit_fn(user, '\"'); + else parse_error(ctx, "Unknown escape sequence \\%c\n", cur_char(ctx)); + advance(ctx, 1); + } + else + { + emit_fn(user, cur_char(ctx)); + advance(ctx, 1); + } + } + if(eof(ctx) || cur_char(ctx) != '"') + parse_error(ctx, "Unfinished string\n"); + advance(ctx, 1); +} + +static void __parse_string_emit(void *user, char c) +{ + char **pstr = (char **)user; + *(*pstr)++ = c; +} + +static void __parse_string_count(void *user, char c) +{ + (void) c; + (*(int *)user)++; +} + +static void parse_string(struct context_t *ctx, struct lexem_t *lexem) +{ + locate_lexem(lexem, ctx); + /* skip " */ + advance(ctx, 1); + /* compute length */ + struct context_t cpy_ctx = *ctx; + int length = 0; + __parse_string(&cpy_ctx, (void *)&length, __parse_string_count); + /* parse again */ + lexem->type = LEX_STRING; + lexem->str = xmalloc(length + 1); + lexem->str[length] = 0; + char *pstr = lexem->str; + __parse_string(ctx, (void *)&pstr, __parse_string_emit); +} + +static void parse_ascii_number(struct context_t *ctx, struct lexem_t *lexem) +{ + locate_lexem(lexem, ctx); + /* skip ' */ + advance(ctx, 1); + /* we expect n<=4 character and then ' */ + int len = 0; + uint32_t value = 0; + while(!eof(ctx)) + { + if(cur_char(ctx) != '\'') + { + value = value << 8 | cur_char(ctx); + len++; + advance(ctx, 1); + } + else + break; + } + if(eof(ctx) || cur_char(ctx) != '\'') + parse_error(ctx, "Unterminated ascii number literal\n"); + if(len == 0 || len > 4) + parse_error(ctx, "Invalid ascii number literal length: only 1 to 4 characters allowed\n"); + /* skip ' */ + advance(ctx, 1); + lexem->type = LEX_NUMBER; + lexem->num = value; +} + +static void parse_number(struct context_t *ctx, struct lexem_t *lexem) +{ + locate_lexem(lexem, ctx); + /* check base */ + int base = 10; + if(cur_char(ctx) == '0' && next_valid(ctx, 1) && next_char(ctx, 1) == 'x') + { + advance(ctx, 2); + base = 16; + } + + lexem->type = LEX_NUMBER; + lexem->num = 0; + while(!eof(ctx) && isxdigit(cur_char(ctx))) + { + if(base == 10 && !isdigit(cur_char(ctx))) + break; + byte v; + if(convxdigit(cur_char(ctx), &v)) + break; + lexem->num = base * lexem->num + v; + advance(ctx, 1); + } +} + +static void parse_identifier(struct context_t *ctx, struct lexem_t *lexem) +{ + locate_lexem(lexem, ctx); + /* remember position */ + char *old = ctx->ptr; + while(!eof(ctx) && (isalnum(cur_char(ctx)) || cur_char(ctx) == '_')) + advance(ctx, 1); + lexem->type = LEX_IDENTIFIER; + int len = ctx->ptr - old; + lexem->str = xmalloc(len + 1); + lexem->str[len] = 0; + memcpy(lexem->str, old, len); +} + +static void next_lexem(struct context_t *ctx, struct lexem_t *lexem) +{ + #define ret_simple(t, adv) \ + do {locate_lexem(lexem, ctx); \ + lexem->type = t; \ + advance(ctx, adv); \ + return;} while(0) + while(!eof(ctx)) + { + char c = cur_char(ctx); + /* skip whitespace */ + if(c == ' ' || c == '\t' || c == '\n' || c == '\r') + { + advance(ctx, 1); + continue; + } + /* skip C++ style comments */ + if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '/') + { + while(!eof(ctx) && cur_char(ctx) != '\n') + advance(ctx, 1); + continue; + } + /* skip C-style comments */ + if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '*') + { + advance(ctx, 2); + while(true) + { + if(!next_valid(ctx, 1)) + parse_error(ctx, "Unterminated comment"); + if(cur_char(ctx) == '*' && next_char(ctx, 1) == '/') + { + advance(ctx, 2); + break; + } + advance(ctx, 1); + } + continue; + } + break; + } + if(eof(ctx)) ret_simple(LEX_EOF, 0); + char c = cur_char(ctx); + bool nv = next_valid(ctx, 1); + char nc = nv ? next_char(ctx, 1) : 0; + if(c == '(') ret_simple(LEX_LPAREN, 1); + if(c == ')') ret_simple(LEX_RPAREN, 1); + if(c == '{') ret_simple(LEX_LBRACE, 1); + if(c == '}') ret_simple(LEX_RBRACE, 1); + if(c == '>') ret_simple(LEX_RANGLE, 1); + if(c == '=') ret_simple(LEX_EQUAL, 1); + if(c == ';') ret_simple(LEX_SEMICOLON, 1); + if(c == ',') ret_simple(LEX_COLON, 1); + if(c == '|') ret_simple(LEX_OR, 1); + if(c == '<' && nv && nc == '<') ret_simple(LEX_LSHIFT, 2); + if(c == '<' && nv && nc == '=') ret_simple(LEX_LE, 2); + if(c == '"') return parse_string(ctx, lexem); + if(c == '\'') return parse_ascii_number(ctx, lexem); + if(isdigit(c)) return parse_number(ctx, lexem); + if(isalpha(c) || c == '_') return parse_identifier(ctx, lexem); + parse_error(ctx, "Unexpected character '%c'\n", c); + #undef ret_simple +} + +#if 0 +static void log_lexem(struct lexem_t *lexem) +{ + switch(lexem->type) + { + case LEX_EOF: printf(""); break; + case LEX_EQUAL: printf("="); break; + case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break; + case LEX_LPAREN: printf("("); break; + case LEX_RPAREN: printf(")"); break; + case LEX_LBRACE: printf("{"); break; + case LEX_RBRACE: printf("}"); break; + case LEX_SEMICOLON: printf(";"); break; + case LEX_NUMBER: printf("num(%d)", lexem->num); break; + case LEX_STRING: printf("str(%s)", lexem->str); break; + case LEX_OR: printf("|"); break; + case LEX_LSHIFT: printf("<<"); break; + default: printf(""); + } +} +#endif + +struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id) +{ + struct cmd_source_t *src = cmd_file->source_list; + while(src) + { + if(strcmp(src->identifier, id) == 0) + return src; + src = src->next; + } + return NULL; +} + +struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name) +{ + while(opt) + { + if(strcmp(opt->name, name) == 0) + return opt; + opt = opt->next; + } + return NULL; +} + +#define INVALID_SB_SUBVERSION 0xffff + +static uint16_t parse_sb_subversion(char *str) +{ + int len = strlen(str); + uint16_t n = 0; + if(len == 0 || len > 4) + return INVALID_SB_SUBVERSION; + for(int i = 0; i < len; i++) + { + if(!isdigit(str[i])) + return INVALID_SB_SUBVERSION; + n = n << 4 | (str[i] - '0'); + } + return n; +} + +bool db_parse_sb_version(struct sb_version_t *ver, char *str) +{ + int len = strlen(str); + int cnt = 0; + int pos[2]; + + for(int i = 0; i < len; i++) + { + if(str[i] != '.') + continue; + if(cnt == 2) + return false; + pos[cnt++] = i + 1; + str[i] = 0; + } + if(cnt != 2) + return false; + ver->major = parse_sb_subversion(str); + ver->minor = parse_sb_subversion(str + pos[0]); + ver->revision = parse_sb_subversion(str + pos[1]); + return ver->major != INVALID_SB_SUBVERSION && + ver->minor != INVALID_SB_SUBVERSION && + ver->revision != INVALID_SB_SUBVERSION; +} + +#undef parse_error +#define parse_error(lexem, ...) \ + do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \ + fprintf(stderr, __VA_ARGS__); exit(2); } while(0) + +struct lex_ctx_t +{ + struct context_t ctx; + struct lexem_t lexem; +}; + +/* When lexems hold strings (like identifier), it might be useful to steal + * the pointer and don't clean the lexem but in other case, one don't want + * to keep the pointer to the string and just want to release the memory. + * Thus clean_lexem should be true except when one keeps a pointer */ +static inline void next(struct lex_ctx_t *ctx, bool clean_lexem) +{ + if(clean_lexem) + free(ctx->lexem.str); + memset(&ctx->lexem, 0, sizeof(struct lexem_t)); + next_lexem(&ctx->ctx, &ctx->lexem); +} + +static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) +{ + uint32_t ret = 0; + if(ctx->lexem.type == LEX_NUMBER) + ret = ctx->lexem.num; + else if(ctx->lexem.type == LEX_IDENTIFIER) + { + struct cmd_option_t *c = db_find_option_by_id(const_list, ctx->lexem.str); + if(c == NULL) + parse_error(ctx->lexem, "Undefined reference to constant '%s'\n", ctx->lexem.str); + if(c->is_string) + parse_error(ctx->lexem, "Internal error: constant '%s' is not an integer\n", ctx->lexem.str); + ret = c->val; + } + else + parse_error(ctx->lexem, "Number or constant identifier expected\n"); + next(ctx, true); + return ret; +} + +static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) +{ + uint32_t v = parse_term_expr(ctx, const_list); + while(ctx->lexem.type == LEX_LSHIFT) + { + next(ctx, true); + v <<= parse_term_expr(ctx, const_list); + } + return v; +} + +static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) +{ + uint32_t v = parse_shift_expr(ctx, const_list); + while(ctx->lexem.type == LEX_OR) + { + next(ctx, true); + v |= parse_shift_expr(ctx, const_list); + } + return v; +} + +static uint32_t parse_intexpr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) +{ + return parse_or_expr(ctx, const_list); +} + +#define NR_INITIAL_CONSTANTS 4 +static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"}; +static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0}; + +struct cmd_file_t *db_parse_file(const char *file) +{ + size_t size; + FILE *f = fopen(file, "r"); + if(f == NULL) + bugp("Cannot open file '%s'", file); + fseek(f, 0, SEEK_END); + size = ftell(f); + fseek(f, 0, SEEK_SET); + char *buf = xmalloc(size); + if(fread(buf, size, 1, f) != 1) + bugp("Cannot read file '%s'", file); + fclose(f); + + if(g_debug) + printf("Parsing db file '%s'\n", file); + struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t)); + memset(cmd_file, 0, sizeof(struct cmd_file_t)); + + /* add initial constants */ + for(int i = 0; i < NR_INITIAL_CONSTANTS; i++) + { + struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); + memset(opt, 0, sizeof(struct cmd_option_t)); + opt->name = strdup(init_const_name[i]); + opt->is_string = false; + opt->val = init_const_value[i]; + opt->next = cmd_file->constant_list; + cmd_file->constant_list = opt; + } + + struct lex_ctx_t lctx; + lctx.ctx.file = file; + lctx.ctx.line = 1; + lctx.ctx.begin = buf; + lctx.ctx.ptr = buf; + lctx.ctx.end = buf + size; + #define next(clean_lexem) next(&lctx, clean_lexem) + #define lexem lctx.lexem + /* init lexer */ + next(false); /* don't clean init lexem because it doesn't exist */ + /* constants ? */ + if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants")) + { + next(true); + if(lexem.type != LEX_LBRACE) + parse_error(lexem, "'{' expected after 'constants'\n"); + + while(true) + { + struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); + memset(opt, 0, sizeof(struct cmd_option_t)); + next(true); + if(lexem.type == LEX_RBRACE) + break; + if(lexem.type != LEX_IDENTIFIER) + parse_error(lexem, "Identifier expected in constants\n"); + opt->name = lexem.str; + next(false); /* lexem string is kept as option name */ + if(lexem.type != LEX_EQUAL) + parse_error(lexem, "'=' expected after identifier\n"); + next(true); + opt->is_string = false; + opt->val = parse_intexpr(&lctx, cmd_file->constant_list); + opt->next = cmd_file->constant_list; + cmd_file->constant_list = opt; + if(lexem.type != LEX_SEMICOLON) + parse_error(lexem, "';' expected after string\n"); + } + next(true); + } + /* options ? */ + if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options")) + { + next(true); + if(lexem.type != LEX_LBRACE) + parse_error(lexem, "'{' expected after 'options'\n"); + + while(true) + { + next(true); + if(lexem.type == LEX_RBRACE) + break; + struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); + memset(opt, 0, sizeof(struct cmd_option_t)); + if(lexem.type != LEX_IDENTIFIER) + parse_error(lexem, "Identifier expected in options\n"); + opt->name = lexem.str; + next(false); /* lexem string is kept as option name */ + if(lexem.type != LEX_EQUAL) + parse_error(lexem, "'=' expected after identifier\n"); + next(true); + if(lexem.type == LEX_STRING) + { + opt->is_string = true; + opt->str = lexem.str; + next(false); /* lexem string is kept as option name */ + } + else + { + opt->is_string = false; + opt->val = parse_intexpr(&lctx, cmd_file->constant_list); + } + opt->next = cmd_file->opt_list; + cmd_file->opt_list = opt; + if(lexem.type != LEX_SEMICOLON) + parse_error(lexem, "';' expected after string\n"); + } + next(true); + } + /* sources */ + if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources")) + parse_error(lexem, "'sources' expected\n"); + next(true); + if(lexem.type != LEX_LBRACE) + parse_error(lexem, "'{' expected after 'sources'\n"); + + while(true) + { + next(true); + if(lexem.type == LEX_RBRACE) + break; + struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t)); + memset(src, 0, sizeof(struct cmd_source_t)); + if(lexem.type != LEX_IDENTIFIER) + parse_error(lexem, "identifier expected in sources\n"); + src->identifier = lexem.str; + next(false); /* lexem string is kept as source name */ + if(lexem.type != LEX_EQUAL) + parse_error(lexem, "'=' expected after identifier\n"); + next(true); + if(lexem.type == LEX_STRING) + { + src->is_extern = false; + src->filename = lexem.str; + next(false); /* lexem string is kept as file name */ + } + else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern")) + { + src->is_extern = true; + src->filename = strdup(""); /* duplicate because it will be free'd */ + next(true); + if(lexem.type != LEX_LPAREN) + parse_error(lexem, "'(' expected after 'extern'\n"); + next(true); + src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list); + if(lexem.type != LEX_RPAREN) + parse_error(lexem, "')' expected\n"); + next(true); + } + else + parse_error(lexem, "String or 'extern' expected after '='\n"); + if(lexem.type != LEX_SEMICOLON) + parse_error(lexem, "';' expected\n"); + if(db_find_source_by_id(cmd_file, src->identifier) != NULL) + parse_error(lexem, "Duplicate source identifier\n"); + /* type filled later */ + src->type = CMD_SRC_UNK; + src->next = cmd_file->source_list; + cmd_file->source_list = src; + } + + /* sections */ + struct cmd_section_t *end_sec = NULL; + while(true) + { + next(true); + if(lexem.type == LEX_EOF) + break; + struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t)); + struct cmd_inst_t *end_list = NULL; + memset(sec, 0, sizeof(struct cmd_section_t)); + if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0) + parse_error(lexem, "'section' expected\n"); + next(true); + if(lexem.type != LEX_LPAREN) + parse_error(lexem, "'(' expected after 'section'\n"); + next(true); + /* can be any number */ + sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list); + /* options ? */ + if(lexem.type == LEX_SEMICOLON) + { + do + { + next(true); + struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); + memset(opt, 0, sizeof(struct cmd_option_t)); + if(lexem.type != LEX_IDENTIFIER) + parse_error(lexem, "Identifier expected for section option\n"); + opt->name = lexem.str; + next(false); /* lexem string is kept as option name */ + if(lexem.type != LEX_EQUAL) + parse_error(lexem, "'=' expected after option identifier\n"); + next(true); + if(lexem.type == LEX_STRING) + { + opt->is_string = true; + opt->str = lexem.str; + next(false); /* lexem string is kept as option string */ + } + else + { + opt->is_string = false; + opt->val = parse_intexpr(&lctx, cmd_file->constant_list); + } + opt->next = sec->opt_list; + sec->opt_list = opt; + }while(lexem.type == LEX_COLON); + } + if(lexem.type != LEX_RPAREN) + parse_error(lexem, "')' expected after section identifier\n"); + next(true); + if(lexem.type == LEX_LBRACE) + { + sec->is_data = false; + /* commands */ + while(true) + { + next(true); + if(lexem.type == LEX_RBRACE) + break; + struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t)); + memset(inst, 0, sizeof(struct cmd_inst_t)); + if(lexem.type != LEX_IDENTIFIER) + parse_error(lexem, "Instruction expected in section\n"); + if(strcmp(lexem.str, "load") == 0) + inst->type = CMD_LOAD; + else if(strcmp(lexem.str, "call") == 0) + inst->type = CMD_CALL; + else if(strcmp(lexem.str, "jump") == 0) + inst->type = CMD_JUMP; + else if(strcmp(lexem.str, "mode") == 0) + inst->type = CMD_MODE; + else + parse_error(lexem, "Instruction expected in section\n"); + next(true); + + if(inst->type == CMD_LOAD) + { + if(lexem.type != LEX_IDENTIFIER) + parse_error(lexem, "Identifier expected after instruction\n"); + inst->identifier = lexem.str; + if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) + parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); + next(false); /* lexem string kept as identifier */ + if(lexem.type == LEX_RANGLE) + { + // load at + inst->type = CMD_LOAD_AT; + next(true); + inst->addr = parse_intexpr(&lctx, cmd_file->constant_list); + } + if(lexem.type != LEX_SEMICOLON) + parse_error(lexem, "';' expected after command\n"); + } + else if(inst->type == CMD_CALL || inst->type == CMD_JUMP) + { + if(lexem.type == LEX_IDENTIFIER) + { + inst->identifier = lexem.str; + if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) + parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); + next(false); /* lexem string kept as identifier */ + } + else + { + inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT; + inst->addr = parse_intexpr(&lctx, cmd_file->constant_list); + } + + if(lexem.type == LEX_LPAREN) + { + next(true); + inst->argument = parse_intexpr(&lctx, cmd_file->constant_list); + if(lexem.type != LEX_RPAREN) + parse_error(lexem, "Expected closing brace\n"); + next(true); + } + if(lexem.type != LEX_SEMICOLON) + parse_error(lexem, "';' expected after command\n"); + } + else if(inst->type == CMD_MODE) + { + inst->argument = parse_intexpr(&lctx, cmd_file->constant_list); + if(lexem.type != LEX_SEMICOLON) + parse_error(lexem, "Expected ';' after command\n"); + } + else + parse_error(lexem, "Internal error"); + if(end_list == NULL) + { + sec->inst_list = inst; + end_list = inst; + } + else + { + end_list->next = inst; + end_list = inst; + } + } + } + else if(lexem.type == LEX_LE) + { + sec->is_data = true; + next(true); + if(lexem.type != LEX_IDENTIFIER) + parse_error(lexem, "Identifier expected after '<='\n"); + sec->source_id = lexem.str; + next(false); /* lexem string is kept as source id */ + if(lexem.type != LEX_SEMICOLON) + parse_error(lexem, "';' expected after identifier\n"); + } + else + parse_error(lexem, "'{' or '<=' expected after section directive\n"); + + if(end_sec == NULL) + { + cmd_file->section_list = sec; + end_sec = sec; + } + else + { + end_sec->next = sec; + end_sec = sec; + } + } + #undef lexem + #undef next + + free(buf); + return cmd_file; +} + +void db_generate_default_sb_version(struct sb_version_t *ver) +{ + ver->major = ver->minor = ver->revision = 0x999; +} + +void db_free_option_list(struct cmd_option_t *opt_list) +{ + while(opt_list) + { + struct cmd_option_t *next = opt_list->next; + fflush(stdout); + free(opt_list->name); + free(opt_list->str); + free(opt_list); + opt_list = next; + } +} + +void db_free(struct cmd_file_t *file) +{ + db_free_option_list(file->opt_list); + db_free_option_list(file->constant_list); + struct cmd_source_t *src = file->source_list; + while(src) + { + struct cmd_source_t *next = src->next; + free(src->identifier); + fflush(stdout); + free(src->filename); + if(src->loaded) + { + if(src->type == CMD_SRC_BIN) + free(src->bin.data); + if(src->type == CMD_SRC_ELF) + elf_release(&src->elf); + } + free(src); + src = next; + } + struct cmd_section_t *sec = file->section_list; + while(sec) + { + struct cmd_section_t *next = sec->next; + db_free_option_list(sec->opt_list); + free(sec->source_id); + struct cmd_inst_t *inst = sec->inst_list; + while(inst) + { + struct cmd_inst_t *next = inst->next; + free(inst->identifier); + free(inst); + inst = next; + } + free(sec); + sec = next; + } + free(file); +} diff --git a/utils/imxtools/dbparser.h b/utils/imxtools/dbparser.h new file mode 100644 index 0000000000..4a36861583 --- /dev/null +++ b/utils/imxtools/dbparser.h @@ -0,0 +1,118 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __DBPARSER__ +#define __DBPARSER__ + +/** + * Command file parsing + */ +#include "sb.h" +#include "elf.h" + +enum cmd_source_type_t +{ + CMD_SRC_UNK, + CMD_SRC_ELF, + CMD_SRC_BIN +}; + +struct bin_param_t +{ + uint32_t size; + void *data; +}; + +struct cmd_source_t +{ + char *identifier; + bool is_extern; + // + int extern_nr; + char *filename; + // + struct cmd_source_t *next; + /* for later use */ + enum cmd_source_type_t type; + bool loaded; + struct elf_params_t elf; + struct bin_param_t bin; +}; + +enum cmd_inst_type_t +{ + CMD_LOAD, /* load image */ + CMD_JUMP, /* jump at image */ + CMD_CALL, /* call image */ + CMD_LOAD_AT, /* load binary at */ + CMD_CALL_AT, /* call at address */ + CMD_JUMP_AT, /* jump at address */ + CMD_MODE, /* change boot mode */ +}; + +struct cmd_inst_t +{ + enum cmd_inst_type_t type; + char *identifier; + uint32_t argument; // for jump, call, mode + uint32_t addr; // for 'at' + struct cmd_inst_t *next; +}; + +struct cmd_option_t +{ + char *name; + bool is_string; + /* */ + uint32_t val; + char *str; + /* */ + struct cmd_option_t *next; +}; + +struct cmd_section_t +{ + uint32_t identifier; + bool is_data; + // + struct cmd_inst_t *inst_list; + char *source_id; + // + struct cmd_section_t *next; + struct cmd_option_t *opt_list; +}; + +struct cmd_file_t +{ + struct cmd_option_t *opt_list; + struct cmd_option_t *constant_list; /* constant are always integers */ + struct cmd_source_t *source_list; + struct cmd_section_t *section_list; +}; + +struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id); +struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name); +bool db_parse_sb_version(struct sb_version_t *ver, char *str); +void db_generate_default_sb_version(struct sb_version_t *ver); +struct cmd_file_t *db_parse_file(const char *file); +void db_free_option_list(struct cmd_option_t *opt_list); +void db_free(struct cmd_file_t *file); + +#endif /* __DBPARSER__ */ diff --git a/utils/imxtools/elf.c b/utils/imxtools/elf.c new file mode 100644 index 0000000000..481ab98dd6 --- /dev/null +++ b/utils/imxtools/elf.c @@ -0,0 +1,575 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "elf.h" +#include "misc.h" + +/** + * Definitions + * taken from elf.h linux header + * based on ELF specification + * based on ARM ELF specification + */ +typedef uint16_t Elf32_Half; + +typedef uint32_t Elf32_Word; +typedef int32_t Elf32_Sword; +typedef uint32_t Elf32_Addr; +typedef uint32_t Elf32_Off; +typedef uint16_t Elf32_Section; + +#define EI_NIDENT 16 + +typedef struct +{ + unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ + Elf32_Half e_type; /* Object file type */ + Elf32_Half e_machine; /* Architecture */ + Elf32_Word e_version; /* Object file version */ + Elf32_Addr e_entry; /* Entry point virtual address */ + Elf32_Off e_phoff; /* Program header table file offset */ + Elf32_Off e_shoff; /* Section header table file offset */ + Elf32_Word e_flags; /* Processor-specific flags */ + Elf32_Half e_ehsize; /* ELF header size in bytes */ + Elf32_Half e_phentsize; /* Program header table entry size */ + Elf32_Half e_phnum; /* Program header table entry count */ + Elf32_Half e_shentsize; /* Section header table entry size */ + Elf32_Half e_shnum; /* Section header table entry count */ + Elf32_Half e_shstrndx; /* Section header string table index */ +}Elf32_Ehdr; + +#define EI_MAG0 0 /* File identification byte 0 index */ +#define ELFMAG0 0x7f /* Magic number byte 0 */ + +#define EI_MAG1 1 /* File identification byte 1 index */ +#define ELFMAG1 'E' /* Magic number byte 1 */ + +#define EI_MAG2 2 /* File identification byte 2 index */ +#define ELFMAG2 'L' /* Magic number byte 2 */ + +#define EI_MAG3 3 /* File identification byte 3 index */ +#define ELFMAG3 'F' /* Magic number byte 3 */ + +#define EI_CLASS 4 /* File class byte index */ +#define ELFCLASS32 1 /* 32-bit objects */ + +#define EI_DATA 5 /* Data encoding byte index */ +#define ELFDATA2LSB 1 /* 2's complement, little endian */ + +#define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */ + +#define EI_OSABI 7 /* OS ABI identification */ +#define ELFOSABI_NONE 0 /* UNIX System V ABI */ +#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ +#define ELFOSABI_ARM 97 /* ARM */ + +#define EI_ABIVERSION 8 /* ABI version */ + +#define EI_PAD 9 /* Byte index of padding bytes */ + +#define ET_EXEC 2 /* Executable file */ + +#define EM_ARM 40 /* ARM */ + +#define EV_CURRENT 1 /* Current version */ + +#define EF_ARM_HASENTRY 0x00000002 + +#define SHN_UNDEF 0 /* Undefined section */ + +typedef struct +{ + Elf32_Word sh_name; /* Section name (string tbl index) */ + Elf32_Word sh_type; /* Section type */ + Elf32_Word sh_flags; /* Section flags */ + Elf32_Addr sh_addr; /* Section virtual addr at execution */ + Elf32_Off sh_offset; /* Section file offset */ + Elf32_Word sh_size; /* Section size in bytes */ + Elf32_Word sh_link; /* Link to another section */ + Elf32_Word sh_info; /* Additional section information */ + Elf32_Word sh_addralign; /* Section alignment */ + Elf32_Word sh_entsize; /* Entry size if section holds table */ +}Elf32_Shdr; + +#define SHT_NULL 0 /* Section header table entry unused */ +#define SHT_PROGBITS 1 /* Program data */ +#define SHT_SYMTAB 2 /* Symbol table */ +#define SHT_STRTAB 3 /* String table */ +#define SHT_RELA 4 /* Relocation entries with addends */ +#define SHT_HASH 5 /* Symbol hash table */ +#define SHT_DYNAMIC 6 /* Dynamic linking information */ +#define SHT_NOTE 7 /* Notes */ +#define SHT_NOBITS 8 /* Program space with no data (bss) */ +#define SHT_REL 9 /* Relocation entries, no addends */ +#define SHT_SHLIB 10 /* Reserved */ +#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ +#define SHT_INIT_ARRAY 14 /* Array of constructors */ +#define SHT_FINI_ARRAY 15 /* Array of destructors */ +#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ +#define SHT_GROUP 17 /* Section group */ +#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ +#define SHT_NUM 19 /* Number of defined types. */ + +#define SHF_WRITE (1 << 0) /* Writable */ +#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ +#define SHF_EXECINSTR (1 << 2) /* Executable */ +#define SHF_MERGE (1 << 4) /* Might be merged */ +#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ + +typedef struct +{ + Elf32_Word p_type; /* Segment type */ + Elf32_Off p_offset; /* Segment file offset */ + Elf32_Addr p_vaddr; /* Segment virtual address */ + Elf32_Addr p_paddr; /* Segment physical address */ + Elf32_Word p_filesz; /* Segment size in file */ + Elf32_Word p_memsz; /* Segment size in memory */ + Elf32_Word p_flags; /* Segment flags */ + Elf32_Word p_align; /* Segment alignment */ +}Elf32_Phdr; + +#define PT_LOAD 1 /* Loadable program segment */ + +#define PF_X (1 << 0) /* Segment is executable */ +#define PF_W (1 << 1) /* Segment is writable */ +#define PF_R (1 << 2) /* Segment is readable */ + +void elf_init(struct elf_params_t *params) +{ + memset(params, 0, sizeof(struct elf_params_t)); +} + +extern void *xmalloc(size_t s); + +static struct elf_section_t *elf_add_section(struct elf_params_t *params) +{ + struct elf_section_t *sec = xmalloc(sizeof(struct elf_section_t)); + if(params->first_section == NULL) + params->first_section = params->last_section = sec; + else + { + params->last_section->next = sec; + params->last_section = sec; + } + sec->next = NULL; + + return sec; +} + +static struct elf_segment_t *elf_add_segment(struct elf_params_t *params) +{ + struct elf_segment_t *seg = xmalloc(sizeof(struct elf_section_t)); + if(params->first_segment == NULL) + params->first_segment = params->last_segment = seg; + else + { + params->last_segment->next = seg; + params->last_segment = seg; + } + seg->next = NULL; + + return seg; +} + +void elf_add_load_section(struct elf_params_t *params, + uint32_t load_addr, uint32_t size, const void *section) +{ + struct elf_section_t *sec = elf_add_section(params); + + sec->type = EST_LOAD; + sec->addr = load_addr; + sec->size = size; + sec->section = xmalloc(size); + memcpy(sec->section, section, size); +} + +void elf_add_fill_section(struct elf_params_t *params, + uint32_t fill_addr, uint32_t size, uint32_t pattern) +{ + if(pattern != 0x00) + { + printf("oops, non-zero filling, ignore fill section\n"); + return; + } + + struct elf_section_t *sec = elf_add_section(params); + + sec->type = EST_FILL; + sec->addr = fill_addr; + sec->size = size; + sec->pattern = pattern; +} + +void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, + elf_printf_fn_t printf, void *user) +{ + (void) printf; + + Elf32_Ehdr ehdr; + uint32_t phnum = 0; + struct elf_section_t *sec = params->first_section; + uint32_t offset = 0; + Elf32_Phdr phdr; + Elf32_Shdr shdr; + memset(&ehdr, 0, EI_NIDENT); + + while(sec) + { + if(sec->type == EST_LOAD) + { + sec->offset = offset; + offset += sec->size; + } + else + { + sec->offset = 0; + } + + phnum++; + sec = sec->next; + } + + uint32_t strtbl_offset = offset; + + ehdr.e_ident[EI_MAG0] = ELFMAG0; + ehdr.e_ident[EI_MAG1] = ELFMAG1; + ehdr.e_ident[EI_MAG2] = ELFMAG2; + ehdr.e_ident[EI_MAG3] = ELFMAG3; + ehdr.e_ident[EI_CLASS] = ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE; + ehdr.e_ident[EI_ABIVERSION] = 0; + ehdr.e_type = ET_EXEC; + ehdr.e_machine = EM_ARM; + ehdr.e_version = EV_CURRENT; + ehdr.e_entry = params->start_addr; + ehdr.e_flags = 0; + if(params->has_start_addr) + ehdr.e_flags |= EF_ARM_HASENTRY; + ehdr.e_ehsize = sizeof ehdr; + ehdr.e_phentsize = sizeof phdr; + ehdr.e_phnum = phnum; + ehdr.e_shentsize = sizeof shdr; + ehdr.e_shnum = phnum + 2; /* one for section 0 and one for string table */ + ehdr.e_shstrndx = ehdr.e_shnum - 1; + ehdr.e_phoff = ehdr.e_ehsize; + ehdr.e_shoff = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize; + + write(user, 0, &ehdr, sizeof ehdr); + + /* allocate enough size to hold any combinaison of .text/.bss in the string table: + * - one empty name ("\0") + * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0" + * - one name ".shstrtab\0" */ + char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 + + phnum * (strlen(".textXXXX") + 1)); + + strtbl_content[0] = '\0'; + strcpy(&strtbl_content[1], ".shstrtab"); + uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1; + + uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + + ehdr.e_shnum * ehdr.e_shentsize; + + sec = params->first_section; + offset = ehdr.e_phoff; + while(sec) + { + sec->offset += data_offset; + + phdr.p_type = PT_LOAD; + if(sec->type == EST_LOAD) + phdr.p_offset = sec->offset; + else + phdr.p_offset = 0; + phdr.p_paddr = sec->addr; + phdr.p_vaddr = phdr.p_paddr; /* assume identity map ? */ + phdr.p_memsz = sec->size; + if(sec->type == EST_LOAD) + phdr.p_filesz = phdr.p_memsz; + else + phdr.p_filesz = 0; + phdr.p_flags = PF_X | PF_W | PF_R; + phdr.p_align = 0; + + write(user, offset, &phdr, sizeof phdr); + + offset += sizeof(Elf32_Phdr); + sec = sec->next; + } + + sec = params->first_section; + offset = ehdr.e_shoff; + + { + shdr.sh_name = 0; + shdr.sh_type = SHT_NULL; + shdr.sh_flags = 0; + shdr.sh_addr = 0; + shdr.sh_offset = 0; + shdr.sh_size = 0; + shdr.sh_link = SHN_UNDEF; + shdr.sh_info = 0; + shdr.sh_addralign = 0; + shdr.sh_entsize = 0; + + write(user, offset, &shdr, sizeof shdr); + + offset += sizeof(Elf32_Shdr); + } + + uint32_t text_idx = 0; + uint32_t bss_idx = 0; + while(sec) + { + shdr.sh_name = strtbl_index; + if(sec->type == EST_LOAD) + { + strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++); + shdr.sh_type = SHT_PROGBITS; + } + else + { + strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++); + shdr.sh_type = SHT_NOBITS; + } + shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; + shdr.sh_addr = sec->addr; + shdr.sh_offset = sec->offset; + shdr.sh_size = sec->size; + shdr.sh_link = SHN_UNDEF; + shdr.sh_info = 0; + shdr.sh_addralign = 1; + shdr.sh_entsize = 0; + + write(user, offset, &shdr, sizeof shdr); + + offset += sizeof(Elf32_Shdr); + sec = sec->next; + } + + { + shdr.sh_name = 1; + shdr.sh_type = SHT_STRTAB; + shdr.sh_flags = 0; + shdr.sh_addr = 0; + shdr.sh_offset = strtbl_offset + data_offset; + shdr.sh_size = strtbl_index; + shdr.sh_link = SHN_UNDEF; + shdr.sh_info = 0; + shdr.sh_addralign = 1; + shdr.sh_entsize = 0; + + write(user, offset, &shdr, sizeof shdr); + + offset += sizeof(Elf32_Shdr); + } + + sec = params->first_section; + while(sec) + { + if(sec->type == EST_LOAD) + write(user, sec->offset, sec->section, sec->size); + sec = sec->next; + } + + write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index); + free(strtbl_content); +} + +bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, + elf_printf_fn_t printf, void *user) +{ + #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) + + /* read header */ + Elf32_Ehdr ehdr; + if(!read(user, 0, &ehdr, sizeof(ehdr))) + { + printf(user, true, "error reading elf header\n"); + return false; + } + /* basic checks */ + if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || + ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) + error_printf("invalid elf header\n"); + if(ehdr.e_ident[EI_CLASS] != ELFCLASS32) + error_printf("invalid elf class: must be a 32-bit object\n"); + if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB) + error_printf("invalid elf data encoding: must be 32-bit lsb\n"); + if(ehdr.e_ident[EI_VERSION] != EV_CURRENT) + error_printf("invalid elf version\n"); + if(ehdr.e_type != ET_EXEC) + error_printf("invalid elf file: must be an executable file\n"); + if(ehdr.e_machine != EM_ARM) + error_printf("invalid elf file: must target an arm machine\n"); + if(ehdr.e_ehsize != sizeof(ehdr)) + error_printf("invalid elf file: size header mismatch\n"); + if(ehdr.e_phnum > 0 && ehdr.e_phentsize != sizeof(Elf32_Phdr)) + error_printf("invalid elf file: program header size mismatch\n"); + if(ehdr.e_shnum > 0 && ehdr.e_shentsize != sizeof(Elf32_Shdr)) + error_printf("invalid elf file: section header size mismatch\n"); + elf_set_start_addr(params, ehdr.e_entry); + + char *strtab = NULL; + if(ehdr.e_shstrndx != SHN_UNDEF) + { + Elf32_Shdr shstrtab; + if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize, + &shstrtab, sizeof(shstrtab))) + { + strtab = xmalloc(shstrtab.sh_size); + if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size)) + { + free(strtab); + strtab = NULL; + } + } + } + /* run through sections */ + printf(user, false, "ELF file:\n"); + for(int i = 1; i < ehdr.e_shnum; i++) + { + uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize; + Elf32_Shdr shdr; + memset(&shdr, 0, sizeof(shdr)); + if(!read(user, off, &shdr, sizeof(shdr))) + error_printf("error reading elf section header"); + + if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC) + { + void *data = xmalloc(shdr.sh_size); + if(!read(user, shdr.sh_offset, data, shdr.sh_size)) + error_printf("error read self section data\n"); + elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); + free(data); + + if(strtab) + printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]); + } + else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC) + { + elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0); + if(strtab) + printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]); + } + else + { + if(strtab) + printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); + } + + } + free(strtab); + /* run through segments */ + for(int i = 1; i < ehdr.e_phnum; i++) + { + uint32_t off = ehdr.e_phoff + i * ehdr.e_phentsize; + Elf32_Phdr phdr; + memset(&phdr, 0, sizeof(phdr)); + if(!read(user, off, &phdr, sizeof(phdr))) + error_printf("error reading elf segment header"); + if(phdr.p_type != PT_LOAD) + continue; + struct elf_segment_t *seg = elf_add_segment(params); + seg->vaddr = phdr.p_vaddr; + seg->paddr = phdr.p_paddr; + seg->vsize = phdr.p_memsz; + seg->psize = phdr.p_filesz; + printf(user, false, "create segment [%#x,+%#x[ -> [%#x,+%#x[\n", + seg->vaddr, seg->vsize, seg->paddr, seg->psize); + } + + return true; +} + +uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr) +{ + struct elf_segment_t *seg = params->first_segment; + while(seg) + { + if(seg->vaddr <= addr && addr < seg->vaddr + seg->vsize) + return addr - seg->vaddr + seg->paddr; + seg = seg->next; + } + return addr; +} + +void elf_translate_addresses(struct elf_params_t *params) +{ + struct elf_section_t *sec = params->first_section; + while(sec) + { + sec->addr = elf_translate_virtual_address(params, sec->addr); + sec = sec->next; + } + params->start_addr = elf_translate_virtual_address(params, params->start_addr); +} + +bool elf_is_empty(struct elf_params_t *params) +{ + return params->first_section == NULL; +} + +void elf_set_start_addr(struct elf_params_t *params, uint32_t addr) +{ + params->has_start_addr = true; + params->start_addr = addr; +} + +bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr) +{ + if(params->has_start_addr && addr != NULL) + *addr = params->start_addr; + return params->has_start_addr; +} + +int elf_get_nr_sections(struct elf_params_t *params) +{ + int nr = 0; + struct elf_section_t *sec = params->first_section; + while(sec) + { + nr++; + sec = sec->next; + } + return nr; +} + +void elf_release(struct elf_params_t *params) +{ + struct elf_section_t *sec = params->first_section; + while(sec) + { + struct elf_section_t *next_sec = sec->next; + if(sec->type == EST_LOAD) + free(sec->section); + free(sec); + sec = next_sec; + } + struct elf_segment_t *seg = params->first_segment; + while(seg) + { + struct elf_segment_t *next_seg = seg->next; + free(seg); + seg = next_seg; + } +} diff --git a/utils/imxtools/elf.h b/utils/imxtools/elf.h new file mode 100644 index 0000000000..2166833276 --- /dev/null +++ b/utils/imxtools/elf.h @@ -0,0 +1,94 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __ELF_H__ +#define __ELF_H__ + +#include +#include +#include +#include +#include +#include + +/** + * API + */ +enum elf_section_type_t +{ + EST_LOAD, + EST_FILL +}; + +struct elf_section_t +{ + uint32_t addr; /* virtual address */ + uint32_t size; /* virtual size */ + enum elf_section_type_t type; + /* */ + void *section; /* data */ + uint32_t pattern; /* fill pattern */ + /* */ + struct elf_section_t *next; + /* Internal to elf_write_file */ + uint32_t offset; +}; + +struct elf_segment_t +{ + uint32_t vaddr; /* virtual address */ + uint32_t paddr; /* physical address */ + uint32_t vsize; /* virtual size */ + uint32_t psize; /* physical size */ + struct elf_segment_t *next; +}; + +struct elf_params_t +{ + bool has_start_addr; + uint32_t start_addr; + struct elf_section_t *first_section; + struct elf_section_t *last_section; + struct elf_segment_t *first_segment; + struct elf_segment_t *last_segment; +}; + +typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count); +/* write function manages it's own error state */ +typedef void (*elf_write_fn_t)(void *user, uint32_t addr, const void *buf, size_t count); +typedef void (*elf_printf_fn_t)(void *user, bool error, const char *fmt, ...); + +void elf_init(struct elf_params_t *params); +void elf_add_load_section(struct elf_params_t *params, + uint32_t load_addr, uint32_t size, const void *section); +void elf_add_fill_section(struct elf_params_t *params, + uint32_t fill_addr, uint32_t size, uint32_t pattern); +uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr); +void elf_translate_addresses(struct elf_params_t *params); +void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, elf_printf_fn_t printf, void *user); +bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, elf_printf_fn_t printf, + void *user); +bool elf_is_empty(struct elf_params_t *params); +void elf_set_start_addr(struct elf_params_t *params, uint32_t addr); +bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr); +int elf_get_nr_sections(struct elf_params_t *params); +void elf_release(struct elf_params_t *params); + +#endif /* __ELF_H__ */ diff --git a/utils/imxtools/elftosb.c b/utils/imxtools/elftosb.c new file mode 100644 index 0000000000..2f8700551f --- /dev/null +++ b/utils/imxtools/elftosb.c @@ -0,0 +1,461 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#define _ISOC99_SOURCE +#define _POSIX_C_SOURCE 200809L /* for strdup */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crypto.h" +#include "elf.h" +#include "sb.h" +#include "dbparser.h" +#include "misc.h" +#include "sb.h" + +char **g_extern; +int g_extern_count; + +#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) + +#define crypto_cbc(...) \ + do { int ret = crypto_cbc(__VA_ARGS__); \ + if(ret != CRYPTO_ERROR_SUCCESS) \ + bug("crypto_cbc error: %d\n", ret); \ + }while(0) + +/** + * command file to sb conversion + */ + +static bool elf_read(void *user, uint32_t addr, void *buf, size_t count) +{ + if(fseek((FILE *)user, addr, SEEK_SET) == -1) + return false; + return fread(buf, 1, count, (FILE *)user) == count; +} + +static void elf_printf(void *user, bool error, const char *fmt, ...) +{ + if(!g_debug && !error) + return; + (void) user; + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +static void resolve_extern(struct cmd_source_t *src) +{ + if(!src->is_extern) + return; + src->is_extern = false; + if(src->extern_nr < 0 || src->extern_nr >= g_extern_count) + bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr); + /* first free the old src->filename content */ + free(src->filename); + src->filename = strdup(g_extern[src->extern_nr]); +} + +static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) +{ + struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); + if(src == NULL) + bug("undefined reference to source '%s'\n", id); + /* avoid reloading */ + if(src->type == CMD_SRC_ELF && src->loaded) + return; + if(src->type != CMD_SRC_UNK) + bug("source '%s' seen both as elf and binary file\n", id); + /* resolve potential extern file */ + resolve_extern(src); + /* load it */ + src->type = CMD_SRC_ELF; + FILE *fd = fopen(src->filename, "rb"); + if(fd == NULL) + bug("cannot open '%s' (id '%s')\n", src->filename, id); + if(g_debug) + printf("Loading ELF file '%s'...\n", src->filename); + elf_init(&src->elf); + src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, fd); + fclose(fd); + if(!src->loaded) + bug("error loading elf file '%s' (id '%s')\n", src->filename, id); + elf_translate_addresses(&src->elf); +} + +static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id) +{ + struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); + if(src == NULL) + bug("undefined reference to source '%s'\n", id); + /* avoid reloading */ + if(src->type == CMD_SRC_BIN && src->loaded) + return; + if(src->type != CMD_SRC_UNK) + bug("source '%s' seen both as elf and binary file\n", id); + /* resolve potential extern file */ + resolve_extern(src); + /* load it */ + src->type = CMD_SRC_BIN; + FILE *fd = fopen(src->filename, "rb"); + if(fd == NULL) + bug("cannot open '%s' (id '%s')\n", src->filename, id); + if(g_debug) + printf("Loading BIN file '%s'...\n", src->filename); + fseek(fd, 0, SEEK_END); + src->bin.size = ftell(fd); + fseek(fd, 0, SEEK_SET); + src->bin.data = xmalloc(src->bin.size); + fread(src->bin.data, 1, src->bin.size, fd); + fclose(fd); + src->loaded = true; +} + +static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) +{ + struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t)); + memset(sb, 0, sizeof(struct sb_file_t)); + + db_generate_default_sb_version(&sb->product_ver); + db_generate_default_sb_version(&sb->component_ver); + + if(g_debug) + printf("Applying command file...\n"); + /* count sections */ + struct cmd_section_t *csec = cmd_file->section_list; + while(csec) + { + sb->nr_sections++; + csec = csec->next; + } + + sb->sections = xmalloc(sb->nr_sections * sizeof(struct sb_section_t)); + memset(sb->sections, 0, sb->nr_sections * sizeof(struct sb_section_t)); + /* flatten sections */ + csec = cmd_file->section_list; + for(int i = 0; i < sb->nr_sections; i++, csec = csec->next) + { + struct sb_section_t *sec = &sb->sections[i]; + sec->identifier = csec->identifier; + + /* options */ + do + { + /* cleartext */ + struct cmd_option_t *opt = db_find_option_by_id(csec->opt_list, "cleartext"); + if(opt != NULL) + { + if(opt->is_string) + bug("Cleartext section attribute must be an integer\n"); + if(opt->val != 0 && opt->val != 1) + bug("Cleartext section attribute must be 0 or 1\n"); + sec->is_cleartext = opt->val; + } + /* alignment */ + opt = db_find_option_by_id(csec->opt_list, "alignment"); + if(opt != NULL) + { + if(opt->is_string) + bug("Cleartext section attribute must be an integer\n"); + // n is a power of 2 iff n & (n - 1) = 0 + // alignement cannot be lower than block size + if((opt->val & (opt->val - 1)) != 0) + bug("Cleartext section attribute must be a power of two\n"); + if(opt->val < BLOCK_SIZE) + sec->alignment = BLOCK_SIZE; + else + sec->alignment = opt->val; + } + else + sec->alignment = BLOCK_SIZE; + }while(0); + + if(csec->is_data) + { + sec->is_data = true; + sec->nr_insts = 1; + sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); + memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); + + load_bin_by_id(cmd_file, csec->source_id); + struct bin_param_t *bin = &db_find_source_by_id(cmd_file, csec->source_id)->bin; + + sec->insts[0].inst = SB_INST_DATA; + sec->insts[0].size = bin->size; + sec->insts[0].data = memdup(bin->data, bin->size); + } + else + { + sec->is_data = false; + /* count instructions and loads things */ + struct cmd_inst_t *cinst = csec->inst_list; + while(cinst) + { + if(cinst->type == CMD_LOAD) + { + load_elf_by_id(cmd_file, cinst->identifier); + struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; + sec->nr_insts += elf_get_nr_sections(elf); + } + else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) + { + load_elf_by_id(cmd_file, cinst->identifier); + struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; + if(!elf_get_start_addr(elf, NULL)) + bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); + sec->nr_insts++; + } + else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT) + { + sec->nr_insts++; + } + else if(cinst->type == CMD_LOAD_AT) + { + load_bin_by_id(cmd_file, cinst->identifier); + sec->nr_insts++; + } + else if(cinst->type == CMD_MODE) + { + sec->nr_insts++; + } + else + bug("die\n"); + + cinst = cinst->next; + } + + sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); + memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); + /* flatten */ + int idx = 0; + cinst = csec->inst_list; + while(cinst) + { + if(cinst->type == CMD_LOAD) + { + struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; + struct elf_section_t *esec = elf->first_section; + while(esec) + { + if(esec->type == EST_LOAD) + { + sec->insts[idx].inst = SB_INST_LOAD; + sec->insts[idx].addr = esec->addr; + sec->insts[idx].size = esec->size; + sec->insts[idx++].data = memdup(esec->section, esec->size); + } + else if(esec->type == EST_FILL) + { + sec->insts[idx].inst = SB_INST_FILL; + sec->insts[idx].addr = esec->addr; + sec->insts[idx].size = esec->size; + sec->insts[idx++].pattern = esec->pattern; + } + esec = esec->next; + } + } + else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) + { + struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; + sec->insts[idx].argument = cinst->argument; + sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; + sec->insts[idx++].addr = elf->start_addr; + } + else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT) + { + sec->insts[idx].argument = cinst->argument; + sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL; + sec->insts[idx++].addr = cinst->addr; + } + else if(cinst->type == CMD_LOAD_AT) + { + struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin; + sec->insts[idx].inst = SB_INST_LOAD; + sec->insts[idx].addr = cinst->addr; + sec->insts[idx].data = memdup(bin->data, bin->size); + sec->insts[idx++].size = bin->size; + } + else if(cinst->type == CMD_MODE) + { + sec->insts[idx].inst = SB_INST_MODE; + sec->insts[idx++].addr = cinst->argument; + } + else + bug("die\n"); + + cinst = cinst->next; + } + } + } + + return sb; +} + +void usage(void) +{ + printf("Usage: elftosb [options | file]...\n"); + printf("Options:\n"); + printf(" -?/--help\tDisplay this message\n"); + printf(" -o \tSet output file\n"); + printf(" -c \tSet command file\n"); + printf(" -d/--debug\tEnable debug output\n"); + printf(" -k \tAdd key file\n"); + printf(" -z\t\tAdd zero key\n"); + printf(" --add-key \tAdd single key (hex or usbotp)\n"); + printf(" --real-key \tOverride real key\n"); + printf(" --crypto-iv \tOverride crypto IV\n"); + exit(1); +} + +static struct crypto_key_t g_zero_key = +{ + .method = CRYPTO_KEY, + .u.key = {0} +}; + +int main(int argc, char **argv) +{ + char *cmd_filename = NULL; + char *output_filename = NULL; + struct crypto_key_t real_key; + struct crypto_key_t crypto_iv; + real_key.method = CRYPTO_NONE; + crypto_iv.method = CRYPTO_NONE; + + while(1) + { + static struct option long_options[] = + { + {"help", no_argument, 0, '?'}, + {"debug", no_argument, 0, 'd'}, + {"add-key", required_argument, 0, 'a'}, + {"real-key", required_argument, 0, 'r'}, + {"crypto-iv", required_argument, 0, 'i'}, + {0, 0, 0, 0} + }; + + int c = getopt_long(argc, argv, "?do:c:k:za:", long_options, NULL); + if(c == -1) + break; + switch(c) + { + case 'd': + g_debug = true; + break; + case '?': + usage(); + break; + case 'o': + output_filename = optarg; + break; + case 'c': + cmd_filename = optarg; + break; + case 'k': + { + add_keys_from_file(optarg); + break; + } + case 'z': + { + add_keys(&g_zero_key, 1); + break; + } + case 'a': + case 'r': + case 'i': + { + struct crypto_key_t key; + char *s = optarg; + if(!parse_key(&s, &key)) + bug("Invalid key/iv specified as argument"); + if(*s != 0) + bug("Trailing characters after key/iv specified as argument"); + if(c == 'r') + memcpy(&real_key, &key, sizeof(key)); + else if(c == 'i') + memcpy(&crypto_iv, &key, sizeof(key)); + else + add_keys(&key, 1); + break; + } + default: + abort(); + } + } + + if(!cmd_filename) + bug("You must specify a command file\n"); + if(!output_filename) + bug("You must specify an output file\n"); + + g_extern = &argv[optind]; + g_extern_count = argc - optind; + + if(g_debug) + { + printf("key: %d\n", g_nr_keys); + for(int i = 0; i < g_nr_keys; i++) + { + printf(" "); + print_key(&g_key_array[i], true); + } + + for(int i = 0; i < g_extern_count; i++) + printf("extern(%d)=%s\n", i, g_extern[i]); + } + + struct cmd_file_t *cmd_file = db_parse_file(cmd_filename); + struct sb_file_t *sb_file = apply_cmd_file(cmd_file); + db_free(cmd_file); + + if(real_key.method == CRYPTO_KEY) + { + sb_file->override_real_key = true; + memcpy(sb_file->real_key, real_key.u.key, 16); + } + if(crypto_iv.method == CRYPTO_KEY) + { + sb_file->override_crypto_iv = true; + memcpy(sb_file->crypto_iv, crypto_iv.u.key, 16); + } + + /* fill with default parameters since there is no command file support for them */ + sb_file->drive_tag = 0; + sb_file->first_boot_sec_id = sb_file->sections[0].identifier; + sb_file->flags = 0; + sb_file->minor_version = 1; + + sb_write_file(sb_file, output_filename); + sb_free(sb_file); + clear_keys(); + + return 0; +} diff --git a/utils/imxtools/fuze+_key_file.txt b/utils/imxtools/fuze+_key_file.txt new file mode 100644 index 0000000000..a965e715f7 --- /dev/null +++ b/utils/imxtools/fuze+_key_file.txt @@ -0,0 +1 @@ +00000000000000000000000000000000 diff --git a/utils/imxtools/misc.c b/utils/imxtools/misc.c new file mode 100644 index 0000000000..8d7cea89d7 --- /dev/null +++ b/utils/imxtools/misc.c @@ -0,0 +1,248 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include +#include +#include +#include "misc.h" + +bool g_debug = false; + +/** + * Misc + */ + +void *memdup(void *p, size_t len) +{ + void *cpy = xmalloc(len); + memcpy(cpy, p, len); + return cpy; +} + +void generate_random_data(void *buf, size_t sz) +{ + FILE *rand_fd = fopen("/dev/urandom", "rb"); + if(rand_fd == NULL) + bugp("failed to open /dev/urandom"); + if(fread(buf, 1, sz, rand_fd) != sz) + bugp("failed to read /dev/urandom"); + fclose(rand_fd); +} + +void *xmalloc(size_t s) +{ + void * r = malloc(s); + if(!r) bugp("malloc"); + return r; +} + +int convxdigit(char digit, byte *val) +{ + if(digit >= '0' && digit <= '9') + { + *val = digit - '0'; + return 0; + } + else if(digit >= 'A' && digit <= 'F') + { + *val = digit - 'A' + 10; + return 0; + } + else if(digit >= 'a' && digit <= 'f') + { + *val = digit - 'a' + 10; + return 0; + } + else + return 1; +} + +/* helper function to augment an array, free old array */ +void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt) +{ + void *p = xmalloc(elem_sz * (cnt + aug_cnt)); + memcpy(p, arr, elem_sz * cnt); + memcpy(p + elem_sz * cnt, aug, elem_sz * aug_cnt); + free(arr); + return p; +} + +/** + * Key file parsing + */ +int g_nr_keys; +key_array_t g_key_array; + +bool parse_key(char **pstr, struct crypto_key_t *key) +{ + char *str = *pstr; + /* ignore spaces */ + while(isspace(*str)) + str++; + /* CRYPTO_KEY: 32 hex characters + * CRYPTO_USBOTP: usbotp(vid:pid) where vid and pid are hex numbers */ + if(isxdigit(str[0])) + { + if(strlen(str) < 32) + return false; + for(int j = 0; j < 16; j++) + { + byte a, b; + if(convxdigit(str[2 * j], &a) || convxdigit(str[2 * j + 1], &b)) + return false; + key->u.key[j] = (a << 4) | b; + } + /* skip key */ + *pstr = str + 32; + key->method = CRYPTO_KEY; + return true; + } + else + { + const char *prefix = "usbotp("; + if(strlen(str) < strlen(prefix)) + return false; + if(strncmp(str, prefix, strlen(prefix)) != 0) + return false; + str += strlen(prefix); + /* vid */ + long vid = strtol(str, &str, 16); + if(vid < 0 || vid > 0xffff) + return false; + if(*str++ != ':') + return false; + /* pid */ + long pid = strtol(str, &str, 16); + if(pid < 0 || pid > 0xffff) + return false; + if(*str++ != ')') + return false; + *pstr = str; + key->method = CRYPTO_USBOTP; + key->u.vid_pid = vid << 16 | pid; + return true; + } +} + +void add_keys(key_array_t ka, int kac) +{ + key_array_t new_ka = xmalloc((g_nr_keys + kac) * sizeof(struct crypto_key_t)); + memcpy(new_ka, g_key_array, g_nr_keys * sizeof(struct crypto_key_t)); + memcpy(new_ka + g_nr_keys, ka, kac * sizeof(struct crypto_key_t)); + free(g_key_array); + g_key_array = new_ka; + g_nr_keys += kac; +} + +void clear_keys() +{ + free(g_key_array); + g_nr_keys = 0; +} + +void add_keys_from_file(const char *key_file) +{ + int size; + FILE *fd = fopen(key_file, "r"); + if(fd == NULL) + bug("opening key file failed"); + fseek(fd, 0, SEEK_END); + size = ftell(fd); + fseek(fd, 0, SEEK_SET); + char *buf = xmalloc(size + 1); + if(fread(buf, 1, size, fd) != (size_t)size) + bug("reading key file"); + buf[size] = 0; + fclose(fd); + + if(g_debug) + printf("Parsing key file '%s'...\n", key_file); + char *p = buf; + while(1) + { + struct crypto_key_t k; + /* parse key */ + if(!parse_key(&p, &k)) + bug("invalid key file"); + if(g_debug) + { + printf("Add key: "); + print_key(&k, true); + } + add_keys(&k, 1); + /* request at least one space character before next key, or end of file */ + if(*p != 0 && !isspace(*p)) + bug("invalid key file"); + /* skip whitespace */ + while(isspace(*p)) + p++; + if(*p == 0) + break; + } + free(buf); +} + +void print_hex(byte *data, int len, bool newline) +{ + for(int i = 0; i < len; i++) + printf("%02X ", data[i]); + if(newline) + printf("\n"); +} + +void print_key(struct crypto_key_t *key, bool newline) +{ + switch(key->method) + { + case CRYPTO_KEY: + print_hex(key->u.key, 16, false); + break; + case CRYPTO_USBOTP: + printf("USB-OTP(%04x:%04x)", key->u.vid_pid >> 16, key->u.vid_pid & 0xffff); + break; + case CRYPTO_NONE: + printf("none"); + break; + } + if(newline) + printf("\n"); +} + +char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' }; + +char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' }; +char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' }; +char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' }; +char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' }; +char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; + +static bool g_color_enable = true; + +void enable_color(bool enable) +{ + g_color_enable = enable; +} + +void color(color_t c) +{ + if(g_color_enable) + printf("%s", (char *)c); +} diff --git a/utils/imxtools/misc.h b/utils/imxtools/misc.h new file mode 100644 index 0000000000..b0b7dfeba6 --- /dev/null +++ b/utils/imxtools/misc.h @@ -0,0 +1,59 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __MISC_H__ +#define __MISC_H__ + +#include +#include "crypto.h" + +#define _STR(a) #a +#define STR(a) _STR(a) + +#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0) +#define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0) + +#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) + +extern bool g_debug; + +typedef struct crypto_key_t *key_array_t; +int g_nr_keys; +key_array_t g_key_array; + +void *memdup(void *p, size_t len); +void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt); +void generate_random_data(void *buf, size_t sz); +void *xmalloc(size_t s); +int convxdigit(char digit, byte *val); +void print_hex(byte *data, int len, bool newline); +void add_keys(key_array_t ka, int kac); +bool parse_key(char **str, struct crypto_key_t *key); +void add_keys_from_file(const char *key_file); +void print_key(struct crypto_key_t *key, bool newline); +void clear_keys(); + +typedef char color_t[]; + +extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; +void color(color_t c); +void enable_color(bool enable); + +#endif /* __MISC_H__ */ diff --git a/utils/imxtools/sb.c b/utils/imxtools/sb.c new file mode 100644 index 0000000000..44db56b7d1 --- /dev/null +++ b/utils/imxtools/sb.c @@ -0,0 +1,1181 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include +#include +#include +#include "misc.h" +#include "crypto.h" +#include "sb.h" + +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; + /* sb header */ + sb->image_size += sizeof(struct sb_header_t) / BLOCK_SIZE; + /* sections headers */ + sb->image_size += sb->nr_sections * sizeof(struct sb_section_header_t) / BLOCK_SIZE; + /* key dictionary */ + sb->image_size += g_nr_keys * sizeof(struct sb_key_dictionary_entry_t) / BLOCK_SIZE; + /* sections */ + for(int i = 0; i < sb->nr_sections; i++) + { + /* each section has a preliminary TAG command */ + sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE; + /* we might need to pad the section so compute next alignment */ + uint32_t alignment = BLOCK_SIZE; + if((i + 1) < sb->nr_sections) + alignment = sb->sections[i + 1].alignment; + alignment /= BLOCK_SIZE; /* alignment in block sizes */ + + struct sb_section_t *sec = &sb->sections[i]; + sec->sec_size = 0; + + if(g_debug) + { + printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot", + sec->identifier); + if(sec->is_cleartext) + printf(" (cleartext)"); + printf("\n"); + } + + sec->file_offset = sb->image_size; + for(int j = 0; j < sec->nr_insts; j++) + { + struct sb_inst_t *inst = &sec->insts[j]; + if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP) + { + if(g_debug) + printf(" %s | addr=0x%08x | arg=0x%08x\n", + inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument); + 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) + { + if(g_debug) + 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) + { + if(g_debug) + 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 + inst->padding_size) / BLOCK_SIZE; + sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE; + } + else if(inst->inst == SB_INST_MODE) + { + if(g_debug) + printf(" MODE | mod=0x%08x", inst->addr); + sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; + sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; + } + else if(inst->inst == SB_INST_DATA) + { + if(g_debug) + printf(" DATA | size=0x%08x\n", inst->size); + sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; + sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; + } + else + bug("die on inst %d\n", inst->inst); + } + /* we need to make sure next section starts on the right alignment. + * Since each section starts with a boot tag, we thus need to ensure + * that this sections ends at adress X such that X+BLOCK_SIZE is + * a multiple of the alignment. + * For data sections, we just add random data, otherwise we add nops */ + uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment); + if(missing_sz != alignment) + { + struct sb_inst_t *aug_insts; + int nr_aug_insts = 0; + + if(sb->sections[i].is_data) + { + nr_aug_insts = 1; + aug_insts = xmalloc(sizeof(struct sb_inst_t)); + memset(aug_insts, 0, sizeof(struct sb_inst_t)); + aug_insts[0].inst = SB_INST_DATA; + aug_insts[0].size = missing_sz * BLOCK_SIZE; + aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE); + generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE); + if(g_debug) + printf(" DATA | size=0x%08x\n", aug_insts[0].size); + } + else + { + nr_aug_insts = missing_sz; + aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts); + memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts); + for(int j = 0; j < nr_aug_insts; j++) + { + aug_insts[j].inst = SB_INST_NOP; + if(g_debug) + printf(" NOOP\n"); + } + } + + sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t), + sb->sections[i].nr_insts, aug_insts, nr_aug_insts); + sb->sections[i].nr_insts += nr_aug_insts; + free(aug_insts); + + /* augment image and section size */ + sb->image_size += missing_sz; + sec->sec_size += missing_sz; + } + } + /* final signature */ + 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; +} + +static uint16_t swap16(uint16_t t) +{ + return (t << 8) | (t >> 8); +} + +static void fix_version(struct sb_version_t *ver) +{ + ver->major = swap16(ver->major); + ver->minor = swap16(ver->minor); + ver->revision = swap16(ver->revision); +} + +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'; + sb_hdr->signature[3] = 'P'; + sb_hdr->major_ver = IMAGE_MAJOR_VERSION; + 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->first_boot_sec_id; + 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)); + /* Version 1.0 has 6 bytes of random padding, + * Version 1.1 requires the last 4 bytes to be 'sgtl' */ + if(sb->minor_version >= 1) + memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4); + + sb_hdr->timestamp = generate_timestamp(); + sb_hdr->product_ver = sb->product_ver; + fix_version(&sb_hdr->product_ver); + sb_hdr->component_ver = sb->component_ver; + fix_version(&sb_hdr->component_ver); + sb_hdr->drive_tag = sb->drive_tag; + + 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 = (sec->is_data ? 0 : SECTION_BOOTABLE) + | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); +} + +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 = (sec->is_data ? 0 : SECTION_BOOTABLE) + | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); + tag->hdr.checksum = instruction_checksum(&tag->hdr); +} + +void produce_sb_instruction(struct sb_inst_t *inst, + struct sb_instruction_common_t *cmd) +{ + memset(cmd, 0, sizeof(struct sb_instruction_common_t)); + cmd->hdr.opcode = inst->inst; + switch(inst->inst) + { + case SB_INST_CALL: + case SB_INST_JUMP: + cmd->addr = inst->addr; + cmd->data = inst->argument; + break; + case SB_INST_FILL: + cmd->addr = inst->addr; + cmd->len = inst->size; + cmd->data = inst->pattern; + break; + case SB_INST_LOAD: + cmd->addr = inst->addr; + cmd->len = inst->size; + cmd->data = crc_continue(crc(inst->data, inst->size), + inst->padding, inst->padding_size); + break; + case SB_INST_MODE: + cmd->data = inst->addr; + break; + case SB_INST_NOP: + break; + default: + bug("die\n"); + } + cmd->hdr.checksum = instruction_checksum(&cmd->hdr); +} + +enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename) +{ + struct crypto_key_t real_key; + real_key.method = CRYPTO_KEY; + byte crypto_iv[16]; + byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys); + /* init CBC-MACs */ + for(int i = 0; i < g_nr_keys; i++) + memset(cbc_macs[i], 0, 16); + + fill_gaps(sb); + compute_sb_offsets(sb); + + generate_random_data(real_key.u.key, 16); + + /* 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); + /* allocate image */ + byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE); + byte *buf_p = buf; + #define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0) + + sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr)); + write(&sb_hdr, sizeof(sb_hdr)); + + memcpy(crypto_iv, &sb_hdr, 16); + + /* update CBC-MACs */ + for(int i = 0; i < g_nr_keys; i++) + crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i], + cbc_macs[i], &cbc_macs[i], 1); + + /* 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(&sb_sec_hdr, sizeof(sb_sec_hdr)); + /* update CBC-MACs */ + for(int j = 0; j < g_nr_keys; j++) + crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE, + &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1); + } + /* produce key dictionary */ + for(int i = 0; i < g_nr_keys; i++) + { + struct sb_key_dictionary_entry_t entry; + memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16); + crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i], + crypto_iv, NULL, 1); + + write(&entry, sizeof(entry)); + sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry)); + } + + free(cbc_macs); + + /* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */ + /* Image crafting, don't use it unless you understand what you do */ + if(sb->override_real_key) + memcpy(real_key.u.key, sb->real_key, 16); + if(sb->override_crypto_iv) + memcpy(crypto_iv, sb->crypto_iv, 16); + /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */ + if(g_debug) + { + printf("Real key: "); + for(int j = 0; j < 16; j++) + printf("%02x", real_key.u.key[j]); + printf("\n"); + printf("IV : "); + for(int j = 0; j < 16; j++) + printf("%02x", crypto_iv[j]); + printf("\n"); + } + /* 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); + if(g_nr_keys > 0) + crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE, + &real_key, crypto_iv, NULL, 1); + sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd)); + write(&tag_cmd, sizeof(tag_cmd)); + /* produce other commands */ + byte cur_cbc_mac[16]; + memcpy(cur_cbc_mac, crypto_iv, 16); + for(int j = 0; j < sb->sections[i].nr_insts; j++) + { + struct sb_inst_t *inst = &sb->sections[i].insts[j]; + /* command */ + if(inst->inst != SB_INST_DATA) + { + struct sb_instruction_common_t cmd; + produce_sb_instruction(inst, &cmd); + if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) + crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE, + &real_key, cur_cbc_mac, &cur_cbc_mac, 1); + sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); + write(&cmd, sizeof(cmd)); + } + /* data */ + if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA) + { + uint32_t sz = inst->size + inst->padding_size; + byte *data = xmalloc(sz); + memcpy(data, inst->data, inst->size); + memcpy(data + inst->size, inst->padding, inst->padding_size); + if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) + crypto_cbc(data, data, sz / BLOCK_SIZE, + &real_key, cur_cbc_mac, &cur_cbc_mac, 1); + sha_1_update(&file_sha1, data, sz); + write(data, sz); + free(data); + } + } + } + /* 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); + if(g_nr_keys > 0) + crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1); + write(final_sig, 32); + + if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE) + bug("SB image buffer was not entirely filled !"); + + FILE *fd = fopen(filename, "wb"); + if(fd == NULL) + return SB_OPEN_ERROR; + if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1) + { + free(buf); + return SB_WRITE_ERROR; + } + fclose(fd); + free(buf); + + return SB_SUCCESS; +} + +static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf, + int size, const char *indent, void *u, sb_color_printf cprintf, enum sb_error_t *err) +{ + #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) + #define fatal(e, ...) \ + do { if(err) *err = e; \ + cprintf(u, true, GREY, __VA_ARGS__); \ + sb_free_section(*sec); \ + free(sec); \ + return NULL; } while(0) + + struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t)); + memset(sec, 0, sizeof(struct sb_section_t)); + sec->identifier = id; + sec->is_data = data_sec; + sec->sec_size = ROUND_UP(size, BLOCK_SIZE) / BLOCK_SIZE; + + if(data_sec) + { + sec->nr_insts = 1; + sec->insts = xmalloc(sizeof(struct sb_inst_t)); + memset(sec->insts, 0, sizeof(struct sb_inst_t)); + sec->insts->inst = SB_INST_DATA; + sec->insts->size = size; + sec->insts->data = memdup(buf, size); + return sec; + } + + /* Pretty print the content */ + int pos = 0; + while(pos < size) + { + struct sb_inst_t inst; + memset(&inst, 0, sizeof(inst)); + + struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos]; + inst.inst = hdr->opcode; + + printf(OFF, "%s", indent); + uint8_t checksum = instruction_checksum(hdr); + if(checksum != hdr->checksum) + fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum"); + if(hdr->flags != 0) + { + printf(GREY, "["); + printf(BLUE, "f=%x", hdr->flags); + printf(GREY, "] "); + } + if(hdr->opcode == SB_INST_LOAD) + { + struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos]; + inst.size = load->len; + inst.addr = load->addr; + inst.data = memdup(load + 1, load->len); + + printf(RED, "LOAD"); + printf(OFF, " | "); + printf(BLUE, "addr=0x%08x", load->addr); + printf(OFF, " | "); + printf(GREEN, "len=0x%08x", load->len); + printf(OFF, " | "); + printf(YELLOW, "crc=0x%08x", load->crc); + /* data is padded to 16-byte boundary with random data and crc'ed with it */ + uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)], + ROUND_UP(load->len, 16)); + if(load->crc == computed_crc) + printf(RED, " Ok\n"); + else + { + printf(RED, " Failed (crc=0x%08x)\n", computed_crc); + fatal(SB_CHECKSUM_ERROR, "Instruction data crc error\n"); + } + + pos += load->len + sizeof(struct sb_instruction_load_t); + } + else if(hdr->opcode == SB_INST_FILL) + { + struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos]; + inst.pattern = fill->pattern; + inst.size = fill->len; + inst.addr = fill->addr; + + printf(RED, "FILL"); + printf(OFF, " | "); + printf(BLUE, "addr=0x%08x", fill->addr); + printf(OFF, " | "); + printf(GREEN, "len=0x%08x", fill->len); + printf(OFF, " | "); + printf(YELLOW, "pattern=0x%08x\n", fill->pattern); + + pos += sizeof(struct sb_instruction_fill_t); + } + else if(hdr->opcode == SB_INST_CALL || + hdr->opcode == SB_INST_JUMP) + { + int is_call = (hdr->opcode == SB_INST_CALL); + struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos]; + inst.addr = call->addr; + inst.argument = call->arg; + + if(is_call) + printf(RED, "CALL"); + else + printf(RED, "JUMP"); + printf(OFF, " | "); + printf(BLUE, "addr=0x%08x", call->addr); + printf(OFF, " | "); + printf(GREEN, "arg=0x%08x\n", call->arg); + + pos += sizeof(struct sb_instruction_call_t); + } + else if(hdr->opcode == SB_INST_MODE) + { + struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr; + inst.argument = mode->mode; + + printf(RED, "MODE"); + printf(OFF, " | "); + printf(BLUE, "mod=0x%08x\n", mode->mode); + + pos += sizeof(struct sb_instruction_mode_t); + } + else if(hdr->opcode == SB_INST_NOP) + { + printf(RED, "NOOP\n"); + pos += sizeof(struct sb_instruction_mode_t); + } + else + { + fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos); + break; + } + + sec->insts = augment_array(sec->insts, sizeof(struct sb_inst_t), sec->nr_insts++, &inst, 1); + pos = ROUND_UP(pos, BLOCK_SIZE); + } + + return sec; + #undef printf + #undef fatal +} + +void sb_fill_section_name(char name[5], uint32_t identifier) +{ + name[0] = (identifier >> 24) & 0xff; + name[1] = (identifier >> 16) & 0xff; + name[2] = (identifier >> 8) & 0xff; + name[3] = identifier & 0xff; + for(int i = 0; i < 4; i++) + if(!isprint(name[i])) + name[i] = '_'; + name[4] = 0; +} + +static uint32_t guess_alignment(uint32_t off) +{ + /* find greatest power of two which divides the offset */ + if(off == 0) + return 1; + uint32_t a = 1; + while(off % (2 * a) == 0) + a *= 2; + return a; +} + +struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u, + sb_color_printf cprintf, enum sb_error_t *err) +{ + uint8_t *buf = NULL; + struct sb_file_t *sb_file = NULL; + + #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) + #define fatal(e, ...) \ + do { if(err) *err = e; \ + cprintf(u, true, GREY, __VA_ARGS__); \ + free(buf); \ + sb_free(sb_file); \ + return NULL; } while(0) + #define print_hex(c, p, len, nl) \ + do { printf(c, ""); print_hex(p, len, nl); } while(0) + + FILE *f = fopen(filename, "rb"); + if(f == NULL) + fatal(SB_OPEN_ERROR, "Cannot open file for reading\n"); + fseek(f, 0, SEEK_END); + long filesize = ftell(f); + fseek(f, 0, SEEK_SET); + buf = xmalloc(filesize); + if(fread(buf, filesize, 1, f) != 1) + { + fclose(f); + fatal(SB_READ_ERROR, "Cannot read file\n"); + } + fclose(f); + + struct sha_1_params_t sha_1_params; + sb_file = xmalloc(sizeof(struct sb_file_t)); + memset(sb_file, 0, sizeof(struct sb_file_t)); + struct sb_header_t *sb_header = (struct sb_header_t *)buf; + + sb_file->image_size = sb_header->image_size; + sb_file->minor_version = sb_header->minor_ver; + sb_file->flags = sb_header->flags; + sb_file->drive_tag = sb_header->drive_tag; + sb_file->first_boot_sec_id = sb_header->first_boot_sec_id; + + if(memcmp(sb_header->signature, "STMP", 4) != 0) + fatal(SB_FORMAT_ERROR, "Bad signature\n"); + if(sb_header->image_size * BLOCK_SIZE > filesize) + fatal(SB_FORMAT_ERROR, "File too small"); + if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t)) + fatal(SB_FORMAT_ERROR, "Bad header size"); + if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t)) + fatal(SB_FORMAT_ERROR, "Bad section header size"); + + if(filesize > sb_header->image_size * BLOCK_SIZE) + { + printf(GREY, "[Restrict file size from %lu to %d bytes]\n", filesize, + sb_header->image_size * BLOCK_SIZE); + filesize = sb_header->image_size * BLOCK_SIZE; + } + + printf(BLUE, "Basic info:\n"); + printf(GREEN, " SB version: "); + printf(YELLOW, "%d.%d\n", sb_header->major_ver, sb_header->minor_ver); + printf(GREEN, " Header SHA-1: "); + byte *hdr_sha1 = sb_header->sha1_header; + print_hex(YELLOW, hdr_sha1, 20, false); + /* Check SHA1 sum */ + byte computed_sha1[20]; + sha_1_init(&sha_1_params); + sha_1_update(&sha_1_params, &sb_header->signature[0], + sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header)); + sha_1_finish(&sha_1_params); + sha_1_output(&sha_1_params, computed_sha1); + if(memcmp(hdr_sha1, computed_sha1, 20) == 0) + printf(RED, " Ok\n"); + else + printf(RED, " Failed\n"); + printf(GREEN, " Flags: "); + printf(YELLOW, "%x\n", sb_header->flags); + printf(GREEN, " Total file size : "); + printf(YELLOW, "%ld\n", filesize); + + /* Sizes and offsets */ + printf(BLUE, "Sizes and offsets:\n"); + printf(GREEN, " # of encryption keys = "); + printf(YELLOW, "%d\n", sb_header->nr_keys); + printf(GREEN, " # of sections = "); + printf(YELLOW, "%d\n", sb_header->nr_sections); + + /* Versions */ + printf(BLUE, "Versions\n"); + + printf(GREEN, " Random 1: "); + print_hex(YELLOW, sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true); + printf(GREEN, " Random 2: "); + print_hex(YELLOW, sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true); + + uint64_t micros = sb_header->timestamp; + time_t seconds = (micros / (uint64_t)1000000L); + struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ + seconds += mktime(&tm_base); + struct tm *time = gmtime(&seconds); + printf(GREEN, " Creation date/time = "); + printf(YELLOW, "%s", asctime(time)); + + struct sb_version_t product_ver = sb_header->product_ver; + fix_version(&product_ver); + struct sb_version_t component_ver = sb_header->component_ver; + fix_version(&component_ver); + + memcpy(&sb_file->product_ver, &product_ver, sizeof(product_ver)); + memcpy(&sb_file->component_ver, &component_ver, sizeof(component_ver)); + + printf(GREEN, " Product version = "); + printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision); + printf(GREEN, " Component version = "); + printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision); + + printf(GREEN, " Drive tag = "); + printf(YELLOW, "%x\n", sb_header->drive_tag); + printf(GREEN, " First boot tag offset = "); + printf(YELLOW, "%x\n", sb_header->first_boot_tag_off); + printf(GREEN, " First boot section ID = "); + printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id); + + /* encryption cbc-mac */ + byte real_key[16]; + bool valid_key = false; /* false until a matching key was found */ + + if(sb_header->nr_keys > 0) + { + byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys); + printf(BLUE, "Encryption keys\n"); + for(int i = 0; i < g_nr_keys; i++) + { + printf(RED, " Key %d: ", i); + printf(YELLOW, ""); + print_key(&g_key_array[i], true); + printf(GREEN, " CBC-MAC: "); + /* check it */ + byte zero[16]; + memset(zero, 0, 16); + int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections, + &g_key_array[i], zero, &cbcmacs[i], 1); + if(ret != CRYPTO_ERROR_SUCCESS) + { + free(cbcmacs); + fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret); + } + print_hex(YELLOW, cbcmacs[i], 16, true); + } + + printf(BLUE, "DEK\n"); + for(int i = 0; i < sb_header->nr_keys; i++) + { + printf(RED, " Entry %d\n", i); + uint32_t ofs = sizeof(struct sb_header_t) + + sizeof(struct sb_section_header_t) * sb_header->nr_sections + + sizeof(struct sb_key_dictionary_entry_t) * i; + struct sb_key_dictionary_entry_t *dict_entry = + (struct sb_key_dictionary_entry_t *)&buf[ofs]; + /* cbc mac */ + printf(GREEN, " Encrypted key: "); + print_hex(YELLOW, dict_entry->key, 16, true); + printf(GREEN, " CBC-MAC : "); + print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false); + /* check it */ + int idx = 0; + while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0) + idx++; + if(idx != g_nr_keys) + { + printf(RED, " Match\n"); + /* decrypt */ + byte decrypted_key[16]; + byte iv[16]; + memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ + int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0); + if(ret != CRYPTO_ERROR_SUCCESS) + { + free(cbcmacs); + fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret); + } + printf(GREEN, " Decrypted key: "); + print_hex(YELLOW, decrypted_key, 16, false); + if(valid_key) + { + if(memcmp(real_key, decrypted_key, 16) == 0) + printf(RED, " Cross-Check Ok"); + else + printf(RED, " Cross-Check Failed"); + } + else + { + memcpy(real_key, decrypted_key, 16); + valid_key = true; + } + printf(OFF, "\n"); + } + else + printf(RED, " Don't Match\n"); + } + + free(cbcmacs); + + if(!valid_key) + fatal(SB_NO_VALID_KEY, "No valid key found\n"); + + if(getenv("SB_REAL_KEY") != 0) + { + struct crypto_key_t k; + char *env = getenv("SB_REAL_KEY"); + if(!parse_key(&env, &k) || *env) + bug("Invalid SB_REAL_KEY\n"); + memcpy(real_key, k.u.key, 16); + } + + printf(RED, " Summary:\n"); + printf(GREEN, " Real key: "); + print_hex(YELLOW, real_key, 16, true); + printf(GREEN, " IV : "); + print_hex(YELLOW, buf, 16, true); + + sb_file->override_real_key = true; + memcpy(sb_file->real_key, real_key, 16); + sb_file->override_crypto_iv = true; + memcpy(sb_file->crypto_iv, buf, 16); + } + + /* sections */ + if(!raw_mode) + { + sb_file->nr_sections = sb_header->nr_sections; + sb_file->sections = xmalloc(sb_file->nr_sections * sizeof(struct sb_section_t)); + memset(sb_file->sections, 0, sb_file->nr_sections * sizeof(struct sb_section_t)); + printf(BLUE, "Sections\n"); + for(int i = 0; i < sb_header->nr_sections; i++) + { + uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t); + struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&buf[ofs]; + + char name[5]; + sb_fill_section_name(name, sec_hdr->identifier); + 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) && sb_header->nr_keys > 0; + + printf(GREEN, " Section "); + printf(YELLOW, "'%s'\n", name); + printf(GREEN, " pos = "); + printf(YELLOW, "%8x - %8x\n", pos, pos+size); + printf(GREEN, " len = "); + printf(YELLOW, "%8x\n", size); + printf(GREEN, " flags = "); + printf(YELLOW, "%8x", sec_hdr->flags); + if(data_sec) + printf(RED, " Data Section"); + else + printf(RED, " Boot Section"); + if(encrypted) + printf(RED, " (Encrypted)"); + printf(OFF, "\n"); + + /* save it */ + byte *sec = xmalloc(size); + if(encrypted) + cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); + else + memcpy(sec, buf + pos, size); + + struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier, + sec, size, " ", u, cprintf, err); + if(s) + { + s->is_cleartext = !encrypted; + s->alignment = guess_alignment(pos); + memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t)); + free(s); + } + else + fatal(*err, "Error reading section\n"); + + free(sec); + } + } + else + { + /* advanced raw mode */ + printf(BLUE, "Commands\n"); + uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE; + byte iv[16]; + const char *indent = " "; + while(true) + { + /* restart with IV */ + memcpy(iv, buf, 16); + byte cmd[BLOCK_SIZE]; + if(sb_header->nr_keys > 0) + cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0); + else + memcpy(cmd, buf + offset, BLOCK_SIZE); + struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd; + printf(OFF, "%s", indent); + uint8_t checksum = instruction_checksum(hdr); + if(checksum != hdr->checksum) + printf(GREY, "[Bad checksum']"); + + if(hdr->opcode == SB_INST_NOP) + { + printf(RED, "NOOP\n"); + offset += BLOCK_SIZE; + } + else if(hdr->opcode == SB_INST_TAG) + { + struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr; + printf(RED, "BTAG"); + printf(OFF, " | "); + printf(BLUE, "sec=0x%08x", tag->identifier); + printf(OFF, " | "); + printf(GREEN, "cnt=0x%08x", tag->len); + printf(OFF, " | "); + printf(YELLOW, "flg=0x%08x", tag->flags); + if(tag->hdr.flags & SB_INST_LAST_TAG) + { + printf(OFF, " | "); + printf(RED, " Last section"); + } + printf(OFF, "\n"); + offset += sizeof(struct sb_instruction_tag_t); + + char name[5]; + sb_fill_section_name(name, tag->identifier); + int pos = offset; + int size = tag->len * BLOCK_SIZE; + int data_sec = !(tag->flags & SECTION_BOOTABLE); + int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; + + printf(GREEN, "%sSection ", indent); + printf(YELLOW, "'%s'\n", name); + printf(GREEN, "%s pos = ", indent); + printf(YELLOW, "%8x - %8x\n", pos, pos+size); + printf(GREEN, "%s len = ", indent); + printf(YELLOW, "%8x\n", size); + printf(GREEN, "%s flags = ", indent); + printf(YELLOW, "%8x", tag->flags); + if(data_sec) + printf(RED, " Data Section"); + else + printf(RED, " Boot Section"); + if(encrypted) + printf(RED, " (Encrypted)"); + printf(OFF, "\n"); + + /* save it */ + byte *sec = xmalloc(size); + if(encrypted) + cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); + else + memcpy(sec, buf + pos, size); + + struct sb_section_t *s = read_section(data_sec, tag->identifier, + sec, size, " ", u, cprintf, err); + if(s) + { + s->is_cleartext = !encrypted; + s->alignment = guess_alignment(pos); + sb_file->sections = augment_array(sb_file->sections, + sizeof(struct sb_section_t), sb_file->nr_sections++, + s, 1); + free(s); + } + else + fatal(*err, "Error reading section\n"); + free(sec); + + /* last one ? */ + if(tag->hdr.flags & SB_INST_LAST_TAG) + break; + offset += size; + } + else + { + fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset); + break; + } + } + } + + /* final signature */ + printf(BLUE, "Final signature:\n"); + byte decrypted_block[32]; + if(sb_header->nr_keys > 0) + { + printf(GREEN, " Encrypted SHA-1:\n"); + byte *encrypted_block = &buf[filesize - 32]; + printf(OFF, " "); + print_hex(YELLOW, encrypted_block, 16, true); + printf(OFF, " "); + print_hex(YELLOW, encrypted_block + 16, 16, true); + /* decrypt it */ + cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0); + } + else + memcpy(decrypted_block, &buf[filesize - 32], 32); + printf(GREEN, " File SHA-1:\n "); + print_hex(YELLOW, decrypted_block, 20, false); + /* check it */ + sha_1_init(&sha_1_params); + sha_1_update(&sha_1_params, buf, filesize - 32); + sha_1_finish(&sha_1_params); + sha_1_output(&sha_1_params, computed_sha1); + if(memcmp(decrypted_block, computed_sha1, 20) == 0) + printf(RED, " Ok\n"); + else + { + printf(RED, " Failed\n"); + fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n"); + } + free(buf); + + return sb_file; + #undef printf + #undef fatal + #undef print_hex +} + +void sb_free_section(struct sb_section_t sec) +{ + for(int j = 0; j < sec.nr_insts; j++) + { + free(sec.insts[j].padding); + free(sec.insts[j].data); + } + free(sec.insts); +} + +void sb_free(struct sb_file_t *file) +{ + if(!file) return; + + for(int i = 0; i < file->nr_sections; i++) + sb_free_section(file->sections[i]); + + free(file->sections); + free(file); +} + +void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf) +{ + #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) + #define print_hex(c, p, len, nl) \ + do { printf(c, ""); print_hex(p, len, nl); } while(0) + + #define TREE RED + #define HEADER GREEN + #define TEXT YELLOW + #define TEXT2 BLUE + #define SEP OFF + + printf(HEADER, "SB File\n"); + printf(TREE, "+-"); + printf(HEADER, "Version: "); + printf(TEXT, "1.%d\n", file->minor_version); + printf(TREE, "+-"); + printf(HEADER, "Flags: "); + printf(TEXT, "%x\n", file->flags); + printf(TREE, "+-"); + printf(HEADER, "Drive Tag: "); + printf(TEXT, "%x\n", file->drive_tag); + printf(TREE, "+-"); + printf(HEADER, "First Boot Section ID: "); + char name[5]; + sb_fill_section_name(name, file->first_boot_sec_id); + printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name); + + if(file->override_real_key) + { + printf(TREE, "+-"); + printf(HEADER, "Real key: "); + print_hex(TEXT, file->real_key, 16, true); + } + if(file->override_crypto_iv) + { + printf(TREE, "+-"); + printf(HEADER, "IV : "); + print_hex(TEXT, file->crypto_iv, 16, true); + } + printf(TREE, "+-"); + printf(HEADER, "Product Version: "); + printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor, + file->product_ver.revision); + printf(TREE, "+-"); + printf(HEADER, "Component Version: "); + printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor, + file->component_ver.revision); + + for(int i = 0; i < file->nr_sections; i++) + { + struct sb_section_t *sec = &file->sections[i]; + printf(TREE, "+-"); + printf(HEADER, "Section\n"); + printf(TREE,"| +-"); + printf(HEADER, "Identifier: "); + sb_fill_section_name(name, sec->identifier); + printf(TEXT, "%08x (%s)\n", sec->identifier, name); + printf(TREE, "| +-"); + printf(HEADER, "Type: "); + printf(TEXT, "%s (%s)\n", sec->is_data ? "Data Section" : "Boot Section", + sec->is_cleartext ? "Cleartext" : "Encrypted"); + printf(TREE, "| +-"); + printf(HEADER, "Alignment: "); + printf(TEXT, "%d (bytes)\n", sec->alignment); + printf(TREE, "| +-"); + printf(HEADER, "Instructions\n"); + for(int j = 0; j < sec->nr_insts; j++) + { + struct sb_inst_t *inst = &sec->insts[j]; + printf(TREE, "| | +-"); + switch(inst->inst) + { + case SB_INST_DATA: + printf(HEADER, "DATA"); + printf(SEP, " | "); + printf(TEXT, "size=0x%08x\n", inst->size); + break; + case SB_INST_CALL: + case SB_INST_JUMP: + printf(HEADER, "%s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP"); + printf(SEP, " | "); + printf(TEXT, "addr=0x%08x", inst->addr); + printf(SEP, " | "); + printf(TEXT2, "arg=0x%08x\n", inst->argument); + break; + case SB_INST_LOAD: + printf(HEADER, "LOAD"); + printf(SEP, " | "); + printf(TEXT, "addr=0x%08x", inst->addr); + printf(SEP, " | "); + printf(TEXT2, "len=0x%08x\n", inst->size); + break; + case SB_INST_FILL: + printf(HEADER, "FILL"); + printf(SEP, " | "); + printf(TEXT, "addr=0x%08x", inst->addr); + printf(SEP, " | "); + printf(TEXT2, "len=0x%08x", inst->size); + printf(SEP, " | "); + printf(TEXT2, "pattern=0x%08x\n", inst->pattern); + break; + case SB_INST_MODE: + printf(HEADER, "MODE"); + printf(SEP, " | "); + printf(TEXT, "mod=0x%08x\n", inst->addr); + break; + case SB_INST_NOP: + printf(HEADER, "NOOP\n"); + break; + default: + printf(GREY, "[Unknown instruction %x]\n", inst->inst); + } + } + } + + #undef printf + #undef print_hex +} diff --git a/utils/imxtools/sb.h b/utils/imxtools/sb.h new file mode 100644 index 0000000000..ced6481a80 --- /dev/null +++ b/utils/imxtools/sb.h @@ -0,0 +1,237 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __SB_H__ +#define __SB_H__ + +#include +#include + +#include "misc.h" + +#define BLOCK_SIZE 16 + +/* All fields are in big-endian BCD */ +struct sb_version_t +{ + uint16_t major; + uint16_t pad0; + uint16_t minor; + uint16_t pad1; + uint16_t revision; + uint16_t pad2; +}; + +struct sb_header_t +{ + uint8_t sha1_header[20]; /* SHA-1 of the rest of the header */ + uint8_t signature[4]; /* Signature "STMP" */ + uint8_t major_ver; /* Should be 1 */ + uint8_t minor_ver; /* Should be 1 */ + uint16_t flags; + uint32_t image_size; /* In blocks (=16bytes) */ + uint32_t first_boot_tag_off; /* Offset in blocks */ + uint32_t first_boot_sec_id; /* First bootable section ID */ + uint16_t nr_keys; /* Number of encryption keys */ + uint16_t key_dict_off; /* Offset to key dictionary (in blocks) */ + uint16_t header_size; /* In blocks */ + uint16_t nr_sections; /* Number of sections */ + uint16_t sec_hdr_size; /* Section header size (in blocks) */ + uint8_t rand_pad0[6]; /* Random padding */ + uint64_t timestamp; /* In microseconds since 2000/1/1 00:00:00 */ + struct sb_version_t product_ver; + struct sb_version_t component_ver; + uint16_t drive_tag; /* first tag to boot ? */ + uint8_t rand_pad1[6]; /* Random padding */ +} __attribute__((packed)); + +struct sb_section_header_t +{ + uint32_t identifier; + uint32_t offset; /* In blocks */ + uint32_t size; /* In blocks */ + uint32_t flags; +} __attribute__((packed)); + +struct sb_key_dictionary_entry_t +{ + uint8_t hdr_cbc_mac[16]; /* CBC-MAC of the header */ + uint8_t key[16]; /* Actual AES Key (encrypted by the global key) */ +} __attribute__((packed)); + +#define IMAGE_MAJOR_VERSION 1 +#define IMAGE_MINOR_VERSION 1 + +#define SECTION_BOOTABLE (1 << 0) +#define SECTION_CLEARTEXT (1 << 1) + +#define SB_INST_NOP 0x0 +#define SB_INST_TAG 0x1 +#define SB_INST_LOAD 0x2 +#define SB_INST_FILL 0x3 +#define SB_INST_JUMP 0x4 +#define SB_INST_CALL 0x5 +#define SB_INST_MODE 0x6 + +/* flags */ +#define SB_INST_LAST_TAG 1 /* for TAG */ +#define SB_INST_LOAD_DCD 1 /* for LOAD */ +#define SB_INST_FILL_BYTE 0 /* for FILL */ +#define SB_INST_FILL_HWORD 1 /* for FILL */ +#define SB_INST_FILL_WORD 2 /* for FILL */ +#define SB_INST_HAB_EXEC 1 /* for JUMP/CALL */ + +struct sb_instruction_header_t +{ + uint8_t checksum; + uint8_t opcode; + 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; + uint32_t addr; + uint32_t len; + uint32_t crc; +} __attribute__((packed)); + +struct sb_instruction_fill_t +{ + struct sb_instruction_header_t hdr; + uint32_t addr; + uint32_t len; + uint32_t pattern; +} __attribute__((packed)); + +struct sb_instruction_mode_t +{ + struct sb_instruction_header_t hdr; + uint32_t zero1; + uint32_t zero2; + uint32_t mode; +} __attribute__((packed)); + +struct sb_instruction_call_t +{ + struct sb_instruction_header_t hdr; + uint32_t addr; + uint32_t zero; + uint32_t arg; +} __attribute__((packed)); + +struct sb_instruction_tag_t +{ + struct sb_instruction_header_t hdr; + uint32_t identifier; /* section identifier */ + uint32_t len; /* length of the section */ + uint32_t flags; /* section flags */ +} __attribute__((packed)); + +/******* + * API * + *******/ + +#define SB_INST_DATA 0xff + +struct sb_inst_t +{ + uint8_t inst; /* SB_INST_* */ + uint32_t size; + uint32_t addr; + // + void *data; + uint32_t pattern; + // + uint32_t argument; // for call, jump and mode + /* for production use */ + uint32_t padding_size; + uint8_t *padding; +}; + +struct sb_section_t +{ + uint32_t identifier; + bool is_data; + bool is_cleartext; + uint32_t alignment; + // data sections are handled as one or more SB_INST_DATA virtual instruction + int nr_insts; + struct sb_inst_t *insts; + /* for production use */ + uint32_t file_offset; /* in blocks */ + uint32_t sec_size; /* in blocks */ +}; + +struct sb_file_t +{ + /* override real, otherwise it is randomly generated */ + bool override_real_key; + uint8_t real_key[16]; + /* override crypto IV, use with caution ! Use NULL to generate it */ + bool override_crypto_iv; + uint8_t crypto_iv[16]; + + int nr_sections; + uint16_t drive_tag; + uint32_t first_boot_sec_id; + uint16_t flags; + uint8_t minor_version; + struct sb_section_t *sections; + struct sb_version_t product_ver; + struct sb_version_t component_ver; + /* for production use */ + uint32_t image_size; /* in blocks */ +}; + +enum sb_error_t +{ + SB_SUCCESS = 0, + SB_ERROR = -1, + SB_OPEN_ERROR = -2, + SB_READ_ERROR = -3, + SB_WRITE_ERROR = -4, + SB_FORMAT_ERROR = -5, + SB_CHECKSUM_ERROR = -6, + SB_NO_VALID_KEY = -7, + SB_FIRST_CRYPTO_ERROR = -8, + SB_LAST_CRYPTO_ERROR = SB_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS, +}; + +enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename); + +typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...); +struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u, + sb_color_printf printf, enum sb_error_t *err); + +void sb_fill_section_name(char name[5], uint32_t identifier); +void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf); +void sb_free_section(struct sb_section_t file); +void sb_free(struct sb_file_t *file); + +#endif /* __SB_H__ */ diff --git a/utils/imxtools/sbloader.c b/utils/imxtools/sbloader.c new file mode 100644 index 0000000000..ba4645f8ab --- /dev/null +++ b/utils/imxtools/sbloader.c @@ -0,0 +1,174 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include +#include +#include +#include +#include + +void put32le(uint8_t *buf, uint32_t i) +{ + *buf++ = i & 0xff; + *buf++ = (i >> 8) & 0xff; + *buf++ = (i >> 16) & 0xff; + *buf++ = (i >> 24) & 0xff; +} + +void put32be(uint8_t *buf, uint32_t i) +{ + *buf++ = (i >> 24) & 0xff; + *buf++ = (i >> 16) & 0xff; + *buf++ = (i >> 8) & 0xff; + *buf++ = i & 0xff; +} + +int main(int argc, char **argv) +{ + int ret; + uint8_t msg[0x20]; + uint8_t *p; + FILE *f; + int i, xfer_size, nr_xfers, recv_size; + + if(argc != 3) + { + printf("usage: %s \n", argv[0]); + return 1; + } + + char *end; + xfer_size = strtol(argv[1], &end, 0); + if(end != (argv[1] + strlen(argv[1]))) + { + printf("Invalid transfer size !\n"); + return 1; + } + + libusb_device_handle *dev; + + libusb_init(NULL); + + libusb_set_debug(NULL, 3); + + /* MX23 */ + dev = libusb_open_device_with_vid_pid(NULL, 0x066F, 0x3780); + if(dev == NULL) + /* MX28 */ + dev = libusb_open_device_with_vid_pid(NULL, 0x15A2, 0x004F); + if(dev == NULL) + { + printf("Cannot open device\n"); + return 1; + } + + libusb_detach_kernel_driver(dev, 0); + libusb_detach_kernel_driver(dev, 4); + + libusb_claim_interface (dev, 0); + libusb_claim_interface (dev, 4); + + if (!dev) + { + printf("No dev\n"); + exit(1); + } + + f = fopen(argv[2], "r"); + if(f == NULL) + { + perror("cannot open file"); + return 1; + } + fseek(f, 0, SEEK_END); + size_t size = ftell(f); + fseek(f, 0, SEEK_SET); + + printf("Transfer size: %d\n", xfer_size); + nr_xfers = (size + xfer_size - 1) / xfer_size; + uint8_t *file_buf = malloc(nr_xfers * xfer_size); + memset(file_buf, 0xff, nr_xfers * xfer_size); // pad with 0xff + if(fread(file_buf, size, 1, f) != 1) + { + perror("read error"); + fclose(f); + return 1; + } + fclose(f); + + memset(msg, 0, 0x20); + + p = msg; + + *p++ = 0x01; // Init upload command + *p++ = 'B'; // Signature + *p++ = 'L'; + *p++ = 'T'; + *p++ = 'C'; + put32le(p, 0x1); // I guess version or sub-command + p += 4; + put32le(p, size); // Payload size + + // The second command starts at 0x20 + + p = &msg[0x10]; + + *p++ = 0x02; // Start upload + put32be(p, size); // Payload size, again + + ret = libusb_control_transfer(dev, + LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 0x9, 0x201, 0, + msg, 0x20, 1000); + if(ret < 0) + { + printf("transfer error at init step\n"); + return 1; + } + + uint8_t *xfer_buf = malloc(1 + xfer_size); + + for(i = 0; i < nr_xfers; i++) + { + xfer_buf[0] = 0x2; + memcpy(&xfer_buf[1], &file_buf[i * xfer_size], xfer_size); + + ret = libusb_control_transfer(dev, + LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, + 0x9, 0x202, 0, xfer_buf, xfer_size + 1, 1000); + if(ret < 0) + { + printf("transfer error at send step %d\n", i); + return 1; + } + } + + ret = libusb_interrupt_transfer(dev, 0x81, xfer_buf, xfer_size, &recv_size, + 1000); + if(ret < 0) + { + printf("transfer error at final stage\n"); + return 1; + } + + printf("ret %i\n", ret); + + return 0; +} + diff --git a/utils/imxtools/sbtoelf.c b/utils/imxtools/sbtoelf.c new file mode 100644 index 0000000000..fda70b1180 --- /dev/null +++ b/utils/imxtools/sbtoelf.c @@ -0,0 +1,302 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Bertrik Sikken + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +/* + * .sb file parser and chunk extractor + * + * Based on amsinfo, which is + * Copyright © 2008 Rafaël Carré + */ + +#define _ISOC99_SOURCE /* snprintf() */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "crypto.h" +#include "elf.h" +#include "sb.h" +#include "misc.h" + +/* all blocks are sized as a multiple of 0x1ff */ +#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) + +/* If you find a firmware that breaks the known format ^^ */ +#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) + +#define crypto_cbc(...) \ + do { int ret = crypto_cbc(__VA_ARGS__); \ + if(ret != CRYPTO_ERROR_SUCCESS) \ + bug("crypto_cbc error: %d\n", ret); \ + }while(0) + +/* globals */ + +char *g_out_prefix; + +static void elf_printf(void *user, bool error, const char *fmt, ...) +{ + if(!g_debug && !error) + return; + (void) user; + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +static void elf_write(void *user, uint32_t addr, const void *buf, size_t count) +{ + FILE *f = user; + fseek(f, addr, SEEK_SET); + fwrite(buf, count, 1, f); +} + +static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id) +{ + char name[5]; + char *filename = xmalloc(strlen(g_out_prefix) + 32); + sb_fill_section_name(name, id); + sprintf(filename, "%s%s.%d.elf", g_out_prefix, name, count); + if(g_debug) + printf("Write boot section %s to %s\n", name, filename); + + FILE *fd = fopen(filename, "wb"); + free(filename); + + if(fd == NULL) + return ; + elf_write_file(elf, elf_write, elf_printf, fd); + fclose(fd); +} + +static void extract_sb_section(struct sb_section_t *sec) +{ + if(sec->is_data) + { + char sec_name[5]; + char *filename = xmalloc(strlen(g_out_prefix) + 32); + sb_fill_section_name(sec_name, sec->identifier); + sprintf(filename, "%s%s.bin", g_out_prefix, sec_name); + FILE *fd = fopen(filename, "wb"); + if(fd == NULL) + bugp("Cannot open %s for writing\n", filename); + if(g_debug) + printf("Write data section %s to %s\n", sec_name, filename); + free(filename); + + for(int j = 0; j < sec->nr_insts; j++) + { + assert(sec->insts[j].inst == SB_INST_DATA); + fwrite(sec->insts[j].data, sec->insts[j].size, 1, fd); + } + fclose(fd); + } + + int elf_count = 0; + struct elf_params_t elf; + elf_init(&elf); + + for(int i = 0; i < sec->nr_insts; i++) + { + struct sb_inst_t *inst = &sec->insts[i]; + switch(inst->inst) + { + case SB_INST_LOAD: + elf_add_load_section(&elf, inst->addr, inst->size, inst->data); + break; + case SB_INST_FILL: + elf_add_fill_section(&elf, inst->addr, inst->size, inst->pattern); + break; + case SB_INST_CALL: + case SB_INST_JUMP: + elf_set_start_addr(&elf, inst->addr); + extract_elf_section(&elf, elf_count++, sec->identifier); + elf_release(&elf); + elf_init(&elf); + break; + default: + /* ignore mode and nop */ + break; + } + } + + if(!elf_is_empty(&elf)) + extract_elf_section(&elf, elf_count, sec->identifier); + elf_release(&elf); +} + +static void extract_sb_file(struct sb_file_t *file) +{ + for(int i = 0; i < file->nr_sections; i++) + extract_sb_section(&file->sections[i]); +} + +static void usage(void) +{ + printf("Usage: sbtoelf [options] sb-file\n"); + printf("Options:\n"); + printf(" -?/--help\tDisplay this message\n"); + printf(" -o \tEnable output and set prefix\n"); + printf(" -d/--debug\tEnable debug output*\n"); + printf(" -k \tAdd key file\n"); + printf(" -z\t\tAdd zero key\n"); + printf(" -r\t\tUse raw command mode\n"); + printf(" -a/--add-key \tAdd single key (hex or usbotp)\n"); + printf(" -n/--no-color\tDisable output colors\n"); + printf(" -l/--loopback \tProduce sb file out of extracted description*\n"); + printf("Options marked with a * are for debug purpose only\n"); + exit(1); +} + +static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...) +{ + (void) user; + (void) error; + va_list args; + va_start(args, fmt); + color(c); + vprintf(fmt, args); + va_end(args); +} + +static struct crypto_key_t g_zero_key = +{ + .method = CRYPTO_KEY, + .u.key = {0} +}; + +int main(int argc, char **argv) +{ + bool raw_mode = false; + const char *loopback = NULL; + + while(1) + { + static struct option long_options[] = + { + {"help", no_argument, 0, '?'}, + {"debug", no_argument, 0, 'd'}, + {"add-key", required_argument, 0, 'a'}, + {"no-color", no_argument, 0, 'n'}, + {"loopback", required_argument, 0, 'l'}, + {0, 0, 0, 0} + }; + + int c = getopt_long(argc, argv, "?do:k:zra:nl:", long_options, NULL); + if(c == -1) + break; + switch(c) + { + case -1: + break; + case 'l': + if(loopback) + bug("Only one loopback file can be specified !\n"); + loopback = optarg; + break; + case 'n': + enable_color(false); + break; + case 'd': + g_debug = true; + break; + case '?': + usage(); + break; + case 'o': + g_out_prefix = optarg; + break; + case 'k': + { + add_keys_from_file(optarg); + break; + } + case 'z': + { + add_keys(&g_zero_key, 1); + break; + } + case 'r': + raw_mode = true; + break; + case 'a': + { + struct crypto_key_t key; + char *s = optarg; + if(!parse_key(&s, &key)) + bug("Invalid key specified as argument"); + if(*s != 0) + bug("Trailing characters after key specified as argument"); + add_keys(&key, 1); + break; + } + default: + abort(); + } + } + + if(argc - optind != 1) + { + usage(); + return 1; + } + + const char *sb_filename = argv[optind]; + + enum sb_error_t err; + struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err); + if(file == NULL) + { + color(OFF); + printf("SB read failed: %d\n", err); + return 1; + } + + color(OFF); + if(g_out_prefix) + extract_sb_file(file); + if(g_debug) + { + color(GREY); + printf("[Debug output]\n"); + sb_dump(file, NULL, sb_printf); + } + if(loopback) + { + /* sb_read_file will fill real key and IV but we don't want to override + * them when looping back otherwise the output will be inconsistent and + * garbage */ + file->override_real_key = false; + file->override_crypto_iv = false; + sb_write_file(file, loopback); + } + sb_free(file); + clear_keys(); + + return 0; +} diff --git a/utils/imxtools/sha1.c b/utils/imxtools/sha1.c new file mode 100644 index 0000000000..0ad05bb5cd --- /dev/null +++ b/utils/imxtools/sha1.c @@ -0,0 +1,150 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +/* Based on http://en.wikipedia.org/wiki/SHA-1 */ +#include "crypto.h" + +static uint32_t rot_left(uint32_t val, int rot) +{ + return (val << rot) | (val >> (32 - rot)); +} + +static inline void byte_swapxx(byte *ptr, int size) +{ + for(int i = 0; i < size / 2; i++) + { + byte c = ptr[i]; + ptr[i] = ptr[size - i - 1]; + ptr[size - i - 1] = c; + } +} + +static void byte_swap32(uint32_t *v) +{ + byte_swapxx((byte *)v, 4); +} + +void sha_1_init(struct sha_1_params_t *params) +{ + params->hash[0] = 0x67452301; + params->hash[1] = 0xEFCDAB89; + params->hash[2] = 0x98BADCFE; + params->hash[3] = 0x10325476; + params->hash[4] = 0xC3D2E1F0; + params->buffer_nr_bits = 0; +} + +void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size) +{ + int buffer_nr_bytes = (params->buffer_nr_bits / 8) % 64; + params->buffer_nr_bits += 8 * size; + int pos = 0; + if(buffer_nr_bytes + size >= 64) + { + pos = 64 - buffer_nr_bytes; + memcpy((byte *)(params->w) + buffer_nr_bytes, buffer, 64 - buffer_nr_bytes); + sha_1_block(params, params->hash, (byte *)params->w); + for(; pos + 64 <= size; pos += 64) + sha_1_block(params, params->hash, buffer + pos); + buffer_nr_bytes = 0; + } + memcpy((byte *)(params->w) + buffer_nr_bytes, buffer + pos, size - pos); +} + +void sha_1_finish(struct sha_1_params_t *params) +{ + /* length (in bits) in big endian BEFORE preprocessing */ + byte length_big_endian[8]; + memcpy(length_big_endian, ¶ms->buffer_nr_bits, 8); + byte_swapxx(length_big_endian, 8); + /* append '1' and then '0's to the message to get 448 bit length for the last block */ + byte b = 0x80; + sha_1_update(params, &b, 1); + b = 0; + while((params->buffer_nr_bits % 512) != 448) + sha_1_update(params, &b, 1); + /* append length */ + sha_1_update(params, length_big_endian, 8); + /* go back to big endian */ + for(int i = 0; i < 5; i++) + byte_swap32(¶ms->hash[i]); +} + +void sha_1_output(struct sha_1_params_t *params, byte *out) +{ + memcpy(out, params->hash, 20); +} + +void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data) +{ + uint32_t a, b, c, d, e; + a = cur_hash[0]; + b = cur_hash[1]; + c = cur_hash[2]; + d = cur_hash[3]; + e = cur_hash[4]; + + #define w params->w + + memmove(w, data, 64); + for(int i = 0; i < 16; i++) + byte_swap32(&w[i]); + + for(int i = 16; i <= 79; i++) + w[i] = rot_left(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); + + for(int i = 0; i<= 79; i++) + { + uint32_t f, k; + if(i <= 19) + { + f = (b & c) | ((~b) & d); + k = 0x5A827999; + } + else if(i <= 39) + { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } + else if(i <= 59) + { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } + else + { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = rot_left(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = rot_left(b, 30); + b = a; + a = temp; + } + #undef w + + cur_hash[0] += a; + cur_hash[1] += b; + cur_hash[2] += c; + cur_hash[3] += d; + cur_hash[4] += e; +} diff --git a/utils/sbtools/Makefile b/utils/sbtools/Makefile deleted file mode 100644 index 69e63c9ac2..0000000000 --- a/utils/sbtools/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -DEFINES=-DCRYPTO_LIBUSB -CC=gcc -LD=gcc -CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES) -LDFLAGS=`pkg-config --libs libusb-1.0` - -all: elftosb sbtoelf - -%.o: %.c - $(CC) $(CFLAGS) -c -o $@ $< - -sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o - $(LD) -o $@ $^ $(LDFLAGS) - -elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o - $(LD) -o $@ $^ $(LDFLAGS) - -clean: - rm -fr *.o - -veryclean: - rm -rf sbtoelf elftosb diff --git a/utils/sbtools/README b/utils/sbtools/README deleted file mode 100644 index 8bf6fd5f8e..0000000000 --- a/utils/sbtools/README +++ /dev/null @@ -1,32 +0,0 @@ -This file document the format of the command file used by the elftosb tool. -By no way our tools tries to be compatible with Freescale's elftosb2. -However, our format is more subset of the general one. - -The parse supports a limited form of comments: comments starting with // and ending at the end of the line. - -A file first contains the list of sources: - -sources -{ - hw_init = "sdram_init.elf"; - rockbox = "rockbox.elf"; -} - -It can then contain an arbitrary number of section. A section is identified by a number. -Within a section, three commands are supported: "load", "jump" and "call": - -section(0x626f6f74) // hex for 'boot' -{ - load hw_init; - call hw_init; - load rockbox; - jump rockbox; -} - -Finally, both elftosb and sbtoelf tools use key files. A key file is a list of keys. -Each key consist is 128-bit long and is written in hexadecimal: - -00000000000000000000000000000000 - -The parser does not handle blank line and only allows a final newline at the end of the file. -A file is allowed to contain zero (0) keys. diff --git a/utils/sbtools/aes128.c b/utils/sbtools/aes128.c deleted file mode 100644 index 5870813db8..0000000000 --- a/utils/sbtools/aes128.c +++ /dev/null @@ -1,284 +0,0 @@ -// Simple, thoroughly commented implementation of 128-bit AES / Rijndael using C -// Chris Hulbert - chris.hulbert@gmail.com - http://splinter.com.au/blog -// References: -// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard -// http://en.wikipedia.org/wiki/Rijndael_key_schedule -// http://en.wikipeia.org/wiki/Rijndael_mix_columns -// http://en.wikipedia.org/wiki/Rijndael_S-box -// This code is public domain, or any OSI-approved license, your choice. No warranty. -#include "crypto.h" - -// Here are all the lookup tables for the row shifts, rcon, s-boxes, and galois field multiplications -byte shift_rows_table[] = {0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11}; -byte shift_rows_table_inv[] = {0,13,10,7,4,1,14,11,8,5,2,15,12,9,6,3}; -byte lookup_rcon[]={0x8d,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a}; -byte lookup_sbox[]={0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16}; -byte lookup_sbox_inv[]={0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d}; -byte lookup_g2 []={0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,0x1b,0x19,0x1f,0x1d,0x13,0x11,0x17,0x15,0x0b,0x09,0x0f,0x0d,0x03,0x01,0x07,0x05,0x3b,0x39,0x3f,0x3d,0x33,0x31,0x37,0x35,0x2b,0x29,0x2f,0x2d,0x23,0x21,0x27,0x25,0x5b,0x59,0x5f,0x5d,0x53,0x51,0x57,0x55,0x4b,0x49,0x4f,0x4d,0x43,0x41,0x47,0x45,0x7b,0x79,0x7f,0x7d,0x73,0x71,0x77,0x75,0x6b,0x69,0x6f,0x6d,0x63,0x61,0x67,0x65,0x9b,0x99,0x9f,0x9d,0x93,0x91,0x97,0x95,0x8b,0x89,0x8f,0x8d,0x83,0x81,0x87,0x85,0xbb,0xb9,0xbf,0xbd,0xb3,0xb1,0xb7,0xb5,0xab,0xa9,0xaf,0xad,0xa3,0xa1,0xa7,0xa5,0xdb,0xd9,0xdf,0xdd,0xd3,0xd1,0xd7,0xd5,0xcb,0xc9,0xcf,0xcd,0xc3,0xc1,0xc7,0xc5,0xfb,0xf9,0xff,0xfd,0xf3,0xf1,0xf7,0xf5,0xeb,0xe9,0xef,0xed,0xe3,0xe1,0xe7,0xe5}; -byte lookup_g3 []={0x00,0x03,0x06,0x05,0x0c,0x0f,0x0a,0x09,0x18,0x1b,0x1e,0x1d,0x14,0x17,0x12,0x11,0x30,0x33,0x36,0x35,0x3c,0x3f,0x3a,0x39,0x28,0x2b,0x2e,0x2d,0x24,0x27,0x22,0x21,0x60,0x63,0x66,0x65,0x6c,0x6f,0x6a,0x69,0x78,0x7b,0x7e,0x7d,0x74,0x77,0x72,0x71,0x50,0x53,0x56,0x55,0x5c,0x5f,0x5a,0x59,0x48,0x4b,0x4e,0x4d,0x44,0x47,0x42,0x41,0xc0,0xc3,0xc6,0xc5,0xcc,0xcf,0xca,0xc9,0xd8,0xdb,0xde,0xdd,0xd4,0xd7,0xd2,0xd1,0xf0,0xf3,0xf6,0xf5,0xfc,0xff,0xfa,0xf9,0xe8,0xeb,0xee,0xed,0xe4,0xe7,0xe2,0xe1,0xa0,0xa3,0xa6,0xa5,0xac,0xaf,0xaa,0xa9,0xb8,0xbb,0xbe,0xbd,0xb4,0xb7,0xb2,0xb1,0x90,0x93,0x96,0x95,0x9c,0x9f,0x9a,0x99,0x88,0x8b,0x8e,0x8d,0x84,0x87,0x82,0x81,0x9b,0x98,0x9d,0x9e,0x97,0x94,0x91,0x92,0x83,0x80,0x85,0x86,0x8f,0x8c,0x89,0x8a,0xab,0xa8,0xad,0xae,0xa7,0xa4,0xa1,0xa2,0xb3,0xb0,0xb5,0xb6,0xbf,0xbc,0xb9,0xba,0xfb,0xf8,0xfd,0xfe,0xf7,0xf4,0xf1,0xf2,0xe3,0xe0,0xe5,0xe6,0xef,0xec,0xe9,0xea,0xcb,0xc8,0xcd,0xce,0xc7,0xc4,0xc1,0xc2,0xd3,0xd0,0xd5,0xd6,0xdf,0xdc,0xd9,0xda,0x5b,0x58,0x5d,0x5e,0x57,0x54,0x51,0x52,0x43,0x40,0x45,0x46,0x4f,0x4c,0x49,0x4a,0x6b,0x68,0x6d,0x6e,0x67,0x64,0x61,0x62,0x73,0x70,0x75,0x76,0x7f,0x7c,0x79,0x7a,0x3b,0x38,0x3d,0x3e,0x37,0x34,0x31,0x32,0x23,0x20,0x25,0x26,0x2f,0x2c,0x29,0x2a,0x0b,0x08,0x0d,0x0e,0x07,0x04,0x01,0x02,0x13,0x10,0x15,0x16,0x1f,0x1c,0x19,0x1a}; -byte lookup_g9 []={0x00,0x09,0x12,0x1b,0x24,0x2d,0x36,0x3f,0x48,0x41,0x5a,0x53,0x6c,0x65,0x7e,0x77,0x90,0x99,0x82,0x8b,0xb4,0xbd,0xa6,0xaf,0xd8,0xd1,0xca,0xc3,0xfc,0xf5,0xee,0xe7,0x3b,0x32,0x29,0x20,0x1f,0x16,0x0d,0x04,0x73,0x7a,0x61,0x68,0x57,0x5e,0x45,0x4c,0xab,0xa2,0xb9,0xb0,0x8f,0x86,0x9d,0x94,0xe3,0xea,0xf1,0xf8,0xc7,0xce,0xd5,0xdc,0x76,0x7f,0x64,0x6d,0x52,0x5b,0x40,0x49,0x3e,0x37,0x2c,0x25,0x1a,0x13,0x08,0x01,0xe6,0xef,0xf4,0xfd,0xc2,0xcb,0xd0,0xd9,0xae,0xa7,0xbc,0xb5,0x8a,0x83,0x98,0x91,0x4d,0x44,0x5f,0x56,0x69,0x60,0x7b,0x72,0x05,0x0c,0x17,0x1e,0x21,0x28,0x33,0x3a,0xdd,0xd4,0xcf,0xc6,0xf9,0xf0,0xeb,0xe2,0x95,0x9c,0x87,0x8e,0xb1,0xb8,0xa3,0xaa,0xec,0xe5,0xfe,0xf7,0xc8,0xc1,0xda,0xd3,0xa4,0xad,0xb6,0xbf,0x80,0x89,0x92,0x9b,0x7c,0x75,0x6e,0x67,0x58,0x51,0x4a,0x43,0x34,0x3d,0x26,0x2f,0x10,0x19,0x02,0x0b,0xd7,0xde,0xc5,0xcc,0xf3,0xfa,0xe1,0xe8,0x9f,0x96,0x8d,0x84,0xbb,0xb2,0xa9,0xa0,0x47,0x4e,0x55,0x5c,0x63,0x6a,0x71,0x78,0x0f,0x06,0x1d,0x14,0x2b,0x22,0x39,0x30,0x9a,0x93,0x88,0x81,0xbe,0xb7,0xac,0xa5,0xd2,0xdb,0xc0,0xc9,0xf6,0xff,0xe4,0xed,0x0a,0x03,0x18,0x11,0x2e,0x27,0x3c,0x35,0x42,0x4b,0x50,0x59,0x66,0x6f,0x74,0x7d,0xa1,0xa8,0xb3,0xba,0x85,0x8c,0x97,0x9e,0xe9,0xe0,0xfb,0xf2,0xcd,0xc4,0xdf,0xd6,0x31,0x38,0x23,0x2a,0x15,0x1c,0x07,0x0e,0x79,0x70,0x6b,0x62,0x5d,0x54,0x4f,0x46}; -byte lookup_g11 []={0x00,0x0b,0x16,0x1d,0x2c,0x27,0x3a,0x31,0x58,0x53,0x4e,0x45,0x74,0x7f,0x62,0x69,0xb0,0xbb,0xa6,0xad,0x9c,0x97,0x8a,0x81,0xe8,0xe3,0xfe,0xf5,0xc4,0xcf,0xd2,0xd9,0x7b,0x70,0x6d,0x66,0x57,0x5c,0x41,0x4a,0x23,0x28,0x35,0x3e,0x0f,0x04,0x19,0x12,0xcb,0xc0,0xdd,0xd6,0xe7,0xec,0xf1,0xfa,0x93,0x98,0x85,0x8e,0xbf,0xb4,0xa9,0xa2,0xf6,0xfd,0xe0,0xeb,0xda,0xd1,0xcc,0xc7,0xae,0xa5,0xb8,0xb3,0x82,0x89,0x94,0x9f,0x46,0x4d,0x50,0x5b,0x6a,0x61,0x7c,0x77,0x1e,0x15,0x08,0x03,0x32,0x39,0x24,0x2f,0x8d,0x86,0x9b,0x90,0xa1,0xaa,0xb7,0xbc,0xd5,0xde,0xc3,0xc8,0xf9,0xf2,0xef,0xe4,0x3d,0x36,0x2b,0x20,0x11,0x1a,0x07,0x0c,0x65,0x6e,0x73,0x78,0x49,0x42,0x5f,0x54,0xf7,0xfc,0xe1,0xea,0xdb,0xd0,0xcd,0xc6,0xaf,0xa4,0xb9,0xb2,0x83,0x88,0x95,0x9e,0x47,0x4c,0x51,0x5a,0x6b,0x60,0x7d,0x76,0x1f,0x14,0x09,0x02,0x33,0x38,0x25,0x2e,0x8c,0x87,0x9a,0x91,0xa0,0xab,0xb6,0xbd,0xd4,0xdf,0xc2,0xc9,0xf8,0xf3,0xee,0xe5,0x3c,0x37,0x2a,0x21,0x10,0x1b,0x06,0x0d,0x64,0x6f,0x72,0x79,0x48,0x43,0x5e,0x55,0x01,0x0a,0x17,0x1c,0x2d,0x26,0x3b,0x30,0x59,0x52,0x4f,0x44,0x75,0x7e,0x63,0x68,0xb1,0xba,0xa7,0xac,0x9d,0x96,0x8b,0x80,0xe9,0xe2,0xff,0xf4,0xc5,0xce,0xd3,0xd8,0x7a,0x71,0x6c,0x67,0x56,0x5d,0x40,0x4b,0x22,0x29,0x34,0x3f,0x0e,0x05,0x18,0x13,0xca,0xc1,0xdc,0xd7,0xe6,0xed,0xf0,0xfb,0x92,0x99,0x84,0x8f,0xbe,0xb5,0xa8,0xa3}; -byte lookup_g13 []={0x00,0x0d,0x1a,0x17,0x34,0x39,0x2e,0x23,0x68,0x65,0x72,0x7f,0x5c,0x51,0x46,0x4b,0xd0,0xdd,0xca,0xc7,0xe4,0xe9,0xfe,0xf3,0xb8,0xb5,0xa2,0xaf,0x8c,0x81,0x96,0x9b,0xbb,0xb6,0xa1,0xac,0x8f,0x82,0x95,0x98,0xd3,0xde,0xc9,0xc4,0xe7,0xea,0xfd,0xf0,0x6b,0x66,0x71,0x7c,0x5f,0x52,0x45,0x48,0x03,0x0e,0x19,0x14,0x37,0x3a,0x2d,0x20,0x6d,0x60,0x77,0x7a,0x59,0x54,0x43,0x4e,0x05,0x08,0x1f,0x12,0x31,0x3c,0x2b,0x26,0xbd,0xb0,0xa7,0xaa,0x89,0x84,0x93,0x9e,0xd5,0xd8,0xcf,0xc2,0xe1,0xec,0xfb,0xf6,0xd6,0xdb,0xcc,0xc1,0xe2,0xef,0xf8,0xf5,0xbe,0xb3,0xa4,0xa9,0x8a,0x87,0x90,0x9d,0x06,0x0b,0x1c,0x11,0x32,0x3f,0x28,0x25,0x6e,0x63,0x74,0x79,0x5a,0x57,0x40,0x4d,0xda,0xd7,0xc0,0xcd,0xee,0xe3,0xf4,0xf9,0xb2,0xbf,0xa8,0xa5,0x86,0x8b,0x9c,0x91,0x0a,0x07,0x10,0x1d,0x3e,0x33,0x24,0x29,0x62,0x6f,0x78,0x75,0x56,0x5b,0x4c,0x41,0x61,0x6c,0x7b,0x76,0x55,0x58,0x4f,0x42,0x09,0x04,0x13,0x1e,0x3d,0x30,0x27,0x2a,0xb1,0xbc,0xab,0xa6,0x85,0x88,0x9f,0x92,0xd9,0xd4,0xc3,0xce,0xed,0xe0,0xf7,0xfa,0xb7,0xba,0xad,0xa0,0x83,0x8e,0x99,0x94,0xdf,0xd2,0xc5,0xc8,0xeb,0xe6,0xf1,0xfc,0x67,0x6a,0x7d,0x70,0x53,0x5e,0x49,0x44,0x0f,0x02,0x15,0x18,0x3b,0x36,0x21,0x2c,0x0c,0x01,0x16,0x1b,0x38,0x35,0x22,0x2f,0x64,0x69,0x7e,0x73,0x50,0x5d,0x4a,0x47,0xdc,0xd1,0xc6,0xcb,0xe8,0xe5,0xf2,0xff,0xb4,0xb9,0xae,0xa3,0x80,0x8d,0x9a,0x97}; -byte lookup_g14 []={0x00,0x0e,0x1c,0x12,0x38,0x36,0x24,0x2a,0x70,0x7e,0x6c,0x62,0x48,0x46,0x54,0x5a,0xe0,0xee,0xfc,0xf2,0xd8,0xd6,0xc4,0xca,0x90,0x9e,0x8c,0x82,0xa8,0xa6,0xb4,0xba,0xdb,0xd5,0xc7,0xc9,0xe3,0xed,0xff,0xf1,0xab,0xa5,0xb7,0xb9,0x93,0x9d,0x8f,0x81,0x3b,0x35,0x27,0x29,0x03,0x0d,0x1f,0x11,0x4b,0x45,0x57,0x59,0x73,0x7d,0x6f,0x61,0xad,0xa3,0xb1,0xbf,0x95,0x9b,0x89,0x87,0xdd,0xd3,0xc1,0xcf,0xe5,0xeb,0xf9,0xf7,0x4d,0x43,0x51,0x5f,0x75,0x7b,0x69,0x67,0x3d,0x33,0x21,0x2f,0x05,0x0b,0x19,0x17,0x76,0x78,0x6a,0x64,0x4e,0x40,0x52,0x5c,0x06,0x08,0x1a,0x14,0x3e,0x30,0x22,0x2c,0x96,0x98,0x8a,0x84,0xae,0xa0,0xb2,0xbc,0xe6,0xe8,0xfa,0xf4,0xde,0xd0,0xc2,0xcc,0x41,0x4f,0x5d,0x53,0x79,0x77,0x65,0x6b,0x31,0x3f,0x2d,0x23,0x09,0x07,0x15,0x1b,0xa1,0xaf,0xbd,0xb3,0x99,0x97,0x85,0x8b,0xd1,0xdf,0xcd,0xc3,0xe9,0xe7,0xf5,0xfb,0x9a,0x94,0x86,0x88,0xa2,0xac,0xbe,0xb0,0xea,0xe4,0xf6,0xf8,0xd2,0xdc,0xce,0xc0,0x7a,0x74,0x66,0x68,0x42,0x4c,0x5e,0x50,0x0a,0x04,0x16,0x18,0x32,0x3c,0x2e,0x20,0xec,0xe2,0xf0,0xfe,0xd4,0xda,0xc8,0xc6,0x9c,0x92,0x80,0x8e,0xa4,0xaa,0xb8,0xb6,0x0c,0x02,0x10,0x1e,0x34,0x3a,0x28,0x26,0x7c,0x72,0x60,0x6e,0x44,0x4a,0x58,0x56,0x37,0x39,0x2b,0x25,0x0f,0x01,0x13,0x1d,0x47,0x49,0x5b,0x55,0x7f,0x71,0x63,0x6d,0xd7,0xd9,0xcb,0xc5,0xef,0xe1,0xf3,0xfd,0xa7,0xa9,0xbb,0xb5,0x9f,0x91,0x83,0x8d}; - -// Xor's all elements in a n byte array a by b -void xor_(byte *a, byte *b, int n) { - int i; - for (i=0;i ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "crypto.h" - -/* Table extracted from firmware, don't know if this is regular CRC32 */ - -static uint32_t crc_table[256] = { - 0x0, 0x4C11DB7, 0x9823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, - 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, - 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, - 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, - 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, - 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, - 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0x0BE2B5B58, 0x0BAEA46EF, 0x0B7A96036, - 0x0B3687D81, 0x0AD2F2D84, 0x0A9EE3033, 0x0A4AD16EA, 0x0A06C0B5D, 0x0D4326D90, - 0x0D0F37027, 0x0DDB056FE, 0x0D9714B49, 0x0C7361B4C, 0x0C3F706FB, 0x0CEB42022, - 0x0CA753D95, 0x0F23A8028, 0x0F6FB9D9F, 0x0FBB8BB46, 0x0FF79A6F1, 0x0E13EF6F4, - 0x0E5FFEB43, 0x0E8BCCD9A, 0x0EC7DD02D, 0x34867077, 0x30476DC0, 0x3D044B19, - 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, 0x128E9DCF, - 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x18AEB13, 0x54BF6A4, 0x808D07D, - 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, - 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, - 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, 0x0ACA5C697, - 0x0A864DB20, 0x0A527FDF9, 0x0A1E6E04E, 0x0BFA1B04B, 0x0BB60ADFC, 0x0B6238B25, - 0x0B2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, - 0x9D684044, 0x902B669D, 0x94EA7B2A, 0x0E0B41DE7, 0x0E4750050, 0x0E9362689, - 0x0EDF73B3E, 0x0F3B06B3B, 0x0F771768C, 0x0FA325055, 0x0FEF34DE2, 0x0C6BCF05F, - 0x0C27DEDE8, 0x0CF3ECB31, 0x0CBFFD686, 0x0D5B88683, 0x0D1799B34, 0x0DC3ABDED, - 0x0D8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, - 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, 0x46863638, - 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, - 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, - 0x3B5A6B9B, 0x315D626, 0x7D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, - 0x14D0BD4D, 0x19939B94, 0x1D528623, 0x0F12F560E, 0x0F5EE4BB9, 0x0F8AD6D60, - 0x0FC6C70D7, 0x0E22B20D2, 0x0E6EA3D65, 0x0EBA91BBC, 0x0EF68060B, 0x0D727BBB6, - 0x0D3E6A601, 0x0DEA580D8, 0x0DA649D6F, 0x0C423CD6A, 0x0C0E2D0DD, 0x0CDA1F604, - 0x0C960EBB3, 0x0BD3E8D7E, 0x0B9FF90C9, 0x0B4BCB610, 0x0B07DABA7, 0x0AE3AFBA2, - 0x0AAFBE615, 0x0A7B8C0CC, 0x0A379DD7B, 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, - 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, 0x5D8A9099, - 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, - 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, - 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087, - 0x1CD86D30, 0x29F3D35, 0x65E2082, 0x0B1D065B, 0x0FDC1BEC, 0x3793A651, - 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, - 0x29D4F654, 0x0C5A92679, 0x0C1683BCE, 0x0CC2B1D17, 0x0C8EA00A0, 0x0D6AD50A5, - 0x0D26C4D12, 0x0DF2F6BCB, 0x0DBEE767C, 0x0E3A1CBC1, 0x0E760D676, 0x0EA23F0AF, - 0x0EEE2ED18, 0x0F0A5BD1D, 0x0F464A0AA, 0x0F9278673, 0x0FDE69BC4, 0x89B8FD09, - 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, - 0x97FFAD0C, 0x0AFB010B1, 0x0AB710D06, 0x0A6322BDF, 0x0A2F33668, 0x0BCB4666D, - 0x0B8757BDA, 0x0B5365D03, 0x0B1F740B4 -}; - -uint32_t crc(byte *data, int size) -{ - 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); - return c; -} diff --git a/utils/sbtools/crypto.c b/utils/sbtools/crypto.c deleted file mode 100644 index d4afc6c816..0000000000 --- a/utils/sbtools/crypto.c +++ /dev/null @@ -1,188 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "crypto.h" -#include -#include -#ifdef CRYPTO_LIBUSB -#include "libusb.h" -#endif -#include "misc.h" - -static enum crypto_method_t cur_method = CRYPTO_NONE; -static byte key[16]; -static uint16_t usb_vid, usb_pid; - -void crypto_setup(enum crypto_method_t method, void *param) -{ - cur_method = method; - switch(method) - { - case CRYPTO_KEY: - memcpy(key, param, sizeof(key)); - break; - case CRYPTO_USBOTP: - { - uint32_t value = *(uint32_t *)param; - usb_vid = value >> 16; - usb_pid = value & 0xffff; - break; - } - default: - break; - } -} - -int crypto_apply( - byte *in_data, /* Input data */ - byte *out_data, /* Output data (or NULL) */ - int nr_blocks, /* Number of blocks (one block=16 bytes) */ - byte iv[16], /* Key */ - byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ - int encrypt) -{ - if(cur_method == CRYPTO_KEY) - { - cbc_mac(in_data, out_data, nr_blocks, key, iv, out_cbc_mac, encrypt); - return CRYPTO_ERROR_SUCCESS; - } - #ifdef CRYPTO_LIBUSB - else if(cur_method == CRYPTO_USBOTP) - { - if(out_cbc_mac && !encrypt) - memcpy(*out_cbc_mac, in_data + 16 * (nr_blocks - 1), 16); - - libusb_device_handle *handle = NULL; - libusb_context *ctx; - /* init library */ - libusb_init(&ctx); - libusb_set_debug(NULL,3); - /* open device */ - handle = libusb_open_device_with_vid_pid(ctx, usb_vid, usb_pid); - if(handle == NULL) - { - printf("usbotp: cannot open device %04x:%04x\n", usb_vid, usb_pid); - return CRYPTO_ERROR_NODEVICE; - } - /* get device pointer */ - libusb_device *mydev = libusb_get_device(handle); - if(g_debug) - printf("usbotp: device found at %d:%d\n", libusb_get_bus_number(mydev), - libusb_get_device_address(mydev)); - int config_id; - /* explore configuration */ - libusb_get_configuration(handle, &config_id); - struct libusb_config_descriptor *config; - libusb_get_active_config_descriptor(mydev, &config); - - if(g_debug) - { - printf("usbotp: configuration: %d\n", config_id); - printf("usbotp: interfaces: %d\n", config->bNumInterfaces); - } - - const struct libusb_endpoint_descriptor *endp = NULL; - int intf, intf_alt; - for(intf = 0; intf < config->bNumInterfaces; intf++) - for(intf_alt = 0; intf_alt < config->interface[intf].num_altsetting; intf_alt++) - for(int ep = 0; ep < config->interface[intf].altsetting[intf_alt].bNumEndpoints; ep++) - { - endp = &config->interface[intf].altsetting[intf_alt].endpoint[ep]; - if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT && - (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN) - goto Lfound; - } - libusb_close(handle); - printf("usbotp: No suitable endpoint found\n"); - return CRYPTO_ERROR_BADENDP; - - if(g_debug) - { - printf("usbotp: use interface %d, alt %d\n", intf, intf_alt); - printf("usbotp: use endpoint %d\n", endp->bEndpointAddress); - } - Lfound: - if(libusb_claim_interface(handle, intf) != 0) - { - if(g_debug) - printf("usbotp: claim error\n"); - return CRYPTO_ERROR_CLAIMFAIL; - } - - int buffer_size = 16 + 16 * nr_blocks; - unsigned char *buffer = xmalloc(buffer_size); - memcpy(buffer, iv, 16); - memcpy(buffer + 16, in_data, 16 * nr_blocks); - int ret = libusb_control_transfer(handle, - LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE, - 0xaa, encrypt ? 0xeeee : 0xdddd, 0, buffer, buffer_size, 1000); - if(ret < 0) - { - if(g_debug) - printf("usbotp: control transfer failed: %d\n", ret); - libusb_release_interface(handle, intf); - libusb_close(handle); - return CRYPTO_ERROR_DEVREJECT; - } - - int recv_size; - ret = libusb_interrupt_transfer(handle, endp->bEndpointAddress, buffer, - buffer_size, &recv_size, 1000); - libusb_release_interface(handle, intf); - libusb_close(handle); - - if(ret < 0) - { - if(g_debug) - printf("usbotp: interrupt transfer failed: %d\n", ret); - return CRYPTO_ERROR_DEVSILENT; - } - if(recv_size != buffer_size) - { - if(g_debug) - printf("usbotp: device returned %d bytes, expected %d\n", recv_size, - buffer_size); - return CRYPTO_ERROR_DEVERR; - } - - if(out_data) - memcpy(out_data, buffer + 16, 16 * nr_blocks); - if(out_cbc_mac && encrypt) - memcpy(*out_cbc_mac, buffer + buffer_size - 16, 16); - - return CRYPTO_ERROR_SUCCESS; - } - #endif - else - return CRYPTO_ERROR_BADSETUP; -} - -int crypto_cbc( - byte *in_data, /* Input data */ - byte *out_data, /* Output data (or NULL) */ - int nr_blocks, /* Number of blocks (one block=16 bytes) */ - struct crypto_key_t *key, /* Key */ - byte iv[16], /* IV */ - byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ - int encrypt) -{ - crypto_setup(key->method, (void *)key->u.param); - return crypto_apply(in_data, out_data, nr_blocks, iv, out_cbc_mac, encrypt); -} diff --git a/utils/sbtools/crypto.h b/utils/sbtools/crypto.h deleted file mode 100644 index 51f44406db..0000000000 --- a/utils/sbtools/crypto.h +++ /dev/null @@ -1,114 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#ifndef __CRYPTO_H__ -#define __CRYPTO_H__ - -#include -#include -#include - -typedef uint8_t byte; - -/* aes128.c */ -void xor_(byte *a, byte *b, int n); -void EncryptAES(byte *msg, byte *key, byte *c); -void DecryptAES(byte *c, byte *key, byte *m); -void Pretty(byte* b,int len,const char* label); -void cbc_mac( - byte *in_data, /* Input data */ - byte *out_data, /* Output data (or NULL) */ - int nr_blocks, /* Number of blocks to encrypt/decrypt (one block=16 bytes) */ - byte key[16], /* Key */ - byte iv[16], /* Initialisation Vector */ - byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ - int encrypt /* 1 to encrypt, 0 to decrypt */ - ); - -/* crypto.c */ -enum crypto_method_t -{ - CRYPTO_NONE, /* disable */ - CRYPTO_KEY, /* key */ - CRYPTO_USBOTP, /* use usbotp device */ -}; - -/* parameter can be: - * - CRYPTO_KEY: array of 16-bytes (the key) - * - CRYPTO_USBOTP: 32-bit integer: vid << 16 | pid */ -void crypto_setup(enum crypto_method_t method, void *param); - -#define CRYPTO_ERROR_SUCCESS 0 -#define CRYPTO_ERROR_BADSETUP -1 /* bad crypto setup */ -#define CRYPTO_ERROR_NODEVICE -2 /* no device with vid:pid */ -#define CRYPTO_ERROR_BADENDP -3 /* device doesn't have the required endpoints */ -#define CRYPTO_ERROR_CLAIMFAIL -4 /* device interface claim error */ -#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */ -#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */ -#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */ -/* return 0 on success, <0 on error */ -int crypto_apply( - byte *in_data, /* Input data */ - byte *out_data, /* Output data (or NULL) */ - int nr_blocks, /* Number of blocks (one block=16 bytes) */ - byte iv[16], /* IV */ - byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ - int encrypt); - -/* all-in-one function */ -struct crypto_key_t -{ - enum crypto_method_t method; - union - { - byte key[16]; - uint32_t vid_pid; - byte param[0]; - }u; -}; - -int crypto_cbc( - byte *in_data, /* Input data */ - byte *out_data, /* Output data (or NULL) */ - int nr_blocks, /* Number of blocks (one block=16 bytes) */ - struct crypto_key_t *key, /* Key */ - byte iv[16], /* IV */ - byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */ - int encrypt); - -/* 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 -{ - uint32_t hash[5]; - uint64_t buffer_nr_bits; - uint32_t w[80]; -}; - -void sha_1_init(struct sha_1_params_t *params); -void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data); -void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size); -void sha_1_finish(struct sha_1_params_t *params); -void sha_1_output(struct sha_1_params_t *params, byte *out); - -#endif /* __CRYPTO_H__ */ diff --git a/utils/sbtools/dbparser.c b/utils/sbtools/dbparser.c deleted file mode 100644 index 3cd0652d49..0000000000 --- a/utils/sbtools/dbparser.c +++ /dev/null @@ -1,785 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2011 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#include -#include -#include -#include -#include "dbparser.h" -#include "misc.h" - -enum lexem_type_t -{ - LEX_IDENTIFIER, - LEX_LPAREN, - LEX_RPAREN, - LEX_NUMBER, - LEX_STRING, /* double-quoted string */ - LEX_EQUAL, - LEX_SEMICOLON, - LEX_LBRACE, - LEX_RBRACE, - LEX_RANGLE, - LEX_OR, - LEX_LSHIFT, - LEX_COLON, - LEX_LE, - LEX_EOF -}; - -struct lexem_t -{ - enum lexem_type_t type; - char *str; - uint32_t num; - int line; - const char *file; -}; - -struct context_t -{ - const char *file; - char *begin; - char *end; - char *ptr; - int line; -}; - -#define parse_error(ctx, ...) \ - do { fprintf(stderr, "%s:%d: ", ctx->file, ctx->line); \ - fprintf(stderr, __VA_ARGS__); exit(2); } while(0) - -static void advance(struct context_t *ctx, int nr_chars) -{ - while(nr_chars--) - { - if(*(ctx->ptr++) == '\n') - ctx->line++; - } -} - -static inline bool eof(struct context_t *ctx) -{ - return ctx->ptr == ctx->end; -} - -static inline bool next_valid(struct context_t *ctx, int nr) -{ - return ctx->ptr + nr < ctx->end; -} - -static inline char cur_char(struct context_t *ctx) -{ - return *ctx->ptr; -} - -static inline char next_char(struct context_t *ctx, int nr) -{ - return ctx->ptr[nr]; -} - -static inline void locate_lexem(struct lexem_t *lex, struct context_t *ctx) -{ - lex->file = ctx->file; - lex->line = ctx->line; -} - -static void __parse_string(struct context_t *ctx, void *user, void (*emit_fn)(void *user, char c)) -{ - while(!eof(ctx)) - { - if(cur_char(ctx) == '"') - break; - else if(cur_char(ctx) == '\\') - { - advance(ctx, 1); - if(eof(ctx)) - parse_error(ctx, "Unfinished string\n"); - if(cur_char(ctx) == '\\') emit_fn(user, '\\'); - else if(cur_char(ctx) == '\'') emit_fn(user, '\''); - else if(cur_char(ctx) == '\"') emit_fn(user, '\"'); - else parse_error(ctx, "Unknown escape sequence \\%c\n", cur_char(ctx)); - advance(ctx, 1); - } - else - { - emit_fn(user, cur_char(ctx)); - advance(ctx, 1); - } - } - if(eof(ctx) || cur_char(ctx) != '"') - parse_error(ctx, "Unfinished string\n"); - advance(ctx, 1); -} - -static void __parse_string_emit(void *user, char c) -{ - char **pstr = (char **)user; - *(*pstr)++ = c; -} - -static void __parse_string_count(void *user, char c) -{ - (void) c; - (*(int *)user)++; -} - -static void parse_string(struct context_t *ctx, struct lexem_t *lexem) -{ - locate_lexem(lexem, ctx); - /* skip " */ - advance(ctx, 1); - /* compute length */ - struct context_t cpy_ctx = *ctx; - int length = 0; - __parse_string(&cpy_ctx, (void *)&length, __parse_string_count); - /* parse again */ - lexem->type = LEX_STRING; - lexem->str = xmalloc(length + 1); - lexem->str[length] = 0; - char *pstr = lexem->str; - __parse_string(ctx, (void *)&pstr, __parse_string_emit); -} - -static void parse_ascii_number(struct context_t *ctx, struct lexem_t *lexem) -{ - locate_lexem(lexem, ctx); - /* skip ' */ - advance(ctx, 1); - /* we expect n<=4 character and then ' */ - int len = 0; - uint32_t value = 0; - while(!eof(ctx)) - { - if(cur_char(ctx) != '\'') - { - value = value << 8 | cur_char(ctx); - len++; - advance(ctx, 1); - } - else - break; - } - if(eof(ctx) || cur_char(ctx) != '\'') - parse_error(ctx, "Unterminated ascii number literal\n"); - if(len == 0 || len > 4) - parse_error(ctx, "Invalid ascii number literal length: only 1 to 4 characters allowed\n"); - /* skip ' */ - advance(ctx, 1); - lexem->type = LEX_NUMBER; - lexem->num = value; -} - -static void parse_number(struct context_t *ctx, struct lexem_t *lexem) -{ - locate_lexem(lexem, ctx); - /* check base */ - int base = 10; - if(cur_char(ctx) == '0' && next_valid(ctx, 1) && next_char(ctx, 1) == 'x') - { - advance(ctx, 2); - base = 16; - } - - lexem->type = LEX_NUMBER; - lexem->num = 0; - while(!eof(ctx) && isxdigit(cur_char(ctx))) - { - if(base == 10 && !isdigit(cur_char(ctx))) - break; - byte v; - if(convxdigit(cur_char(ctx), &v)) - break; - lexem->num = base * lexem->num + v; - advance(ctx, 1); - } -} - -static void parse_identifier(struct context_t *ctx, struct lexem_t *lexem) -{ - locate_lexem(lexem, ctx); - /* remember position */ - char *old = ctx->ptr; - while(!eof(ctx) && (isalnum(cur_char(ctx)) || cur_char(ctx) == '_')) - advance(ctx, 1); - lexem->type = LEX_IDENTIFIER; - int len = ctx->ptr - old; - lexem->str = xmalloc(len + 1); - lexem->str[len] = 0; - memcpy(lexem->str, old, len); -} - -static void next_lexem(struct context_t *ctx, struct lexem_t *lexem) -{ - #define ret_simple(t, adv) \ - do {locate_lexem(lexem, ctx); \ - lexem->type = t; \ - advance(ctx, adv); \ - return;} while(0) - while(!eof(ctx)) - { - char c = cur_char(ctx); - /* skip whitespace */ - if(c == ' ' || c == '\t' || c == '\n' || c == '\r') - { - advance(ctx, 1); - continue; - } - /* skip C++ style comments */ - if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '/') - { - while(!eof(ctx) && cur_char(ctx) != '\n') - advance(ctx, 1); - continue; - } - /* skip C-style comments */ - if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '*') - { - advance(ctx, 2); - while(true) - { - if(!next_valid(ctx, 1)) - parse_error(ctx, "Unterminated comment"); - if(cur_char(ctx) == '*' && next_char(ctx, 1) == '/') - { - advance(ctx, 2); - break; - } - advance(ctx, 1); - } - continue; - } - break; - } - if(eof(ctx)) ret_simple(LEX_EOF, 0); - char c = cur_char(ctx); - bool nv = next_valid(ctx, 1); - char nc = nv ? next_char(ctx, 1) : 0; - if(c == '(') ret_simple(LEX_LPAREN, 1); - if(c == ')') ret_simple(LEX_RPAREN, 1); - if(c == '{') ret_simple(LEX_LBRACE, 1); - if(c == '}') ret_simple(LEX_RBRACE, 1); - if(c == '>') ret_simple(LEX_RANGLE, 1); - if(c == '=') ret_simple(LEX_EQUAL, 1); - if(c == ';') ret_simple(LEX_SEMICOLON, 1); - if(c == ',') ret_simple(LEX_COLON, 1); - if(c == '|') ret_simple(LEX_OR, 1); - if(c == '<' && nv && nc == '<') ret_simple(LEX_LSHIFT, 2); - if(c == '<' && nv && nc == '=') ret_simple(LEX_LE, 2); - if(c == '"') return parse_string(ctx, lexem); - if(c == '\'') return parse_ascii_number(ctx, lexem); - if(isdigit(c)) return parse_number(ctx, lexem); - if(isalpha(c) || c == '_') return parse_identifier(ctx, lexem); - parse_error(ctx, "Unexpected character '%c'\n", c); - #undef ret_simple -} - -#if 0 -static void log_lexem(struct lexem_t *lexem) -{ - switch(lexem->type) - { - case LEX_EOF: printf(""); break; - case LEX_EQUAL: printf("="); break; - case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break; - case LEX_LPAREN: printf("("); break; - case LEX_RPAREN: printf(")"); break; - case LEX_LBRACE: printf("{"); break; - case LEX_RBRACE: printf("}"); break; - case LEX_SEMICOLON: printf(";"); break; - case LEX_NUMBER: printf("num(%d)", lexem->num); break; - case LEX_STRING: printf("str(%s)", lexem->str); break; - case LEX_OR: printf("|"); break; - case LEX_LSHIFT: printf("<<"); break; - default: printf(""); - } -} -#endif - -struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id) -{ - struct cmd_source_t *src = cmd_file->source_list; - while(src) - { - if(strcmp(src->identifier, id) == 0) - return src; - src = src->next; - } - return NULL; -} - -struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name) -{ - while(opt) - { - if(strcmp(opt->name, name) == 0) - return opt; - opt = opt->next; - } - return NULL; -} - -#define INVALID_SB_SUBVERSION 0xffff - -static uint16_t parse_sb_subversion(char *str) -{ - int len = strlen(str); - uint16_t n = 0; - if(len == 0 || len > 4) - return INVALID_SB_SUBVERSION; - for(int i = 0; i < len; i++) - { - if(!isdigit(str[i])) - return INVALID_SB_SUBVERSION; - n = n << 4 | (str[i] - '0'); - } - return n; -} - -bool db_parse_sb_version(struct sb_version_t *ver, char *str) -{ - int len = strlen(str); - int cnt = 0; - int pos[2]; - - for(int i = 0; i < len; i++) - { - if(str[i] != '.') - continue; - if(cnt == 2) - return false; - pos[cnt++] = i + 1; - str[i] = 0; - } - if(cnt != 2) - return false; - ver->major = parse_sb_subversion(str); - ver->minor = parse_sb_subversion(str + pos[0]); - ver->revision = parse_sb_subversion(str + pos[1]); - return ver->major != INVALID_SB_SUBVERSION && - ver->minor != INVALID_SB_SUBVERSION && - ver->revision != INVALID_SB_SUBVERSION; -} - -#undef parse_error -#define parse_error(lexem, ...) \ - do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \ - fprintf(stderr, __VA_ARGS__); exit(2); } while(0) - -struct lex_ctx_t -{ - struct context_t ctx; - struct lexem_t lexem; -}; - -static inline void next(struct lex_ctx_t *ctx) -{ - next_lexem(&ctx->ctx, &ctx->lexem); -} - -static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) -{ - uint32_t ret = 0; - if(ctx->lexem.type == LEX_NUMBER) - ret = ctx->lexem.num; - else if(ctx->lexem.type == LEX_IDENTIFIER) - { - struct cmd_option_t *c = db_find_option_by_id(const_list, ctx->lexem.str); - if(c == NULL) - parse_error(ctx->lexem, "Undefined reference to constant '%s'\n", ctx->lexem.str); - if(c->is_string) - parse_error(ctx->lexem, "Internal error: constant '%s' is not an integer\n", ctx->lexem.str); - ret = c->val; - } - else - parse_error(ctx->lexem, "Number or constant identifier expected\n"); - next(ctx); - return ret; -} - -static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) -{ - uint32_t v = parse_term_expr(ctx, const_list); - while(ctx->lexem.type == LEX_LSHIFT) - { - next(ctx); - v <<= parse_term_expr(ctx, const_list); - } - return v; -} - -static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) -{ - uint32_t v = parse_shift_expr(ctx, const_list); - while(ctx->lexem.type == LEX_OR) - { - next(ctx); - v |= parse_shift_expr(ctx, const_list); - } - return v; -} - -static uint32_t parse_intexpr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list) -{ - return parse_or_expr(ctx, const_list); -} - -#define NR_INITIAL_CONSTANTS 4 -static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"}; -static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0}; - -struct cmd_file_t *db_parse_file(const char *file) -{ - size_t size; - FILE *f = fopen(file, "r"); - if(f == NULL) - bugp("Cannot open file '%s'", file); - fseek(f, 0, SEEK_END); - size = ftell(f); - fseek(f, 0, SEEK_SET); - char *buf = xmalloc(size); - if(fread(buf, size, 1, f) != 1) - bugp("Cannot read file '%s'", file); - fclose(f); - - if(g_debug) - printf("Parsing db file '%s'\n", file); - struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t)); - memset(cmd_file, 0, sizeof(struct cmd_file_t)); - - /* add initial constants */ - for(int i = 0; i < NR_INITIAL_CONSTANTS; i++) - { - struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); - memset(opt, 0, sizeof(struct cmd_option_t)); - opt->name = init_const_name[i]; - opt->is_string = false; - opt->val = init_const_value[i]; - opt->next = cmd_file->constant_list; - cmd_file->constant_list = opt; - } - - struct lex_ctx_t lctx; - lctx.ctx.file = file; - lctx.ctx.line = 1; - lctx.ctx.begin = buf; - lctx.ctx.ptr = buf; - lctx.ctx.end = buf + size; - #define next() next(&lctx) - #define lexem lctx.lexem - /* init lexer */ - next(); - /* constants ? */ - if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants")) - { - next(); - if(lexem.type != LEX_LBRACE) - parse_error(lexem, "'{' expected after 'constants'\n"); - - while(true) - { - struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); - memset(opt, 0, sizeof(struct cmd_option_t)); - next(); - if(lexem.type == LEX_RBRACE) - break; - if(lexem.type != LEX_IDENTIFIER) - parse_error(lexem, "Identifier expected in constants\n"); - opt->name = lexem.str; - next(); - if(lexem.type != LEX_EQUAL) - parse_error(lexem, "'=' expected after identifier\n"); - next(); - opt->is_string = false; - opt->val = parse_intexpr(&lctx, cmd_file->constant_list); - opt->next = cmd_file->constant_list; - cmd_file->constant_list = opt; - if(lexem.type != LEX_SEMICOLON) - parse_error(lexem, "';' expected after string\n"); - } - next(); - } - /* options ? */ - if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options")) - { - next(); - if(lexem.type != LEX_LBRACE) - parse_error(lexem, "'{' expected after 'options'\n"); - - while(true) - { - struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); - memset(opt, 0, sizeof(struct cmd_option_t)); - next(); - if(lexem.type == LEX_RBRACE) - break; - if(lexem.type != LEX_IDENTIFIER) - parse_error(lexem, "Identifier expected in options\n"); - opt->name = lexem.str; - next(); - if(lexem.type != LEX_EQUAL) - parse_error(lexem, "'=' expected after identifier\n"); - next(); - if(lexem.type == LEX_STRING) - { - opt->is_string = true; - opt->str = lexem.str; - next(); - } - else - { - opt->is_string = false; - opt->val = parse_intexpr(&lctx, cmd_file->constant_list); - } - opt->next = cmd_file->opt_list; - cmd_file->opt_list = opt; - if(lexem.type != LEX_SEMICOLON) - parse_error(lexem, "';' expected after string\n"); - } - next(); - } - /* sources */ - if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources")) - parse_error(lexem, "'sources' expected\n"); - next(); - if(lexem.type != LEX_LBRACE) - parse_error(lexem, "'{' expected after 'sources'\n"); - - while(true) - { - next(); - if(lexem.type == LEX_RBRACE) - break; - struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t)); - memset(src, 0, sizeof(struct cmd_source_t)); - if(lexem.type != LEX_IDENTIFIER) - parse_error(lexem, "identifier expected in sources\n"); - src->identifier = lexem.str; - next(); - if(lexem.type != LEX_EQUAL) - parse_error(lexem, "'=' expected after identifier\n"); - next(); - if(lexem.type == LEX_STRING) - { - src->is_extern = false; - src->filename = lexem.str; - next(); - } - else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern")) - { - src->is_extern = true; - src->filename = ""; - next(); - if(lexem.type != LEX_LPAREN) - parse_error(lexem, "'(' expected after 'extern'\n"); - next(); - src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list); - if(lexem.type != LEX_RPAREN) - parse_error(lexem, "')' expected\n"); - next(); - } - else - parse_error(lexem, "String or 'extern' expected after '='\n"); - if(lexem.type != LEX_SEMICOLON) - parse_error(lexem, "';' expected\n"); - if(db_find_source_by_id(cmd_file, src->identifier) != NULL) - parse_error(lexem, "Duplicate source identifier\n"); - /* type filled later */ - src->type = CMD_SRC_UNK; - src->next = cmd_file->source_list; - cmd_file->source_list = src; - } - - /* sections */ - struct cmd_section_t *end_sec = NULL; - while(true) - { - struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t)); - struct cmd_inst_t *end_list = NULL; - memset(sec, 0, sizeof(struct cmd_section_t)); - next(); - if(lexem.type == LEX_EOF) - break; - if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0) - parse_error(lexem, "'section' expected\n"); - next(); - if(lexem.type != LEX_LPAREN) - parse_error(lexem, "'(' expected after 'section'\n"); - next(); - /* can be any number */ - sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list); - /* options ? */ - if(lexem.type == LEX_SEMICOLON) - { - do - { - next(); - struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t)); - memset(opt, 0, sizeof(struct cmd_option_t)); - if(lexem.type != LEX_IDENTIFIER) - parse_error(lexem, "Identifier expected for section option\n"); - opt->name = lexem.str; - next(); - if(lexem.type != LEX_EQUAL) - parse_error(lexem, "'=' expected after option identifier\n"); - next(); - if(lexem.type == LEX_STRING) - { - opt->is_string = true; - opt->str = lexem.str; - next(); - } - else - { - opt->is_string = false; - opt->val = parse_intexpr(&lctx, cmd_file->constant_list); - } - opt->next = sec->opt_list; - sec->opt_list = opt; - }while(lexem.type == LEX_COLON); - } - if(lexem.type != LEX_RPAREN) - parse_error(lexem, "')' expected after section identifier\n"); - next(); - if(lexem.type == LEX_LBRACE) - { - sec->is_data = false; - /* commands */ - while(true) - { - struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t)); - memset(inst, 0, sizeof(struct cmd_inst_t)); - next(); - if(lexem.type == LEX_RBRACE) - break; - if(lexem.type != LEX_IDENTIFIER) - parse_error(lexem, "Instruction expected in section\n"); - if(strcmp(lexem.str, "load") == 0) - inst->type = CMD_LOAD; - else if(strcmp(lexem.str, "call") == 0) - inst->type = CMD_CALL; - else if(strcmp(lexem.str, "jump") == 0) - inst->type = CMD_JUMP; - else if(strcmp(lexem.str, "mode") == 0) - inst->type = CMD_MODE; - else - parse_error(lexem, "Instruction expected in section\n"); - next(); - - if(inst->type == CMD_LOAD) - { - if(lexem.type != LEX_IDENTIFIER) - parse_error(lexem, "Identifier expected after instruction\n"); - inst->identifier = lexem.str; - if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) - parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); - next(); - if(lexem.type == LEX_RANGLE) - { - // load at - inst->type = CMD_LOAD_AT; - next(); - inst->addr = parse_intexpr(&lctx, cmd_file->constant_list); - } - if(lexem.type != LEX_SEMICOLON) - parse_error(lexem, "';' expected after command\n"); - } - else if(inst->type == CMD_CALL || inst->type == CMD_JUMP) - { - if(lexem.type == LEX_IDENTIFIER) - { - inst->identifier = lexem.str; - if(db_find_source_by_id(cmd_file, inst->identifier) == NULL) - parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier); - next(); - } - else - { - inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT; - inst->addr = parse_intexpr(&lctx, cmd_file->constant_list); - } - - if(lexem.type == LEX_LPAREN) - { - next(); - inst->argument = parse_intexpr(&lctx, cmd_file->constant_list); - if(lexem.type != LEX_RPAREN) - parse_error(lexem, "Expected closing brace\n"); - next(); - } - if(lexem.type != LEX_SEMICOLON) - parse_error(lexem, "';' expected after command\n"); - } - else if(inst->type == CMD_MODE) - { - inst->argument = parse_intexpr(&lctx, cmd_file->constant_list); - if(lexem.type != LEX_SEMICOLON) - parse_error(lexem, "Expected ';' after command\n"); - } - else - parse_error(lexem, "Internal error"); - if(end_list == NULL) - { - sec->inst_list = inst; - end_list = inst; - } - else - { - end_list->next = inst; - end_list = inst; - } - } - } - else if(lexem.type == LEX_LE) - { - sec->is_data = true; - next(); - if(lexem.type != LEX_IDENTIFIER) - parse_error(lexem, "Identifier expected after '<='\n"); - sec->source_id = lexem.str; - next(); - if(lexem.type != LEX_SEMICOLON) - parse_error(lexem, "';' expected after identifier\n"); - } - else - parse_error(lexem, "'{' or '<=' expected after section directive\n"); - - if(end_sec == NULL) - { - cmd_file->section_list = sec; - end_sec = sec; - } - else - { - end_sec->next = sec; - end_sec = sec; - } - } - #undef lexem - #undef next - - return cmd_file; -} - -void db_generate_default_sb_version(struct sb_version_t *ver) -{ - ver->major = ver->minor = ver->revision = 0x999; -} diff --git a/utils/sbtools/dbparser.h b/utils/sbtools/dbparser.h deleted file mode 100644 index cfb1a692fa..0000000000 --- a/utils/sbtools/dbparser.h +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2011 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#ifndef __DBPARSER__ -#define __DBPARSER__ - -/** - * Command file parsing - */ -#include "sb.h" -#include "elf.h" - -enum cmd_source_type_t -{ - CMD_SRC_UNK, - CMD_SRC_ELF, - CMD_SRC_BIN -}; - -struct bin_param_t -{ - uint32_t size; - void *data; -}; - -struct cmd_source_t -{ - char *identifier; - bool is_extern; - // - int extern_nr; - char *filename; - // - struct cmd_source_t *next; - /* for later use */ - enum cmd_source_type_t type; - bool loaded; - struct elf_params_t elf; - struct bin_param_t bin; -}; - -enum cmd_inst_type_t -{ - CMD_LOAD, /* load image */ - CMD_JUMP, /* jump at image */ - CMD_CALL, /* call image */ - CMD_LOAD_AT, /* load binary at */ - CMD_CALL_AT, /* call at address */ - CMD_JUMP_AT, /* jump at address */ - CMD_MODE, /* change boot mode */ -}; - -struct cmd_inst_t -{ - enum cmd_inst_type_t type; - char *identifier; - uint32_t argument; // for jump, call, mode - uint32_t addr; // for 'at' - struct cmd_inst_t *next; -}; - -struct cmd_option_t -{ - char *name; - bool is_string; - /* */ - uint32_t val; - char *str; - /* */ - struct cmd_option_t *next; -}; - -struct cmd_section_t -{ - uint32_t identifier; - bool is_data; - // - struct cmd_inst_t *inst_list; - char *source_id; - // - struct cmd_section_t *next; - struct cmd_option_t *opt_list; -}; - -struct cmd_file_t -{ - struct cmd_option_t *opt_list; - struct cmd_option_t *constant_list; /* constant all always integers */ - struct cmd_source_t *source_list; - struct cmd_section_t *section_list; -}; - -struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id); -struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name); -bool db_parse_sb_version(struct sb_version_t *ver, char *str); -void db_generate_default_sb_version(struct sb_version_t *ver); -struct cmd_file_t *db_parse_file(const char *file); - -#endif /* __DBPARSER__ */ diff --git a/utils/sbtools/elf.c b/utils/sbtools/elf.c deleted file mode 100644 index 91b5d74848..0000000000 --- a/utils/sbtools/elf.c +++ /dev/null @@ -1,572 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2011 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include "elf.h" -#include "misc.h" - -/** - * Definitions - * taken from elf.h linux header - * based on ELF specification - * based on ARM ELF specification - */ -typedef uint16_t Elf32_Half; - -typedef uint32_t Elf32_Word; -typedef int32_t Elf32_Sword; -typedef uint32_t Elf32_Addr; -typedef uint32_t Elf32_Off; -typedef uint16_t Elf32_Section; - -#define EI_NIDENT 16 - -typedef struct -{ - unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ - Elf32_Half e_type; /* Object file type */ - Elf32_Half e_machine; /* Architecture */ - Elf32_Word e_version; /* Object file version */ - Elf32_Addr e_entry; /* Entry point virtual address */ - Elf32_Off e_phoff; /* Program header table file offset */ - Elf32_Off e_shoff; /* Section header table file offset */ - Elf32_Word e_flags; /* Processor-specific flags */ - Elf32_Half e_ehsize; /* ELF header size in bytes */ - Elf32_Half e_phentsize; /* Program header table entry size */ - Elf32_Half e_phnum; /* Program header table entry count */ - Elf32_Half e_shentsize; /* Section header table entry size */ - Elf32_Half e_shnum; /* Section header table entry count */ - Elf32_Half e_shstrndx; /* Section header string table index */ -}Elf32_Ehdr; - -#define EI_MAG0 0 /* File identification byte 0 index */ -#define ELFMAG0 0x7f /* Magic number byte 0 */ - -#define EI_MAG1 1 /* File identification byte 1 index */ -#define ELFMAG1 'E' /* Magic number byte 1 */ - -#define EI_MAG2 2 /* File identification byte 2 index */ -#define ELFMAG2 'L' /* Magic number byte 2 */ - -#define EI_MAG3 3 /* File identification byte 3 index */ -#define ELFMAG3 'F' /* Magic number byte 3 */ - -#define EI_CLASS 4 /* File class byte index */ -#define ELFCLASS32 1 /* 32-bit objects */ - -#define EI_DATA 5 /* Data encoding byte index */ -#define ELFDATA2LSB 1 /* 2's complement, little endian */ - -#define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */ - -#define EI_OSABI 7 /* OS ABI identification */ -#define ELFOSABI_NONE 0 /* UNIX System V ABI */ -#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */ -#define ELFOSABI_ARM 97 /* ARM */ - -#define EI_ABIVERSION 8 /* ABI version */ - -#define EI_PAD 9 /* Byte index of padding bytes */ - -#define ET_EXEC 2 /* Executable file */ - -#define EM_ARM 40 /* ARM */ - -#define EV_CURRENT 1 /* Current version */ - -#define EF_ARM_HASENTRY 0x00000002 - -#define SHN_UNDEF 0 /* Undefined section */ - -typedef struct -{ - Elf32_Word sh_name; /* Section name (string tbl index) */ - Elf32_Word sh_type; /* Section type */ - Elf32_Word sh_flags; /* Section flags */ - Elf32_Addr sh_addr; /* Section virtual addr at execution */ - Elf32_Off sh_offset; /* Section file offset */ - Elf32_Word sh_size; /* Section size in bytes */ - Elf32_Word sh_link; /* Link to another section */ - Elf32_Word sh_info; /* Additional section information */ - Elf32_Word sh_addralign; /* Section alignment */ - Elf32_Word sh_entsize; /* Entry size if section holds table */ -}Elf32_Shdr; - -#define SHT_NULL 0 /* Section header table entry unused */ -#define SHT_PROGBITS 1 /* Program data */ -#define SHT_SYMTAB 2 /* Symbol table */ -#define SHT_STRTAB 3 /* String table */ -#define SHT_RELA 4 /* Relocation entries with addends */ -#define SHT_HASH 5 /* Symbol hash table */ -#define SHT_DYNAMIC 6 /* Dynamic linking information */ -#define SHT_NOTE 7 /* Notes */ -#define SHT_NOBITS 8 /* Program space with no data (bss) */ -#define SHT_REL 9 /* Relocation entries, no addends */ -#define SHT_SHLIB 10 /* Reserved */ -#define SHT_DYNSYM 11 /* Dynamic linker symbol table */ -#define SHT_INIT_ARRAY 14 /* Array of constructors */ -#define SHT_FINI_ARRAY 15 /* Array of destructors */ -#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */ -#define SHT_GROUP 17 /* Section group */ -#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ -#define SHT_NUM 19 /* Number of defined types. */ - -#define SHF_WRITE (1 << 0) /* Writable */ -#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */ -#define SHF_EXECINSTR (1 << 2) /* Executable */ -#define SHF_MERGE (1 << 4) /* Might be merged */ -#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */ - -typedef struct -{ - Elf32_Word p_type; /* Segment type */ - Elf32_Off p_offset; /* Segment file offset */ - Elf32_Addr p_vaddr; /* Segment virtual address */ - Elf32_Addr p_paddr; /* Segment physical address */ - Elf32_Word p_filesz; /* Segment size in file */ - Elf32_Word p_memsz; /* Segment size in memory */ - Elf32_Word p_flags; /* Segment flags */ - Elf32_Word p_align; /* Segment alignment */ -}Elf32_Phdr; - -#define PT_LOAD 1 /* Loadable program segment */ - -#define PF_X (1 << 0) /* Segment is executable */ -#define PF_W (1 << 1) /* Segment is writable */ -#define PF_R (1 << 2) /* Segment is readable */ - -void elf_init(struct elf_params_t *params) -{ - params->has_start_addr = false; - params->start_addr = 0; - params->first_section = NULL; - params->last_section = NULL; -} - -extern void *xmalloc(size_t s); - -static struct elf_section_t *elf_add_section(struct elf_params_t *params) -{ - struct elf_section_t *sec = xmalloc(sizeof(struct elf_section_t)); - if(params->first_section == NULL) - params->first_section = params->last_section = sec; - else - { - params->last_section->next = sec; - params->last_section = sec; - } - sec->next = NULL; - - return sec; -} - -static struct elf_segment_t *elf_add_segment(struct elf_params_t *params) -{ - struct elf_segment_t *seg = xmalloc(sizeof(struct elf_section_t)); - if(params->first_segment == NULL) - params->first_segment = params->last_segment = seg; - else - { - params->last_segment->next = seg; - params->last_segment = seg; - } - seg->next = NULL; - - return seg; -} - -void elf_add_load_section(struct elf_params_t *params, - uint32_t load_addr, uint32_t size, const void *section) -{ - struct elf_section_t *sec = elf_add_section(params); - - sec->type = EST_LOAD; - sec->addr = load_addr; - sec->size = size; - sec->section = xmalloc(size); - memcpy(sec->section, section, size); -} - -void elf_add_fill_section(struct elf_params_t *params, - uint32_t fill_addr, uint32_t size, uint32_t pattern) -{ - if(pattern != 0x00) - { - printf("oops, non-zero filling, ignore fill section\n"); - return; - } - - struct elf_section_t *sec = elf_add_section(params); - - sec->type = EST_FILL; - sec->addr = fill_addr; - sec->size = size; - sec->pattern = pattern; -} - -void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, - elf_printf_fn_t printf, void *user) -{ - (void) printf; - - Elf32_Ehdr ehdr; - uint32_t phnum = 0; - struct elf_section_t *sec = params->first_section; - uint32_t offset = 0; - Elf32_Phdr phdr; - Elf32_Shdr shdr; - memset(&ehdr, 0, EI_NIDENT); - - while(sec) - { - if(sec->type == EST_LOAD) - { - sec->offset = offset; - offset += sec->size; - } - else - { - sec->offset = 0; - } - - phnum++; - sec = sec->next; - } - - uint32_t strtbl_offset = offset; - - ehdr.e_ident[EI_MAG0] = ELFMAG0; - ehdr.e_ident[EI_MAG1] = ELFMAG1; - ehdr.e_ident[EI_MAG2] = ELFMAG2; - ehdr.e_ident[EI_MAG3] = ELFMAG3; - ehdr.e_ident[EI_CLASS] = ELFCLASS32; - ehdr.e_ident[EI_DATA] = ELFDATA2LSB; - ehdr.e_ident[EI_VERSION] = EV_CURRENT; - ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE; - ehdr.e_ident[EI_ABIVERSION] = 0; - ehdr.e_type = ET_EXEC; - ehdr.e_machine = EM_ARM; - ehdr.e_version = EV_CURRENT; - ehdr.e_entry = params->start_addr; - ehdr.e_flags = 0; - if(params->has_start_addr) - ehdr.e_flags |= EF_ARM_HASENTRY; - ehdr.e_ehsize = sizeof ehdr; - ehdr.e_phentsize = sizeof phdr; - ehdr.e_phnum = phnum; - ehdr.e_shentsize = sizeof shdr; - ehdr.e_shnum = phnum + 2; /* one for section 0 and one for string table */ - ehdr.e_shstrndx = ehdr.e_shnum - 1; - ehdr.e_phoff = ehdr.e_ehsize; - ehdr.e_shoff = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize; - - write(user, 0, &ehdr, sizeof ehdr); - - /* allocate enough size to hold any combinaison of .text/.bss in the string table: - * - one empty name ("\0") - * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0" - * - one name ".shstrtab\0" */ - char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 + - phnum * (strlen(".textXXXX") + 1)); - - strtbl_content[0] = '\0'; - strcpy(&strtbl_content[1], ".shstrtab"); - uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1; - - uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize + - ehdr.e_shnum * ehdr.e_shentsize; - - sec = params->first_section; - offset = ehdr.e_phoff; - while(sec) - { - sec->offset += data_offset; - - phdr.p_type = PT_LOAD; - if(sec->type == EST_LOAD) - phdr.p_offset = sec->offset; - else - phdr.p_offset = 0; - phdr.p_paddr = sec->addr; - phdr.p_vaddr = phdr.p_paddr; /* assume identity map ? */ - phdr.p_memsz = sec->size; - if(sec->type == EST_LOAD) - phdr.p_filesz = phdr.p_memsz; - else - phdr.p_filesz = 0; - phdr.p_flags = PF_X | PF_W | PF_R; - phdr.p_align = 0; - - write(user, offset, &phdr, sizeof phdr); - - offset += sizeof(Elf32_Phdr); - sec = sec->next; - } - - sec = params->first_section; - offset = ehdr.e_shoff; - - { - shdr.sh_name = 0; - shdr.sh_type = SHT_NULL; - shdr.sh_flags = 0; - shdr.sh_addr = 0; - shdr.sh_offset = 0; - shdr.sh_size = 0; - shdr.sh_link = SHN_UNDEF; - shdr.sh_info = 0; - shdr.sh_addralign = 0; - shdr.sh_entsize = 0; - - write(user, offset, &shdr, sizeof shdr); - - offset += sizeof(Elf32_Shdr); - } - - uint32_t text_idx = 0; - uint32_t bss_idx = 0; - while(sec) - { - shdr.sh_name = strtbl_index; - if(sec->type == EST_LOAD) - { - strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++); - shdr.sh_type = SHT_PROGBITS; - } - else - { - strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++); - shdr.sh_type = SHT_NOBITS; - } - shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR; - shdr.sh_addr = sec->addr; - shdr.sh_offset = sec->offset; - shdr.sh_size = sec->size; - shdr.sh_link = SHN_UNDEF; - shdr.sh_info = 0; - shdr.sh_addralign = 1; - shdr.sh_entsize = 0; - - write(user, offset, &shdr, sizeof shdr); - - offset += sizeof(Elf32_Shdr); - sec = sec->next; - } - - { - shdr.sh_name = 1; - shdr.sh_type = SHT_STRTAB; - shdr.sh_flags = 0; - shdr.sh_addr = 0; - shdr.sh_offset = strtbl_offset + data_offset; - shdr.sh_size = strtbl_index; - shdr.sh_link = SHN_UNDEF; - shdr.sh_info = 0; - shdr.sh_addralign = 1; - shdr.sh_entsize = 0; - - write(user, offset, &shdr, sizeof shdr); - - offset += sizeof(Elf32_Shdr); - } - - sec = params->first_section; - while(sec) - { - if(sec->type == EST_LOAD) - write(user, sec->offset, sec->section, sec->size); - sec = sec->next; - } - - write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index); - free(strtbl_content); -} - -bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, - elf_printf_fn_t printf, void *user) -{ - #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;}) - - /* read header */ - Elf32_Ehdr ehdr; - if(!read(user, 0, &ehdr, sizeof(ehdr))) - { - printf(user, true, "error reading elf header\n"); - return false; - } - /* basic checks */ - if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 || - ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3) - error_printf("invalid elf header\n"); - if(ehdr.e_ident[EI_CLASS] != ELFCLASS32) - error_printf("invalid elf class: must be a 32-bit object\n"); - if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB) - error_printf("invalid elf data encoding: must be 32-bit lsb\n"); - if(ehdr.e_ident[EI_VERSION] != EV_CURRENT) - error_printf("invalid elf version\n"); - if(ehdr.e_type != ET_EXEC) - error_printf("invalid elf file: must be an executable file\n"); - if(ehdr.e_machine != EM_ARM) - error_printf("invalid elf file: must target an arm machine\n"); - if(ehdr.e_ehsize != sizeof(ehdr)) - error_printf("invalid elf file: size header mismatch\n"); - if(ehdr.e_phnum > 0 && ehdr.e_phentsize != sizeof(Elf32_Phdr)) - error_printf("invalid elf file: program header size mismatch\n"); - if(ehdr.e_shnum > 0 && ehdr.e_shentsize != sizeof(Elf32_Shdr)) - error_printf("invalid elf file: section header size mismatch\n"); - elf_set_start_addr(params, ehdr.e_entry); - - char *strtab = NULL; - if(ehdr.e_shstrndx != SHN_UNDEF) - { - Elf32_Shdr shstrtab; - if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize, - &shstrtab, sizeof(shstrtab))) - { - strtab = xmalloc(shstrtab.sh_size); - if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size)) - { - free(strtab); - strtab = NULL; - } - } - } - /* run through sections */ - printf(user, false, "ELF file:\n"); - for(int i = 1; i < ehdr.e_shnum; i++) - { - uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize; - Elf32_Shdr shdr; - memset(&shdr, 0, sizeof(shdr)); - if(!read(user, off, &shdr, sizeof(shdr))) - error_printf("error reading elf section header"); - - if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC) - { - void *data = xmalloc(shdr.sh_size); - if(!read(user, shdr.sh_offset, data, shdr.sh_size)) - error_printf("error read self section data\n"); - elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data); - - if(strtab) - printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]); - } - else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC) - { - elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0); - if(strtab) - printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]); - } - else - { - if(strtab) - printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type); - } - - } - /* run through segments */ - for(int i = 1; i < ehdr.e_phnum; i++) - { - uint32_t off = ehdr.e_phoff + i * ehdr.e_phentsize; - Elf32_Phdr phdr; - memset(&phdr, 0, sizeof(phdr)); - if(!read(user, off, &phdr, sizeof(phdr))) - error_printf("error reading elf segment header"); - if(phdr.p_type != PT_LOAD) - continue; - struct elf_segment_t *seg = elf_add_segment(params); - seg->vaddr = phdr.p_vaddr; - seg->paddr = phdr.p_paddr; - seg->vsize = phdr.p_memsz; - seg->psize = phdr.p_filesz; - printf(user, false, "create segment [%#x,+%#x[ -> [%#x,+%#x[\n", - seg->vaddr, seg->vsize, seg->paddr, seg->psize); - } - - return true; -} - -uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr) -{ - struct elf_segment_t *seg = params->first_segment; - while(seg) - { - if(seg->vaddr <= addr && addr < seg->vaddr + seg->vsize) - return addr - seg->vaddr + seg->paddr; - seg = seg->next; - } - return addr; -} - -void elf_translate_addresses(struct elf_params_t *params) -{ - struct elf_section_t *sec = params->first_section; - while(sec) - { - sec->addr = elf_translate_virtual_address(params, sec->addr); - sec = sec->next; - } - params->start_addr = elf_translate_virtual_address(params, params->start_addr); -} - -bool elf_is_empty(struct elf_params_t *params) -{ - return params->first_section == NULL; -} - -void elf_set_start_addr(struct elf_params_t *params, uint32_t addr) -{ - params->has_start_addr = true; - params->start_addr = addr; -} - -bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr) -{ - if(params->has_start_addr && addr != NULL) - *addr = params->start_addr; - return params->has_start_addr; -} - -int elf_get_nr_sections(struct elf_params_t *params) -{ - int nr = 0; - struct elf_section_t *sec = params->first_section; - while(sec) - { - nr++; - sec = sec->next; - } - return nr; -} - -void elf_release(struct elf_params_t *params) -{ - struct elf_section_t *sec, *next_sec; - sec = params->first_section; - while(sec) - { - next_sec = sec->next; - if(sec->type == EST_LOAD) - free(sec->section); - free(sec); - sec = next_sec; - } - params->first_section = NULL; - params->last_section = NULL; -} diff --git a/utils/sbtools/elf.h b/utils/sbtools/elf.h deleted file mode 100644 index 2166833276..0000000000 --- a/utils/sbtools/elf.h +++ /dev/null @@ -1,94 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2011 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#ifndef __ELF_H__ -#define __ELF_H__ - -#include -#include -#include -#include -#include -#include - -/** - * API - */ -enum elf_section_type_t -{ - EST_LOAD, - EST_FILL -}; - -struct elf_section_t -{ - uint32_t addr; /* virtual address */ - uint32_t size; /* virtual size */ - enum elf_section_type_t type; - /* */ - void *section; /* data */ - uint32_t pattern; /* fill pattern */ - /* */ - struct elf_section_t *next; - /* Internal to elf_write_file */ - uint32_t offset; -}; - -struct elf_segment_t -{ - uint32_t vaddr; /* virtual address */ - uint32_t paddr; /* physical address */ - uint32_t vsize; /* virtual size */ - uint32_t psize; /* physical size */ - struct elf_segment_t *next; -}; - -struct elf_params_t -{ - bool has_start_addr; - uint32_t start_addr; - struct elf_section_t *first_section; - struct elf_section_t *last_section; - struct elf_segment_t *first_segment; - struct elf_segment_t *last_segment; -}; - -typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count); -/* write function manages it's own error state */ -typedef void (*elf_write_fn_t)(void *user, uint32_t addr, const void *buf, size_t count); -typedef void (*elf_printf_fn_t)(void *user, bool error, const char *fmt, ...); - -void elf_init(struct elf_params_t *params); -void elf_add_load_section(struct elf_params_t *params, - uint32_t load_addr, uint32_t size, const void *section); -void elf_add_fill_section(struct elf_params_t *params, - uint32_t fill_addr, uint32_t size, uint32_t pattern); -uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr); -void elf_translate_addresses(struct elf_params_t *params); -void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, elf_printf_fn_t printf, void *user); -bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, elf_printf_fn_t printf, - void *user); -bool elf_is_empty(struct elf_params_t *params); -void elf_set_start_addr(struct elf_params_t *params, uint32_t addr); -bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr); -int elf_get_nr_sections(struct elf_params_t *params); -void elf_release(struct elf_params_t *params); - -#endif /* __ELF_H__ */ diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c deleted file mode 100644 index b8d68b82e7..0000000000 --- a/utils/sbtools/elftosb.c +++ /dev/null @@ -1,449 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2011 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -#define _ISOC99_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "crypto.h" -#include "elf.h" -#include "sb.h" -#include "dbparser.h" -#include "misc.h" -#include "sb.h" - -char **g_extern; -int g_extern_count; - -#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) - -#define crypto_cbc(...) \ - do { int ret = crypto_cbc(__VA_ARGS__); \ - if(ret != CRYPTO_ERROR_SUCCESS) \ - bug("crypto_cbc error: %d\n", ret); \ - }while(0) - -/** - * command file to sb conversion - */ - -static bool elf_read(void *user, uint32_t addr, void *buf, size_t count) -{ - if(fseek((FILE *)user, addr, SEEK_SET) == -1) - return false; - return fread(buf, 1, count, (FILE *)user) == count; -} - -static void elf_printf(void *user, bool error, const char *fmt, ...) -{ - if(!g_debug && !error) - return; - (void) user; - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); -} - -static void resolve_extern(struct cmd_source_t *src) -{ - if(!src->is_extern) - return; - src->is_extern = false; - if(src->extern_nr < 0 || src->extern_nr >= g_extern_count) - bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr); - src->filename = g_extern[src->extern_nr]; -} - -static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id) -{ - struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); - if(src == NULL) - bug("undefined reference to source '%s'\n", id); - /* avoid reloading */ - if(src->type == CMD_SRC_ELF && src->loaded) - return; - if(src->type != CMD_SRC_UNK) - bug("source '%s' seen both as elf and binary file\n", id); - /* resolve potential extern file */ - resolve_extern(src); - /* load it */ - src->type = CMD_SRC_ELF; - FILE *fd = fopen(src->filename, "rb"); - if(fd == NULL) - bug("cannot open '%s' (id '%s')\n", src->filename, id); - if(g_debug) - printf("Loading ELF file '%s'...\n", src->filename); - elf_init(&src->elf); - src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, fd); - fclose(fd); - if(!src->loaded) - bug("error loading elf file '%s' (id '%s')\n", src->filename, id); - elf_translate_addresses(&src->elf); -} - -static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id) -{ - struct cmd_source_t *src = db_find_source_by_id(cmd_file, id); - if(src == NULL) - bug("undefined reference to source '%s'\n", id); - /* avoid reloading */ - if(src->type == CMD_SRC_BIN && src->loaded) - return; - if(src->type != CMD_SRC_UNK) - bug("source '%s' seen both as elf and binary file\n", id); - /* resolve potential extern file */ - resolve_extern(src); - /* load it */ - src->type = CMD_SRC_BIN; - FILE *fd = fopen(src->filename, "rb"); - if(fd == NULL) - bug("cannot open '%s' (id '%s')\n", src->filename, id); - if(g_debug) - printf("Loading BIN file '%s'...\n", src->filename); - fseek(fd, 0, SEEK_END); - src->bin.size = ftell(fd); - fseek(fd, 0, SEEK_SET); - src->bin.data = xmalloc(src->bin.size); - fread(src->bin.data, 1, src->bin.size, fd); - fclose(fd); - src->loaded = true; -} - -static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file) -{ - struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t)); - memset(sb, 0, sizeof(struct sb_file_t)); - - db_generate_default_sb_version(&sb->product_ver); - db_generate_default_sb_version(&sb->component_ver); - - if(g_debug) - printf("Applying command file...\n"); - /* count sections */ - struct cmd_section_t *csec = cmd_file->section_list; - while(csec) - { - sb->nr_sections++; - csec = csec->next; - } - - sb->sections = xmalloc(sb->nr_sections * sizeof(struct sb_section_t)); - memset(sb->sections, 0, sb->nr_sections * sizeof(struct sb_section_t)); - /* flatten sections */ - csec = cmd_file->section_list; - for(int i = 0; i < sb->nr_sections; i++, csec = csec->next) - { - struct sb_section_t *sec = &sb->sections[i]; - sec->identifier = csec->identifier; - - /* options */ - do - { - /* cleartext */ - struct cmd_option_t *opt = db_find_option_by_id(csec->opt_list, "cleartext"); - if(opt != NULL) - { - if(opt->is_string) - bug("Cleartext section attribute must be an integer\n"); - if(opt->val != 0 && opt->val != 1) - bug("Cleartext section attribute must be 0 or 1\n"); - sec->is_cleartext = opt->val; - } - /* alignment */ - opt = db_find_option_by_id(csec->opt_list, "alignment"); - if(opt != NULL) - { - if(opt->is_string) - bug("Cleartext section attribute must be an integer\n"); - // n is a power of 2 iff n & (n - 1) = 0 - // alignement cannot be lower than block size - if((opt->val & (opt->val - 1)) != 0) - bug("Cleartext section attribute must be a power of two\n"); - if(opt->val < BLOCK_SIZE) - sec->alignment = BLOCK_SIZE; - else - sec->alignment = opt->val; - } - else - sec->alignment = BLOCK_SIZE; - }while(0); - - if(csec->is_data) - { - sec->is_data = true; - sec->nr_insts = 1; - sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); - memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); - - load_bin_by_id(cmd_file, csec->source_id); - struct bin_param_t *bin = &db_find_source_by_id(cmd_file, csec->source_id)->bin; - - sec->insts[0].inst = SB_INST_DATA; - sec->insts[0].size = bin->size; - sec->insts[0].data = bin->data; - } - else - { - sec->is_data = false; - /* count instructions and loads things */ - struct cmd_inst_t *cinst = csec->inst_list; - while(cinst) - { - if(cinst->type == CMD_LOAD) - { - load_elf_by_id(cmd_file, cinst->identifier); - struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; - sec->nr_insts += elf_get_nr_sections(elf); - } - else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) - { - load_elf_by_id(cmd_file, cinst->identifier); - struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; - if(!elf_get_start_addr(elf, NULL)) - bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier); - sec->nr_insts++; - } - else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT) - { - sec->nr_insts++; - } - else if(cinst->type == CMD_LOAD_AT) - { - load_bin_by_id(cmd_file, cinst->identifier); - sec->nr_insts++; - } - else if(cinst->type == CMD_MODE) - { - sec->nr_insts++; - } - else - bug("die\n"); - - cinst = cinst->next; - } - - sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t)); - memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t)); - /* flatten */ - int idx = 0; - cinst = csec->inst_list; - while(cinst) - { - if(cinst->type == CMD_LOAD) - { - struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; - struct elf_section_t *esec = elf->first_section; - while(esec) - { - if(esec->type == EST_LOAD) - { - sec->insts[idx].inst = SB_INST_LOAD; - sec->insts[idx].addr = esec->addr; - sec->insts[idx].size = esec->size; - sec->insts[idx++].data = esec->section; - } - else if(esec->type == EST_FILL) - { - sec->insts[idx].inst = SB_INST_FILL; - sec->insts[idx].addr = esec->addr; - sec->insts[idx].size = esec->size; - sec->insts[idx++].pattern = esec->pattern; - } - esec = esec->next; - } - } - else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL) - { - struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf; - sec->insts[idx].argument = cinst->argument; - sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL; - sec->insts[idx++].addr = elf->start_addr; - } - else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT) - { - sec->insts[idx].argument = cinst->argument; - sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL; - sec->insts[idx++].addr = cinst->addr; - } - else if(cinst->type == CMD_LOAD_AT) - { - struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin; - sec->insts[idx].inst = SB_INST_LOAD; - sec->insts[idx].addr = cinst->addr; - sec->insts[idx].data = bin->data; - sec->insts[idx++].size = bin->size; - } - else if(cinst->type == CMD_MODE) - { - sec->insts[idx].inst = SB_INST_MODE; - sec->insts[idx++].addr = cinst->argument; - } - else - bug("die\n"); - - cinst = cinst->next; - } - } - } - - return sb; -} - -void usage(void) -{ - printf("Usage: elftosb [options | file]...\n"); - printf("Options:\n"); - printf(" -?/--help\tDisplay this message\n"); - printf(" -o \tSet output file\n"); - printf(" -c \tSet command file\n"); - printf(" -d/--debug\tEnable debug output\n"); - printf(" -k \tAdd key file\n"); - printf(" -z\t\tAdd zero key\n"); - printf(" --add-key \tAdd single key (hex or usbotp)\n"); - printf(" --real-key \tOverride real key\n"); - printf(" --crypto-iv \tOverride crypto IV\n"); - exit(1); -} - -static struct crypto_key_t g_zero_key = -{ - .method = CRYPTO_KEY, - .u.key = {0} -}; - -int main(int argc, char **argv) -{ - char *cmd_filename = NULL; - char *output_filename = NULL; - struct crypto_key_t real_key; - struct crypto_key_t crypto_iv; - real_key.method = CRYPTO_NONE; - crypto_iv.method = CRYPTO_NONE; - - while(1) - { - static struct option long_options[] = - { - {"help", no_argument, 0, '?'}, - {"debug", no_argument, 0, 'd'}, - {"add-key", required_argument, 0, 'a'}, - {"real-key", required_argument, 0, 'r'}, - {"crypto-iv", required_argument, 0, 'i'}, - {0, 0, 0, 0} - }; - - int c = getopt_long(argc, argv, "?do:c:k:za:", long_options, NULL); - if(c == -1) - break; - switch(c) - { - case 'd': - g_debug = true; - break; - case '?': - usage(); - break; - case 'o': - output_filename = optarg; - break; - case 'c': - cmd_filename = optarg; - break; - case 'k': - { - add_keys_from_file(optarg); - break; - } - case 'z': - { - add_keys(&g_zero_key, 1); - break; - } - case 'a': - case 'r': - case 'i': - { - struct crypto_key_t key; - char *s = optarg; - if(!parse_key(&s, &key)) - bug("Invalid key/iv specified as argument"); - if(*s != 0) - bug("Trailing characters after key/iv specified as argument"); - if(c == 'r') - memcpy(&real_key, &key, sizeof(key)); - else if(c == 'i') - memcpy(&crypto_iv, &key, sizeof(key)); - else - add_keys(&key, 1); - break; - } - default: - abort(); - } - } - - if(!cmd_filename) - bug("You must specify a command file\n"); - if(!output_filename) - bug("You must specify an output file\n"); - - g_extern = &argv[optind]; - g_extern_count = argc - optind; - - if(g_debug) - { - printf("key: %d\n", g_nr_keys); - for(int i = 0; i < g_nr_keys; i++) - { - printf(" "); - print_key(&g_key_array[i], true); - } - - for(int i = 0; i < g_extern_count; i++) - printf("extern(%d)=%s\n", i, g_extern[i]); - } - - struct cmd_file_t *cmd_file = db_parse_file(cmd_filename); - struct sb_file_t *sb_file = apply_cmd_file(cmd_file); - - if(real_key.method == CRYPTO_KEY) - sb_file->real_key = &real_key.u.key; - if(crypto_iv.method == CRYPTO_KEY) - sb_file->crypto_iv = &crypto_iv.u.key; - - /* fill with default parameters since there is no command file support for them */ - sb_file->drive_tag = 0; - sb_file->first_boot_sec_id = sb_file->sections[0].identifier; - sb_file->flags = 0; - sb_file->minor_version = 1; - - sb_write_file(sb_file, output_filename); - - return 0; -} diff --git a/utils/sbtools/fuze+_key_file.txt b/utils/sbtools/fuze+_key_file.txt deleted file mode 100644 index a965e715f7..0000000000 --- a/utils/sbtools/fuze+_key_file.txt +++ /dev/null @@ -1 +0,0 @@ -00000000000000000000000000000000 diff --git a/utils/sbtools/misc.c b/utils/sbtools/misc.c deleted file mode 100644 index 4eeda4ef33..0000000000 --- a/utils/sbtools/misc.c +++ /dev/null @@ -1,234 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include -#include -#include -#include -#include "misc.h" - -bool g_debug = false; - -/** - * Misc - */ -void generate_random_data(void *buf, size_t sz) -{ - FILE *rand_fd = fopen("/dev/urandom", "rb"); - if(rand_fd == NULL) - bugp("failed to open /dev/urandom"); - if(fread(buf, 1, sz, rand_fd) != sz) - bugp("failed to read /dev/urandom"); - fclose(rand_fd); -} - -void *xmalloc(size_t s) -{ - void * r = malloc(s); - if(!r) bugp("malloc"); - return r; -} - -int convxdigit(char digit, byte *val) -{ - if(digit >= '0' && digit <= '9') - { - *val = digit - '0'; - return 0; - } - else if(digit >= 'A' && digit <= 'F') - { - *val = digit - 'A' + 10; - return 0; - } - else if(digit >= 'a' && digit <= 'f') - { - *val = digit - 'a' + 10; - return 0; - } - else - return 1; -} - -/* helper function to augment an array, free old array */ -void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt) -{ - void *p = xmalloc(elem_sz * (cnt + aug_cnt)); - memcpy(p, arr, elem_sz * cnt); - memcpy(p + elem_sz * cnt, aug, elem_sz * aug_cnt); - free(arr); - return p; -} - -/** - * Key file parsing - */ -int g_nr_keys; -key_array_t g_key_array; - -bool parse_key(char **pstr, struct crypto_key_t *key) -{ - char *str = *pstr; - /* ignore spaces */ - while(isspace(*str)) - str++; - /* CRYPTO_KEY: 32 hex characters - * CRYPTO_USBOTP: usbotp(vid:pid) where vid and pid are hex numbers */ - if(isxdigit(str[0])) - { - if(strlen(str) < 32) - return false; - for(int j = 0; j < 16; j++) - { - byte a, b; - if(convxdigit(str[2 * j], &a) || convxdigit(str[2 * j + 1], &b)) - return false; - key->u.key[j] = (a << 4) | b; - } - /* skip key */ - *pstr = str + 32; - key->method = CRYPTO_KEY; - return true; - } - else - { - const char *prefix = "usbotp("; - if(strlen(str) < strlen(prefix)) - return false; - if(strncmp(str, prefix, strlen(prefix)) != 0) - return false; - str += strlen(prefix); - /* vid */ - long vid = strtol(str, &str, 16); - if(vid < 0 || vid > 0xffff) - return false; - if(*str++ != ':') - return false; - /* pid */ - long pid = strtol(str, &str, 16); - if(pid < 0 || pid > 0xffff) - return false; - if(*str++ != ')') - return false; - *pstr = str; - key->method = CRYPTO_USBOTP; - key->u.vid_pid = vid << 16 | pid; - return true; - } -} - -void add_keys(key_array_t ka, int kac) -{ - key_array_t new_ka = xmalloc((g_nr_keys + kac) * sizeof(struct crypto_key_t)); - memcpy(new_ka, g_key_array, g_nr_keys * sizeof(struct crypto_key_t)); - memcpy(new_ka + g_nr_keys, ka, kac * sizeof(struct crypto_key_t)); - free(g_key_array); - g_key_array = new_ka; - g_nr_keys += kac; -} - -void add_keys_from_file(const char *key_file) -{ - int size; - FILE *fd = fopen(key_file, "r"); - if(fd == NULL) - bug("opening key file failed"); - fseek(fd, 0, SEEK_END); - size = ftell(fd); - fseek(fd, 0, SEEK_SET); - char *buf = xmalloc(size + 1); - if(fread(buf, 1, size, fd) != (size_t)size) - bug("reading key file"); - buf[size] = 0; - fclose(fd); - - if(g_debug) - printf("Parsing key file '%s'...\n", key_file); - char *p = buf; - while(1) - { - struct crypto_key_t k; - /* parse key */ - if(!parse_key(&p, &k)) - bug("invalid key file"); - if(g_debug) - { - printf("Add key: "); - print_key(&k, true); - } - add_keys(&k, 1); - /* request at least one space character before next key, or end of file */ - if(*p != 0 && !isspace(*p)) - bug("invalid key file"); - /* skip whitespace */ - while(isspace(*p)) - p++; - if(*p == 0) - break; - } - free(buf); -} - -void print_hex(byte *data, int len, bool newline) -{ - for(int i = 0; i < len; i++) - printf("%02X ", data[i]); - if(newline) - printf("\n"); -} - -void print_key(struct crypto_key_t *key, bool newline) -{ - switch(key->method) - { - case CRYPTO_KEY: - print_hex(key->u.key, 16, false); - break; - case CRYPTO_USBOTP: - printf("USB-OTP(%04x:%04x)", key->u.vid_pid >> 16, key->u.vid_pid & 0xffff); - break; - case CRYPTO_NONE: - printf("none"); - break; - } - if(newline) - printf("\n"); -} - -char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' }; - -char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' }; -char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' }; -char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' }; -char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' }; -char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; - -static bool g_color_enable = true; - -void enable_color(bool enable) -{ - g_color_enable = enable; -} - -void color(color_t c) -{ - if(g_color_enable) - printf("%s", (char *)c); -} diff --git a/utils/sbtools/misc.h b/utils/sbtools/misc.h deleted file mode 100644 index 9f14497680..0000000000 --- a/utils/sbtools/misc.h +++ /dev/null @@ -1,57 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#ifndef __MISC_H__ -#define __MISC_H__ - -#include -#include "crypto.h" - -#define _STR(a) #a -#define STR(a) _STR(a) - -#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0) -#define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0) - -#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) - -extern bool g_debug; - -typedef struct crypto_key_t *key_array_t; -int g_nr_keys; -key_array_t g_key_array; - -void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt); -void generate_random_data(void *buf, size_t sz); -void *xmalloc(size_t s); -int convxdigit(char digit, byte *val); -void print_hex(byte *data, int len, bool newline); -void add_keys(key_array_t ka, int kac); -bool parse_key(char **str, struct crypto_key_t *key); -void add_keys_from_file(const char *key_file); -void print_key(struct crypto_key_t *key, bool newline); - -typedef char color_t[]; - -extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; -void color(color_t c); -void enable_color(bool enable); - -#endif /* __MISC_H__ */ diff --git a/utils/sbtools/sb.c b/utils/sbtools/sb.c deleted file mode 100644 index d620c00f42..0000000000 --- a/utils/sbtools/sb.c +++ /dev/null @@ -1,1100 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2011 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#include -#include -#include -#include -#include "misc.h" -#include "crypto.h" -#include "sb.h" - -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; - /* sb header */ - sb->image_size += sizeof(struct sb_header_t) / BLOCK_SIZE; - /* sections headers */ - sb->image_size += sb->nr_sections * sizeof(struct sb_section_header_t) / BLOCK_SIZE; - /* key dictionary */ - sb->image_size += g_nr_keys * sizeof(struct sb_key_dictionary_entry_t) / BLOCK_SIZE; - /* sections */ - for(int i = 0; i < sb->nr_sections; i++) - { - /* each section has a preliminary TAG command */ - sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE; - /* we might need to pad the section so compute next alignment */ - uint32_t alignment = BLOCK_SIZE; - if((i + 1) < sb->nr_sections) - alignment = sb->sections[i + 1].alignment; - alignment /= BLOCK_SIZE; /* alignment in block sizes */ - - struct sb_section_t *sec = &sb->sections[i]; - sec->sec_size = 0; - - if(g_debug) - { - printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot", - sec->identifier); - if(sec->is_cleartext) - printf(" (cleartext)"); - printf("\n"); - } - - sec->file_offset = sb->image_size; - for(int j = 0; j < sec->nr_insts; j++) - { - struct sb_inst_t *inst = &sec->insts[j]; - if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP) - { - if(g_debug) - printf(" %s | addr=0x%08x | arg=0x%08x\n", - inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument); - 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) - { - if(g_debug) - 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) - { - if(g_debug) - 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 + inst->padding_size) / BLOCK_SIZE; - sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE; - } - else if(inst->inst == SB_INST_MODE) - { - if(g_debug) - printf(" MODE | mod=0x%08x", inst->addr); - sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; - sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE; - } - else if(inst->inst == SB_INST_DATA) - { - if(g_debug) - printf(" DATA | size=0x%08x\n", inst->size); - sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; - sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE; - } - else - bug("die on inst %d\n", inst->inst); - } - /* we need to make sure next section starts on the right alignment. - * Since each section starts with a boot tag, we thus need to ensure - * that this sections ends at adress X such that X+BLOCK_SIZE is - * a multiple of the alignment. - * For data sections, we just add random data, otherwise we add nops */ - uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment); - if(missing_sz != alignment) - { - struct sb_inst_t *aug_insts; - int nr_aug_insts = 0; - - if(sb->sections[i].is_data) - { - nr_aug_insts = 1; - aug_insts = malloc(sizeof(struct sb_inst_t)); - memset(aug_insts, 0, sizeof(struct sb_inst_t)); - aug_insts[0].inst = SB_INST_DATA; - aug_insts[0].size = missing_sz * BLOCK_SIZE; - aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE); - generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE); - if(g_debug) - printf(" DATA | size=0x%08x\n", aug_insts[0].size); - } - else - { - nr_aug_insts = missing_sz; - aug_insts = malloc(sizeof(struct sb_inst_t) * nr_aug_insts); - memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts); - for(int j = 0; j < nr_aug_insts; j++) - { - aug_insts[j].inst = SB_INST_NOP; - if(g_debug) - printf(" NOOP\n"); - } - } - - sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t), - sb->sections[i].nr_insts, aug_insts, nr_aug_insts); - sb->sections[i].nr_insts += nr_aug_insts; - - /* augment image and section size */ - sb->image_size += missing_sz; - sec->sec_size += missing_sz; - } - } - /* final signature */ - 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; -} - -static uint16_t swap16(uint16_t t) -{ - return (t << 8) | (t >> 8); -} - -static void fix_version(struct sb_version_t *ver) -{ - ver->major = swap16(ver->major); - ver->minor = swap16(ver->minor); - ver->revision = swap16(ver->revision); -} - -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'; - sb_hdr->signature[3] = 'P'; - sb_hdr->major_ver = IMAGE_MAJOR_VERSION; - 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->first_boot_sec_id; - 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)); - /* Version 1.0 has 6 bytes of random padding, - * Version 1.1 requires the last 4 bytes to be 'sgtl' */ - if(sb->minor_version >= 1) - memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4); - - sb_hdr->timestamp = generate_timestamp(); - sb_hdr->product_ver = sb->product_ver; - fix_version(&sb_hdr->product_ver); - sb_hdr->component_ver = sb->component_ver; - fix_version(&sb_hdr->component_ver); - sb_hdr->drive_tag = sb->drive_tag; - - 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 = (sec->is_data ? 0 : SECTION_BOOTABLE) - | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); -} - -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 = (sec->is_data ? 0 : SECTION_BOOTABLE) - | (sec->is_cleartext ? SECTION_CLEARTEXT : 0); - tag->hdr.checksum = instruction_checksum(&tag->hdr); -} - -void produce_sb_instruction(struct sb_inst_t *inst, - struct sb_instruction_common_t *cmd) -{ - memset(cmd, 0, sizeof(struct sb_instruction_common_t)); - cmd->hdr.opcode = inst->inst; - switch(inst->inst) - { - case SB_INST_CALL: - case SB_INST_JUMP: - cmd->addr = inst->addr; - cmd->data = inst->argument; - break; - case SB_INST_FILL: - cmd->addr = inst->addr; - cmd->len = inst->size; - cmd->data = inst->pattern; - break; - case SB_INST_LOAD: - cmd->addr = inst->addr; - cmd->len = inst->size; - cmd->data = crc_continue(crc(inst->data, inst->size), - inst->padding, inst->padding_size); - break; - case SB_INST_MODE: - cmd->data = inst->addr; - break; - case SB_INST_NOP: - break; - default: - bug("die\n"); - } - cmd->hdr.checksum = instruction_checksum(&cmd->hdr); -} - -void sb_write_file(struct sb_file_t *sb, const char *filename) -{ - FILE *fd = fopen(filename, "wb"); - if(fd == NULL) - bugp("cannot open output file"); - - struct crypto_key_t real_key; - real_key.method = CRYPTO_KEY; - byte crypto_iv[16]; - byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys); - /* init CBC-MACs */ - for(int i = 0; i < g_nr_keys; i++) - memset(cbc_macs[i], 0, 16); - - fill_gaps(sb); - compute_sb_offsets(sb); - - generate_random_data(real_key.u.key, 16); - - /* 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)); - fwrite(&sb_hdr, 1, sizeof(sb_hdr), fd); - - memcpy(crypto_iv, &sb_hdr, 16); - - /* update CBC-MACs */ - for(int i = 0; i < g_nr_keys; i++) - crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i], - cbc_macs[i], &cbc_macs[i], 1); - - /* 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)); - fwrite(&sb_sec_hdr, 1, sizeof(sb_sec_hdr), fd); - /* update CBC-MACs */ - for(int j = 0; j < g_nr_keys; j++) - crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE, - &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1); - } - /* produce key dictionary */ - for(int i = 0; i < g_nr_keys; i++) - { - struct sb_key_dictionary_entry_t entry; - memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16); - crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i], - crypto_iv, NULL, 1); - - fwrite(&entry, 1, sizeof(entry), fd); - sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry)); - } - - /* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */ - /* Image crafting, don't use it unless you understand what you do */ - if(sb->real_key != NULL) - memcpy(real_key.u.key, *sb->real_key, 16); - if(sb->crypto_iv != NULL) - memcpy(crypto_iv, *sb->crypto_iv, 16); - /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */ - if(g_debug) - { - printf("Real key: "); - for(int j = 0; j < 16; j++) - printf("%02x", real_key.u.key[j]); - printf("\n"); - printf("IV : "); - for(int j = 0; j < 16; j++) - printf("%02x", crypto_iv[j]); - printf("\n"); - } - /* 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); - if(g_nr_keys > 0) - crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE, - &real_key, crypto_iv, NULL, 1); - sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd)); - fwrite(&tag_cmd, 1, sizeof(tag_cmd), fd); - /* produce other commands */ - byte cur_cbc_mac[16]; - memcpy(cur_cbc_mac, crypto_iv, 16); - for(int j = 0; j < sb->sections[i].nr_insts; j++) - { - struct sb_inst_t *inst = &sb->sections[i].insts[j]; - /* command */ - if(inst->inst != SB_INST_DATA) - { - struct sb_instruction_common_t cmd; - produce_sb_instruction(inst, &cmd); - if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) - crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE, - &real_key, cur_cbc_mac, &cur_cbc_mac, 1); - sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); - fwrite(&cmd, 1, sizeof(cmd), fd); - } - /* data */ - if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA) - { - uint32_t sz = inst->size + inst->padding_size; - byte *data = xmalloc(sz); - memcpy(data, inst->data, inst->size); - memcpy(data + inst->size, inst->padding, inst->padding_size); - if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) - crypto_cbc(data, data, sz / BLOCK_SIZE, - &real_key, cur_cbc_mac, &cur_cbc_mac, 1); - sha_1_update(&file_sha1, data, sz); - fwrite(data, 1, sz, fd); - free(data); - } - } - } - /* 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); - if(g_nr_keys > 0) - crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1); - fwrite(final_sig, 1, 32, fd); - - fclose(fd); -} - -static void *memdup(void *p, size_t len) -{ - void *cpy = xmalloc(len); - memcpy(cpy, p, len); - return cpy; -} - -static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf, - int size, const char *indent, void *u, sb_color_printf cprintf) -{ - #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) - - struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t)); - memset(sec, 0, sizeof(struct sb_section_t)); - sec->identifier = id; - sec->is_data = data_sec; - sec->sec_size = ROUND_UP(size, BLOCK_SIZE) / BLOCK_SIZE; - - if(data_sec) - { - sec->nr_insts = 1; - sec->insts = xmalloc(sizeof(struct sb_inst_t)); - memset(sec->insts, 0, sizeof(struct sb_inst_t)); - sec->insts->inst = SB_INST_DATA; - sec->insts->size = size; - sec->insts->data = memdup(buf, size); - return sec; - } - - /* Pretty print the content */ - int pos = 0; - while(pos < size) - { - struct sb_inst_t inst; - memset(&inst, 0, sizeof(inst)); - - struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos]; - inst.inst = hdr->opcode; - - printf(OFF, "%s", indent); - uint8_t checksum = instruction_checksum(hdr); - if(checksum != hdr->checksum) - printf(GREY, "[Bad checksum]"); - if(hdr->flags != 0) - { - printf(GREY, "["); - printf(BLUE, "f=%x", hdr->flags); - printf(GREY, "] "); - } - if(hdr->opcode == SB_INST_LOAD) - { - struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos]; - inst.size = load->len; - inst.addr = load->addr; - inst.data = memdup(load + 1, load->len); - - printf(RED, "LOAD"); - printf(OFF, " | "); - printf(BLUE, "addr=0x%08x", load->addr); - printf(OFF, " | "); - printf(GREEN, "len=0x%08x", load->len); - printf(OFF, " | "); - printf(YELLOW, "crc=0x%08x", load->crc); - /* data is padded to 16-byte boundary with random data and crc'ed with it */ - uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)], - ROUND_UP(load->len, 16)); - if(load->crc == computed_crc) - printf(RED, " Ok\n"); - else - printf(RED, " Failed (crc=0x%08x)\n", computed_crc); - - pos += load->len + sizeof(struct sb_instruction_load_t); - } - else if(hdr->opcode == SB_INST_FILL) - { - struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos]; - inst.pattern = fill->pattern; - inst.size = fill->len; - inst.addr = fill->addr; - - printf(RED, "FILL"); - printf(OFF, " | "); - printf(BLUE, "addr=0x%08x", fill->addr); - printf(OFF, " | "); - printf(GREEN, "len=0x%08x", fill->len); - printf(OFF, " | "); - printf(YELLOW, "pattern=0x%08x\n", fill->pattern); - - pos += sizeof(struct sb_instruction_fill_t); - } - else if(hdr->opcode == SB_INST_CALL || - hdr->opcode == SB_INST_JUMP) - { - int is_call = (hdr->opcode == SB_INST_CALL); - struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos]; - inst.addr = call->addr; - inst.argument = call->arg; - - if(is_call) - printf(RED, "CALL"); - else - printf(RED, "JUMP"); - printf(OFF, " | "); - printf(BLUE, "addr=0x%08x", call->addr); - printf(OFF, " | "); - printf(GREEN, "arg=0x%08x\n", call->arg); - - pos += sizeof(struct sb_instruction_call_t); - } - else if(hdr->opcode == SB_INST_MODE) - { - struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr; - inst.argument = mode->mode; - - printf(RED, "MODE"); - printf(OFF, " | "); - printf(BLUE, "mod=0x%08x\n", mode->mode); - - pos += sizeof(struct sb_instruction_mode_t); - } - else if(hdr->opcode == SB_INST_NOP) - { - printf(RED, "NOOP\n"); - pos += sizeof(struct sb_instruction_mode_t); - } - else - { - printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos); - break; - } - - sec->insts = augment_array(sec->insts, sizeof(struct sb_inst_t), sec->nr_insts++, &inst, 1); - pos = ROUND_UP(pos, BLOCK_SIZE); - } - - return sec; - #undef printf -} - -void sb_fill_section_name(char name[5], uint32_t identifier) -{ - name[0] = (identifier >> 24) & 0xff; - name[1] = (identifier >> 16) & 0xff; - name[2] = (identifier >> 8) & 0xff; - name[3] = identifier & 0xff; - for(int i = 0; i < 4; i++) - if(!isprint(name[i])) - name[i] = '_'; - name[4] = 0; -} - -static uint32_t guess_alignment(uint32_t off) -{ - /* find greatest power of two which divides the offset */ - if(off == 0) - return 1; - uint32_t a = 1; - while(off % (2 * a) == 0) - a *= 2; - return a; -} - -struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u, - sb_color_printf cprintf) -{ - #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) - #define fatal(...) do { cprintf(u, true, GREY, __VA_ARGS__); return NULL; } while(0) - #define print_hex(c, p, len, nl) \ - do { printf(c, ""); print_hex(p, len, nl); } while(0) - - FILE *f = fopen(filename, "rb"); - if(f == NULL) - fatal("Cannot open file for reading\n"); - fseek(f, 0, SEEK_END); - long filesize = ftell(f); - fseek(f, 0, SEEK_SET); - uint8_t *buf = xmalloc(filesize); - fread(buf, 1, filesize, f); - fclose(f); - - struct sha_1_params_t sha_1_params; - struct sb_file_t *sb_file = xmalloc(sizeof(struct sb_file_t)); - memset(sb_file, 0, sizeof(struct sb_file_t)); - struct sb_header_t *sb_header = (struct sb_header_t *)buf; - - sb_file->image_size = sb_header->image_size; - sb_file->minor_version = sb_header->minor_ver; - sb_file->flags = sb_header->flags; - sb_file->drive_tag = sb_header->drive_tag; - sb_file->first_boot_sec_id = sb_header->first_boot_sec_id; - - if(memcmp(sb_header->signature, "STMP", 4) != 0) - fatal("Bad signature\n"); - if(sb_header->image_size * BLOCK_SIZE > filesize) - fatal("File too small mismatch"); - if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t)) - fatal("Bad header size"); - if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t)) - fatal("Bad section header size"); - - if(filesize > sb_header->image_size * BLOCK_SIZE) - { - printf(GREY, "[Restrict file size from %lu to %d bytes]\n", filesize, - sb_header->image_size * BLOCK_SIZE); - filesize = sb_header->image_size * BLOCK_SIZE; - } - - printf(BLUE, "Basic info:\n"); - printf(GREEN, " SB version: "); - printf(YELLOW, "%d.%d\n", sb_header->major_ver, sb_header->minor_ver); - printf(GREEN, " Header SHA-1: "); - byte *hdr_sha1 = sb_header->sha1_header; - print_hex(YELLOW, hdr_sha1, 20, false); - /* Check SHA1 sum */ - byte computed_sha1[20]; - sha_1_init(&sha_1_params); - sha_1_update(&sha_1_params, &sb_header->signature[0], - sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header)); - sha_1_finish(&sha_1_params); - sha_1_output(&sha_1_params, computed_sha1); - if(memcmp(hdr_sha1, computed_sha1, 20) == 0) - printf(RED, " Ok\n"); - else - printf(RED, " Failed\n"); - printf(GREEN, " Flags: "); - printf(YELLOW, "%x\n", sb_header->flags); - printf(GREEN, " Total file size : "); - printf(YELLOW, "%ld\n", filesize); - - /* Sizes and offsets */ - printf(BLUE, "Sizes and offsets:\n"); - printf(GREEN, " # of encryption keys = "); - printf(YELLOW, "%d\n", sb_header->nr_keys); - printf(GREEN, " # of sections = "); - printf(YELLOW, "%d\n", sb_header->nr_sections); - - /* Versions */ - printf(BLUE, "Versions\n"); - - printf(GREEN, " Random 1: "); - print_hex(YELLOW, sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true); - printf(GREEN, " Random 2: "); - print_hex(YELLOW, sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true); - - uint64_t micros = sb_header->timestamp; - time_t seconds = (micros / (uint64_t)1000000L); - struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ - seconds += mktime(&tm_base); - struct tm *time = gmtime(&seconds); - printf(GREEN, " Creation date/time = "); - printf(YELLOW, "%s", asctime(time)); - - struct sb_version_t product_ver = sb_header->product_ver; - fix_version(&product_ver); - struct sb_version_t component_ver = sb_header->component_ver; - fix_version(&component_ver); - - memcpy(&sb_file->product_ver, &product_ver, sizeof(product_ver)); - memcpy(&sb_file->component_ver, &component_ver, sizeof(component_ver)); - - printf(GREEN, " Product version = "); - printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision); - printf(GREEN, " Component version = "); - printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision); - - printf(GREEN, " Drive tag = "); - printf(YELLOW, "%x\n", sb_header->drive_tag); - printf(GREEN, " First boot tag offset = "); - printf(YELLOW, "%x\n", sb_header->first_boot_tag_off); - printf(GREEN, " First boot section ID = "); - printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id); - - /* encryption cbc-mac */ - byte real_key[16]; - bool valid_key = false; /* false until a matching key was found */ - if(sb_header->nr_keys > 0) - { - if(sb_header->nr_keys > g_nr_keys) - { - fatal("SB file has %d keys but only %d were specified\n", - sb_header->nr_keys, g_nr_keys); - } - printf(BLUE, "Encryption data\n"); - for(int i = 0; i < sb_header->nr_keys; i++) - { - printf(RED, " Key %d: ", i); - printf(YELLOW, ""); - print_key(&g_key_array[i], true); - printf(GREEN, " CBC-MAC of headers: "); - - uint32_t ofs = sizeof(struct sb_header_t) - + sizeof(struct sb_section_header_t) * sb_header->nr_sections - + sizeof(struct sb_key_dictionary_entry_t) * i; - struct sb_key_dictionary_entry_t *dict_entry = - (struct sb_key_dictionary_entry_t *)&buf[ofs]; - /* cbc mac */ - print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false); - /* check it */ - byte computed_cbc_mac[16]; - byte zero[16]; - memset(zero, 0, 16); - crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections, - &g_key_array[i], zero, &computed_cbc_mac, 1); - - bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0; - if(ok) - { - valid_key = true; - printf(RED, " Ok\n"); - } - else - printf(RED, " Failed\n"); - - printf(GREEN, " Encrypted key : "); - print_hex(YELLOW, dict_entry->key, 16, true); - /* decrypt */ - byte decrypted_key[16]; - byte iv[16]; - memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ - crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0); - printf(GREEN, " Decrypted key : "); - print_hex(YELLOW, decrypted_key, 16, false); - /* cross-check or copy */ - if(valid_key && ok) - memcpy(real_key, decrypted_key, 16); - else if(valid_key) - { - if(memcmp(real_key, decrypted_key, 16) == 0) - printf(RED, " Cross-Check Ok"); - else - printf(RED, " Cross-Check Failed"); - } - printf(OFF, "\n"); - } - } - - if(getenv("SB_REAL_KEY") != 0) - { - struct crypto_key_t k; - char *env = getenv("SB_REAL_KEY"); - if(!parse_key(&env, &k) || *env) - bug("Invalid SB_REAL_KEY\n"); - memcpy(real_key, k.u.key, 16); - } - - printf(RED, " Summary:\n"); - printf(GREEN, " Real key: "); - print_hex(YELLOW, real_key, 16, true); - printf(GREEN, " IV : "); - print_hex(YELLOW, buf, 16, true); - - sb_file->real_key = xmalloc(16); - memcpy(*sb_file->real_key, real_key, 16); - sb_file->crypto_iv = xmalloc(16); - memcpy(*sb_file->crypto_iv, buf, 16); - - /* sections */ - if(!raw_mode) - { - sb_file->nr_sections = sb_header->nr_sections; - sb_file->sections = xmalloc(sb_file->nr_sections * sizeof(struct sb_section_t)); - memset(sb_file->sections, 0, sb_file->nr_sections * sizeof(struct sb_section_t)); - printf(BLUE, "Sections\n"); - for(int i = 0; i < sb_header->nr_sections; i++) - { - uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t); - struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&buf[ofs]; - - char name[5]; - sb_fill_section_name(name, sec_hdr->identifier); - 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) && sb_header->nr_keys > 0; - - printf(GREEN, " Section "); - printf(YELLOW, "'%s'\n", name); - printf(GREEN, " pos = "); - printf(YELLOW, "%8x - %8x\n", pos, pos+size); - printf(GREEN, " len = "); - printf(YELLOW, "%8x\n", size); - printf(GREEN, " flags = "); - printf(YELLOW, "%8x", sec_hdr->flags); - if(data_sec) - printf(RED, " Data Section"); - else - printf(RED, " Boot Section"); - if(encrypted) - printf(RED, " (Encrypted)"); - printf(OFF, "\n"); - - /* save it */ - byte *sec = xmalloc(size); - if(encrypted) - cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); - else - memcpy(sec, buf + pos, size); - - struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier, - sec, size, " ", u, cprintf); - if(s) - { - s->is_cleartext = !encrypted; - s->alignment = guess_alignment(pos); - memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t)); - free(s); - } - - free(sec); - } - } - else - { - /* advanced raw mode */ - printf(BLUE, "Commands\n"); - uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE; - byte iv[16]; - const char *indent = " "; - while(true) - { - /* restart with IV */ - memcpy(iv, buf, 16); - byte cmd[BLOCK_SIZE]; - if(sb_header->nr_keys > 0) - cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0); - else - memcpy(cmd, buf + offset, BLOCK_SIZE); - struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd; - printf(OFF, "%s", indent); - uint8_t checksum = instruction_checksum(hdr); - if(checksum != hdr->checksum) - printf(GREY, "[Bad checksum']"); - - if(hdr->opcode == SB_INST_NOP) - { - printf(RED, "NOOP\n"); - offset += BLOCK_SIZE; - } - else if(hdr->opcode == SB_INST_TAG) - { - struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr; - printf(RED, "BTAG"); - printf(OFF, " | "); - printf(BLUE, "sec=0x%08x", tag->identifier); - printf(OFF, " | "); - printf(GREEN, "cnt=0x%08x", tag->len); - printf(OFF, " | "); - printf(YELLOW, "flg=0x%08x", tag->flags); - if(tag->hdr.flags & SB_INST_LAST_TAG) - { - printf(OFF, " | "); - printf(RED, " Last section"); - } - printf(OFF, "\n"); - offset += sizeof(struct sb_instruction_tag_t); - - char name[5]; - sb_fill_section_name(name, tag->identifier); - int pos = offset; - int size = tag->len * BLOCK_SIZE; - int data_sec = !(tag->flags & SECTION_BOOTABLE); - int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; - - printf(GREEN, "%sSection ", indent); - printf(YELLOW, "'%s'\n", name); - printf(GREEN, "%s pos = ", indent); - printf(YELLOW, "%8x - %8x\n", pos, pos+size); - printf(GREEN, "%s len = ", indent); - printf(YELLOW, "%8x\n", size); - printf(GREEN, "%s flags = ", indent); - printf(YELLOW, "%8x", tag->flags); - if(data_sec) - printf(RED, " Data Section"); - else - printf(RED, " Boot Section"); - if(encrypted) - printf(RED, " (Encrypted)"); - printf(OFF, "\n"); - - /* save it */ - byte *sec = xmalloc(size); - if(encrypted) - cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); - else - memcpy(sec, buf + pos, size); - - struct sb_section_t *s = read_section(data_sec, tag->identifier, - sec, size, " ", u, cprintf); - if(s) - { - s->is_cleartext = !encrypted; - s->alignment = guess_alignment(pos); - sb_file->sections = augment_array(sb_file->sections, - sizeof(struct sb_section_t), sb_file->nr_sections++, - s, 1); - free(s); - } - free(sec); - - /* last one ? */ - if(tag->hdr.flags & SB_INST_LAST_TAG) - break; - offset += size; - } - else - { - printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset); - break; - } - } - } - - /* final signature */ - printf(BLUE, "Final signature:\n"); - byte decrypted_block[32]; - if(sb_header->nr_keys > 0) - { - printf(GREEN, " Encrypted SHA-1:\n"); - byte *encrypted_block = &buf[filesize - 32]; - printf(OFF, " "); - print_hex(YELLOW, encrypted_block, 16, true); - printf(OFF, " "); - print_hex(YELLOW, encrypted_block + 16, 16, true); - /* decrypt it */ - cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0); - } - else - memcpy(decrypted_block, &buf[filesize - 32], 32); - printf(GREEN, " File SHA-1:\n "); - print_hex(YELLOW, decrypted_block, 20, false); - /* check it */ - sha_1_init(&sha_1_params); - sha_1_update(&sha_1_params, buf, filesize - 32); - sha_1_finish(&sha_1_params); - sha_1_output(&sha_1_params, computed_sha1); - if(memcmp(decrypted_block, computed_sha1, 20) == 0) - printf(RED, " Ok\n"); - else - printf(RED, " Failed\n"); - free(buf); - - return sb_file; - #undef printf - #undef fatal - #undef print_hex -} - -void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf) -{ - #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) - #define print_hex(c, p, len, nl) \ - do { printf(c, ""); print_hex(p, len, nl); } while(0) - - #define TREE RED - #define HEADER GREEN - #define TEXT YELLOW - #define TEXT2 BLUE - #define SEP OFF - - printf(HEADER, "SB File\n"); - printf(TREE, "+-"); - printf(HEADER, "Version: "); - printf(TEXT, "1.%d\n", file->minor_version); - printf(TREE, "+-"); - printf(HEADER, "Flags: "); - printf(TEXT, "%x\n", file->flags); - printf(TREE, "+-"); - printf(HEADER, "Drive Tag: "); - printf(TEXT, "%x\n", file->drive_tag); - printf(TREE, "+-"); - printf(HEADER, "First Boot Section ID: "); - char name[5]; - sb_fill_section_name(name, file->first_boot_sec_id); - printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name); - - if(file->real_key) - { - printf(TREE, "+-"); - printf(HEADER, "Real key: "); - print_hex(TEXT, *file->real_key, 16, true); - } - if(file->crypto_iv) - { - printf(TREE, "+-"); - printf(HEADER, "IV : "); - print_hex(TEXT, *file->crypto_iv, 16, true); - } - printf(TREE, "+-"); - printf(HEADER, "Product Version: "); - printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor, - file->product_ver.revision); - printf(TREE, "+-"); - printf(HEADER, "Component Version: "); - printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor, - file->component_ver.revision); - - for(int i = 0; i < file->nr_sections; i++) - { - struct sb_section_t *sec = &file->sections[i]; - printf(TREE, "+-"); - printf(HEADER, "Section\n"); - printf(TREE,"| +-"); - printf(HEADER, "Identifier: "); - sb_fill_section_name(name, sec->identifier); - printf(TEXT, "%08x (%s)\n", sec->identifier, name); - printf(TREE, "| +-"); - printf(HEADER, "Type: "); - printf(TEXT, "%s (%s)\n", sec->is_data ? "Data Section" : "Boot Section", - sec->is_cleartext ? "Cleartext" : "Encrypted"); - printf(TREE, "| +-"); - printf(HEADER, "Alignment: "); - printf(TEXT, "%d (bytes)\n", sec->alignment); - printf(TREE, "| +-"); - printf(HEADER, "Instructions\n"); - for(int j = 0; j < sec->nr_insts; j++) - { - struct sb_inst_t *inst = &sec->insts[j]; - printf(TREE, "| | +-"); - switch(inst->inst) - { - case SB_INST_DATA: - printf(HEADER, "DATA"); - printf(SEP, " | "); - printf(TEXT, "size=0x%08x\n", inst->size); - break; - case SB_INST_CALL: - case SB_INST_JUMP: - printf(HEADER, "%s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP"); - printf(SEP, " | "); - printf(TEXT, "addr=0x%08x", inst->addr); - printf(SEP, " | "); - printf(TEXT2, "arg=0x%08x\n", inst->argument); - break; - case SB_INST_LOAD: - printf(HEADER, "LOAD"); - printf(SEP, " | "); - printf(TEXT, "addr=0x%08x", inst->addr); - printf(SEP, " | "); - printf(TEXT2, "len=0x%08x\n", inst->size); - break; - case SB_INST_FILL: - printf(HEADER, "FILL"); - printf(SEP, " | "); - printf(TEXT, "addr=0x%08x", inst->addr); - printf(SEP, " | "); - printf(TEXT2, "len=0x%08x", inst->size); - printf(SEP, " | "); - printf(TEXT2, "pattern=0x%08x\n", inst->pattern); - break; - case SB_INST_MODE: - printf(HEADER, "MODE"); - printf(SEP, " | "); - printf(TEXT, "mod=0x%08x\n", inst->addr); - break; - case SB_INST_NOP: - printf(HEADER, "NOOP\n"); - break; - default: - printf(GREY, "[Unknown instruction %x]\n", inst->inst); - } - } - } - - #undef printf - #undef print_hex -} diff --git a/utils/sbtools/sb.h b/utils/sbtools/sb.h deleted file mode 100644 index 39bb8ce59b..0000000000 --- a/utils/sbtools/sb.h +++ /dev/null @@ -1,219 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2011 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -#ifndef __SB_H__ -#define __SB_H__ - -#include -#include - -#include "misc.h" - -#define BLOCK_SIZE 16 - -/* All fields are in big-endian BCD */ -struct sb_version_t -{ - uint16_t major; - uint16_t pad0; - uint16_t minor; - uint16_t pad1; - uint16_t revision; - uint16_t pad2; -}; - -struct sb_header_t -{ - uint8_t sha1_header[20]; /* SHA-1 of the rest of the header */ - uint8_t signature[4]; /* Signature "STMP" */ - uint8_t major_ver; /* Should be 1 */ - uint8_t minor_ver; /* Should be 1 */ - uint16_t flags; - uint32_t image_size; /* In blocks (=16bytes) */ - uint32_t first_boot_tag_off; /* Offset in blocks */ - uint32_t first_boot_sec_id; /* First bootable section ID */ - uint16_t nr_keys; /* Number of encryption keys */ - uint16_t key_dict_off; /* Offset to key dictionary (in blocks) */ - uint16_t header_size; /* In blocks */ - uint16_t nr_sections; /* Number of sections */ - uint16_t sec_hdr_size; /* Section header size (in blocks) */ - uint8_t rand_pad0[6]; /* Random padding */ - uint64_t timestamp; /* In microseconds since 2000/1/1 00:00:00 */ - struct sb_version_t product_ver; - struct sb_version_t component_ver; - uint16_t drive_tag; /* first tag to boot ? */ - uint8_t rand_pad1[6]; /* Random padding */ -} __attribute__((packed)); - -struct sb_section_header_t -{ - uint32_t identifier; - uint32_t offset; /* In blocks */ - uint32_t size; /* In blocks */ - uint32_t flags; -} __attribute__((packed)); - -struct sb_key_dictionary_entry_t -{ - uint8_t hdr_cbc_mac[16]; /* CBC-MAC of the header */ - uint8_t key[16]; /* Actual AES Key (encrypted by the global key) */ -} __attribute__((packed)); - -#define IMAGE_MAJOR_VERSION 1 -#define IMAGE_MINOR_VERSION 1 - -#define SECTION_BOOTABLE (1 << 0) -#define SECTION_CLEARTEXT (1 << 1) - -#define SB_INST_NOP 0x0 -#define SB_INST_TAG 0x1 -#define SB_INST_LOAD 0x2 -#define SB_INST_FILL 0x3 -#define SB_INST_JUMP 0x4 -#define SB_INST_CALL 0x5 -#define SB_INST_MODE 0x6 - -/* flags */ -#define SB_INST_LAST_TAG 1 /* for TAG */ -#define SB_INST_LOAD_DCD 1 /* for LOAD */ -#define SB_INST_FILL_BYTE 0 /* for FILL */ -#define SB_INST_FILL_HWORD 1 /* for FILL */ -#define SB_INST_FILL_WORD 2 /* for FILL */ -#define SB_INST_HAB_EXEC 1 /* for JUMP/CALL */ - -struct sb_instruction_header_t -{ - uint8_t checksum; - uint8_t opcode; - 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; - uint32_t addr; - uint32_t len; - uint32_t crc; -} __attribute__((packed)); - -struct sb_instruction_fill_t -{ - struct sb_instruction_header_t hdr; - uint32_t addr; - uint32_t len; - uint32_t pattern; -} __attribute__((packed)); - -struct sb_instruction_mode_t -{ - struct sb_instruction_header_t hdr; - uint32_t zero1; - uint32_t zero2; - uint32_t mode; -} __attribute__((packed)); - -struct sb_instruction_call_t -{ - struct sb_instruction_header_t hdr; - uint32_t addr; - uint32_t zero; - uint32_t arg; -} __attribute__((packed)); - -struct sb_instruction_tag_t -{ - struct sb_instruction_header_t hdr; - uint32_t identifier; /* section identifier */ - uint32_t len; /* length of the section */ - uint32_t flags; /* section flags */ -} __attribute__((packed)); - -/******* - * API * - *******/ - -#define SB_INST_DATA 0xff - -struct sb_inst_t -{ - uint8_t inst; /* SB_INST_* */ - uint32_t size; - uint32_t addr; - // - void *data; - uint32_t pattern; - // - uint32_t argument; // for call, jump and mode - /* for production use */ - uint32_t padding_size; - uint8_t *padding; -}; - -struct sb_section_t -{ - uint32_t identifier; - bool is_data; - bool is_cleartext; - uint32_t alignment; - // data sections are handled as one or more SB_INST_DATA virtual instruction - int nr_insts; - struct sb_inst_t *insts; - /* for production use */ - uint32_t file_offset; /* in blocks */ - uint32_t sec_size; /* in blocks */ -}; - -struct sb_file_t -{ - /* override real, otherwise it is randomly generated */ - uint8_t (*real_key)[16]; - /* override crypto IV, use with caution ! Use NULL to generate it */ - uint8_t (*crypto_iv)[16]; - - int nr_sections; - uint16_t drive_tag; - uint32_t first_boot_sec_id; - uint16_t flags; - uint8_t minor_version; - struct sb_section_t *sections; - struct sb_version_t product_ver; - struct sb_version_t component_ver; - /* for production use */ - uint32_t image_size; /* in blocks */ -}; - -void sb_write_file(struct sb_file_t *sb, const char *filename); - -typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...); -struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u, - sb_color_printf printf); - -void sb_fill_section_name(char name[5], uint32_t identifier); -void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf); - -#endif /* __SB_H__ */ diff --git a/utils/sbtools/sbtoelf.c b/utils/sbtools/sbtoelf.c deleted file mode 100644 index 179f91262f..0000000000 --- a/utils/sbtools/sbtoelf.c +++ /dev/null @@ -1,294 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Bertrik Sikken - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ - -/* - * .sb file parser and chunk extractor - * - * Based on amsinfo, which is - * Copyright © 2008 Rafaël Carré - */ - -#define _ISOC99_SOURCE /* snprintf() */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "crypto.h" -#include "elf.h" -#include "sb.h" -#include "misc.h" - -/* all blocks are sized as a multiple of 0x1ff */ -#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) - -/* If you find a firmware that breaks the known format ^^ */ -#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) - -#define crypto_cbc(...) \ - do { int ret = crypto_cbc(__VA_ARGS__); \ - if(ret != CRYPTO_ERROR_SUCCESS) \ - bug("crypto_cbc error: %d\n", ret); \ - }while(0) - -/* globals */ - -char *g_out_prefix; - -static void elf_printf(void *user, bool error, const char *fmt, ...) -{ - if(!g_debug && !error) - return; - (void) user; - va_list args; - va_start(args, fmt); - vprintf(fmt, args); - va_end(args); -} - -static void elf_write(void *user, uint32_t addr, const void *buf, size_t count) -{ - FILE *f = user; - fseek(f, addr, SEEK_SET); - fwrite(buf, count, 1, f); -} - -static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id) -{ - char name[5]; - char *filename = xmalloc(strlen(g_out_prefix) + 32); - sb_fill_section_name(name, id); - sprintf(filename, "%s%s.%d.elf", g_out_prefix, name, count); - if(g_debug) - printf("Write boot section %s to %s\n", name, filename); - - FILE *fd = fopen(filename, "wb"); - free(filename); - - if(fd == NULL) - return ; - elf_write_file(elf, elf_write, elf_printf, fd); - fclose(fd); -} - -static void extract_sb_section(struct sb_section_t *sec) -{ - if(sec->is_data) - { - char sec_name[5]; - char *filename = xmalloc(strlen(g_out_prefix) + 32); - sb_fill_section_name(sec_name, sec->identifier); - sprintf(filename, "%s%s.bin", g_out_prefix, sec_name); - FILE *fd = fopen(filename, "wb"); - if(fd == NULL) - bugp("Cannot open %s for writing\n", filename); - if(g_debug) - printf("Write data section %s to %s\n", sec_name, filename); - free(filename); - - for(int j = 0; j < sec->nr_insts; j++) - { - assert(sec->insts[j].inst == SB_INST_DATA); - fwrite(sec->insts[j].data, sec->insts[j].size, 1, fd); - } - fclose(fd); - } - - int elf_count = 0; - struct elf_params_t elf; - elf_init(&elf); - - for(int i = 0; i < sec->nr_insts; i++) - { - struct sb_inst_t *inst = &sec->insts[i]; - switch(inst->inst) - { - case SB_INST_LOAD: - elf_add_load_section(&elf, inst->addr, inst->size, inst->data); - break; - case SB_INST_FILL: - elf_add_fill_section(&elf, inst->addr, inst->size, inst->pattern); - break; - case SB_INST_CALL: - case SB_INST_JUMP: - elf_set_start_addr(&elf, inst->addr); - extract_elf_section(&elf, elf_count++, sec->identifier); - elf_release(&elf); - elf_init(&elf); - break; - default: - /* ignore mode and nop */ - break; - } - } - - if(!elf_is_empty(&elf)) - extract_elf_section(&elf, elf_count, sec->identifier); - elf_release(&elf); -} - -static void extract_sb_file(struct sb_file_t *file) -{ - for(int i = 0; i < file->nr_sections; i++) - extract_sb_section(&file->sections[i]); -} - -static void usage(void) -{ - printf("Usage: sbtoelf [options] sb-file\n"); - printf("Options:\n"); - printf(" -?/--help\tDisplay this message\n"); - printf(" -o \tEnable output and set prefix\n"); - printf(" -d/--debug\tEnable debug output*\n"); - printf(" -k \tAdd key file\n"); - printf(" -z\t\tAdd zero key\n"); - printf(" -r\t\tUse raw command mode\n"); - printf(" -a/--add-key \tAdd single key (hex or usbotp)\n"); - printf(" -n/--no-color\tDisable output colors\n"); - printf(" -l/--loopback \tProduce sb file out of extracted description*\n"); - printf("Options marked with a * are for debug purpose only\n"); - exit(1); -} - -static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...) -{ - (void) user; - (void) error; - va_list args; - va_start(args, fmt); - color(c); - vprintf(fmt, args); - va_end(args); -} - -static struct crypto_key_t g_zero_key = -{ - .method = CRYPTO_KEY, - .u.key = {0} -}; - -int main(int argc, char **argv) -{ - bool raw_mode = false; - const char *loopback = NULL; - - while(1) - { - static struct option long_options[] = - { - {"help", no_argument, 0, '?'}, - {"debug", no_argument, 0, 'd'}, - {"add-key", required_argument, 0, 'a'}, - {"no-color", no_argument, 0, 'n'}, - {"loopback", required_argument, 0, 'l'}, - {0, 0, 0, 0} - }; - - int c = getopt_long(argc, argv, "?do:k:zra:nl:", long_options, NULL); - if(c == -1) - break; - switch(c) - { - case -1: - break; - case 'l': - if(loopback) - bug("Only one loopback file can be specified !\n"); - loopback = optarg; - break; - case 'n': - enable_color(false); - break; - case 'd': - g_debug = true; - break; - case '?': - usage(); - break; - case 'o': - g_out_prefix = optarg; - break; - case 'k': - { - add_keys_from_file(optarg); - break; - } - case 'z': - { - add_keys(&g_zero_key, 1); - break; - } - case 'r': - raw_mode = true; - break; - case 'a': - { - struct crypto_key_t key; - char *s = optarg; - if(!parse_key(&s, &key)) - bug("Invalid key specified as argument"); - if(*s != 0) - bug("Trailing characters after key specified as argument"); - add_keys(&key, 1); - break; - } - default: - abort(); - } - } - - if(argc - optind != 1) - { - usage(); - return 1; - } - - const char *sb_filename = argv[optind]; - - struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf); - color(OFF); - if(g_out_prefix) - extract_sb_file(file); - if(g_debug) - { - color(GREY); - printf("[Debug output]\n"); - sb_dump(file, NULL, sb_printf); - } - if(loopback) - { - /* sb_read_file will fill real key and IV but we don't want to override - * them when looping back otherwise the output will be inconsistent and - * garbage */ - free(file->real_key); - file->real_key = NULL; - free(file->crypto_iv); - file->crypto_iv = NULL; - sb_write_file(file, loopback); - } - - return 0; -} diff --git a/utils/sbtools/sha1.c b/utils/sbtools/sha1.c deleted file mode 100644 index 0ad05bb5cd..0000000000 --- a/utils/sbtools/sha1.c +++ /dev/null @@ -1,150 +0,0 @@ -/*************************************************************************** - * __________ __ ___. - * Open \______ \ ____ ____ | | _\_ |__ _______ ___ - * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / - * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < - * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ - * \/ \/ \/ \/ \/ - * $Id$ - * - * Copyright (C) 2010 Amaury Pouly - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ****************************************************************************/ -/* Based on http://en.wikipedia.org/wiki/SHA-1 */ -#include "crypto.h" - -static uint32_t rot_left(uint32_t val, int rot) -{ - return (val << rot) | (val >> (32 - rot)); -} - -static inline void byte_swapxx(byte *ptr, int size) -{ - for(int i = 0; i < size / 2; i++) - { - byte c = ptr[i]; - ptr[i] = ptr[size - i - 1]; - ptr[size - i - 1] = c; - } -} - -static void byte_swap32(uint32_t *v) -{ - byte_swapxx((byte *)v, 4); -} - -void sha_1_init(struct sha_1_params_t *params) -{ - params->hash[0] = 0x67452301; - params->hash[1] = 0xEFCDAB89; - params->hash[2] = 0x98BADCFE; - params->hash[3] = 0x10325476; - params->hash[4] = 0xC3D2E1F0; - params->buffer_nr_bits = 0; -} - -void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size) -{ - int buffer_nr_bytes = (params->buffer_nr_bits / 8) % 64; - params->buffer_nr_bits += 8 * size; - int pos = 0; - if(buffer_nr_bytes + size >= 64) - { - pos = 64 - buffer_nr_bytes; - memcpy((byte *)(params->w) + buffer_nr_bytes, buffer, 64 - buffer_nr_bytes); - sha_1_block(params, params->hash, (byte *)params->w); - for(; pos + 64 <= size; pos += 64) - sha_1_block(params, params->hash, buffer + pos); - buffer_nr_bytes = 0; - } - memcpy((byte *)(params->w) + buffer_nr_bytes, buffer + pos, size - pos); -} - -void sha_1_finish(struct sha_1_params_t *params) -{ - /* length (in bits) in big endian BEFORE preprocessing */ - byte length_big_endian[8]; - memcpy(length_big_endian, ¶ms->buffer_nr_bits, 8); - byte_swapxx(length_big_endian, 8); - /* append '1' and then '0's to the message to get 448 bit length for the last block */ - byte b = 0x80; - sha_1_update(params, &b, 1); - b = 0; - while((params->buffer_nr_bits % 512) != 448) - sha_1_update(params, &b, 1); - /* append length */ - sha_1_update(params, length_big_endian, 8); - /* go back to big endian */ - for(int i = 0; i < 5; i++) - byte_swap32(¶ms->hash[i]); -} - -void sha_1_output(struct sha_1_params_t *params, byte *out) -{ - memcpy(out, params->hash, 20); -} - -void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data) -{ - uint32_t a, b, c, d, e; - a = cur_hash[0]; - b = cur_hash[1]; - c = cur_hash[2]; - d = cur_hash[3]; - e = cur_hash[4]; - - #define w params->w - - memmove(w, data, 64); - for(int i = 0; i < 16; i++) - byte_swap32(&w[i]); - - for(int i = 16; i <= 79; i++) - w[i] = rot_left(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1); - - for(int i = 0; i<= 79; i++) - { - uint32_t f, k; - if(i <= 19) - { - f = (b & c) | ((~b) & d); - k = 0x5A827999; - } - else if(i <= 39) - { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } - else if(i <= 59) - { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } - else - { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - uint32_t temp = rot_left(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = rot_left(b, 30); - b = a; - a = temp; - } - #undef w - - cur_hash[0] += a; - cur_hash[1] += b; - cur_hash[2] += c; - cur_hash[3] += d; - cur_hash[4] += e; -} -- cgit v1.2.3