summaryrefslogtreecommitdiff
path: root/utils/imxtools
diff options
context:
space:
mode:
Diffstat (limited to 'utils/imxtools')
-rw-r--r--utils/imxtools/Makefile26
-rw-r--r--utils/imxtools/README32
-rw-r--r--utils/imxtools/aes128.c284
-rw-r--r--utils/imxtools/crc.c83
-rw-r--r--utils/imxtools/crypto.c188
-rw-r--r--utils/imxtools/crypto.h115
-rw-r--r--utils/imxtools/dbparser.c849
-rw-r--r--utils/imxtools/dbparser.h118
-rw-r--r--utils/imxtools/elf.c575
-rw-r--r--utils/imxtools/elf.h94
-rw-r--r--utils/imxtools/elftosb.c461
-rw-r--r--utils/imxtools/fuze+_key_file.txt1
-rw-r--r--utils/imxtools/misc.c248
-rw-r--r--utils/imxtools/misc.h59
-rw-r--r--utils/imxtools/sb.c1181
-rw-r--r--utils/imxtools/sb.h237
-rw-r--r--utils/imxtools/sbloader.c174
-rw-r--r--utils/imxtools/sbtoelf.c302
-rw-r--r--utils/imxtools/sha1.c150
19 files changed, 5177 insertions, 0 deletions
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 @@
1DEFINES=-DCRYPTO_LIBUSB
2CC=gcc
3LD=gcc
4CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
5LDFLAGS=`pkg-config --libs libusb-1.0`
6BINS=elftosb sbtoelf sbloader
7
8all: $(BINS)
9
10%.o: %.c
11 $(CC) $(CFLAGS) -c -o $@ $<
12
13sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o
14 $(LD) -o $@ $^ $(LDFLAGS)
15
16elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
17 $(LD) -o $@ $^ $(LDFLAGS)
18
19sbloader: sbloader.o
20 $(LD) -o $@ $^ $(LDFLAGS)
21
22clean:
23 rm -fr *.o
24
25veryclean:
26 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 @@
1This file document the format of the command file used by the elftosb tool.
2By no way our tools tries to be compatible with Freescale's elftosb2.
3However, our format is more subset of the general one.
4
5The parse supports a limited form of comments: comments starting with // and ending at the end of the line.
6
7A file first contains the list of sources:
8
9sources
10{
11 hw_init = "sdram_init.elf";
12 rockbox = "rockbox.elf";
13}
14
15It can then contain an arbitrary number of section. A section is identified by a number.
16Within a section, three commands are supported: "load", "jump" and "call":
17
18section(0x626f6f74) // hex for 'boot'
19{
20 load hw_init;
21 call hw_init;
22 load rockbox;
23 jump rockbox;
24}
25
26Finally, both elftosb and sbtoelf tools use key files. A key file is a list of keys.
27Each key consist is 128-bit long and is written in hexadecimal:
28
2900000000000000000000000000000000
30
31The parser does not handle blank line and only allows a final newline at the end of the file.
32A 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 @@
1// Simple, thoroughly commented implementation of 128-bit AES / Rijndael using C
2// Chris Hulbert - chris.hulbert@gmail.com - http://splinter.com.au/blog
3// References:
4// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
5// http://en.wikipedia.org/wiki/Rijndael_key_schedule
6// http://en.wikipeia.org/wiki/Rijndael_mix_columns
7// http://en.wikipedia.org/wiki/Rijndael_S-box
8// This code is public domain, or any OSI-approved license, your choice. No warranty.
9#include "crypto.h"
10
11// Here are all the lookup tables for the row shifts, rcon, s-boxes, and galois field multiplications
12byte shift_rows_table[] = {0,5,10,15,4,9,14,3,8,13,2,7,12,1,6,11};
13byte shift_rows_table_inv[] = {0,13,10,7,4,1,14,11,8,5,2,15,12,9,6,3};
14byte lookup_rcon[]={0x8d,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a};
15byte 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};
16byte 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};
17byte 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};
18byte 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};
19byte 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};
20byte 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};
21byte 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};
22byte 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};
23
24// Xor's all elements in a n byte array a by b
25void xor_(byte *a, byte *b, int n) {
26 int i;
27 for (i=0;i<n;i++)
28 a[i] ^= b[i];
29}
30
31// Xor the current cipher state by a specific round key
32static void xor_round_key(byte *state, byte *keys, int round) {
33 xor_(state,keys+round*16,16);
34}
35
36// Apply and reverse the rijndael s-box to all elements in an array
37// http://en.wikipedia.org/wiki/Rijndael_S-box
38static void sub_bytes(byte *a,int n) {
39 int i;
40 for (i=0;i<n;i++)
41 a[i] = lookup_sbox[a[i]];
42}
43static void sub_bytes_inv(byte *a,int n) {
44 int i;
45 for (i=0;i<n;i++)
46 a[i] = lookup_sbox_inv[a[i]];
47}
48
49// Perform the core key schedule transform on 4 bytes, as part of the key expansion process
50// http://en.wikipedia.org/wiki/Rijndael_key_schedule#Key_schedule_core
51static void key_schedule_core(byte *a, int i) {
52 byte temp = a[0]; // Rotate the output eight bits to the left
53 a[0]=a[1];
54 a[1]=a[2];
55 a[2]=a[3];
56 a[3]=temp;
57 sub_bytes(a,4); // Apply Rijndael's S-box on all four individual bytes in the output word
58 a[0]^=lookup_rcon[i]; // On just the first (leftmost) byte of the output word, perform the rcon operation with i
59 // as the input, and exclusive or the rcon output with the first byte of the output word
60}
61
62// Expand the 16-byte key to 11 round keys (176 bytes)
63// http://en.wikipedia.org/wiki/Rijndael_key_schedule#The_key_schedule
64static void expand_key(byte *key, byte *keys) {
65 int bytes=16; // The count of how many bytes we've created so far
66 int i=1; // The rcon iteration value i is set to 1
67 int j; // For repeating the second stage 3 times
68 byte t[4]; // Temporary working area known as 't' in the Wiki article
69 memcpy(keys,key,16); // The first 16 bytes of the expanded key are simply the encryption key
70
71 while (bytes<176) { // Until we have 176 bytes of expanded key, we do the following:
72 memcpy(t,keys+bytes-4,4); // We assign the value of the previous four bytes in the expanded key to t
73 key_schedule_core(t, i); // We perform the key schedule core on t, with i as the rcon iteration value
74 i++; // We increment i by 1
75 xor_(t,keys+bytes-16,4); // We exclusive-or t with the four-byte block 16 bytes before the new expanded key.
76 memcpy(keys+bytes,t,4); // This becomes the next 4 bytes in the expanded key
77 bytes+=4; // Keep track of how many expanded key bytes we've added
78
79 // We then do the following three times to create the next twelve bytes
80 for (j=0;j<3;j++) {
81 memcpy(t,keys+bytes-4,4); // We assign the value of the previous 4 bytes in the expanded key to t
82 xor_(t,keys+bytes-16,4); // We exclusive-or t with the four-byte block n bytes before
83 memcpy(keys+bytes,t,4); // This becomes the next 4 bytes in the expanded key
84 bytes+=4; // Keep track of how many expanded key bytes we've added
85 }
86 }
87}
88
89// Apply / reverse the shift rows step on the 16 byte cipher state
90// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard#The_ShiftRows_step
91static void shift_rows(byte *state) {
92 int i;
93 byte temp[16];
94 memcpy(temp,state,16);
95 for (i=0;i<16;i++)
96 state[i]=temp[shift_rows_table[i]];
97}
98static void shift_rows_inv(byte *state) {
99 int i;
100 byte temp[16];
101 memcpy(temp,state,16);
102 for (i=0;i<16;i++)
103 state[i]=temp[shift_rows_table_inv[i]];
104}
105
106// Perform the mix columns matrix on one column of 4 bytes
107// http://en.wikipedia.org/wiki/Rijndael_mix_columns
108static void mix_col (byte *state) {
109 byte a0 = state[0];
110 byte a1 = state[1];
111 byte a2 = state[2];
112 byte a3 = state[3];
113 state[0] = lookup_g2[a0] ^ lookup_g3[a1] ^ a2 ^ a3;
114 state[1] = lookup_g2[a1] ^ lookup_g3[a2] ^ a3 ^ a0;
115 state[2] = lookup_g2[a2] ^ lookup_g3[a3] ^ a0 ^ a1;
116 state[3] = lookup_g2[a3] ^ lookup_g3[a0] ^ a1 ^ a2;
117}
118
119// Perform the mix columns matrix on each column of the 16 bytes
120static void mix_cols (byte *state) {
121 mix_col(state);
122 mix_col(state+4);
123 mix_col(state+8);
124 mix_col(state+12);
125}
126
127// Perform the inverse mix columns matrix on one column of 4 bytes
128// http://en.wikipedia.org/wiki/Rijndael_mix_columns
129static void mix_col_inv (byte *state) {
130 byte a0 = state[0];
131 byte a1 = state[1];
132 byte a2 = state[2];
133 byte a3 = state[3];
134 state[0] = lookup_g14[a0] ^ lookup_g9[a3] ^ lookup_g13[a2] ^ lookup_g11[a1];
135 state[1] = lookup_g14[a1] ^ lookup_g9[a0] ^ lookup_g13[a3] ^ lookup_g11[a2];
136 state[2] = lookup_g14[a2] ^ lookup_g9[a1] ^ lookup_g13[a0] ^ lookup_g11[a3];
137 state[3] = lookup_g14[a3] ^ lookup_g9[a2] ^ lookup_g13[a1] ^ lookup_g11[a0];
138}
139
140// Perform the inverse mix columns matrix on each column of the 16 bytes
141static void mix_cols_inv (byte *state) {
142 mix_col_inv(state);
143 mix_col_inv(state+4);
144 mix_col_inv(state+8);
145 mix_col_inv(state+12);
146}
147
148// Encrypt a single 128 bit block by a 128 bit key using AES
149// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
150void EncryptAES(byte *msg, byte *key, byte *c) {
151 int i; // To count the rounds
152
153 // Key expansion
154 byte keys[176];
155 expand_key(key,keys);
156
157 // First Round
158 memmove(c, msg, 16);
159 xor_round_key(c,keys,0);
160
161 // Middle rounds
162 for(i=0; i<9; i++) {
163 sub_bytes(c,16);
164 shift_rows(c);
165 mix_cols(c);
166 xor_round_key(c, keys, i+1);
167 }
168
169 // Final Round
170 sub_bytes(c,16);
171 shift_rows(c);
172 xor_round_key(c, keys, 10);
173}
174
175// Decrypt a single 128 bit block by a 128 bit key using AES
176// http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
177void DecryptAES(byte *c, byte *key, byte *m) {
178 int i; // To count the rounds
179
180 // Key expansion
181 byte keys[176];
182 expand_key(key,keys);
183
184 // Reverse the final Round
185 memcpy(m,c,16);
186 xor_round_key(m,keys,10);
187 shift_rows_inv(m);
188 sub_bytes_inv(m, 16);
189
190 // Reverse the middle rounds
191 for (i=0; i<9; i++) {
192 xor_round_key(m,keys,9-i);
193 mix_cols_inv(m);
194 shift_rows_inv(m);
195 sub_bytes_inv(m, 16);
196 }
197
198 // Reverse the first Round
199 xor_round_key(m, keys, 0);
200}
201
202/*
203// Pretty-print a key (or any smallish buffer) onto screen as hex
204void Pretty(byte* b,int len,const char* label)
205{
206 char out[100];
207 int i;
208 for (i=0;i<len;i++)
209 sprintf(out+i*2,"%02x",b[i]);
210
211 printf("%s%s",label, out);
212}
213*/
214
215/*
216// Test AES
217int main(void)
218{
219 byte key[] = {0x12,0x34,0x56,0x12,0x34,0x56,0x12,0x34,0x56,0x12,0x34,0x56,0x12,0x34,0x56,0x12};
220 byte msg[] = {0xab,0xcd,0xef,0xab,0xcd,0xef,0xab,0xcd,0xef,0xab,0xcd,0xef,0xab,0xcd,0xef,0xab};
221 byte encrypted[16], decrypted[16];
222
223 printf("Test AES\r\n\n");
224 Pretty(key,16,"Key: ");
225 Pretty(msg,16,"Original: ");
226
227 EncryptAES(msg,key,encrypted);
228 printf("Encrypted should be: 85E5A3D7356A61E29A8AFA559AD67102\r\n");
229 Pretty(encrypted,16,"Encrypted: ");
230
231 DecryptAES(encrypted,key,decrypted);
232 Pretty(decrypted,16,"Decrypted: ");
233
234 return 0;
235}
236*/
237
238void cbc_mac(
239 byte *in_data, /* Input data */
240 byte *out_data, /* Output data (or NULL) */
241 int nr_blocks, /* Number of blocks to encrypt/decrypt (one block=16 bytes) */
242 byte key[16], /* Key */
243 byte iv[16], /* Initialisation Vector */
244 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
245 int encrypt /* 1 to encrypt, 0 to decrypt */
246 )
247{
248 byte feedback[16];
249 memcpy(feedback, iv, 16);
250
251 if(encrypt)
252 {
253 /* for each block */
254 for(int i = 0; i < nr_blocks; i++)
255 {
256 /* xor it with feedback */
257 xor_(feedback, &in_data[i * 16], 16);
258 /* encrypt it using aes */
259 EncryptAES(feedback, key, feedback);
260 /* write cipher to output */
261 if(out_data)
262 memcpy(&out_data[i * 16], feedback, 16);
263 }
264 if(out_cbc_mac)
265 memcpy(out_cbc_mac, feedback, 16);
266 }
267 else
268 {
269 /* nothing to do ? */
270 if(out_data == NULL)
271 return;
272
273 /* for each block */
274 for(int i = 0; i < nr_blocks; i++)
275 {
276 /* decrypt it using aes */
277 DecryptAES(&in_data[i * 16], key, &out_data[i * 16]);
278 /* xor it with iv */
279 xor_(&out_data[i * 16], feedback, 16);
280 /* copy cipher to iv */
281 memcpy(feedback, &in_data[i * 16], 16);
282 }
283 }
284}
diff --git a/utils/imxtools/crc.c b/utils/imxtools/crc.c
new file mode 100644
index 0000000000..eaf257ddfe
--- /dev/null
+++ b/utils/imxtools/crc.c
@@ -0,0 +1,83 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "crypto.h"
22
23/* Table extracted from firmware, don't know if this is regular CRC32 */
24
25static uint32_t crc_table[256] = {
26 0x0, 0x4C11DB7, 0x9823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2,
27 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64,
28 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 0x4C11DB70, 0x48D0C6C7, 0x4593E01E,
29 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8,
30 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
31 0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C,
32 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0x0BE2B5B58, 0x0BAEA46EF, 0x0B7A96036,
33 0x0B3687D81, 0x0AD2F2D84, 0x0A9EE3033, 0x0A4AD16EA, 0x0A06C0B5D, 0x0D4326D90,
34 0x0D0F37027, 0x0DDB056FE, 0x0D9714B49, 0x0C7361B4C, 0x0C3F706FB, 0x0CEB42022,
35 0x0CA753D95, 0x0F23A8028, 0x0F6FB9D9F, 0x0FBB8BB46, 0x0FF79A6F1, 0x0E13EF6F4,
36 0x0E5FFEB43, 0x0E8BCCD9A, 0x0EC7DD02D, 0x34867077, 0x30476DC0, 0x3D044B19,
37 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, 0x128E9DCF,
38 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x18AEB13, 0x54BF6A4, 0x808D07D,
39 0x0CC9CDCA, 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB,
40 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
41 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, 0x0ACA5C697,
42 0x0A864DB20, 0x0A527FDF9, 0x0A1E6E04E, 0x0BFA1B04B, 0x0BB60ADFC, 0x0B6238B25,
43 0x0B2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3,
44 0x9D684044, 0x902B669D, 0x94EA7B2A, 0x0E0B41DE7, 0x0E4750050, 0x0E9362689,
45 0x0EDF73B3E, 0x0F3B06B3B, 0x0F771768C, 0x0FA325055, 0x0FEF34DE2, 0x0C6BCF05F,
46 0x0C27DEDE8, 0x0CF3ECB31, 0x0CBFFD686, 0x0D5B88683, 0x0D1799B34, 0x0DC3ABDED,
47 0x0D8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632,
48 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, 0x46863638,
49 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E,
50 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
51 0x3B5A6B9B, 0x315D626, 0x7D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA,
52 0x14D0BD4D, 0x19939B94, 0x1D528623, 0x0F12F560E, 0x0F5EE4BB9, 0x0F8AD6D60,
53 0x0FC6C70D7, 0x0E22B20D2, 0x0E6EA3D65, 0x0EBA91BBC, 0x0EF68060B, 0x0D727BBB6,
54 0x0D3E6A601, 0x0DEA580D8, 0x0DA649D6F, 0x0C423CD6A, 0x0C0E2D0DD, 0x0CDA1F604,
55 0x0C960EBB3, 0x0BD3E8D7E, 0x0B9FF90C9, 0x0B4BCB610, 0x0B07DABA7, 0x0AE3AFBA2,
56 0x0AAFBE615, 0x0A7B8C0CC, 0x0A379DD7B, 0x9B3660C6, 0x9FF77D71, 0x92B45BA8,
57 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, 0x5D8A9099,
58 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B,
59 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD,
60 0x6C47164A, 0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
61 0x1CD86D30, 0x29F3D35, 0x65E2082, 0x0B1D065B, 0x0FDC1BEC, 0x3793A651,
62 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3,
63 0x29D4F654, 0x0C5A92679, 0x0C1683BCE, 0x0CC2B1D17, 0x0C8EA00A0, 0x0D6AD50A5,
64 0x0D26C4D12, 0x0DF2F6BCB, 0x0DBEE767C, 0x0E3A1CBC1, 0x0E760D676, 0x0EA23F0AF,
65 0x0EEE2ED18, 0x0F0A5BD1D, 0x0F464A0AA, 0x0F9278673, 0x0FDE69BC4, 0x89B8FD09,
66 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB,
67 0x97FFAD0C, 0x0AFB010B1, 0x0AB710D06, 0x0A6322BDF, 0x0A2F33668, 0x0BCB4666D,
68 0x0B8757BDA, 0x0B5365D03, 0x0B1F740B4
69};
70
71uint32_t crc(byte *data, int size)
72{
73 return crc_continue(0xffffffff, data, size);
74}
75
76uint32_t crc_continue(uint32_t previous_crc, byte *data, int size)
77{
78 uint32_t c = previous_crc;
79 /* normal CRC */
80 for(int i = 0; i < size; i++)
81 c = crc_table[data[i] ^ (c >> 24)] ^ (c << 8);
82 return c;
83}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "crypto.h"
22#include <stdio.h>
23#include <stdbool.h>
24#ifdef CRYPTO_LIBUSB
25#include "libusb.h"
26#endif
27#include "misc.h"
28
29static enum crypto_method_t cur_method = CRYPTO_NONE;
30static byte key[16];
31static uint16_t usb_vid, usb_pid;
32
33void crypto_setup(enum crypto_method_t method, void *param)
34{
35 cur_method = method;
36 switch(method)
37 {
38 case CRYPTO_KEY:
39 memcpy(key, param, sizeof(key));
40 break;
41 case CRYPTO_USBOTP:
42 {
43 uint32_t value = *(uint32_t *)param;
44 usb_vid = value >> 16;
45 usb_pid = value & 0xffff;
46 break;
47 }
48 default:
49 break;
50 }
51}
52
53int crypto_apply(
54 byte *in_data, /* Input data */
55 byte *out_data, /* Output data (or NULL) */
56 int nr_blocks, /* Number of blocks (one block=16 bytes) */
57 byte iv[16], /* Key */
58 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
59 int encrypt)
60{
61 if(cur_method == CRYPTO_KEY)
62 {
63 cbc_mac(in_data, out_data, nr_blocks, key, iv, out_cbc_mac, encrypt);
64 return CRYPTO_ERROR_SUCCESS;
65 }
66 #ifdef CRYPTO_LIBUSB
67 else if(cur_method == CRYPTO_USBOTP)
68 {
69 if(out_cbc_mac && !encrypt)
70 memcpy(*out_cbc_mac, in_data + 16 * (nr_blocks - 1), 16);
71
72 libusb_device_handle *handle = NULL;
73 libusb_context *ctx;
74 /* init library */
75 libusb_init(&ctx);
76 libusb_set_debug(NULL,3);
77 /* open device */
78 handle = libusb_open_device_with_vid_pid(ctx, usb_vid, usb_pid);
79 if(handle == NULL)
80 {
81 printf("usbotp: cannot open device %04x:%04x\n", usb_vid, usb_pid);
82 return CRYPTO_ERROR_NODEVICE;
83 }
84 /* get device pointer */
85 libusb_device *mydev = libusb_get_device(handle);
86 if(g_debug)
87 printf("usbotp: device found at %d:%d\n", libusb_get_bus_number(mydev),
88 libusb_get_device_address(mydev));
89 int config_id;
90 /* explore configuration */
91 libusb_get_configuration(handle, &config_id);
92 struct libusb_config_descriptor *config;
93 libusb_get_active_config_descriptor(mydev, &config);
94
95 if(g_debug)
96 {
97 printf("usbotp: configuration: %d\n", config_id);
98 printf("usbotp: interfaces: %d\n", config->bNumInterfaces);
99 }
100
101 const struct libusb_endpoint_descriptor *endp = NULL;
102 int intf, intf_alt;
103 for(intf = 0; intf < config->bNumInterfaces; intf++)
104 for(intf_alt = 0; intf_alt < config->interface[intf].num_altsetting; intf_alt++)
105 for(int ep = 0; ep < config->interface[intf].altsetting[intf_alt].bNumEndpoints; ep++)
106 {
107 endp = &config->interface[intf].altsetting[intf_alt].endpoint[ep];
108 if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
109 (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
110 goto Lfound;
111 }
112 libusb_close(handle);
113 printf("usbotp: No suitable endpoint found\n");
114 return CRYPTO_ERROR_BADENDP;
115
116 if(g_debug)
117 {
118 printf("usbotp: use interface %d, alt %d\n", intf, intf_alt);
119 printf("usbotp: use endpoint %d\n", endp->bEndpointAddress);
120 }
121 Lfound:
122 if(libusb_claim_interface(handle, intf) != 0)
123 {
124 if(g_debug)
125 printf("usbotp: claim error\n");
126 return CRYPTO_ERROR_CLAIMFAIL;
127 }
128
129 int buffer_size = 16 + 16 * nr_blocks;
130 unsigned char *buffer = xmalloc(buffer_size);
131 memcpy(buffer, iv, 16);
132 memcpy(buffer + 16, in_data, 16 * nr_blocks);
133 int ret = libusb_control_transfer(handle,
134 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
135 0xaa, encrypt ? 0xeeee : 0xdddd, 0, buffer, buffer_size, 1000);
136 if(ret < 0)
137 {
138 if(g_debug)
139 printf("usbotp: control transfer failed: %d\n", ret);
140 libusb_release_interface(handle, intf);
141 libusb_close(handle);
142 return CRYPTO_ERROR_DEVREJECT;
143 }
144
145 int recv_size;
146 ret = libusb_interrupt_transfer(handle, endp->bEndpointAddress, buffer,
147 buffer_size, &recv_size, 1000);
148 libusb_release_interface(handle, intf);
149 libusb_close(handle);
150
151 if(ret < 0)
152 {
153 if(g_debug)
154 printf("usbotp: interrupt transfer failed: %d\n", ret);
155 return CRYPTO_ERROR_DEVSILENT;
156 }
157 if(recv_size != buffer_size)
158 {
159 if(g_debug)
160 printf("usbotp: device returned %d bytes, expected %d\n", recv_size,
161 buffer_size);
162 return CRYPTO_ERROR_DEVERR;
163 }
164
165 if(out_data)
166 memcpy(out_data, buffer + 16, 16 * nr_blocks);
167 if(out_cbc_mac && encrypt)
168 memcpy(*out_cbc_mac, buffer + buffer_size - 16, 16);
169
170 return CRYPTO_ERROR_SUCCESS;
171 }
172 #endif
173 else
174 return CRYPTO_ERROR_BADSETUP;
175}
176
177int crypto_cbc(
178 byte *in_data, /* Input data */
179 byte *out_data, /* Output data (or NULL) */
180 int nr_blocks, /* Number of blocks (one block=16 bytes) */
181 struct crypto_key_t *key, /* Key */
182 byte iv[16], /* IV */
183 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
184 int encrypt)
185{
186 crypto_setup(key->method, (void *)key->u.param);
187 return crypto_apply(in_data, out_data, nr_blocks, iv, out_cbc_mac, encrypt);
188}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef __CRYPTO_H__
22#define __CRYPTO_H__
23
24#include <stdio.h>
25#include <stdint.h>
26#include <string.h>
27
28typedef uint8_t byte;
29
30/* aes128.c */
31void xor_(byte *a, byte *b, int n);
32void EncryptAES(byte *msg, byte *key, byte *c);
33void DecryptAES(byte *c, byte *key, byte *m);
34void Pretty(byte* b,int len,const char* label);
35void cbc_mac(
36 byte *in_data, /* Input data */
37 byte *out_data, /* Output data (or NULL) */
38 int nr_blocks, /* Number of blocks to encrypt/decrypt (one block=16 bytes) */
39 byte key[16], /* Key */
40 byte iv[16], /* Initialisation Vector */
41 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
42 int encrypt /* 1 to encrypt, 0 to decrypt */
43 );
44
45/* crypto.c */
46enum crypto_method_t
47{
48 CRYPTO_NONE, /* disable */
49 CRYPTO_KEY, /* key */
50 CRYPTO_USBOTP, /* use usbotp device */
51};
52
53/* parameter can be:
54 * - CRYPTO_KEY: array of 16-bytes (the key)
55 * - CRYPTO_USBOTP: 32-bit integer: vid << 16 | pid */
56void crypto_setup(enum crypto_method_t method, void *param);
57
58#define CRYPTO_ERROR_SUCCESS 0
59#define CRYPTO_ERROR_BADSETUP -1 /* bad crypto setup */
60#define CRYPTO_ERROR_NODEVICE -2 /* no device with vid:pid */
61#define CRYPTO_ERROR_BADENDP -3 /* device doesn't have the required endpoints */
62#define CRYPTO_ERROR_CLAIMFAIL -4 /* device interface claim error */
63#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */
64#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */
65#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */
66#define CRYPTO_NUM_ERRORS 8
67/* return 0 on success, <0 on error */
68int crypto_apply(
69 byte *in_data, /* Input data */
70 byte *out_data, /* Output data (or NULL) */
71 int nr_blocks, /* Number of blocks (one block=16 bytes) */
72 byte iv[16], /* IV */
73 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
74 int encrypt);
75
76/* all-in-one function */
77struct crypto_key_t
78{
79 enum crypto_method_t method;
80 union
81 {
82 byte key[16];
83 uint32_t vid_pid;
84 byte param[0];
85 }u;
86};
87
88int crypto_cbc(
89 byte *in_data, /* Input data */
90 byte *out_data, /* Output data (or NULL) */
91 int nr_blocks, /* Number of blocks (one block=16 bytes) */
92 struct crypto_key_t *key, /* Key */
93 byte iv[16], /* IV */
94 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
95 int encrypt);
96
97/* crc.c */
98uint32_t crc(byte *data, int size);
99uint32_t crc_continue(uint32_t previous_crc, byte *data, int size);
100
101/* sha1.c */
102struct sha_1_params_t
103{
104 uint32_t hash[5];
105 uint64_t buffer_nr_bits;
106 uint32_t w[80];
107};
108
109void sha_1_init(struct sha_1_params_t *params);
110void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data);
111void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size);
112void sha_1_finish(struct sha_1_params_t *params);
113void sha_1_output(struct sha_1_params_t *params, byte *out);
114
115#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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#define _POSIX_C_SOURCE 200809L /* for strdup */
23#include <stdio.h>
24#include <ctype.h>
25#include <stdint.h>
26#include <string.h>
27#include "dbparser.h"
28#include "misc.h"
29
30enum lexem_type_t
31{
32 LEX_IDENTIFIER,
33 LEX_LPAREN,
34 LEX_RPAREN,
35 LEX_NUMBER,
36 LEX_STRING, /* double-quoted string */
37 LEX_EQUAL,
38 LEX_SEMICOLON,
39 LEX_LBRACE,
40 LEX_RBRACE,
41 LEX_RANGLE,
42 LEX_OR,
43 LEX_LSHIFT,
44 LEX_COLON,
45 LEX_LE,
46 LEX_EOF
47};
48
49struct lexem_t
50{
51 enum lexem_type_t type;
52 /* if str is not NULL, it must be a malloc'd pointer */
53 char *str;
54 uint32_t num;
55 int line;
56 const char *file;
57};
58
59struct context_t
60{
61 const char *file;
62 char *begin;
63 char *end;
64 char *ptr;
65 int line;
66};
67
68#define parse_error(ctx, ...) \
69 do { fprintf(stderr, "%s:%d: ", ctx->file, ctx->line); \
70 fprintf(stderr, __VA_ARGS__); exit(2); } while(0)
71
72static void advance(struct context_t *ctx, int nr_chars)
73{
74 while(nr_chars--)
75 {
76 if(*(ctx->ptr++) == '\n')
77 ctx->line++;
78 }
79}
80
81static inline bool eof(struct context_t *ctx)
82{
83 return ctx->ptr == ctx->end;
84}
85
86static inline bool next_valid(struct context_t *ctx, int nr)
87{
88 return ctx->ptr + nr < ctx->end;
89}
90
91static inline char cur_char(struct context_t *ctx)
92{
93 return *ctx->ptr;
94}
95
96static inline char next_char(struct context_t *ctx, int nr)
97{
98 return ctx->ptr[nr];
99}
100
101static inline void locate_lexem(struct lexem_t *lex, struct context_t *ctx)
102{
103 lex->file = ctx->file;
104 lex->line = ctx->line;
105}
106
107static void __parse_string(struct context_t *ctx, void *user, void (*emit_fn)(void *user, char c))
108{
109 while(!eof(ctx))
110 {
111 if(cur_char(ctx) == '"')
112 break;
113 else if(cur_char(ctx) == '\\')
114 {
115 advance(ctx, 1);
116 if(eof(ctx))
117 parse_error(ctx, "Unfinished string\n");
118 if(cur_char(ctx) == '\\') emit_fn(user, '\\');
119 else if(cur_char(ctx) == '\'') emit_fn(user, '\'');
120 else if(cur_char(ctx) == '\"') emit_fn(user, '\"');
121 else parse_error(ctx, "Unknown escape sequence \\%c\n", cur_char(ctx));
122 advance(ctx, 1);
123 }
124 else
125 {
126 emit_fn(user, cur_char(ctx));
127 advance(ctx, 1);
128 }
129 }
130 if(eof(ctx) || cur_char(ctx) != '"')
131 parse_error(ctx, "Unfinished string\n");
132 advance(ctx, 1);
133}
134
135static void __parse_string_emit(void *user, char c)
136{
137 char **pstr = (char **)user;
138 *(*pstr)++ = c;
139}
140
141static void __parse_string_count(void *user, char c)
142{
143 (void) c;
144 (*(int *)user)++;
145}
146
147static void parse_string(struct context_t *ctx, struct lexem_t *lexem)
148{
149 locate_lexem(lexem, ctx);
150 /* skip " */
151 advance(ctx, 1);
152 /* compute length */
153 struct context_t cpy_ctx = *ctx;
154 int length = 0;
155 __parse_string(&cpy_ctx, (void *)&length, __parse_string_count);
156 /* parse again */
157 lexem->type = LEX_STRING;
158 lexem->str = xmalloc(length + 1);
159 lexem->str[length] = 0;
160 char *pstr = lexem->str;
161 __parse_string(ctx, (void *)&pstr, __parse_string_emit);
162}
163
164static void parse_ascii_number(struct context_t *ctx, struct lexem_t *lexem)
165{
166 locate_lexem(lexem, ctx);
167 /* skip ' */
168 advance(ctx, 1);
169 /* we expect n<=4 character and then ' */
170 int len = 0;
171 uint32_t value = 0;
172 while(!eof(ctx))
173 {
174 if(cur_char(ctx) != '\'')
175 {
176 value = value << 8 | cur_char(ctx);
177 len++;
178 advance(ctx, 1);
179 }
180 else
181 break;
182 }
183 if(eof(ctx) || cur_char(ctx) != '\'')
184 parse_error(ctx, "Unterminated ascii number literal\n");
185 if(len == 0 || len > 4)
186 parse_error(ctx, "Invalid ascii number literal length: only 1 to 4 characters allowed\n");
187 /* skip ' */
188 advance(ctx, 1);
189 lexem->type = LEX_NUMBER;
190 lexem->num = value;
191}
192
193static void parse_number(struct context_t *ctx, struct lexem_t *lexem)
194{
195 locate_lexem(lexem, ctx);
196 /* check base */
197 int base = 10;
198 if(cur_char(ctx) == '0' && next_valid(ctx, 1) && next_char(ctx, 1) == 'x')
199 {
200 advance(ctx, 2);
201 base = 16;
202 }
203
204 lexem->type = LEX_NUMBER;
205 lexem->num = 0;
206 while(!eof(ctx) && isxdigit(cur_char(ctx)))
207 {
208 if(base == 10 && !isdigit(cur_char(ctx)))
209 break;
210 byte v;
211 if(convxdigit(cur_char(ctx), &v))
212 break;
213 lexem->num = base * lexem->num + v;
214 advance(ctx, 1);
215 }
216}
217
218static void parse_identifier(struct context_t *ctx, struct lexem_t *lexem)
219{
220 locate_lexem(lexem, ctx);
221 /* remember position */
222 char *old = ctx->ptr;
223 while(!eof(ctx) && (isalnum(cur_char(ctx)) || cur_char(ctx) == '_'))
224 advance(ctx, 1);
225 lexem->type = LEX_IDENTIFIER;
226 int len = ctx->ptr - old;
227 lexem->str = xmalloc(len + 1);
228 lexem->str[len] = 0;
229 memcpy(lexem->str, old, len);
230}
231
232static void next_lexem(struct context_t *ctx, struct lexem_t *lexem)
233{
234 #define ret_simple(t, adv) \
235 do {locate_lexem(lexem, ctx); \
236 lexem->type = t; \
237 advance(ctx, adv); \
238 return;} while(0)
239 while(!eof(ctx))
240 {
241 char c = cur_char(ctx);
242 /* skip whitespace */
243 if(c == ' ' || c == '\t' || c == '\n' || c == '\r')
244 {
245 advance(ctx, 1);
246 continue;
247 }
248 /* skip C++ style comments */
249 if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '/')
250 {
251 while(!eof(ctx) && cur_char(ctx) != '\n')
252 advance(ctx, 1);
253 continue;
254 }
255 /* skip C-style comments */
256 if(c == '/' && next_valid(ctx, 1) && next_char(ctx, 1) == '*')
257 {
258 advance(ctx, 2);
259 while(true)
260 {
261 if(!next_valid(ctx, 1))
262 parse_error(ctx, "Unterminated comment");
263 if(cur_char(ctx) == '*' && next_char(ctx, 1) == '/')
264 {
265 advance(ctx, 2);
266 break;
267 }
268 advance(ctx, 1);
269 }
270 continue;
271 }
272 break;
273 }
274 if(eof(ctx)) ret_simple(LEX_EOF, 0);
275 char c = cur_char(ctx);
276 bool nv = next_valid(ctx, 1);
277 char nc = nv ? next_char(ctx, 1) : 0;
278 if(c == '(') ret_simple(LEX_LPAREN, 1);
279 if(c == ')') ret_simple(LEX_RPAREN, 1);
280 if(c == '{') ret_simple(LEX_LBRACE, 1);
281 if(c == '}') ret_simple(LEX_RBRACE, 1);
282 if(c == '>') ret_simple(LEX_RANGLE, 1);
283 if(c == '=') ret_simple(LEX_EQUAL, 1);
284 if(c == ';') ret_simple(LEX_SEMICOLON, 1);
285 if(c == ',') ret_simple(LEX_COLON, 1);
286 if(c == '|') ret_simple(LEX_OR, 1);
287 if(c == '<' && nv && nc == '<') ret_simple(LEX_LSHIFT, 2);
288 if(c == '<' && nv && nc == '=') ret_simple(LEX_LE, 2);
289 if(c == '"') return parse_string(ctx, lexem);
290 if(c == '\'') return parse_ascii_number(ctx, lexem);
291 if(isdigit(c)) return parse_number(ctx, lexem);
292 if(isalpha(c) || c == '_') return parse_identifier(ctx, lexem);
293 parse_error(ctx, "Unexpected character '%c'\n", c);
294 #undef ret_simple
295}
296
297#if 0
298static void log_lexem(struct lexem_t *lexem)
299{
300 switch(lexem->type)
301 {
302 case LEX_EOF: printf("<eof>"); break;
303 case LEX_EQUAL: printf("="); break;
304 case LEX_IDENTIFIER: printf("id(%s)", lexem->str); break;
305 case LEX_LPAREN: printf("("); break;
306 case LEX_RPAREN: printf(")"); break;
307 case LEX_LBRACE: printf("{"); break;
308 case LEX_RBRACE: printf("}"); break;
309 case LEX_SEMICOLON: printf(";"); break;
310 case LEX_NUMBER: printf("num(%d)", lexem->num); break;
311 case LEX_STRING: printf("str(%s)", lexem->str); break;
312 case LEX_OR: printf("|"); break;
313 case LEX_LSHIFT: printf("<<"); break;
314 default: printf("<unk>");
315 }
316}
317#endif
318
319struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id)
320{
321 struct cmd_source_t *src = cmd_file->source_list;
322 while(src)
323 {
324 if(strcmp(src->identifier, id) == 0)
325 return src;
326 src = src->next;
327 }
328 return NULL;
329}
330
331struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name)
332{
333 while(opt)
334 {
335 if(strcmp(opt->name, name) == 0)
336 return opt;
337 opt = opt->next;
338 }
339 return NULL;
340}
341
342#define INVALID_SB_SUBVERSION 0xffff
343
344static uint16_t parse_sb_subversion(char *str)
345{
346 int len = strlen(str);
347 uint16_t n = 0;
348 if(len == 0 || len > 4)
349 return INVALID_SB_SUBVERSION;
350 for(int i = 0; i < len; i++)
351 {
352 if(!isdigit(str[i]))
353 return INVALID_SB_SUBVERSION;
354 n = n << 4 | (str[i] - '0');
355 }
356 return n;
357}
358
359bool db_parse_sb_version(struct sb_version_t *ver, char *str)
360{
361 int len = strlen(str);
362 int cnt = 0;
363 int pos[2];
364
365 for(int i = 0; i < len; i++)
366 {
367 if(str[i] != '.')
368 continue;
369 if(cnt == 2)
370 return false;
371 pos[cnt++] = i + 1;
372 str[i] = 0;
373 }
374 if(cnt != 2)
375 return false;
376 ver->major = parse_sb_subversion(str);
377 ver->minor = parse_sb_subversion(str + pos[0]);
378 ver->revision = parse_sb_subversion(str + pos[1]);
379 return ver->major != INVALID_SB_SUBVERSION &&
380 ver->minor != INVALID_SB_SUBVERSION &&
381 ver->revision != INVALID_SB_SUBVERSION;
382}
383
384#undef parse_error
385#define parse_error(lexem, ...) \
386 do { fprintf(stderr, "%s:%d: ", lexem.file, lexem.line); \
387 fprintf(stderr, __VA_ARGS__); exit(2); } while(0)
388
389struct lex_ctx_t
390{
391 struct context_t ctx;
392 struct lexem_t lexem;
393};
394
395/* When lexems hold strings (like identifier), it might be useful to steal
396 * the pointer and don't clean the lexem but in other case, one don't want
397 * to keep the pointer to the string and just want to release the memory.
398 * Thus clean_lexem should be true except when one keeps a pointer */
399static inline void next(struct lex_ctx_t *ctx, bool clean_lexem)
400{
401 if(clean_lexem)
402 free(ctx->lexem.str);
403 memset(&ctx->lexem, 0, sizeof(struct lexem_t));
404 next_lexem(&ctx->ctx, &ctx->lexem);
405}
406
407static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
408{
409 uint32_t ret = 0;
410 if(ctx->lexem.type == LEX_NUMBER)
411 ret = ctx->lexem.num;
412 else if(ctx->lexem.type == LEX_IDENTIFIER)
413 {
414 struct cmd_option_t *c = db_find_option_by_id(const_list, ctx->lexem.str);
415 if(c == NULL)
416 parse_error(ctx->lexem, "Undefined reference to constant '%s'\n", ctx->lexem.str);
417 if(c->is_string)
418 parse_error(ctx->lexem, "Internal error: constant '%s' is not an integer\n", ctx->lexem.str);
419 ret = c->val;
420 }
421 else
422 parse_error(ctx->lexem, "Number or constant identifier expected\n");
423 next(ctx, true);
424 return ret;
425}
426
427static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
428{
429 uint32_t v = parse_term_expr(ctx, const_list);
430 while(ctx->lexem.type == LEX_LSHIFT)
431 {
432 next(ctx, true);
433 v <<= parse_term_expr(ctx, const_list);
434 }
435 return v;
436}
437
438static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
439{
440 uint32_t v = parse_shift_expr(ctx, const_list);
441 while(ctx->lexem.type == LEX_OR)
442 {
443 next(ctx, true);
444 v |= parse_shift_expr(ctx, const_list);
445 }
446 return v;
447}
448
449static uint32_t parse_intexpr(struct lex_ctx_t *ctx, struct cmd_option_t *const_list)
450{
451 return parse_or_expr(ctx, const_list);
452}
453
454#define NR_INITIAL_CONSTANTS 4
455static char *init_const_name[NR_INITIAL_CONSTANTS] = {"true", "false", "yes", "no"};
456static uint32_t init_const_value[NR_INITIAL_CONSTANTS] = {1, 0, 1, 0};
457
458struct cmd_file_t *db_parse_file(const char *file)
459{
460 size_t size;
461 FILE *f = fopen(file, "r");
462 if(f == NULL)
463 bugp("Cannot open file '%s'", file);
464 fseek(f, 0, SEEK_END);
465 size = ftell(f);
466 fseek(f, 0, SEEK_SET);
467 char *buf = xmalloc(size);
468 if(fread(buf, size, 1, f) != 1)
469 bugp("Cannot read file '%s'", file);
470 fclose(f);
471
472 if(g_debug)
473 printf("Parsing db file '%s'\n", file);
474 struct cmd_file_t *cmd_file = xmalloc(sizeof(struct cmd_file_t));
475 memset(cmd_file, 0, sizeof(struct cmd_file_t));
476
477 /* add initial constants */
478 for(int i = 0; i < NR_INITIAL_CONSTANTS; i++)
479 {
480 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
481 memset(opt, 0, sizeof(struct cmd_option_t));
482 opt->name = strdup(init_const_name[i]);
483 opt->is_string = false;
484 opt->val = init_const_value[i];
485 opt->next = cmd_file->constant_list;
486 cmd_file->constant_list = opt;
487 }
488
489 struct lex_ctx_t lctx;
490 lctx.ctx.file = file;
491 lctx.ctx.line = 1;
492 lctx.ctx.begin = buf;
493 lctx.ctx.ptr = buf;
494 lctx.ctx.end = buf + size;
495 #define next(clean_lexem) next(&lctx, clean_lexem)
496 #define lexem lctx.lexem
497 /* init lexer */
498 next(false); /* don't clean init lexem because it doesn't exist */
499 /* constants ? */
500 if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants"))
501 {
502 next(true);
503 if(lexem.type != LEX_LBRACE)
504 parse_error(lexem, "'{' expected after 'constants'\n");
505
506 while(true)
507 {
508 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
509 memset(opt, 0, sizeof(struct cmd_option_t));
510 next(true);
511 if(lexem.type == LEX_RBRACE)
512 break;
513 if(lexem.type != LEX_IDENTIFIER)
514 parse_error(lexem, "Identifier expected in constants\n");
515 opt->name = lexem.str;
516 next(false); /* lexem string is kept as option name */
517 if(lexem.type != LEX_EQUAL)
518 parse_error(lexem, "'=' expected after identifier\n");
519 next(true);
520 opt->is_string = false;
521 opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
522 opt->next = cmd_file->constant_list;
523 cmd_file->constant_list = opt;
524 if(lexem.type != LEX_SEMICOLON)
525 parse_error(lexem, "';' expected after string\n");
526 }
527 next(true);
528 }
529 /* options ? */
530 if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options"))
531 {
532 next(true);
533 if(lexem.type != LEX_LBRACE)
534 parse_error(lexem, "'{' expected after 'options'\n");
535
536 while(true)
537 {
538 next(true);
539 if(lexem.type == LEX_RBRACE)
540 break;
541 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
542 memset(opt, 0, sizeof(struct cmd_option_t));
543 if(lexem.type != LEX_IDENTIFIER)
544 parse_error(lexem, "Identifier expected in options\n");
545 opt->name = lexem.str;
546 next(false); /* lexem string is kept as option name */
547 if(lexem.type != LEX_EQUAL)
548 parse_error(lexem, "'=' expected after identifier\n");
549 next(true);
550 if(lexem.type == LEX_STRING)
551 {
552 opt->is_string = true;
553 opt->str = lexem.str;
554 next(false); /* lexem string is kept as option name */
555 }
556 else
557 {
558 opt->is_string = false;
559 opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
560 }
561 opt->next = cmd_file->opt_list;
562 cmd_file->opt_list = opt;
563 if(lexem.type != LEX_SEMICOLON)
564 parse_error(lexem, "';' expected after string\n");
565 }
566 next(true);
567 }
568 /* sources */
569 if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources"))
570 parse_error(lexem, "'sources' expected\n");
571 next(true);
572 if(lexem.type != LEX_LBRACE)
573 parse_error(lexem, "'{' expected after 'sources'\n");
574
575 while(true)
576 {
577 next(true);
578 if(lexem.type == LEX_RBRACE)
579 break;
580 struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t));
581 memset(src, 0, sizeof(struct cmd_source_t));
582 if(lexem.type != LEX_IDENTIFIER)
583 parse_error(lexem, "identifier expected in sources\n");
584 src->identifier = lexem.str;
585 next(false); /* lexem string is kept as source name */
586 if(lexem.type != LEX_EQUAL)
587 parse_error(lexem, "'=' expected after identifier\n");
588 next(true);
589 if(lexem.type == LEX_STRING)
590 {
591 src->is_extern = false;
592 src->filename = lexem.str;
593 next(false); /* lexem string is kept as file name */
594 }
595 else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern"))
596 {
597 src->is_extern = true;
598 src->filename = strdup("<extern>"); /* duplicate because it will be free'd */
599 next(true);
600 if(lexem.type != LEX_LPAREN)
601 parse_error(lexem, "'(' expected after 'extern'\n");
602 next(true);
603 src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list);
604 if(lexem.type != LEX_RPAREN)
605 parse_error(lexem, "')' expected\n");
606 next(true);
607 }
608 else
609 parse_error(lexem, "String or 'extern' expected after '='\n");
610 if(lexem.type != LEX_SEMICOLON)
611 parse_error(lexem, "';' expected\n");
612 if(db_find_source_by_id(cmd_file, src->identifier) != NULL)
613 parse_error(lexem, "Duplicate source identifier\n");
614 /* type filled later */
615 src->type = CMD_SRC_UNK;
616 src->next = cmd_file->source_list;
617 cmd_file->source_list = src;
618 }
619
620 /* sections */
621 struct cmd_section_t *end_sec = NULL;
622 while(true)
623 {
624 next(true);
625 if(lexem.type == LEX_EOF)
626 break;
627 struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
628 struct cmd_inst_t *end_list = NULL;
629 memset(sec, 0, sizeof(struct cmd_section_t));
630 if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
631 parse_error(lexem, "'section' expected\n");
632 next(true);
633 if(lexem.type != LEX_LPAREN)
634 parse_error(lexem, "'(' expected after 'section'\n");
635 next(true);
636 /* can be any number */
637 sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list);
638 /* options ? */
639 if(lexem.type == LEX_SEMICOLON)
640 {
641 do
642 {
643 next(true);
644 struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
645 memset(opt, 0, sizeof(struct cmd_option_t));
646 if(lexem.type != LEX_IDENTIFIER)
647 parse_error(lexem, "Identifier expected for section option\n");
648 opt->name = lexem.str;
649 next(false); /* lexem string is kept as option name */
650 if(lexem.type != LEX_EQUAL)
651 parse_error(lexem, "'=' expected after option identifier\n");
652 next(true);
653 if(lexem.type == LEX_STRING)
654 {
655 opt->is_string = true;
656 opt->str = lexem.str;
657 next(false); /* lexem string is kept as option string */
658 }
659 else
660 {
661 opt->is_string = false;
662 opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
663 }
664 opt->next = sec->opt_list;
665 sec->opt_list = opt;
666 }while(lexem.type == LEX_COLON);
667 }
668 if(lexem.type != LEX_RPAREN)
669 parse_error(lexem, "')' expected after section identifier\n");
670 next(true);
671 if(lexem.type == LEX_LBRACE)
672 {
673 sec->is_data = false;
674 /* commands */
675 while(true)
676 {
677 next(true);
678 if(lexem.type == LEX_RBRACE)
679 break;
680 struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
681 memset(inst, 0, sizeof(struct cmd_inst_t));
682 if(lexem.type != LEX_IDENTIFIER)
683 parse_error(lexem, "Instruction expected in section\n");
684 if(strcmp(lexem.str, "load") == 0)
685 inst->type = CMD_LOAD;
686 else if(strcmp(lexem.str, "call") == 0)
687 inst->type = CMD_CALL;
688 else if(strcmp(lexem.str, "jump") == 0)
689 inst->type = CMD_JUMP;
690 else if(strcmp(lexem.str, "mode") == 0)
691 inst->type = CMD_MODE;
692 else
693 parse_error(lexem, "Instruction expected in section\n");
694 next(true);
695
696 if(inst->type == CMD_LOAD)
697 {
698 if(lexem.type != LEX_IDENTIFIER)
699 parse_error(lexem, "Identifier expected after instruction\n");
700 inst->identifier = lexem.str;
701 if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
702 parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
703 next(false); /* lexem string kept as identifier */
704 if(lexem.type == LEX_RANGLE)
705 {
706 // load at
707 inst->type = CMD_LOAD_AT;
708 next(true);
709 inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
710 }
711 if(lexem.type != LEX_SEMICOLON)
712 parse_error(lexem, "';' expected after command\n");
713 }
714 else if(inst->type == CMD_CALL || inst->type == CMD_JUMP)
715 {
716 if(lexem.type == LEX_IDENTIFIER)
717 {
718 inst->identifier = lexem.str;
719 if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
720 parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
721 next(false); /* lexem string kept as identifier */
722 }
723 else
724 {
725 inst->type = (inst->type == CMD_CALL) ? CMD_CALL_AT : CMD_JUMP_AT;
726 inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
727 }
728
729 if(lexem.type == LEX_LPAREN)
730 {
731 next(true);
732 inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
733 if(lexem.type != LEX_RPAREN)
734 parse_error(lexem, "Expected closing brace\n");
735 next(true);
736 }
737 if(lexem.type != LEX_SEMICOLON)
738 parse_error(lexem, "';' expected after command\n");
739 }
740 else if(inst->type == CMD_MODE)
741 {
742 inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
743 if(lexem.type != LEX_SEMICOLON)
744 parse_error(lexem, "Expected ';' after command\n");
745 }
746 else
747 parse_error(lexem, "Internal error");
748 if(end_list == NULL)
749 {
750 sec->inst_list = inst;
751 end_list = inst;
752 }
753 else
754 {
755 end_list->next = inst;
756 end_list = inst;
757 }
758 }
759 }
760 else if(lexem.type == LEX_LE)
761 {
762 sec->is_data = true;
763 next(true);
764 if(lexem.type != LEX_IDENTIFIER)
765 parse_error(lexem, "Identifier expected after '<='\n");
766 sec->source_id = lexem.str;
767 next(false); /* lexem string is kept as source id */
768 if(lexem.type != LEX_SEMICOLON)
769 parse_error(lexem, "';' expected after identifier\n");
770 }
771 else
772 parse_error(lexem, "'{' or '<=' expected after section directive\n");
773
774 if(end_sec == NULL)
775 {
776 cmd_file->section_list = sec;
777 end_sec = sec;
778 }
779 else
780 {
781 end_sec->next = sec;
782 end_sec = sec;
783 }
784 }
785 #undef lexem
786 #undef next
787
788 free(buf);
789 return cmd_file;
790}
791
792void db_generate_default_sb_version(struct sb_version_t *ver)
793{
794 ver->major = ver->minor = ver->revision = 0x999;
795}
796
797void db_free_option_list(struct cmd_option_t *opt_list)
798{
799 while(opt_list)
800 {
801 struct cmd_option_t *next = opt_list->next;
802 fflush(stdout);
803 free(opt_list->name);
804 free(opt_list->str);
805 free(opt_list);
806 opt_list = next;
807 }
808}
809
810void db_free(struct cmd_file_t *file)
811{
812 db_free_option_list(file->opt_list);
813 db_free_option_list(file->constant_list);
814 struct cmd_source_t *src = file->source_list;
815 while(src)
816 {
817 struct cmd_source_t *next = src->next;
818 free(src->identifier);
819 fflush(stdout);
820 free(src->filename);
821 if(src->loaded)
822 {
823 if(src->type == CMD_SRC_BIN)
824 free(src->bin.data);
825 if(src->type == CMD_SRC_ELF)
826 elf_release(&src->elf);
827 }
828 free(src);
829 src = next;
830 }
831 struct cmd_section_t *sec = file->section_list;
832 while(sec)
833 {
834 struct cmd_section_t *next = sec->next;
835 db_free_option_list(sec->opt_list);
836 free(sec->source_id);
837 struct cmd_inst_t *inst = sec->inst_list;
838 while(inst)
839 {
840 struct cmd_inst_t *next = inst->next;
841 free(inst->identifier);
842 free(inst);
843 inst = next;
844 }
845 free(sec);
846 sec = next;
847 }
848 free(file);
849}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef __DBPARSER__
22#define __DBPARSER__
23
24/**
25 * Command file parsing
26 */
27#include "sb.h"
28#include "elf.h"
29
30enum cmd_source_type_t
31{
32 CMD_SRC_UNK,
33 CMD_SRC_ELF,
34 CMD_SRC_BIN
35};
36
37struct bin_param_t
38{
39 uint32_t size;
40 void *data;
41};
42
43struct cmd_source_t
44{
45 char *identifier;
46 bool is_extern;
47 // <union>
48 int extern_nr;
49 char *filename;
50 // </union>
51 struct cmd_source_t *next;
52 /* for later use */
53 enum cmd_source_type_t type;
54 bool loaded;
55 struct elf_params_t elf;
56 struct bin_param_t bin;
57};
58
59enum cmd_inst_type_t
60{
61 CMD_LOAD, /* load image */
62 CMD_JUMP, /* jump at image */
63 CMD_CALL, /* call image */
64 CMD_LOAD_AT, /* load binary at */
65 CMD_CALL_AT, /* call at address */
66 CMD_JUMP_AT, /* jump at address */
67 CMD_MODE, /* change boot mode */
68};
69
70struct cmd_inst_t
71{
72 enum cmd_inst_type_t type;
73 char *identifier;
74 uint32_t argument; // for jump, call, mode
75 uint32_t addr; // for 'at'
76 struct cmd_inst_t *next;
77};
78
79struct cmd_option_t
80{
81 char *name;
82 bool is_string;
83 /* <union> */
84 uint32_t val;
85 char *str;
86 /* </union> */
87 struct cmd_option_t *next;
88};
89
90struct cmd_section_t
91{
92 uint32_t identifier;
93 bool is_data;
94 // <union>
95 struct cmd_inst_t *inst_list;
96 char *source_id;
97 // </union>
98 struct cmd_section_t *next;
99 struct cmd_option_t *opt_list;
100};
101
102struct cmd_file_t
103{
104 struct cmd_option_t *opt_list;
105 struct cmd_option_t *constant_list; /* constant are always integers */
106 struct cmd_source_t *source_list;
107 struct cmd_section_t *section_list;
108};
109
110struct cmd_source_t *db_find_source_by_id(struct cmd_file_t *cmd_file, const char *id);
111struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *name);
112bool db_parse_sb_version(struct sb_version_t *ver, char *str);
113void db_generate_default_sb_version(struct sb_version_t *ver);
114struct cmd_file_t *db_parse_file(const char *file);
115void db_free_option_list(struct cmd_option_t *opt_list);
116void db_free(struct cmd_file_t *file);
117
118#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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "elf.h"
22#include "misc.h"
23
24/**
25 * Definitions
26 * taken from elf.h linux header
27 * based on ELF specification
28 * based on ARM ELF specification
29 */
30typedef uint16_t Elf32_Half;
31
32typedef uint32_t Elf32_Word;
33typedef int32_t Elf32_Sword;
34typedef uint32_t Elf32_Addr;
35typedef uint32_t Elf32_Off;
36typedef uint16_t Elf32_Section;
37
38#define EI_NIDENT 16
39
40typedef struct
41{
42 unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
43 Elf32_Half e_type; /* Object file type */
44 Elf32_Half e_machine; /* Architecture */
45 Elf32_Word e_version; /* Object file version */
46 Elf32_Addr e_entry; /* Entry point virtual address */
47 Elf32_Off e_phoff; /* Program header table file offset */
48 Elf32_Off e_shoff; /* Section header table file offset */
49 Elf32_Word e_flags; /* Processor-specific flags */
50 Elf32_Half e_ehsize; /* ELF header size in bytes */
51 Elf32_Half e_phentsize; /* Program header table entry size */
52 Elf32_Half e_phnum; /* Program header table entry count */
53 Elf32_Half e_shentsize; /* Section header table entry size */
54 Elf32_Half e_shnum; /* Section header table entry count */
55 Elf32_Half e_shstrndx; /* Section header string table index */
56}Elf32_Ehdr;
57
58#define EI_MAG0 0 /* File identification byte 0 index */
59#define ELFMAG0 0x7f /* Magic number byte 0 */
60
61#define EI_MAG1 1 /* File identification byte 1 index */
62#define ELFMAG1 'E' /* Magic number byte 1 */
63
64#define EI_MAG2 2 /* File identification byte 2 index */
65#define ELFMAG2 'L' /* Magic number byte 2 */
66
67#define EI_MAG3 3 /* File identification byte 3 index */
68#define ELFMAG3 'F' /* Magic number byte 3 */
69
70#define EI_CLASS 4 /* File class byte index */
71#define ELFCLASS32 1 /* 32-bit objects */
72
73#define EI_DATA 5 /* Data encoding byte index */
74#define ELFDATA2LSB 1 /* 2's complement, little endian */
75
76#define EI_VERSION 6 /* File version byte index, Value must be EV_CURRENT */
77
78#define EI_OSABI 7 /* OS ABI identification */
79#define ELFOSABI_NONE 0 /* UNIX System V ABI */
80#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */
81#define ELFOSABI_ARM 97 /* ARM */
82
83#define EI_ABIVERSION 8 /* ABI version */
84
85#define EI_PAD 9 /* Byte index of padding bytes */
86
87#define ET_EXEC 2 /* Executable file */
88
89#define EM_ARM 40 /* ARM */
90
91#define EV_CURRENT 1 /* Current version */
92
93#define EF_ARM_HASENTRY 0x00000002
94
95#define SHN_UNDEF 0 /* Undefined section */
96
97typedef struct
98{
99 Elf32_Word sh_name; /* Section name (string tbl index) */
100 Elf32_Word sh_type; /* Section type */
101 Elf32_Word sh_flags; /* Section flags */
102 Elf32_Addr sh_addr; /* Section virtual addr at execution */
103 Elf32_Off sh_offset; /* Section file offset */
104 Elf32_Word sh_size; /* Section size in bytes */
105 Elf32_Word sh_link; /* Link to another section */
106 Elf32_Word sh_info; /* Additional section information */
107 Elf32_Word sh_addralign; /* Section alignment */
108 Elf32_Word sh_entsize; /* Entry size if section holds table */
109}Elf32_Shdr;
110
111#define SHT_NULL 0 /* Section header table entry unused */
112#define SHT_PROGBITS 1 /* Program data */
113#define SHT_SYMTAB 2 /* Symbol table */
114#define SHT_STRTAB 3 /* String table */
115#define SHT_RELA 4 /* Relocation entries with addends */
116#define SHT_HASH 5 /* Symbol hash table */
117#define SHT_DYNAMIC 6 /* Dynamic linking information */
118#define SHT_NOTE 7 /* Notes */
119#define SHT_NOBITS 8 /* Program space with no data (bss) */
120#define SHT_REL 9 /* Relocation entries, no addends */
121#define SHT_SHLIB 10 /* Reserved */
122#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
123#define SHT_INIT_ARRAY 14 /* Array of constructors */
124#define SHT_FINI_ARRAY 15 /* Array of destructors */
125#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
126#define SHT_GROUP 17 /* Section group */
127#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
128#define SHT_NUM 19 /* Number of defined types. */
129
130#define SHF_WRITE (1 << 0) /* Writable */
131#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
132#define SHF_EXECINSTR (1 << 2) /* Executable */
133#define SHF_MERGE (1 << 4) /* Might be merged */
134#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
135
136typedef struct
137{
138 Elf32_Word p_type; /* Segment type */
139 Elf32_Off p_offset; /* Segment file offset */
140 Elf32_Addr p_vaddr; /* Segment virtual address */
141 Elf32_Addr p_paddr; /* Segment physical address */
142 Elf32_Word p_filesz; /* Segment size in file */
143 Elf32_Word p_memsz; /* Segment size in memory */
144 Elf32_Word p_flags; /* Segment flags */
145 Elf32_Word p_align; /* Segment alignment */
146}Elf32_Phdr;
147
148#define PT_LOAD 1 /* Loadable program segment */
149
150#define PF_X (1 << 0) /* Segment is executable */
151#define PF_W (1 << 1) /* Segment is writable */
152#define PF_R (1 << 2) /* Segment is readable */
153
154void elf_init(struct elf_params_t *params)
155{
156 memset(params, 0, sizeof(struct elf_params_t));
157}
158
159extern void *xmalloc(size_t s);
160
161static struct elf_section_t *elf_add_section(struct elf_params_t *params)
162{
163 struct elf_section_t *sec = xmalloc(sizeof(struct elf_section_t));
164 if(params->first_section == NULL)
165 params->first_section = params->last_section = sec;
166 else
167 {
168 params->last_section->next = sec;
169 params->last_section = sec;
170 }
171 sec->next = NULL;
172
173 return sec;
174}
175
176static struct elf_segment_t *elf_add_segment(struct elf_params_t *params)
177{
178 struct elf_segment_t *seg = xmalloc(sizeof(struct elf_section_t));
179 if(params->first_segment == NULL)
180 params->first_segment = params->last_segment = seg;
181 else
182 {
183 params->last_segment->next = seg;
184 params->last_segment = seg;
185 }
186 seg->next = NULL;
187
188 return seg;
189}
190
191void elf_add_load_section(struct elf_params_t *params,
192 uint32_t load_addr, uint32_t size, const void *section)
193{
194 struct elf_section_t *sec = elf_add_section(params);
195
196 sec->type = EST_LOAD;
197 sec->addr = load_addr;
198 sec->size = size;
199 sec->section = xmalloc(size);
200 memcpy(sec->section, section, size);
201}
202
203void elf_add_fill_section(struct elf_params_t *params,
204 uint32_t fill_addr, uint32_t size, uint32_t pattern)
205{
206 if(pattern != 0x00)
207 {
208 printf("oops, non-zero filling, ignore fill section\n");
209 return;
210 }
211
212 struct elf_section_t *sec = elf_add_section(params);
213
214 sec->type = EST_FILL;
215 sec->addr = fill_addr;
216 sec->size = size;
217 sec->pattern = pattern;
218}
219
220void elf_write_file(struct elf_params_t *params, elf_write_fn_t write,
221 elf_printf_fn_t printf, void *user)
222{
223 (void) printf;
224
225 Elf32_Ehdr ehdr;
226 uint32_t phnum = 0;
227 struct elf_section_t *sec = params->first_section;
228 uint32_t offset = 0;
229 Elf32_Phdr phdr;
230 Elf32_Shdr shdr;
231 memset(&ehdr, 0, EI_NIDENT);
232
233 while(sec)
234 {
235 if(sec->type == EST_LOAD)
236 {
237 sec->offset = offset;
238 offset += sec->size;
239 }
240 else
241 {
242 sec->offset = 0;
243 }
244
245 phnum++;
246 sec = sec->next;
247 }
248
249 uint32_t strtbl_offset = offset;
250
251 ehdr.e_ident[EI_MAG0] = ELFMAG0;
252 ehdr.e_ident[EI_MAG1] = ELFMAG1;
253 ehdr.e_ident[EI_MAG2] = ELFMAG2;
254 ehdr.e_ident[EI_MAG3] = ELFMAG3;
255 ehdr.e_ident[EI_CLASS] = ELFCLASS32;
256 ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
257 ehdr.e_ident[EI_VERSION] = EV_CURRENT;
258 ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE;
259 ehdr.e_ident[EI_ABIVERSION] = 0;
260 ehdr.e_type = ET_EXEC;
261 ehdr.e_machine = EM_ARM;
262 ehdr.e_version = EV_CURRENT;
263 ehdr.e_entry = params->start_addr;
264 ehdr.e_flags = 0;
265 if(params->has_start_addr)
266 ehdr.e_flags |= EF_ARM_HASENTRY;
267 ehdr.e_ehsize = sizeof ehdr;
268 ehdr.e_phentsize = sizeof phdr;
269 ehdr.e_phnum = phnum;
270 ehdr.e_shentsize = sizeof shdr;
271 ehdr.e_shnum = phnum + 2; /* one for section 0 and one for string table */
272 ehdr.e_shstrndx = ehdr.e_shnum - 1;
273 ehdr.e_phoff = ehdr.e_ehsize;
274 ehdr.e_shoff = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize;
275
276 write(user, 0, &ehdr, sizeof ehdr);
277
278 /* allocate enough size to hold any combinaison of .text/.bss in the string table:
279 * - one empty name ("\0")
280 * - at most N names of the form ".textXXXX\0" or ".bssXXXX\0"
281 * - one name ".shstrtab\0" */
282 char *strtbl_content = malloc(1 + strlen(".shstrtab") + 1 +
283 phnum * (strlen(".textXXXX") + 1));
284
285 strtbl_content[0] = '\0';
286 strcpy(&strtbl_content[1], ".shstrtab");
287 uint32_t strtbl_index = 1 + strlen(".shstrtab") + 1;
288
289 uint32_t data_offset = ehdr.e_ehsize + ehdr.e_phnum * ehdr.e_phentsize +
290 ehdr.e_shnum * ehdr.e_shentsize;
291
292 sec = params->first_section;
293 offset = ehdr.e_phoff;
294 while(sec)
295 {
296 sec->offset += data_offset;
297
298 phdr.p_type = PT_LOAD;
299 if(sec->type == EST_LOAD)
300 phdr.p_offset = sec->offset;
301 else
302 phdr.p_offset = 0;
303 phdr.p_paddr = sec->addr;
304 phdr.p_vaddr = phdr.p_paddr; /* assume identity map ? */
305 phdr.p_memsz = sec->size;
306 if(sec->type == EST_LOAD)
307 phdr.p_filesz = phdr.p_memsz;
308 else
309 phdr.p_filesz = 0;
310 phdr.p_flags = PF_X | PF_W | PF_R;
311 phdr.p_align = 0;
312
313 write(user, offset, &phdr, sizeof phdr);
314
315 offset += sizeof(Elf32_Phdr);
316 sec = sec->next;
317 }
318
319 sec = params->first_section;
320 offset = ehdr.e_shoff;
321
322 {
323 shdr.sh_name = 0;
324 shdr.sh_type = SHT_NULL;
325 shdr.sh_flags = 0;
326 shdr.sh_addr = 0;
327 shdr.sh_offset = 0;
328 shdr.sh_size = 0;
329 shdr.sh_link = SHN_UNDEF;
330 shdr.sh_info = 0;
331 shdr.sh_addralign = 0;
332 shdr.sh_entsize = 0;
333
334 write(user, offset, &shdr, sizeof shdr);
335
336 offset += sizeof(Elf32_Shdr);
337 }
338
339 uint32_t text_idx = 0;
340 uint32_t bss_idx = 0;
341 while(sec)
342 {
343 shdr.sh_name = strtbl_index;
344 if(sec->type == EST_LOAD)
345 {
346 strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".text%d", text_idx++);
347 shdr.sh_type = SHT_PROGBITS;
348 }
349 else
350 {
351 strtbl_index += 1 + sprintf(&strtbl_content[strtbl_index], ".bss%d", bss_idx++);
352 shdr.sh_type = SHT_NOBITS;
353 }
354 shdr.sh_flags = SHF_ALLOC | SHF_EXECINSTR;
355 shdr.sh_addr = sec->addr;
356 shdr.sh_offset = sec->offset;
357 shdr.sh_size = sec->size;
358 shdr.sh_link = SHN_UNDEF;
359 shdr.sh_info = 0;
360 shdr.sh_addralign = 1;
361 shdr.sh_entsize = 0;
362
363 write(user, offset, &shdr, sizeof shdr);
364
365 offset += sizeof(Elf32_Shdr);
366 sec = sec->next;
367 }
368
369 {
370 shdr.sh_name = 1;
371 shdr.sh_type = SHT_STRTAB;
372 shdr.sh_flags = 0;
373 shdr.sh_addr = 0;
374 shdr.sh_offset = strtbl_offset + data_offset;
375 shdr.sh_size = strtbl_index;
376 shdr.sh_link = SHN_UNDEF;
377 shdr.sh_info = 0;
378 shdr.sh_addralign = 1;
379 shdr.sh_entsize = 0;
380
381 write(user, offset, &shdr, sizeof shdr);
382
383 offset += sizeof(Elf32_Shdr);
384 }
385
386 sec = params->first_section;
387 while(sec)
388 {
389 if(sec->type == EST_LOAD)
390 write(user, sec->offset, sec->section, sec->size);
391 sec = sec->next;
392 }
393
394 write(user, strtbl_offset + data_offset, strtbl_content, strtbl_index);
395 free(strtbl_content);
396}
397
398bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
399 elf_printf_fn_t printf, void *user)
400{
401 #define error_printf(...) ({printf(user, true, __VA_ARGS__); return false;})
402
403 /* read header */
404 Elf32_Ehdr ehdr;
405 if(!read(user, 0, &ehdr, sizeof(ehdr)))
406 {
407 printf(user, true, "error reading elf header\n");
408 return false;
409 }
410 /* basic checks */
411 if(ehdr.e_ident[EI_MAG0] != ELFMAG0 || ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
412 ehdr.e_ident[EI_MAG2] != ELFMAG2 || ehdr.e_ident[EI_MAG3] != ELFMAG3)
413 error_printf("invalid elf header\n");
414 if(ehdr.e_ident[EI_CLASS] != ELFCLASS32)
415 error_printf("invalid elf class: must be a 32-bit object\n");
416 if(ehdr.e_ident[EI_DATA] != ELFDATA2LSB)
417 error_printf("invalid elf data encoding: must be 32-bit lsb\n");
418 if(ehdr.e_ident[EI_VERSION] != EV_CURRENT)
419 error_printf("invalid elf version\n");
420 if(ehdr.e_type != ET_EXEC)
421 error_printf("invalid elf file: must be an executable file\n");
422 if(ehdr.e_machine != EM_ARM)
423 error_printf("invalid elf file: must target an arm machine\n");
424 if(ehdr.e_ehsize != sizeof(ehdr))
425 error_printf("invalid elf file: size header mismatch\n");
426 if(ehdr.e_phnum > 0 && ehdr.e_phentsize != sizeof(Elf32_Phdr))
427 error_printf("invalid elf file: program header size mismatch\n");
428 if(ehdr.e_shnum > 0 && ehdr.e_shentsize != sizeof(Elf32_Shdr))
429 error_printf("invalid elf file: section header size mismatch\n");
430 elf_set_start_addr(params, ehdr.e_entry);
431
432 char *strtab = NULL;
433 if(ehdr.e_shstrndx != SHN_UNDEF)
434 {
435 Elf32_Shdr shstrtab;
436 if(read(user, ehdr.e_shoff + ehdr.e_shstrndx * ehdr.e_shentsize,
437 &shstrtab, sizeof(shstrtab)))
438 {
439 strtab = xmalloc(shstrtab.sh_size);
440 if(!read(user, shstrtab.sh_offset, strtab, shstrtab.sh_size))
441 {
442 free(strtab);
443 strtab = NULL;
444 }
445 }
446 }
447 /* run through sections */
448 printf(user, false, "ELF file:\n");
449 for(int i = 1; i < ehdr.e_shnum; i++)
450 {
451 uint32_t off = ehdr.e_shoff + i * ehdr.e_shentsize;
452 Elf32_Shdr shdr;
453 memset(&shdr, 0, sizeof(shdr));
454 if(!read(user, off, &shdr, sizeof(shdr)))
455 error_printf("error reading elf section header");
456
457 if(shdr.sh_type == SHT_PROGBITS && shdr.sh_flags & SHF_ALLOC)
458 {
459 void *data = xmalloc(shdr.sh_size);
460 if(!read(user, shdr.sh_offset, data, shdr.sh_size))
461 error_printf("error read self section data\n");
462 elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data);
463 free(data);
464
465 if(strtab)
466 printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]);
467 }
468 else if(shdr.sh_type == SHT_NOBITS && shdr.sh_flags & SHF_ALLOC)
469 {
470 elf_add_fill_section(params, shdr.sh_addr, shdr.sh_size, 0);
471 if(strtab)
472 printf(user, false, "create fill segment for %s\n", &strtab[shdr.sh_name]);
473 }
474 else
475 {
476 if(strtab)
477 printf(user, false, "filter out %s\n", &strtab[shdr.sh_name], shdr.sh_type);
478 }
479
480 }
481 free(strtab);
482 /* run through segments */
483 for(int i = 1; i < ehdr.e_phnum; i++)
484 {
485 uint32_t off = ehdr.e_phoff + i * ehdr.e_phentsize;
486 Elf32_Phdr phdr;
487 memset(&phdr, 0, sizeof(phdr));
488 if(!read(user, off, &phdr, sizeof(phdr)))
489 error_printf("error reading elf segment header");
490 if(phdr.p_type != PT_LOAD)
491 continue;
492 struct elf_segment_t *seg = elf_add_segment(params);
493 seg->vaddr = phdr.p_vaddr;
494 seg->paddr = phdr.p_paddr;
495 seg->vsize = phdr.p_memsz;
496 seg->psize = phdr.p_filesz;
497 printf(user, false, "create segment [%#x,+%#x[ -> [%#x,+%#x[\n",
498 seg->vaddr, seg->vsize, seg->paddr, seg->psize);
499 }
500
501 return true;
502}
503
504uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr)
505{
506 struct elf_segment_t *seg = params->first_segment;
507 while(seg)
508 {
509 if(seg->vaddr <= addr && addr < seg->vaddr + seg->vsize)
510 return addr - seg->vaddr + seg->paddr;
511 seg = seg->next;
512 }
513 return addr;
514}
515
516void elf_translate_addresses(struct elf_params_t *params)
517{
518 struct elf_section_t *sec = params->first_section;
519 while(sec)
520 {
521 sec->addr = elf_translate_virtual_address(params, sec->addr);
522 sec = sec->next;
523 }
524 params->start_addr = elf_translate_virtual_address(params, params->start_addr);
525}
526
527bool elf_is_empty(struct elf_params_t *params)
528{
529 return params->first_section == NULL;
530}
531
532void elf_set_start_addr(struct elf_params_t *params, uint32_t addr)
533{
534 params->has_start_addr = true;
535 params->start_addr = addr;
536}
537
538bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr)
539{
540 if(params->has_start_addr && addr != NULL)
541 *addr = params->start_addr;
542 return params->has_start_addr;
543}
544
545int elf_get_nr_sections(struct elf_params_t *params)
546{
547 int nr = 0;
548 struct elf_section_t *sec = params->first_section;
549 while(sec)
550 {
551 nr++;
552 sec = sec->next;
553 }
554 return nr;
555}
556
557void elf_release(struct elf_params_t *params)
558{
559 struct elf_section_t *sec = params->first_section;
560 while(sec)
561 {
562 struct elf_section_t *next_sec = sec->next;
563 if(sec->type == EST_LOAD)
564 free(sec->section);
565 free(sec);
566 sec = next_sec;
567 }
568 struct elf_segment_t *seg = params->first_segment;
569 while(seg)
570 {
571 struct elf_segment_t *next_seg = seg->next;
572 free(seg);
573 seg = next_seg;
574 }
575}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef __ELF_H__
22#define __ELF_H__
23
24#include <stdio.h>
25#include <stdint.h>
26#include <string.h>
27#include <stdbool.h>
28#include <stdlib.h>
29#include <unistd.h>
30
31/**
32 * API
33 */
34enum elf_section_type_t
35{
36 EST_LOAD,
37 EST_FILL
38};
39
40struct elf_section_t
41{
42 uint32_t addr; /* virtual address */
43 uint32_t size; /* virtual size */
44 enum elf_section_type_t type;
45 /* <union> */
46 void *section; /* data */
47 uint32_t pattern; /* fill pattern */
48 /* </union> */
49 struct elf_section_t *next;
50 /* Internal to elf_write_file */
51 uint32_t offset;
52};
53
54struct elf_segment_t
55{
56 uint32_t vaddr; /* virtual address */
57 uint32_t paddr; /* physical address */
58 uint32_t vsize; /* virtual size */
59 uint32_t psize; /* physical size */
60 struct elf_segment_t *next;
61};
62
63struct elf_params_t
64{
65 bool has_start_addr;
66 uint32_t start_addr;
67 struct elf_section_t *first_section;
68 struct elf_section_t *last_section;
69 struct elf_segment_t *first_segment;
70 struct elf_segment_t *last_segment;
71};
72
73typedef bool (*elf_read_fn_t)(void *user, uint32_t addr, void *buf, size_t count);
74/* write function manages it's own error state */
75typedef void (*elf_write_fn_t)(void *user, uint32_t addr, const void *buf, size_t count);
76typedef void (*elf_printf_fn_t)(void *user, bool error, const char *fmt, ...);
77
78void elf_init(struct elf_params_t *params);
79void elf_add_load_section(struct elf_params_t *params,
80 uint32_t load_addr, uint32_t size, const void *section);
81void elf_add_fill_section(struct elf_params_t *params,
82 uint32_t fill_addr, uint32_t size, uint32_t pattern);
83uint32_t elf_translate_virtual_address(struct elf_params_t *params, uint32_t addr);
84void elf_translate_addresses(struct elf_params_t *params);
85void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, elf_printf_fn_t printf, void *user);
86bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read, elf_printf_fn_t printf,
87 void *user);
88bool elf_is_empty(struct elf_params_t *params);
89void elf_set_start_addr(struct elf_params_t *params, uint32_t addr);
90bool elf_get_start_addr(struct elf_params_t *params, uint32_t *addr);
91int elf_get_nr_sections(struct elf_params_t *params);
92void elf_release(struct elf_params_t *params);
93
94#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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#define _ISOC99_SOURCE
23#define _POSIX_C_SOURCE 200809L /* for strdup */
24#include <stdio.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ctype.h>
29#include <time.h>
30#include <stdarg.h>
31#include <strings.h>
32#include <getopt.h>
33
34#include "crypto.h"
35#include "elf.h"
36#include "sb.h"
37#include "dbparser.h"
38#include "misc.h"
39#include "sb.h"
40
41char **g_extern;
42int g_extern_count;
43
44#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
45
46#define crypto_cbc(...) \
47 do { int ret = crypto_cbc(__VA_ARGS__); \
48 if(ret != CRYPTO_ERROR_SUCCESS) \
49 bug("crypto_cbc error: %d\n", ret); \
50 }while(0)
51
52/**
53 * command file to sb conversion
54 */
55
56static bool elf_read(void *user, uint32_t addr, void *buf, size_t count)
57{
58 if(fseek((FILE *)user, addr, SEEK_SET) == -1)
59 return false;
60 return fread(buf, 1, count, (FILE *)user) == count;
61}
62
63static void elf_printf(void *user, bool error, const char *fmt, ...)
64{
65 if(!g_debug && !error)
66 return;
67 (void) user;
68 va_list args;
69 va_start(args, fmt);
70 vprintf(fmt, args);
71 va_end(args);
72}
73
74static void resolve_extern(struct cmd_source_t *src)
75{
76 if(!src->is_extern)
77 return;
78 src->is_extern = false;
79 if(src->extern_nr < 0 || src->extern_nr >= g_extern_count)
80 bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr);
81 /* first free the old src->filename content */
82 free(src->filename);
83 src->filename = strdup(g_extern[src->extern_nr]);
84}
85
86static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
87{
88 struct cmd_source_t *src = db_find_source_by_id(cmd_file, id);
89 if(src == NULL)
90 bug("undefined reference to source '%s'\n", id);
91 /* avoid reloading */
92 if(src->type == CMD_SRC_ELF && src->loaded)
93 return;
94 if(src->type != CMD_SRC_UNK)
95 bug("source '%s' seen both as elf and binary file\n", id);
96 /* resolve potential extern file */
97 resolve_extern(src);
98 /* load it */
99 src->type = CMD_SRC_ELF;
100 FILE *fd = fopen(src->filename, "rb");
101 if(fd == NULL)
102 bug("cannot open '%s' (id '%s')\n", src->filename, id);
103 if(g_debug)
104 printf("Loading ELF file '%s'...\n", src->filename);
105 elf_init(&src->elf);
106 src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, fd);
107 fclose(fd);
108 if(!src->loaded)
109 bug("error loading elf file '%s' (id '%s')\n", src->filename, id);
110 elf_translate_addresses(&src->elf);
111}
112
113static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id)
114{
115 struct cmd_source_t *src = db_find_source_by_id(cmd_file, id);
116 if(src == NULL)
117 bug("undefined reference to source '%s'\n", id);
118 /* avoid reloading */
119 if(src->type == CMD_SRC_BIN && src->loaded)
120 return;
121 if(src->type != CMD_SRC_UNK)
122 bug("source '%s' seen both as elf and binary file\n", id);
123 /* resolve potential extern file */
124 resolve_extern(src);
125 /* load it */
126 src->type = CMD_SRC_BIN;
127 FILE *fd = fopen(src->filename, "rb");
128 if(fd == NULL)
129 bug("cannot open '%s' (id '%s')\n", src->filename, id);
130 if(g_debug)
131 printf("Loading BIN file '%s'...\n", src->filename);
132 fseek(fd, 0, SEEK_END);
133 src->bin.size = ftell(fd);
134 fseek(fd, 0, SEEK_SET);
135 src->bin.data = xmalloc(src->bin.size);
136 fread(src->bin.data, 1, src->bin.size, fd);
137 fclose(fd);
138 src->loaded = true;
139}
140
141static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
142{
143 struct sb_file_t *sb = xmalloc(sizeof(struct sb_file_t));
144 memset(sb, 0, sizeof(struct sb_file_t));
145
146 db_generate_default_sb_version(&sb->product_ver);
147 db_generate_default_sb_version(&sb->component_ver);
148
149 if(g_debug)
150 printf("Applying command file...\n");
151 /* count sections */
152 struct cmd_section_t *csec = cmd_file->section_list;
153 while(csec)
154 {
155 sb->nr_sections++;
156 csec = csec->next;
157 }
158
159 sb->sections = xmalloc(sb->nr_sections * sizeof(struct sb_section_t));
160 memset(sb->sections, 0, sb->nr_sections * sizeof(struct sb_section_t));
161 /* flatten sections */
162 csec = cmd_file->section_list;
163 for(int i = 0; i < sb->nr_sections; i++, csec = csec->next)
164 {
165 struct sb_section_t *sec = &sb->sections[i];
166 sec->identifier = csec->identifier;
167
168 /* options */
169 do
170 {
171 /* cleartext */
172 struct cmd_option_t *opt = db_find_option_by_id(csec->opt_list, "cleartext");
173 if(opt != NULL)
174 {
175 if(opt->is_string)
176 bug("Cleartext section attribute must be an integer\n");
177 if(opt->val != 0 && opt->val != 1)
178 bug("Cleartext section attribute must be 0 or 1\n");
179 sec->is_cleartext = opt->val;
180 }
181 /* alignment */
182 opt = db_find_option_by_id(csec->opt_list, "alignment");
183 if(opt != NULL)
184 {
185 if(opt->is_string)
186 bug("Cleartext section attribute must be an integer\n");
187 // n is a power of 2 iff n & (n - 1) = 0
188 // alignement cannot be lower than block size
189 if((opt->val & (opt->val - 1)) != 0)
190 bug("Cleartext section attribute must be a power of two\n");
191 if(opt->val < BLOCK_SIZE)
192 sec->alignment = BLOCK_SIZE;
193 else
194 sec->alignment = opt->val;
195 }
196 else
197 sec->alignment = BLOCK_SIZE;
198 }while(0);
199
200 if(csec->is_data)
201 {
202 sec->is_data = true;
203 sec->nr_insts = 1;
204 sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t));
205 memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t));
206
207 load_bin_by_id(cmd_file, csec->source_id);
208 struct bin_param_t *bin = &db_find_source_by_id(cmd_file, csec->source_id)->bin;
209
210 sec->insts[0].inst = SB_INST_DATA;
211 sec->insts[0].size = bin->size;
212 sec->insts[0].data = memdup(bin->data, bin->size);
213 }
214 else
215 {
216 sec->is_data = false;
217 /* count instructions and loads things */
218 struct cmd_inst_t *cinst = csec->inst_list;
219 while(cinst)
220 {
221 if(cinst->type == CMD_LOAD)
222 {
223 load_elf_by_id(cmd_file, cinst->identifier);
224 struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
225 sec->nr_insts += elf_get_nr_sections(elf);
226 }
227 else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL)
228 {
229 load_elf_by_id(cmd_file, cinst->identifier);
230 struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
231 if(!elf_get_start_addr(elf, NULL))
232 bug("cannot jump/call '%s' because it has no starting point !\n", cinst->identifier);
233 sec->nr_insts++;
234 }
235 else if(cinst->type == CMD_CALL_AT || cinst->type == CMD_JUMP_AT)
236 {
237 sec->nr_insts++;
238 }
239 else if(cinst->type == CMD_LOAD_AT)
240 {
241 load_bin_by_id(cmd_file, cinst->identifier);
242 sec->nr_insts++;
243 }
244 else if(cinst->type == CMD_MODE)
245 {
246 sec->nr_insts++;
247 }
248 else
249 bug("die\n");
250
251 cinst = cinst->next;
252 }
253
254 sec->insts = xmalloc(sec->nr_insts * sizeof(struct sb_inst_t));
255 memset(sec->insts, 0, sec->nr_insts * sizeof(struct sb_inst_t));
256 /* flatten */
257 int idx = 0;
258 cinst = csec->inst_list;
259 while(cinst)
260 {
261 if(cinst->type == CMD_LOAD)
262 {
263 struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
264 struct elf_section_t *esec = elf->first_section;
265 while(esec)
266 {
267 if(esec->type == EST_LOAD)
268 {
269 sec->insts[idx].inst = SB_INST_LOAD;
270 sec->insts[idx].addr = esec->addr;
271 sec->insts[idx].size = esec->size;
272 sec->insts[idx++].data = memdup(esec->section, esec->size);
273 }
274 else if(esec->type == EST_FILL)
275 {
276 sec->insts[idx].inst = SB_INST_FILL;
277 sec->insts[idx].addr = esec->addr;
278 sec->insts[idx].size = esec->size;
279 sec->insts[idx++].pattern = esec->pattern;
280 }
281 esec = esec->next;
282 }
283 }
284 else if(cinst->type == CMD_JUMP || cinst->type == CMD_CALL)
285 {
286 struct elf_params_t *elf = &db_find_source_by_id(cmd_file, cinst->identifier)->elf;
287 sec->insts[idx].argument = cinst->argument;
288 sec->insts[idx].inst = (cinst->type == CMD_JUMP) ? SB_INST_JUMP : SB_INST_CALL;
289 sec->insts[idx++].addr = elf->start_addr;
290 }
291 else if(cinst->type == CMD_JUMP_AT || cinst->type == CMD_CALL_AT)
292 {
293 sec->insts[idx].argument = cinst->argument;
294 sec->insts[idx].inst = (cinst->type == CMD_JUMP_AT) ? SB_INST_JUMP : SB_INST_CALL;
295 sec->insts[idx++].addr = cinst->addr;
296 }
297 else if(cinst->type == CMD_LOAD_AT)
298 {
299 struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin;
300 sec->insts[idx].inst = SB_INST_LOAD;
301 sec->insts[idx].addr = cinst->addr;
302 sec->insts[idx].data = memdup(bin->data, bin->size);
303 sec->insts[idx++].size = bin->size;
304 }
305 else if(cinst->type == CMD_MODE)
306 {
307 sec->insts[idx].inst = SB_INST_MODE;
308 sec->insts[idx++].addr = cinst->argument;
309 }
310 else
311 bug("die\n");
312
313 cinst = cinst->next;
314 }
315 }
316 }
317
318 return sb;
319}
320
321void usage(void)
322{
323 printf("Usage: elftosb [options | file]...\n");
324 printf("Options:\n");
325 printf(" -?/--help\tDisplay this message\n");
326 printf(" -o <file>\tSet output file\n");
327 printf(" -c <file>\tSet command file\n");
328 printf(" -d/--debug\tEnable debug output\n");
329 printf(" -k <file>\tAdd key file\n");
330 printf(" -z\t\tAdd zero key\n");
331 printf(" --add-key <key>\tAdd single key (hex or usbotp)\n");
332 printf(" --real-key <key>\tOverride real key\n");
333 printf(" --crypto-iv <iv>\tOverride crypto IV\n");
334 exit(1);
335}
336
337static struct crypto_key_t g_zero_key =
338{
339 .method = CRYPTO_KEY,
340 .u.key = {0}
341};
342
343int main(int argc, char **argv)
344{
345 char *cmd_filename = NULL;
346 char *output_filename = NULL;
347 struct crypto_key_t real_key;
348 struct crypto_key_t crypto_iv;
349 real_key.method = CRYPTO_NONE;
350 crypto_iv.method = CRYPTO_NONE;
351
352 while(1)
353 {
354 static struct option long_options[] =
355 {
356 {"help", no_argument, 0, '?'},
357 {"debug", no_argument, 0, 'd'},
358 {"add-key", required_argument, 0, 'a'},
359 {"real-key", required_argument, 0, 'r'},
360 {"crypto-iv", required_argument, 0, 'i'},
361 {0, 0, 0, 0}
362 };
363
364 int c = getopt_long(argc, argv, "?do:c:k:za:", long_options, NULL);
365 if(c == -1)
366 break;
367 switch(c)
368 {
369 case 'd':
370 g_debug = true;
371 break;
372 case '?':
373 usage();
374 break;
375 case 'o':
376 output_filename = optarg;
377 break;
378 case 'c':
379 cmd_filename = optarg;
380 break;
381 case 'k':
382 {
383 add_keys_from_file(optarg);
384 break;
385 }
386 case 'z':
387 {
388 add_keys(&g_zero_key, 1);
389 break;
390 }
391 case 'a':
392 case 'r':
393 case 'i':
394 {
395 struct crypto_key_t key;
396 char *s = optarg;
397 if(!parse_key(&s, &key))
398 bug("Invalid key/iv specified as argument");
399 if(*s != 0)
400 bug("Trailing characters after key/iv specified as argument");
401 if(c == 'r')
402 memcpy(&real_key, &key, sizeof(key));
403 else if(c == 'i')
404 memcpy(&crypto_iv, &key, sizeof(key));
405 else
406 add_keys(&key, 1);
407 break;
408 }
409 default:
410 abort();
411 }
412 }
413
414 if(!cmd_filename)
415 bug("You must specify a command file\n");
416 if(!output_filename)
417 bug("You must specify an output file\n");
418
419 g_extern = &argv[optind];
420 g_extern_count = argc - optind;
421
422 if(g_debug)
423 {
424 printf("key: %d\n", g_nr_keys);
425 for(int i = 0; i < g_nr_keys; i++)
426 {
427 printf(" ");
428 print_key(&g_key_array[i], true);
429 }
430
431 for(int i = 0; i < g_extern_count; i++)
432 printf("extern(%d)=%s\n", i, g_extern[i]);
433 }
434
435 struct cmd_file_t *cmd_file = db_parse_file(cmd_filename);
436 struct sb_file_t *sb_file = apply_cmd_file(cmd_file);
437 db_free(cmd_file);
438
439 if(real_key.method == CRYPTO_KEY)
440 {
441 sb_file->override_real_key = true;
442 memcpy(sb_file->real_key, real_key.u.key, 16);
443 }
444 if(crypto_iv.method == CRYPTO_KEY)
445 {
446 sb_file->override_crypto_iv = true;
447 memcpy(sb_file->crypto_iv, crypto_iv.u.key, 16);
448 }
449
450 /* fill with default parameters since there is no command file support for them */
451 sb_file->drive_tag = 0;
452 sb_file->first_boot_sec_id = sb_file->sections[0].identifier;
453 sb_file->flags = 0;
454 sb_file->minor_version = 1;
455
456 sb_write_file(sb_file, output_filename);
457 sb_free(sb_file);
458 clear_keys();
459
460 return 0;
461}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdlib.h>
22#include <stdio.h>
23#include <time.h>
24#include <ctype.h>
25#include "misc.h"
26
27bool g_debug = false;
28
29/**
30 * Misc
31 */
32
33void *memdup(void *p, size_t len)
34{
35 void *cpy = xmalloc(len);
36 memcpy(cpy, p, len);
37 return cpy;
38}
39
40void generate_random_data(void *buf, size_t sz)
41{
42 FILE *rand_fd = fopen("/dev/urandom", "rb");
43 if(rand_fd == NULL)
44 bugp("failed to open /dev/urandom");
45 if(fread(buf, 1, sz, rand_fd) != sz)
46 bugp("failed to read /dev/urandom");
47 fclose(rand_fd);
48}
49
50void *xmalloc(size_t s)
51{
52 void * r = malloc(s);
53 if(!r) bugp("malloc");
54 return r;
55}
56
57int convxdigit(char digit, byte *val)
58{
59 if(digit >= '0' && digit <= '9')
60 {
61 *val = digit - '0';
62 return 0;
63 }
64 else if(digit >= 'A' && digit <= 'F')
65 {
66 *val = digit - 'A' + 10;
67 return 0;
68 }
69 else if(digit >= 'a' && digit <= 'f')
70 {
71 *val = digit - 'a' + 10;
72 return 0;
73 }
74 else
75 return 1;
76}
77
78/* helper function to augment an array, free old array */
79void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt)
80{
81 void *p = xmalloc(elem_sz * (cnt + aug_cnt));
82 memcpy(p, arr, elem_sz * cnt);
83 memcpy(p + elem_sz * cnt, aug, elem_sz * aug_cnt);
84 free(arr);
85 return p;
86}
87
88/**
89 * Key file parsing
90 */
91int g_nr_keys;
92key_array_t g_key_array;
93
94bool parse_key(char **pstr, struct crypto_key_t *key)
95{
96 char *str = *pstr;
97 /* ignore spaces */
98 while(isspace(*str))
99 str++;
100 /* CRYPTO_KEY: 32 hex characters
101 * CRYPTO_USBOTP: usbotp(vid:pid) where vid and pid are hex numbers */
102 if(isxdigit(str[0]))
103 {
104 if(strlen(str) < 32)
105 return false;
106 for(int j = 0; j < 16; j++)
107 {
108 byte a, b;
109 if(convxdigit(str[2 * j], &a) || convxdigit(str[2 * j + 1], &b))
110 return false;
111 key->u.key[j] = (a << 4) | b;
112 }
113 /* skip key */
114 *pstr = str + 32;
115 key->method = CRYPTO_KEY;
116 return true;
117 }
118 else
119 {
120 const char *prefix = "usbotp(";
121 if(strlen(str) < strlen(prefix))
122 return false;
123 if(strncmp(str, prefix, strlen(prefix)) != 0)
124 return false;
125 str += strlen(prefix);
126 /* vid */
127 long vid = strtol(str, &str, 16);
128 if(vid < 0 || vid > 0xffff)
129 return false;
130 if(*str++ != ':')
131 return false;
132 /* pid */
133 long pid = strtol(str, &str, 16);
134 if(pid < 0 || pid > 0xffff)
135 return false;
136 if(*str++ != ')')
137 return false;
138 *pstr = str;
139 key->method = CRYPTO_USBOTP;
140 key->u.vid_pid = vid << 16 | pid;
141 return true;
142 }
143}
144
145void add_keys(key_array_t ka, int kac)
146{
147 key_array_t new_ka = xmalloc((g_nr_keys + kac) * sizeof(struct crypto_key_t));
148 memcpy(new_ka, g_key_array, g_nr_keys * sizeof(struct crypto_key_t));
149 memcpy(new_ka + g_nr_keys, ka, kac * sizeof(struct crypto_key_t));
150 free(g_key_array);
151 g_key_array = new_ka;
152 g_nr_keys += kac;
153}
154
155void clear_keys()
156{
157 free(g_key_array);
158 g_nr_keys = 0;
159}
160
161void add_keys_from_file(const char *key_file)
162{
163 int size;
164 FILE *fd = fopen(key_file, "r");
165 if(fd == NULL)
166 bug("opening key file failed");
167 fseek(fd, 0, SEEK_END);
168 size = ftell(fd);
169 fseek(fd, 0, SEEK_SET);
170 char *buf = xmalloc(size + 1);
171 if(fread(buf, 1, size, fd) != (size_t)size)
172 bug("reading key file");
173 buf[size] = 0;
174 fclose(fd);
175
176 if(g_debug)
177 printf("Parsing key file '%s'...\n", key_file);
178 char *p = buf;
179 while(1)
180 {
181 struct crypto_key_t k;
182 /* parse key */
183 if(!parse_key(&p, &k))
184 bug("invalid key file");
185 if(g_debug)
186 {
187 printf("Add key: ");
188 print_key(&k, true);
189 }
190 add_keys(&k, 1);
191 /* request at least one space character before next key, or end of file */
192 if(*p != 0 && !isspace(*p))
193 bug("invalid key file");
194 /* skip whitespace */
195 while(isspace(*p))
196 p++;
197 if(*p == 0)
198 break;
199 }
200 free(buf);
201}
202
203void print_hex(byte *data, int len, bool newline)
204{
205 for(int i = 0; i < len; i++)
206 printf("%02X ", data[i]);
207 if(newline)
208 printf("\n");
209}
210
211void print_key(struct crypto_key_t *key, bool newline)
212{
213 switch(key->method)
214 {
215 case CRYPTO_KEY:
216 print_hex(key->u.key, 16, false);
217 break;
218 case CRYPTO_USBOTP:
219 printf("USB-OTP(%04x:%04x)", key->u.vid_pid >> 16, key->u.vid_pid & 0xffff);
220 break;
221 case CRYPTO_NONE:
222 printf("none");
223 break;
224 }
225 if(newline)
226 printf("\n");
227}
228
229char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' };
230
231char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' };
232char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' };
233char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' };
234char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' };
235char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
236
237static bool g_color_enable = true;
238
239void enable_color(bool enable)
240{
241 g_color_enable = enable;
242}
243
244void color(color_t c)
245{
246 if(g_color_enable)
247 printf("%s", (char *)c);
248}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef __MISC_H__
22#define __MISC_H__
23
24#include <stdbool.h>
25#include "crypto.h"
26
27#define _STR(a) #a
28#define STR(a) _STR(a)
29
30#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0)
31#define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0)
32
33#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
34
35extern bool g_debug;
36
37typedef struct crypto_key_t *key_array_t;
38int g_nr_keys;
39key_array_t g_key_array;
40
41void *memdup(void *p, size_t len);
42void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt);
43void generate_random_data(void *buf, size_t sz);
44void *xmalloc(size_t s);
45int convxdigit(char digit, byte *val);
46void print_hex(byte *data, int len, bool newline);
47void add_keys(key_array_t ka, int kac);
48bool parse_key(char **str, struct crypto_key_t *key);
49void add_keys_from_file(const char *key_file);
50void print_key(struct crypto_key_t *key, bool newline);
51void clear_keys();
52
53typedef char color_t[];
54
55extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE;
56void color(color_t c);
57void enable_color(bool enable);
58
59#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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <time.h>
23#include <stdlib.h>
24#include <ctype.h>
25#include "misc.h"
26#include "crypto.h"
27#include "sb.h"
28
29static void fill_gaps(struct sb_file_t *sb)
30{
31 for(int i = 0; i < sb->nr_sections; i++)
32 {
33 struct sb_section_t *sec = &sb->sections[i];
34 for(int j = 0; j < sec->nr_insts; j++)
35 {
36 struct sb_inst_t *inst = &sec->insts[j];
37 if(inst->inst != SB_INST_LOAD)
38 continue;
39 inst->padding_size = ROUND_UP(inst->size, BLOCK_SIZE) - inst->size;
40 /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */
41 inst->padding = xmalloc(15);
42 generate_random_data(inst->padding, 15);
43 }
44 }
45}
46
47static void compute_sb_offsets(struct sb_file_t *sb)
48{
49 sb->image_size = 0;
50 /* sb header */
51 sb->image_size += sizeof(struct sb_header_t) / BLOCK_SIZE;
52 /* sections headers */
53 sb->image_size += sb->nr_sections * sizeof(struct sb_section_header_t) / BLOCK_SIZE;
54 /* key dictionary */
55 sb->image_size += g_nr_keys * sizeof(struct sb_key_dictionary_entry_t) / BLOCK_SIZE;
56 /* sections */
57 for(int i = 0; i < sb->nr_sections; i++)
58 {
59 /* each section has a preliminary TAG command */
60 sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE;
61 /* we might need to pad the section so compute next alignment */
62 uint32_t alignment = BLOCK_SIZE;
63 if((i + 1) < sb->nr_sections)
64 alignment = sb->sections[i + 1].alignment;
65 alignment /= BLOCK_SIZE; /* alignment in block sizes */
66
67 struct sb_section_t *sec = &sb->sections[i];
68 sec->sec_size = 0;
69
70 if(g_debug)
71 {
72 printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot",
73 sec->identifier);
74 if(sec->is_cleartext)
75 printf(" (cleartext)");
76 printf("\n");
77 }
78
79 sec->file_offset = sb->image_size;
80 for(int j = 0; j < sec->nr_insts; j++)
81 {
82 struct sb_inst_t *inst = &sec->insts[j];
83 if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP)
84 {
85 if(g_debug)
86 printf(" %s | addr=0x%08x | arg=0x%08x\n",
87 inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument);
88 sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
89 sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
90 }
91 else if(inst->inst == SB_INST_FILL)
92 {
93 if(g_debug)
94 printf(" FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n",
95 inst->addr, inst->size, inst->pattern);
96 sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
97 sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
98 }
99 else if(inst->inst == SB_INST_LOAD)
100 {
101 if(g_debug)
102 printf(" LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size);
103 /* load header */
104 sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
105 sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
106 /* data + alignment */
107 sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
108 sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
109 }
110 else if(inst->inst == SB_INST_MODE)
111 {
112 if(g_debug)
113 printf(" MODE | mod=0x%08x", inst->addr);
114 sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
115 sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
116 }
117 else if(inst->inst == SB_INST_DATA)
118 {
119 if(g_debug)
120 printf(" DATA | size=0x%08x\n", inst->size);
121 sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
122 sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
123 }
124 else
125 bug("die on inst %d\n", inst->inst);
126 }
127 /* we need to make sure next section starts on the right alignment.
128 * Since each section starts with a boot tag, we thus need to ensure
129 * that this sections ends at adress X such that X+BLOCK_SIZE is
130 * a multiple of the alignment.
131 * For data sections, we just add random data, otherwise we add nops */
132 uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment);
133 if(missing_sz != alignment)
134 {
135 struct sb_inst_t *aug_insts;
136 int nr_aug_insts = 0;
137
138 if(sb->sections[i].is_data)
139 {
140 nr_aug_insts = 1;
141 aug_insts = xmalloc(sizeof(struct sb_inst_t));
142 memset(aug_insts, 0, sizeof(struct sb_inst_t));
143 aug_insts[0].inst = SB_INST_DATA;
144 aug_insts[0].size = missing_sz * BLOCK_SIZE;
145 aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE);
146 generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE);
147 if(g_debug)
148 printf(" DATA | size=0x%08x\n", aug_insts[0].size);
149 }
150 else
151 {
152 nr_aug_insts = missing_sz;
153 aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts);
154 memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
155 for(int j = 0; j < nr_aug_insts; j++)
156 {
157 aug_insts[j].inst = SB_INST_NOP;
158 if(g_debug)
159 printf(" NOOP\n");
160 }
161 }
162
163 sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
164 sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
165 sb->sections[i].nr_insts += nr_aug_insts;
166 free(aug_insts);
167
168 /* augment image and section size */
169 sb->image_size += missing_sz;
170 sec->sec_size += missing_sz;
171 }
172 }
173 /* final signature */
174 sb->image_size += 2;
175}
176
177static uint64_t generate_timestamp()
178{
179 struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
180 time_t t = time(NULL) - mktime(&tm_base);
181 return (uint64_t)t * 1000000L;
182}
183
184static uint16_t swap16(uint16_t t)
185{
186 return (t << 8) | (t >> 8);
187}
188
189static void fix_version(struct sb_version_t *ver)
190{
191 ver->major = swap16(ver->major);
192 ver->minor = swap16(ver->minor);
193 ver->revision = swap16(ver->revision);
194}
195
196static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr)
197{
198 struct sha_1_params_t sha_1_params;
199
200 sb_hdr->signature[0] = 'S';
201 sb_hdr->signature[1] = 'T';
202 sb_hdr->signature[2] = 'M';
203 sb_hdr->signature[3] = 'P';
204 sb_hdr->major_ver = IMAGE_MAJOR_VERSION;
205 sb_hdr->minor_ver = IMAGE_MINOR_VERSION;
206 sb_hdr->flags = 0;
207 sb_hdr->image_size = sb->image_size;
208 sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE;
209 sb_hdr->first_boot_sec_id = sb->first_boot_sec_id;
210 sb_hdr->nr_keys = g_nr_keys;
211 sb_hdr->nr_sections = sb->nr_sections;
212 sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE;
213 sb_hdr->key_dict_off = sb_hdr->header_size +
214 sb_hdr->sec_hdr_size * sb_hdr->nr_sections;
215 sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off +
216 sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE;
217 generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0));
218 generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1));
219 /* Version 1.0 has 6 bytes of random padding,
220 * Version 1.1 requires the last 4 bytes to be 'sgtl' */
221 if(sb->minor_version >= 1)
222 memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4);
223
224 sb_hdr->timestamp = generate_timestamp();
225 sb_hdr->product_ver = sb->product_ver;
226 fix_version(&sb_hdr->product_ver);
227 sb_hdr->component_ver = sb->component_ver;
228 fix_version(&sb_hdr->component_ver);
229 sb_hdr->drive_tag = sb->drive_tag;
230
231 sha_1_init(&sha_1_params);
232 sha_1_update(&sha_1_params, &sb_hdr->signature[0],
233 sizeof(struct sb_header_t) - sizeof(sb_hdr->sha1_header));
234 sha_1_finish(&sha_1_params);
235 sha_1_output(&sha_1_params, sb_hdr->sha1_header);
236}
237
238static void produce_sb_section_header(struct sb_section_t *sec,
239 struct sb_section_header_t *sec_hdr)
240{
241 sec_hdr->identifier = sec->identifier;
242 sec_hdr->offset = sec->file_offset;
243 sec_hdr->size = sec->sec_size;
244 sec_hdr->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
245 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
246}
247
248static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
249{
250 uint8_t sum = 90;
251 byte *ptr = (byte *)hdr;
252 for(int i = 1; i < 16; i++)
253 sum += ptr[i];
254 return sum;
255}
256
257static void produce_section_tag_cmd(struct sb_section_t *sec,
258 struct sb_instruction_tag_t *tag, bool is_last)
259{
260 tag->hdr.opcode = SB_INST_TAG;
261 tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0;
262 tag->identifier = sec->identifier;
263 tag->len = sec->sec_size;
264 tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
265 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
266 tag->hdr.checksum = instruction_checksum(&tag->hdr);
267}
268
269void produce_sb_instruction(struct sb_inst_t *inst,
270 struct sb_instruction_common_t *cmd)
271{
272 memset(cmd, 0, sizeof(struct sb_instruction_common_t));
273 cmd->hdr.opcode = inst->inst;
274 switch(inst->inst)
275 {
276 case SB_INST_CALL:
277 case SB_INST_JUMP:
278 cmd->addr = inst->addr;
279 cmd->data = inst->argument;
280 break;
281 case SB_INST_FILL:
282 cmd->addr = inst->addr;
283 cmd->len = inst->size;
284 cmd->data = inst->pattern;
285 break;
286 case SB_INST_LOAD:
287 cmd->addr = inst->addr;
288 cmd->len = inst->size;
289 cmd->data = crc_continue(crc(inst->data, inst->size),
290 inst->padding, inst->padding_size);
291 break;
292 case SB_INST_MODE:
293 cmd->data = inst->addr;
294 break;
295 case SB_INST_NOP:
296 break;
297 default:
298 bug("die\n");
299 }
300 cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
301}
302
303enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename)
304{
305 struct crypto_key_t real_key;
306 real_key.method = CRYPTO_KEY;
307 byte crypto_iv[16];
308 byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys);
309 /* init CBC-MACs */
310 for(int i = 0; i < g_nr_keys; i++)
311 memset(cbc_macs[i], 0, 16);
312
313 fill_gaps(sb);
314 compute_sb_offsets(sb);
315
316 generate_random_data(real_key.u.key, 16);
317
318 /* global SHA-1 */
319 struct sha_1_params_t file_sha1;
320 sha_1_init(&file_sha1);
321 /* produce and write header */
322 struct sb_header_t sb_hdr;
323 produce_sb_header(sb, &sb_hdr);
324 /* allocate image */
325 byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE);
326 byte *buf_p = buf;
327 #define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0)
328
329 sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
330 write(&sb_hdr, sizeof(sb_hdr));
331
332 memcpy(crypto_iv, &sb_hdr, 16);
333
334 /* update CBC-MACs */
335 for(int i = 0; i < g_nr_keys; i++)
336 crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i],
337 cbc_macs[i], &cbc_macs[i], 1);
338
339 /* produce and write section headers */
340 for(int i = 0; i < sb_hdr.nr_sections; i++)
341 {
342 struct sb_section_header_t sb_sec_hdr;
343 produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
344 sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
345 write(&sb_sec_hdr, sizeof(sb_sec_hdr));
346 /* update CBC-MACs */
347 for(int j = 0; j < g_nr_keys; j++)
348 crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
349 &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
350 }
351 /* produce key dictionary */
352 for(int i = 0; i < g_nr_keys; i++)
353 {
354 struct sb_key_dictionary_entry_t entry;
355 memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16);
356 crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
357 crypto_iv, NULL, 1);
358
359 write(&entry, sizeof(entry));
360 sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
361 }
362
363 free(cbc_macs);
364
365 /* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
366 /* Image crafting, don't use it unless you understand what you do */
367 if(sb->override_real_key)
368 memcpy(real_key.u.key, sb->real_key, 16);
369 if(sb->override_crypto_iv)
370 memcpy(crypto_iv, sb->crypto_iv, 16);
371 /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
372 if(g_debug)
373 {
374 printf("Real key: ");
375 for(int j = 0; j < 16; j++)
376 printf("%02x", real_key.u.key[j]);
377 printf("\n");
378 printf("IV : ");
379 for(int j = 0; j < 16; j++)
380 printf("%02x", crypto_iv[j]);
381 printf("\n");
382 }
383 /* produce sections data */
384 for(int i = 0; i< sb_hdr.nr_sections; i++)
385 {
386 /* produce tag command */
387 struct sb_instruction_tag_t tag_cmd;
388 produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
389 if(g_nr_keys > 0)
390 crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
391 &real_key, crypto_iv, NULL, 1);
392 sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
393 write(&tag_cmd, sizeof(tag_cmd));
394 /* produce other commands */
395 byte cur_cbc_mac[16];
396 memcpy(cur_cbc_mac, crypto_iv, 16);
397 for(int j = 0; j < sb->sections[i].nr_insts; j++)
398 {
399 struct sb_inst_t *inst = &sb->sections[i].insts[j];
400 /* command */
401 if(inst->inst != SB_INST_DATA)
402 {
403 struct sb_instruction_common_t cmd;
404 produce_sb_instruction(inst, &cmd);
405 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
406 crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
407 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
408 sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
409 write(&cmd, sizeof(cmd));
410 }
411 /* data */
412 if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
413 {
414 uint32_t sz = inst->size + inst->padding_size;
415 byte *data = xmalloc(sz);
416 memcpy(data, inst->data, inst->size);
417 memcpy(data + inst->size, inst->padding, inst->padding_size);
418 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
419 crypto_cbc(data, data, sz / BLOCK_SIZE,
420 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
421 sha_1_update(&file_sha1, data, sz);
422 write(data, sz);
423 free(data);
424 }
425 }
426 }
427 /* write file SHA-1 */
428 byte final_sig[32];
429 sha_1_finish(&file_sha1);
430 sha_1_output(&file_sha1, final_sig);
431 generate_random_data(final_sig + 20, 12);
432 if(g_nr_keys > 0)
433 crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
434 write(final_sig, 32);
435
436 if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE)
437 bug("SB image buffer was not entirely filled !");
438
439 FILE *fd = fopen(filename, "wb");
440 if(fd == NULL)
441 return SB_OPEN_ERROR;
442 if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1)
443 {
444 free(buf);
445 return SB_WRITE_ERROR;
446 }
447 fclose(fd);
448 free(buf);
449
450 return SB_SUCCESS;
451}
452
453static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
454 int size, const char *indent, void *u, sb_color_printf cprintf, enum sb_error_t *err)
455{
456 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
457 #define fatal(e, ...) \
458 do { if(err) *err = e; \
459 cprintf(u, true, GREY, __VA_ARGS__); \
460 sb_free_section(*sec); \
461 free(sec); \
462 return NULL; } while(0)
463
464 struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t));
465 memset(sec, 0, sizeof(struct sb_section_t));
466 sec->identifier = id;
467 sec->is_data = data_sec;
468 sec->sec_size = ROUND_UP(size, BLOCK_SIZE) / BLOCK_SIZE;
469
470 if(data_sec)
471 {
472 sec->nr_insts = 1;
473 sec->insts = xmalloc(sizeof(struct sb_inst_t));
474 memset(sec->insts, 0, sizeof(struct sb_inst_t));
475 sec->insts->inst = SB_INST_DATA;
476 sec->insts->size = size;
477 sec->insts->data = memdup(buf, size);
478 return sec;
479 }
480
481 /* Pretty print the content */
482 int pos = 0;
483 while(pos < size)
484 {
485 struct sb_inst_t inst;
486 memset(&inst, 0, sizeof(inst));
487
488 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos];
489 inst.inst = hdr->opcode;
490
491 printf(OFF, "%s", indent);
492 uint8_t checksum = instruction_checksum(hdr);
493 if(checksum != hdr->checksum)
494 fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum");
495 if(hdr->flags != 0)
496 {
497 printf(GREY, "[");
498 printf(BLUE, "f=%x", hdr->flags);
499 printf(GREY, "] ");
500 }
501 if(hdr->opcode == SB_INST_LOAD)
502 {
503 struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos];
504 inst.size = load->len;
505 inst.addr = load->addr;
506 inst.data = memdup(load + 1, load->len);
507
508 printf(RED, "LOAD");
509 printf(OFF, " | ");
510 printf(BLUE, "addr=0x%08x", load->addr);
511 printf(OFF, " | ");
512 printf(GREEN, "len=0x%08x", load->len);
513 printf(OFF, " | ");
514 printf(YELLOW, "crc=0x%08x", load->crc);
515 /* data is padded to 16-byte boundary with random data and crc'ed with it */
516 uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)],
517 ROUND_UP(load->len, 16));
518 if(load->crc == computed_crc)
519 printf(RED, " Ok\n");
520 else
521 {
522 printf(RED, " Failed (crc=0x%08x)\n", computed_crc);
523 fatal(SB_CHECKSUM_ERROR, "Instruction data crc error\n");
524 }
525
526 pos += load->len + sizeof(struct sb_instruction_load_t);
527 }
528 else if(hdr->opcode == SB_INST_FILL)
529 {
530 struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos];
531 inst.pattern = fill->pattern;
532 inst.size = fill->len;
533 inst.addr = fill->addr;
534
535 printf(RED, "FILL");
536 printf(OFF, " | ");
537 printf(BLUE, "addr=0x%08x", fill->addr);
538 printf(OFF, " | ");
539 printf(GREEN, "len=0x%08x", fill->len);
540 printf(OFF, " | ");
541 printf(YELLOW, "pattern=0x%08x\n", fill->pattern);
542
543 pos += sizeof(struct sb_instruction_fill_t);
544 }
545 else if(hdr->opcode == SB_INST_CALL ||
546 hdr->opcode == SB_INST_JUMP)
547 {
548 int is_call = (hdr->opcode == SB_INST_CALL);
549 struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos];
550 inst.addr = call->addr;
551 inst.argument = call->arg;
552
553 if(is_call)
554 printf(RED, "CALL");
555 else
556 printf(RED, "JUMP");
557 printf(OFF, " | ");
558 printf(BLUE, "addr=0x%08x", call->addr);
559 printf(OFF, " | ");
560 printf(GREEN, "arg=0x%08x\n", call->arg);
561
562 pos += sizeof(struct sb_instruction_call_t);
563 }
564 else if(hdr->opcode == SB_INST_MODE)
565 {
566 struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr;
567 inst.argument = mode->mode;
568
569 printf(RED, "MODE");
570 printf(OFF, " | ");
571 printf(BLUE, "mod=0x%08x\n", mode->mode);
572
573 pos += sizeof(struct sb_instruction_mode_t);
574 }
575 else if(hdr->opcode == SB_INST_NOP)
576 {
577 printf(RED, "NOOP\n");
578 pos += sizeof(struct sb_instruction_mode_t);
579 }
580 else
581 {
582 fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
583 break;
584 }
585
586 sec->insts = augment_array(sec->insts, sizeof(struct sb_inst_t), sec->nr_insts++, &inst, 1);
587 pos = ROUND_UP(pos, BLOCK_SIZE);
588 }
589
590 return sec;
591 #undef printf
592 #undef fatal
593}
594
595void sb_fill_section_name(char name[5], uint32_t identifier)
596{
597 name[0] = (identifier >> 24) & 0xff;
598 name[1] = (identifier >> 16) & 0xff;
599 name[2] = (identifier >> 8) & 0xff;
600 name[3] = identifier & 0xff;
601 for(int i = 0; i < 4; i++)
602 if(!isprint(name[i]))
603 name[i] = '_';
604 name[4] = 0;
605}
606
607static uint32_t guess_alignment(uint32_t off)
608{
609 /* find greatest power of two which divides the offset */
610 if(off == 0)
611 return 1;
612 uint32_t a = 1;
613 while(off % (2 * a) == 0)
614 a *= 2;
615 return a;
616}
617
618struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
619 sb_color_printf cprintf, enum sb_error_t *err)
620{
621 uint8_t *buf = NULL;
622 struct sb_file_t *sb_file = NULL;
623
624 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
625 #define fatal(e, ...) \
626 do { if(err) *err = e; \
627 cprintf(u, true, GREY, __VA_ARGS__); \
628 free(buf); \
629 sb_free(sb_file); \
630 return NULL; } while(0)
631 #define print_hex(c, p, len, nl) \
632 do { printf(c, ""); print_hex(p, len, nl); } while(0)
633
634 FILE *f = fopen(filename, "rb");
635 if(f == NULL)
636 fatal(SB_OPEN_ERROR, "Cannot open file for reading\n");
637 fseek(f, 0, SEEK_END);
638 long filesize = ftell(f);
639 fseek(f, 0, SEEK_SET);
640 buf = xmalloc(filesize);
641 if(fread(buf, filesize, 1, f) != 1)
642 {
643 fclose(f);
644 fatal(SB_READ_ERROR, "Cannot read file\n");
645 }
646 fclose(f);
647
648 struct sha_1_params_t sha_1_params;
649 sb_file = xmalloc(sizeof(struct sb_file_t));
650 memset(sb_file, 0, sizeof(struct sb_file_t));
651 struct sb_header_t *sb_header = (struct sb_header_t *)buf;
652
653 sb_file->image_size = sb_header->image_size;
654 sb_file->minor_version = sb_header->minor_ver;
655 sb_file->flags = sb_header->flags;
656 sb_file->drive_tag = sb_header->drive_tag;
657 sb_file->first_boot_sec_id = sb_header->first_boot_sec_id;
658
659 if(memcmp(sb_header->signature, "STMP", 4) != 0)
660 fatal(SB_FORMAT_ERROR, "Bad signature\n");
661 if(sb_header->image_size * BLOCK_SIZE > filesize)
662 fatal(SB_FORMAT_ERROR, "File too small");
663 if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
664 fatal(SB_FORMAT_ERROR, "Bad header size");
665 if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
666 fatal(SB_FORMAT_ERROR, "Bad section header size");
667
668 if(filesize > sb_header->image_size * BLOCK_SIZE)
669 {
670 printf(GREY, "[Restrict file size from %lu to %d bytes]\n", filesize,
671 sb_header->image_size * BLOCK_SIZE);
672 filesize = sb_header->image_size * BLOCK_SIZE;
673 }
674
675 printf(BLUE, "Basic info:\n");
676 printf(GREEN, " SB version: ");
677 printf(YELLOW, "%d.%d\n", sb_header->major_ver, sb_header->minor_ver);
678 printf(GREEN, " Header SHA-1: ");
679 byte *hdr_sha1 = sb_header->sha1_header;
680 print_hex(YELLOW, hdr_sha1, 20, false);
681 /* Check SHA1 sum */
682 byte computed_sha1[20];
683 sha_1_init(&sha_1_params);
684 sha_1_update(&sha_1_params, &sb_header->signature[0],
685 sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header));
686 sha_1_finish(&sha_1_params);
687 sha_1_output(&sha_1_params, computed_sha1);
688 if(memcmp(hdr_sha1, computed_sha1, 20) == 0)
689 printf(RED, " Ok\n");
690 else
691 printf(RED, " Failed\n");
692 printf(GREEN, " Flags: ");
693 printf(YELLOW, "%x\n", sb_header->flags);
694 printf(GREEN, " Total file size : ");
695 printf(YELLOW, "%ld\n", filesize);
696
697 /* Sizes and offsets */
698 printf(BLUE, "Sizes and offsets:\n");
699 printf(GREEN, " # of encryption keys = ");
700 printf(YELLOW, "%d\n", sb_header->nr_keys);
701 printf(GREEN, " # of sections = ");
702 printf(YELLOW, "%d\n", sb_header->nr_sections);
703
704 /* Versions */
705 printf(BLUE, "Versions\n");
706
707 printf(GREEN, " Random 1: ");
708 print_hex(YELLOW, sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true);
709 printf(GREEN, " Random 2: ");
710 print_hex(YELLOW, sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true);
711
712 uint64_t micros = sb_header->timestamp;
713 time_t seconds = (micros / (uint64_t)1000000L);
714 struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
715 seconds += mktime(&tm_base);
716 struct tm *time = gmtime(&seconds);
717 printf(GREEN, " Creation date/time = ");
718 printf(YELLOW, "%s", asctime(time));
719
720 struct sb_version_t product_ver = sb_header->product_ver;
721 fix_version(&product_ver);
722 struct sb_version_t component_ver = sb_header->component_ver;
723 fix_version(&component_ver);
724
725 memcpy(&sb_file->product_ver, &product_ver, sizeof(product_ver));
726 memcpy(&sb_file->component_ver, &component_ver, sizeof(component_ver));
727
728 printf(GREEN, " Product version = ");
729 printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision);
730 printf(GREEN, " Component version = ");
731 printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision);
732
733 printf(GREEN, " Drive tag = ");
734 printf(YELLOW, "%x\n", sb_header->drive_tag);
735 printf(GREEN, " First boot tag offset = ");
736 printf(YELLOW, "%x\n", sb_header->first_boot_tag_off);
737 printf(GREEN, " First boot section ID = ");
738 printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id);
739
740 /* encryption cbc-mac */
741 byte real_key[16];
742 bool valid_key = false; /* false until a matching key was found */
743
744 if(sb_header->nr_keys > 0)
745 {
746 byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
747 printf(BLUE, "Encryption keys\n");
748 for(int i = 0; i < g_nr_keys; i++)
749 {
750 printf(RED, " Key %d: ", i);
751 printf(YELLOW, "");
752 print_key(&g_key_array[i], true);
753 printf(GREEN, " CBC-MAC: ");
754 /* check it */
755 byte zero[16];
756 memset(zero, 0, 16);
757 int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
758 &g_key_array[i], zero, &cbcmacs[i], 1);
759 if(ret != CRYPTO_ERROR_SUCCESS)
760 {
761 free(cbcmacs);
762 fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret);
763 }
764 print_hex(YELLOW, cbcmacs[i], 16, true);
765 }
766
767 printf(BLUE, "DEK\n");
768 for(int i = 0; i < sb_header->nr_keys; i++)
769 {
770 printf(RED, " Entry %d\n", i);
771 uint32_t ofs = sizeof(struct sb_header_t)
772 + sizeof(struct sb_section_header_t) * sb_header->nr_sections
773 + sizeof(struct sb_key_dictionary_entry_t) * i;
774 struct sb_key_dictionary_entry_t *dict_entry =
775 (struct sb_key_dictionary_entry_t *)&buf[ofs];
776 /* cbc mac */
777 printf(GREEN, " Encrypted key: ");
778 print_hex(YELLOW, dict_entry->key, 16, true);
779 printf(GREEN, " CBC-MAC : ");
780 print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
781 /* check it */
782 int idx = 0;
783 while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0)
784 idx++;
785 if(idx != g_nr_keys)
786 {
787 printf(RED, " Match\n");
788 /* decrypt */
789 byte decrypted_key[16];
790 byte iv[16];
791 memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
792 int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0);
793 if(ret != CRYPTO_ERROR_SUCCESS)
794 {
795 free(cbcmacs);
796 fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret);
797 }
798 printf(GREEN, " Decrypted key: ");
799 print_hex(YELLOW, decrypted_key, 16, false);
800 if(valid_key)
801 {
802 if(memcmp(real_key, decrypted_key, 16) == 0)
803 printf(RED, " Cross-Check Ok");
804 else
805 printf(RED, " Cross-Check Failed");
806 }
807 else
808 {
809 memcpy(real_key, decrypted_key, 16);
810 valid_key = true;
811 }
812 printf(OFF, "\n");
813 }
814 else
815 printf(RED, " Don't Match\n");
816 }
817
818 free(cbcmacs);
819
820 if(!valid_key)
821 fatal(SB_NO_VALID_KEY, "No valid key found\n");
822
823 if(getenv("SB_REAL_KEY") != 0)
824 {
825 struct crypto_key_t k;
826 char *env = getenv("SB_REAL_KEY");
827 if(!parse_key(&env, &k) || *env)
828 bug("Invalid SB_REAL_KEY\n");
829 memcpy(real_key, k.u.key, 16);
830 }
831
832 printf(RED, " Summary:\n");
833 printf(GREEN, " Real key: ");
834 print_hex(YELLOW, real_key, 16, true);
835 printf(GREEN, " IV : ");
836 print_hex(YELLOW, buf, 16, true);
837
838 sb_file->override_real_key = true;
839 memcpy(sb_file->real_key, real_key, 16);
840 sb_file->override_crypto_iv = true;
841 memcpy(sb_file->crypto_iv, buf, 16);
842 }
843
844 /* sections */
845 if(!raw_mode)
846 {
847 sb_file->nr_sections = sb_header->nr_sections;
848 sb_file->sections = xmalloc(sb_file->nr_sections * sizeof(struct sb_section_t));
849 memset(sb_file->sections, 0, sb_file->nr_sections * sizeof(struct sb_section_t));
850 printf(BLUE, "Sections\n");
851 for(int i = 0; i < sb_header->nr_sections; i++)
852 {
853 uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t);
854 struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&buf[ofs];
855
856 char name[5];
857 sb_fill_section_name(name, sec_hdr->identifier);
858 int pos = sec_hdr->offset * BLOCK_SIZE;
859 int size = sec_hdr->size * BLOCK_SIZE;
860 int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE);
861 int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
862
863 printf(GREEN, " Section ");
864 printf(YELLOW, "'%s'\n", name);
865 printf(GREEN, " pos = ");
866 printf(YELLOW, "%8x - %8x\n", pos, pos+size);
867 printf(GREEN, " len = ");
868 printf(YELLOW, "%8x\n", size);
869 printf(GREEN, " flags = ");
870 printf(YELLOW, "%8x", sec_hdr->flags);
871 if(data_sec)
872 printf(RED, " Data Section");
873 else
874 printf(RED, " Boot Section");
875 if(encrypted)
876 printf(RED, " (Encrypted)");
877 printf(OFF, "\n");
878
879 /* save it */
880 byte *sec = xmalloc(size);
881 if(encrypted)
882 cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
883 else
884 memcpy(sec, buf + pos, size);
885
886 struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
887 sec, size, " ", u, cprintf, err);
888 if(s)
889 {
890 s->is_cleartext = !encrypted;
891 s->alignment = guess_alignment(pos);
892 memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t));
893 free(s);
894 }
895 else
896 fatal(*err, "Error reading section\n");
897
898 free(sec);
899 }
900 }
901 else
902 {
903 /* advanced raw mode */
904 printf(BLUE, "Commands\n");
905 uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE;
906 byte iv[16];
907 const char *indent = " ";
908 while(true)
909 {
910 /* restart with IV */
911 memcpy(iv, buf, 16);
912 byte cmd[BLOCK_SIZE];
913 if(sb_header->nr_keys > 0)
914 cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0);
915 else
916 memcpy(cmd, buf + offset, BLOCK_SIZE);
917 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd;
918 printf(OFF, "%s", indent);
919 uint8_t checksum = instruction_checksum(hdr);
920 if(checksum != hdr->checksum)
921 printf(GREY, "[Bad checksum']");
922
923 if(hdr->opcode == SB_INST_NOP)
924 {
925 printf(RED, "NOOP\n");
926 offset += BLOCK_SIZE;
927 }
928 else if(hdr->opcode == SB_INST_TAG)
929 {
930 struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr;
931 printf(RED, "BTAG");
932 printf(OFF, " | ");
933 printf(BLUE, "sec=0x%08x", tag->identifier);
934 printf(OFF, " | ");
935 printf(GREEN, "cnt=0x%08x", tag->len);
936 printf(OFF, " | ");
937 printf(YELLOW, "flg=0x%08x", tag->flags);
938 if(tag->hdr.flags & SB_INST_LAST_TAG)
939 {
940 printf(OFF, " | ");
941 printf(RED, " Last section");
942 }
943 printf(OFF, "\n");
944 offset += sizeof(struct sb_instruction_tag_t);
945
946 char name[5];
947 sb_fill_section_name(name, tag->identifier);
948 int pos = offset;
949 int size = tag->len * BLOCK_SIZE;
950 int data_sec = !(tag->flags & SECTION_BOOTABLE);
951 int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
952
953 printf(GREEN, "%sSection ", indent);
954 printf(YELLOW, "'%s'\n", name);
955 printf(GREEN, "%s pos = ", indent);
956 printf(YELLOW, "%8x - %8x\n", pos, pos+size);
957 printf(GREEN, "%s len = ", indent);
958 printf(YELLOW, "%8x\n", size);
959 printf(GREEN, "%s flags = ", indent);
960 printf(YELLOW, "%8x", tag->flags);
961 if(data_sec)
962 printf(RED, " Data Section");
963 else
964 printf(RED, " Boot Section");
965 if(encrypted)
966 printf(RED, " (Encrypted)");
967 printf(OFF, "\n");
968
969 /* save it */
970 byte *sec = xmalloc(size);
971 if(encrypted)
972 cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
973 else
974 memcpy(sec, buf + pos, size);
975
976 struct sb_section_t *s = read_section(data_sec, tag->identifier,
977 sec, size, " ", u, cprintf, err);
978 if(s)
979 {
980 s->is_cleartext = !encrypted;
981 s->alignment = guess_alignment(pos);
982 sb_file->sections = augment_array(sb_file->sections,
983 sizeof(struct sb_section_t), sb_file->nr_sections++,
984 s, 1);
985 free(s);
986 }
987 else
988 fatal(*err, "Error reading section\n");
989 free(sec);
990
991 /* last one ? */
992 if(tag->hdr.flags & SB_INST_LAST_TAG)
993 break;
994 offset += size;
995 }
996 else
997 {
998 fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
999 break;
1000 }
1001 }
1002 }
1003
1004 /* final signature */
1005 printf(BLUE, "Final signature:\n");
1006 byte decrypted_block[32];
1007 if(sb_header->nr_keys > 0)
1008 {
1009 printf(GREEN, " Encrypted SHA-1:\n");
1010 byte *encrypted_block = &buf[filesize - 32];
1011 printf(OFF, " ");
1012 print_hex(YELLOW, encrypted_block, 16, true);
1013 printf(OFF, " ");
1014 print_hex(YELLOW, encrypted_block + 16, 16, true);
1015 /* decrypt it */
1016 cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0);
1017 }
1018 else
1019 memcpy(decrypted_block, &buf[filesize - 32], 32);
1020 printf(GREEN, " File SHA-1:\n ");
1021 print_hex(YELLOW, decrypted_block, 20, false);
1022 /* check it */
1023 sha_1_init(&sha_1_params);
1024 sha_1_update(&sha_1_params, buf, filesize - 32);
1025 sha_1_finish(&sha_1_params);
1026 sha_1_output(&sha_1_params, computed_sha1);
1027 if(memcmp(decrypted_block, computed_sha1, 20) == 0)
1028 printf(RED, " Ok\n");
1029 else
1030 {
1031 printf(RED, " Failed\n");
1032 fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n");
1033 }
1034 free(buf);
1035
1036 return sb_file;
1037 #undef printf
1038 #undef fatal
1039 #undef print_hex
1040}
1041
1042void sb_free_section(struct sb_section_t sec)
1043{
1044 for(int j = 0; j < sec.nr_insts; j++)
1045 {
1046 free(sec.insts[j].padding);
1047 free(sec.insts[j].data);
1048 }
1049 free(sec.insts);
1050}
1051
1052void sb_free(struct sb_file_t *file)
1053{
1054 if(!file) return;
1055
1056 for(int i = 0; i < file->nr_sections; i++)
1057 sb_free_section(file->sections[i]);
1058
1059 free(file->sections);
1060 free(file);
1061}
1062
1063void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
1064{
1065 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
1066 #define print_hex(c, p, len, nl) \
1067 do { printf(c, ""); print_hex(p, len, nl); } while(0)
1068
1069 #define TREE RED
1070 #define HEADER GREEN
1071 #define TEXT YELLOW
1072 #define TEXT2 BLUE
1073 #define SEP OFF
1074
1075 printf(HEADER, "SB File\n");
1076 printf(TREE, "+-");
1077 printf(HEADER, "Version: ");
1078 printf(TEXT, "1.%d\n", file->minor_version);
1079 printf(TREE, "+-");
1080 printf(HEADER, "Flags: ");
1081 printf(TEXT, "%x\n", file->flags);
1082 printf(TREE, "+-");
1083 printf(HEADER, "Drive Tag: ");
1084 printf(TEXT, "%x\n", file->drive_tag);
1085 printf(TREE, "+-");
1086 printf(HEADER, "First Boot Section ID: ");
1087 char name[5];
1088 sb_fill_section_name(name, file->first_boot_sec_id);
1089 printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name);
1090
1091 if(file->override_real_key)
1092 {
1093 printf(TREE, "+-");
1094 printf(HEADER, "Real key: ");
1095 print_hex(TEXT, file->real_key, 16, true);
1096 }
1097 if(file->override_crypto_iv)
1098 {
1099 printf(TREE, "+-");
1100 printf(HEADER, "IV : ");
1101 print_hex(TEXT, file->crypto_iv, 16, true);
1102 }
1103 printf(TREE, "+-");
1104 printf(HEADER, "Product Version: ");
1105 printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor,
1106 file->product_ver.revision);
1107 printf(TREE, "+-");
1108 printf(HEADER, "Component Version: ");
1109 printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor,
1110 file->component_ver.revision);
1111
1112 for(int i = 0; i < file->nr_sections; i++)
1113 {
1114 struct sb_section_t *sec = &file->sections[i];
1115 printf(TREE, "+-");
1116 printf(HEADER, "Section\n");
1117 printf(TREE,"| +-");
1118 printf(HEADER, "Identifier: ");
1119 sb_fill_section_name(name, sec->identifier);
1120 printf(TEXT, "%08x (%s)\n", sec->identifier, name);
1121 printf(TREE, "| +-");
1122 printf(HEADER, "Type: ");
1123 printf(TEXT, "%s (%s)\n", sec->is_data ? "Data Section" : "Boot Section",
1124 sec->is_cleartext ? "Cleartext" : "Encrypted");
1125 printf(TREE, "| +-");
1126 printf(HEADER, "Alignment: ");
1127 printf(TEXT, "%d (bytes)\n", sec->alignment);
1128 printf(TREE, "| +-");
1129 printf(HEADER, "Instructions\n");
1130 for(int j = 0; j < sec->nr_insts; j++)
1131 {
1132 struct sb_inst_t *inst = &sec->insts[j];
1133 printf(TREE, "| | +-");
1134 switch(inst->inst)
1135 {
1136 case SB_INST_DATA:
1137 printf(HEADER, "DATA");
1138 printf(SEP, " | ");
1139 printf(TEXT, "size=0x%08x\n", inst->size);
1140 break;
1141 case SB_INST_CALL:
1142 case SB_INST_JUMP:
1143 printf(HEADER, "%s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP");
1144 printf(SEP, " | ");
1145 printf(TEXT, "addr=0x%08x", inst->addr);
1146 printf(SEP, " | ");
1147 printf(TEXT2, "arg=0x%08x\n", inst->argument);
1148 break;
1149 case SB_INST_LOAD:
1150 printf(HEADER, "LOAD");
1151 printf(SEP, " | ");
1152 printf(TEXT, "addr=0x%08x", inst->addr);
1153 printf(SEP, " | ");
1154 printf(TEXT2, "len=0x%08x\n", inst->size);
1155 break;
1156 case SB_INST_FILL:
1157 printf(HEADER, "FILL");
1158 printf(SEP, " | ");
1159 printf(TEXT, "addr=0x%08x", inst->addr);
1160 printf(SEP, " | ");
1161 printf(TEXT2, "len=0x%08x", inst->size);
1162 printf(SEP, " | ");
1163 printf(TEXT2, "pattern=0x%08x\n", inst->pattern);
1164 break;
1165 case SB_INST_MODE:
1166 printf(HEADER, "MODE");
1167 printf(SEP, " | ");
1168 printf(TEXT, "mod=0x%08x\n", inst->addr);
1169 break;
1170 case SB_INST_NOP:
1171 printf(HEADER, "NOOP\n");
1172 break;
1173 default:
1174 printf(GREY, "[Unknown instruction %x]\n", inst->inst);
1175 }
1176 }
1177 }
1178
1179 #undef printf
1180 #undef print_hex
1181}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#ifndef __SB_H__
22#define __SB_H__
23
24#include <stdint.h>
25#include <stdbool.h>
26
27#include "misc.h"
28
29#define BLOCK_SIZE 16
30
31/* All fields are in big-endian BCD */
32struct sb_version_t
33{
34 uint16_t major;
35 uint16_t pad0;
36 uint16_t minor;
37 uint16_t pad1;
38 uint16_t revision;
39 uint16_t pad2;
40};
41
42struct sb_header_t
43{
44 uint8_t sha1_header[20]; /* SHA-1 of the rest of the header */
45 uint8_t signature[4]; /* Signature "STMP" */
46 uint8_t major_ver; /* Should be 1 */
47 uint8_t minor_ver; /* Should be 1 */
48 uint16_t flags;
49 uint32_t image_size; /* In blocks (=16bytes) */
50 uint32_t first_boot_tag_off; /* Offset in blocks */
51 uint32_t first_boot_sec_id; /* First bootable section ID */
52 uint16_t nr_keys; /* Number of encryption keys */
53 uint16_t key_dict_off; /* Offset to key dictionary (in blocks) */
54 uint16_t header_size; /* In blocks */
55 uint16_t nr_sections; /* Number of sections */
56 uint16_t sec_hdr_size; /* Section header size (in blocks) */
57 uint8_t rand_pad0[6]; /* Random padding */
58 uint64_t timestamp; /* In microseconds since 2000/1/1 00:00:00 */
59 struct sb_version_t product_ver;
60 struct sb_version_t component_ver;
61 uint16_t drive_tag; /* first tag to boot ? */
62 uint8_t rand_pad1[6]; /* Random padding */
63} __attribute__((packed));
64
65struct sb_section_header_t
66{
67 uint32_t identifier;
68 uint32_t offset; /* In blocks */
69 uint32_t size; /* In blocks */
70 uint32_t flags;
71} __attribute__((packed));
72
73struct sb_key_dictionary_entry_t
74{
75 uint8_t hdr_cbc_mac[16]; /* CBC-MAC of the header */
76 uint8_t key[16]; /* Actual AES Key (encrypted by the global key) */
77} __attribute__((packed));
78
79#define IMAGE_MAJOR_VERSION 1
80#define IMAGE_MINOR_VERSION 1
81
82#define SECTION_BOOTABLE (1 << 0)
83#define SECTION_CLEARTEXT (1 << 1)
84
85#define SB_INST_NOP 0x0
86#define SB_INST_TAG 0x1
87#define SB_INST_LOAD 0x2
88#define SB_INST_FILL 0x3
89#define SB_INST_JUMP 0x4
90#define SB_INST_CALL 0x5
91#define SB_INST_MODE 0x6
92
93/* flags */
94#define SB_INST_LAST_TAG 1 /* for TAG */
95#define SB_INST_LOAD_DCD 1 /* for LOAD */
96#define SB_INST_FILL_BYTE 0 /* for FILL */
97#define SB_INST_FILL_HWORD 1 /* for FILL */
98#define SB_INST_FILL_WORD 2 /* for FILL */
99#define SB_INST_HAB_EXEC 1 /* for JUMP/CALL */
100
101struct sb_instruction_header_t
102{
103 uint8_t checksum;
104 uint8_t opcode;
105 uint16_t flags;
106} __attribute__((packed));
107
108struct sb_instruction_common_t
109{
110 struct sb_instruction_header_t hdr;
111 uint32_t addr;
112 uint32_t len;
113 uint32_t data;
114} __attribute__((packed));
115
116struct sb_instruction_load_t
117{
118 struct sb_instruction_header_t hdr;
119 uint32_t addr;
120 uint32_t len;
121 uint32_t crc;
122} __attribute__((packed));
123
124struct sb_instruction_fill_t
125{
126 struct sb_instruction_header_t hdr;
127 uint32_t addr;
128 uint32_t len;
129 uint32_t pattern;
130} __attribute__((packed));
131
132struct sb_instruction_mode_t
133{
134 struct sb_instruction_header_t hdr;
135 uint32_t zero1;
136 uint32_t zero2;
137 uint32_t mode;
138} __attribute__((packed));
139
140struct sb_instruction_call_t
141{
142 struct sb_instruction_header_t hdr;
143 uint32_t addr;
144 uint32_t zero;
145 uint32_t arg;
146} __attribute__((packed));
147
148struct sb_instruction_tag_t
149{
150 struct sb_instruction_header_t hdr;
151 uint32_t identifier; /* section identifier */
152 uint32_t len; /* length of the section */
153 uint32_t flags; /* section flags */
154} __attribute__((packed));
155
156/*******
157 * API *
158 *******/
159
160#define SB_INST_DATA 0xff
161
162struct sb_inst_t
163{
164 uint8_t inst; /* SB_INST_* */
165 uint32_t size;
166 uint32_t addr;
167 // <union>
168 void *data;
169 uint32_t pattern;
170 // </union>
171 uint32_t argument; // for call, jump and mode
172 /* for production use */
173 uint32_t padding_size;
174 uint8_t *padding;
175};
176
177struct sb_section_t
178{
179 uint32_t identifier;
180 bool is_data;
181 bool is_cleartext;
182 uint32_t alignment;
183 // data sections are handled as one or more SB_INST_DATA virtual instruction
184 int nr_insts;
185 struct sb_inst_t *insts;
186 /* for production use */
187 uint32_t file_offset; /* in blocks */
188 uint32_t sec_size; /* in blocks */
189};
190
191struct sb_file_t
192{
193 /* override real, otherwise it is randomly generated */
194 bool override_real_key;
195 uint8_t real_key[16];
196 /* override crypto IV, use with caution ! Use NULL to generate it */
197 bool override_crypto_iv;
198 uint8_t crypto_iv[16];
199
200 int nr_sections;
201 uint16_t drive_tag;
202 uint32_t first_boot_sec_id;
203 uint16_t flags;
204 uint8_t minor_version;
205 struct sb_section_t *sections;
206 struct sb_version_t product_ver;
207 struct sb_version_t component_ver;
208 /* for production use */
209 uint32_t image_size; /* in blocks */
210};
211
212enum sb_error_t
213{
214 SB_SUCCESS = 0,
215 SB_ERROR = -1,
216 SB_OPEN_ERROR = -2,
217 SB_READ_ERROR = -3,
218 SB_WRITE_ERROR = -4,
219 SB_FORMAT_ERROR = -5,
220 SB_CHECKSUM_ERROR = -6,
221 SB_NO_VALID_KEY = -7,
222 SB_FIRST_CRYPTO_ERROR = -8,
223 SB_LAST_CRYPTO_ERROR = SB_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS,
224};
225
226enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename);
227
228typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...);
229struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
230 sb_color_printf printf, enum sb_error_t *err);
231
232void sb_fill_section_name(char name[5], uint32_t identifier);
233void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf);
234void sb_free_section(struct sb_section_t file);
235void sb_free(struct sb_file_t *file);
236
237#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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <libusb.h>
25#include <stdint.h>
26
27void put32le(uint8_t *buf, uint32_t i)
28{
29 *buf++ = i & 0xff;
30 *buf++ = (i >> 8) & 0xff;
31 *buf++ = (i >> 16) & 0xff;
32 *buf++ = (i >> 24) & 0xff;
33}
34
35void put32be(uint8_t *buf, uint32_t i)
36{
37 *buf++ = (i >> 24) & 0xff;
38 *buf++ = (i >> 16) & 0xff;
39 *buf++ = (i >> 8) & 0xff;
40 *buf++ = i & 0xff;
41}
42
43int main(int argc, char **argv)
44{
45 int ret;
46 uint8_t msg[0x20];
47 uint8_t *p;
48 FILE *f;
49 int i, xfer_size, nr_xfers, recv_size;
50
51 if(argc != 3)
52 {
53 printf("usage: %s <xfer size> <file>\n", argv[0]);
54 return 1;
55 }
56
57 char *end;
58 xfer_size = strtol(argv[1], &end, 0);
59 if(end != (argv[1] + strlen(argv[1])))
60 {
61 printf("Invalid transfer size !\n");
62 return 1;
63 }
64
65 libusb_device_handle *dev;
66
67 libusb_init(NULL);
68
69 libusb_set_debug(NULL, 3);
70
71 /* MX23 */
72 dev = libusb_open_device_with_vid_pid(NULL, 0x066F, 0x3780);
73 if(dev == NULL)
74 /* MX28 */
75 dev = libusb_open_device_with_vid_pid(NULL, 0x15A2, 0x004F);
76 if(dev == NULL)
77 {
78 printf("Cannot open device\n");
79 return 1;
80 }
81
82 libusb_detach_kernel_driver(dev, 0);
83 libusb_detach_kernel_driver(dev, 4);
84
85 libusb_claim_interface (dev, 0);
86 libusb_claim_interface (dev, 4);
87
88 if (!dev)
89 {
90 printf("No dev\n");
91 exit(1);
92 }
93
94 f = fopen(argv[2], "r");
95 if(f == NULL)
96 {
97 perror("cannot open file");
98 return 1;
99 }
100 fseek(f, 0, SEEK_END);
101 size_t size = ftell(f);
102 fseek(f, 0, SEEK_SET);
103
104 printf("Transfer size: %d\n", xfer_size);
105 nr_xfers = (size + xfer_size - 1) / xfer_size;
106 uint8_t *file_buf = malloc(nr_xfers * xfer_size);
107 memset(file_buf, 0xff, nr_xfers * xfer_size); // pad with 0xff
108 if(fread(file_buf, size, 1, f) != 1)
109 {
110 perror("read error");
111 fclose(f);
112 return 1;
113 }
114 fclose(f);
115
116 memset(msg, 0, 0x20);
117
118 p = msg;
119
120 *p++ = 0x01; // Init upload command
121 *p++ = 'B'; // Signature
122 *p++ = 'L';
123 *p++ = 'T';
124 *p++ = 'C';
125 put32le(p, 0x1); // I guess version or sub-command
126 p += 4;
127 put32le(p, size); // Payload size
128
129 // The second command starts at 0x20
130
131 p = &msg[0x10];
132
133 *p++ = 0x02; // Start upload
134 put32be(p, size); // Payload size, again
135
136 ret = libusb_control_transfer(dev,
137 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 0x9, 0x201, 0,
138 msg, 0x20, 1000);
139 if(ret < 0)
140 {
141 printf("transfer error at init step\n");
142 return 1;
143 }
144
145 uint8_t *xfer_buf = malloc(1 + xfer_size);
146
147 for(i = 0; i < nr_xfers; i++)
148 {
149 xfer_buf[0] = 0x2;
150 memcpy(&xfer_buf[1], &file_buf[i * xfer_size], xfer_size);
151
152 ret = libusb_control_transfer(dev,
153 LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
154 0x9, 0x202, 0, xfer_buf, xfer_size + 1, 1000);
155 if(ret < 0)
156 {
157 printf("transfer error at send step %d\n", i);
158 return 1;
159 }
160 }
161
162 ret = libusb_interrupt_transfer(dev, 0x81, xfer_buf, xfer_size, &recv_size,
163 1000);
164 if(ret < 0)
165 {
166 printf("transfer error at final stage\n");
167 return 1;
168 }
169
170 printf("ret %i\n", ret);
171
172 return 0;
173}
174
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Bertrik Sikken
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22/*
23 * .sb file parser and chunk extractor
24 *
25 * Based on amsinfo, which is
26 * Copyright © 2008 Rafaël Carré <rafael.carre@gmail.com>
27 */
28
29#define _ISOC99_SOURCE /* snprintf() */
30#include <stdio.h>
31#include <errno.h>
32#include <stdlib.h>
33#include <string.h>
34#include <ctype.h>
35#include <time.h>
36#include <stdarg.h>
37#include <strings.h>
38#include <getopt.h>
39
40#include "crypto.h"
41#include "elf.h"
42#include "sb.h"
43#include "misc.h"
44
45/* all blocks are sized as a multiple of 0x1ff */
46#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
47
48/* If you find a firmware that breaks the known format ^^ */
49#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)
50
51#define crypto_cbc(...) \
52 do { int ret = crypto_cbc(__VA_ARGS__); \
53 if(ret != CRYPTO_ERROR_SUCCESS) \
54 bug("crypto_cbc error: %d\n", ret); \
55 }while(0)
56
57/* globals */
58
59char *g_out_prefix;
60
61static void elf_printf(void *user, bool error, const char *fmt, ...)
62{
63 if(!g_debug && !error)
64 return;
65 (void) user;
66 va_list args;
67 va_start(args, fmt);
68 vprintf(fmt, args);
69 va_end(args);
70}
71
72static void elf_write(void *user, uint32_t addr, const void *buf, size_t count)
73{
74 FILE *f = user;
75 fseek(f, addr, SEEK_SET);
76 fwrite(buf, count, 1, f);
77}
78
79static void extract_elf_section(struct elf_params_t *elf, int count, uint32_t id)
80{
81 char name[5];
82 char *filename = xmalloc(strlen(g_out_prefix) + 32);
83 sb_fill_section_name(name, id);
84 sprintf(filename, "%s%s.%d.elf", g_out_prefix, name, count);
85 if(g_debug)
86 printf("Write boot section %s to %s\n", name, filename);
87
88 FILE *fd = fopen(filename, "wb");
89 free(filename);
90
91 if(fd == NULL)
92 return ;
93 elf_write_file(elf, elf_write, elf_printf, fd);
94 fclose(fd);
95}
96
97static void extract_sb_section(struct sb_section_t *sec)
98{
99 if(sec->is_data)
100 {
101 char sec_name[5];
102 char *filename = xmalloc(strlen(g_out_prefix) + 32);
103 sb_fill_section_name(sec_name, sec->identifier);
104 sprintf(filename, "%s%s.bin", g_out_prefix, sec_name);
105 FILE *fd = fopen(filename, "wb");
106 if(fd == NULL)
107 bugp("Cannot open %s for writing\n", filename);
108 if(g_debug)
109 printf("Write data section %s to %s\n", sec_name, filename);
110 free(filename);
111
112 for(int j = 0; j < sec->nr_insts; j++)
113 {
114 assert(sec->insts[j].inst == SB_INST_DATA);
115 fwrite(sec->insts[j].data, sec->insts[j].size, 1, fd);
116 }
117 fclose(fd);
118 }
119
120 int elf_count = 0;
121 struct elf_params_t elf;
122 elf_init(&elf);
123
124 for(int i = 0; i < sec->nr_insts; i++)
125 {
126 struct sb_inst_t *inst = &sec->insts[i];
127 switch(inst->inst)
128 {
129 case SB_INST_LOAD:
130 elf_add_load_section(&elf, inst->addr, inst->size, inst->data);
131 break;
132 case SB_INST_FILL:
133 elf_add_fill_section(&elf, inst->addr, inst->size, inst->pattern);
134 break;
135 case SB_INST_CALL:
136 case SB_INST_JUMP:
137 elf_set_start_addr(&elf, inst->addr);
138 extract_elf_section(&elf, elf_count++, sec->identifier);
139 elf_release(&elf);
140 elf_init(&elf);
141 break;
142 default:
143 /* ignore mode and nop */
144 break;
145 }
146 }
147
148 if(!elf_is_empty(&elf))
149 extract_elf_section(&elf, elf_count, sec->identifier);
150 elf_release(&elf);
151}
152
153static void extract_sb_file(struct sb_file_t *file)
154{
155 for(int i = 0; i < file->nr_sections; i++)
156 extract_sb_section(&file->sections[i]);
157}
158
159static void usage(void)
160{
161 printf("Usage: sbtoelf [options] sb-file\n");
162 printf("Options:\n");
163 printf(" -?/--help\tDisplay this message\n");
164 printf(" -o <prefix>\tEnable output and set prefix\n");
165 printf(" -d/--debug\tEnable debug output*\n");
166 printf(" -k <file>\tAdd key file\n");
167 printf(" -z\t\tAdd zero key\n");
168 printf(" -r\t\tUse raw command mode\n");
169 printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n");
170 printf(" -n/--no-color\tDisable output colors\n");
171 printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n");
172 printf("Options marked with a * are for debug purpose only\n");
173 exit(1);
174}
175
176static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...)
177{
178 (void) user;
179 (void) error;
180 va_list args;
181 va_start(args, fmt);
182 color(c);
183 vprintf(fmt, args);
184 va_end(args);
185}
186
187static struct crypto_key_t g_zero_key =
188{
189 .method = CRYPTO_KEY,
190 .u.key = {0}
191};
192
193int main(int argc, char **argv)
194{
195 bool raw_mode = false;
196 const char *loopback = NULL;
197
198 while(1)
199 {
200 static struct option long_options[] =
201 {
202 {"help", no_argument, 0, '?'},
203 {"debug", no_argument, 0, 'd'},
204 {"add-key", required_argument, 0, 'a'},
205 {"no-color", no_argument, 0, 'n'},
206 {"loopback", required_argument, 0, 'l'},
207 {0, 0, 0, 0}
208 };
209
210 int c = getopt_long(argc, argv, "?do:k:zra:nl:", long_options, NULL);
211 if(c == -1)
212 break;
213 switch(c)
214 {
215 case -1:
216 break;
217 case 'l':
218 if(loopback)
219 bug("Only one loopback file can be specified !\n");
220 loopback = optarg;
221 break;
222 case 'n':
223 enable_color(false);
224 break;
225 case 'd':
226 g_debug = true;
227 break;
228 case '?':
229 usage();
230 break;
231 case 'o':
232 g_out_prefix = optarg;
233 break;
234 case 'k':
235 {
236 add_keys_from_file(optarg);
237 break;
238 }
239 case 'z':
240 {
241 add_keys(&g_zero_key, 1);
242 break;
243 }
244 case 'r':
245 raw_mode = true;
246 break;
247 case 'a':
248 {
249 struct crypto_key_t key;
250 char *s = optarg;
251 if(!parse_key(&s, &key))
252 bug("Invalid key specified as argument");
253 if(*s != 0)
254 bug("Trailing characters after key specified as argument");
255 add_keys(&key, 1);
256 break;
257 }
258 default:
259 abort();
260 }
261 }
262
263 if(argc - optind != 1)
264 {
265 usage();
266 return 1;
267 }
268
269 const char *sb_filename = argv[optind];
270
271 enum sb_error_t err;
272 struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err);
273 if(file == NULL)
274 {
275 color(OFF);
276 printf("SB read failed: %d\n", err);
277 return 1;
278 }
279
280 color(OFF);
281 if(g_out_prefix)
282 extract_sb_file(file);
283 if(g_debug)
284 {
285 color(GREY);
286 printf("[Debug output]\n");
287 sb_dump(file, NULL, sb_printf);
288 }
289 if(loopback)
290 {
291 /* sb_read_file will fill real key and IV but we don't want to override
292 * them when looping back otherwise the output will be inconsistent and
293 * garbage */
294 file->override_real_key = false;
295 file->override_crypto_iv = false;
296 sb_write_file(file, loopback);
297 }
298 sb_free(file);
299 clear_keys();
300
301 return 0;
302}
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21/* Based on http://en.wikipedia.org/wiki/SHA-1 */
22#include "crypto.h"
23
24static uint32_t rot_left(uint32_t val, int rot)
25{
26 return (val << rot) | (val >> (32 - rot));
27}
28
29static inline void byte_swapxx(byte *ptr, int size)
30{
31 for(int i = 0; i < size / 2; i++)
32 {
33 byte c = ptr[i];
34 ptr[i] = ptr[size - i - 1];
35 ptr[size - i - 1] = c;
36 }
37}
38
39static void byte_swap32(uint32_t *v)
40{
41 byte_swapxx((byte *)v, 4);
42}
43
44void sha_1_init(struct sha_1_params_t *params)
45{
46 params->hash[0] = 0x67452301;
47 params->hash[1] = 0xEFCDAB89;
48 params->hash[2] = 0x98BADCFE;
49 params->hash[3] = 0x10325476;
50 params->hash[4] = 0xC3D2E1F0;
51 params->buffer_nr_bits = 0;
52}
53
54void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size)
55{
56 int buffer_nr_bytes = (params->buffer_nr_bits / 8) % 64;
57 params->buffer_nr_bits += 8 * size;
58 int pos = 0;
59 if(buffer_nr_bytes + size >= 64)
60 {
61 pos = 64 - buffer_nr_bytes;
62 memcpy((byte *)(params->w) + buffer_nr_bytes, buffer, 64 - buffer_nr_bytes);
63 sha_1_block(params, params->hash, (byte *)params->w);
64 for(; pos + 64 <= size; pos += 64)
65 sha_1_block(params, params->hash, buffer + pos);
66 buffer_nr_bytes = 0;
67 }
68 memcpy((byte *)(params->w) + buffer_nr_bytes, buffer + pos, size - pos);
69}
70
71void sha_1_finish(struct sha_1_params_t *params)
72{
73 /* length (in bits) in big endian BEFORE preprocessing */
74 byte length_big_endian[8];
75 memcpy(length_big_endian, &params->buffer_nr_bits, 8);
76 byte_swapxx(length_big_endian, 8);
77 /* append '1' and then '0's to the message to get 448 bit length for the last block */
78 byte b = 0x80;
79 sha_1_update(params, &b, 1);
80 b = 0;
81 while((params->buffer_nr_bits % 512) != 448)
82 sha_1_update(params, &b, 1);
83 /* append length */
84 sha_1_update(params, length_big_endian, 8);
85 /* go back to big endian */
86 for(int i = 0; i < 5; i++)
87 byte_swap32(&params->hash[i]);
88}
89
90void sha_1_output(struct sha_1_params_t *params, byte *out)
91{
92 memcpy(out, params->hash, 20);
93}
94
95void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data)
96{
97 uint32_t a, b, c, d, e;
98 a = cur_hash[0];
99 b = cur_hash[1];
100 c = cur_hash[2];
101 d = cur_hash[3];
102 e = cur_hash[4];
103
104 #define w params->w
105
106 memmove(w, data, 64);
107 for(int i = 0; i < 16; i++)
108 byte_swap32(&w[i]);
109
110 for(int i = 16; i <= 79; i++)
111 w[i] = rot_left(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
112
113 for(int i = 0; i<= 79; i++)
114 {
115 uint32_t f, k;
116 if(i <= 19)
117 {
118 f = (b & c) | ((~b) & d);
119 k = 0x5A827999;
120 }
121 else if(i <= 39)
122 {
123 f = b ^ c ^ d;
124 k = 0x6ED9EBA1;
125 }
126 else if(i <= 59)
127 {
128 f = (b & c) | (b & d) | (c & d);
129 k = 0x8F1BBCDC;
130 }
131 else
132 {
133 f = b ^ c ^ d;
134 k = 0xCA62C1D6;
135 }
136 uint32_t temp = rot_left(a, 5) + f + e + k + w[i];
137 e = d;
138 d = c;
139 c = rot_left(b, 30);
140 b = a;
141 a = temp;
142 }
143 #undef w
144
145 cur_hash[0] += a;
146 cur_hash[1] += b;
147 cur_hash[2] += c;
148 cur_hash[3] += d;
149 cur_hash[4] += e;
150}