summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2011-10-29 14:22:17 +0000
committerAmaury Pouly <pamaury@rockbox.org>2011-10-29 14:22:17 +0000
commit9fe029b12a0828b247718fc89b08547b1ab916b5 (patch)
tree3266139e28cc4d0a5e768796d0477088928cffd2
parentb7547e58680c32879392e424bdd70d1719d384b9 (diff)
downloadrockbox-9fe029b12a0828b247718fc89b08547b1ab916b5.tar.gz
rockbox-9fe029b12a0828b247718fc89b08547b1ab916b5.zip
sbtools: factor key code, introduce crypto layer, move from open/read/... to fopen/fread/..., add support for encryption/decryption using a device when the key is not known, move sbtoelf to use getopt for command line
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30849 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--utils/sbtools/Makefile22
-rw-r--r--utils/sbtools/crypto.c188
-rw-r--r--utils/sbtools/crypto.h56
-rw-r--r--utils/sbtools/elftosb.c270
-rw-r--r--utils/sbtools/misc.c174
-rw-r--r--utils/sbtools/misc.h48
-rw-r--r--utils/sbtools/sbtoelf.c274
7 files changed, 720 insertions, 312 deletions
diff --git a/utils/sbtools/Makefile b/utils/sbtools/Makefile
index dc9c0966a7..15d3adb8a1 100644
--- a/utils/sbtools/Makefile
+++ b/utils/sbtools/Makefile
@@ -1,10 +1,22 @@
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`
6
1all: elftosb sbtoelf 7all: elftosb sbtoelf
2 8
3sbtoelf: sbtoelf.c crc.c crypto.h aes128.c sha1.c elf.c sb.h 9%.o: %.c
4 gcc -g -std=c99 -o $@ -W -Wall $^ 10 $(CC) $(CFLAGS) -c -o $@ $<
11
12sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o
13 $(LD) $(LDFLAGS) -o $@ $^
5 14
6elftosb: elftosb.c crc.c crypto.h aes128.c sha1.c elf.c sb.h dbparser.h dbparser.c 15elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o
7 gcc -g -std=c99 -o $@ -W -Wall $^ 16 $(LD) $(LDFLAGS) -o $@ $^
8 17
9clean: 18clean:
10 rm -fr elftosb sbtoelf 19 rm -fr *.o
20
21veryclean:
22 rm -rf sbtoelf elftosb
diff --git a/utils/sbtools/crypto.c b/utils/sbtools/crypto.c
new file mode 100644
index 0000000000..d4afc6c816
--- /dev/null
+++ b/utils/sbtools/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/sbtools/crypto.h b/utils/sbtools/crypto.h
index 0662ef8587..51f44406db 100644
--- a/utils/sbtools/crypto.h
+++ b/utils/sbtools/crypto.h
@@ -18,6 +18,9 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#ifndef __CRYPTO_H__
22#define __CRYPTO_H__
23
21#include <stdio.h> 24#include <stdio.h>
22#include <stdint.h> 25#include <stdint.h>
23#include <string.h> 26#include <string.h>
@@ -39,6 +42,57 @@ void cbc_mac(
39 int encrypt /* 1 to encrypt, 0 to decrypt */ 42 int encrypt /* 1 to encrypt, 0 to decrypt */
40 ); 43 );
41 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/* return 0 on success, <0 on error */
67int crypto_apply(
68 byte *in_data, /* Input data */
69 byte *out_data, /* Output data (or NULL) */
70 int nr_blocks, /* Number of blocks (one block=16 bytes) */
71 byte iv[16], /* IV */
72 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
73 int encrypt);
74
75/* all-in-one function */
76struct crypto_key_t
77{
78 enum crypto_method_t method;
79 union
80 {
81 byte key[16];
82 uint32_t vid_pid;
83 byte param[0];
84 }u;
85};
86
87int crypto_cbc(
88 byte *in_data, /* Input data */
89 byte *out_data, /* Output data (or NULL) */
90 int nr_blocks, /* Number of blocks (one block=16 bytes) */
91 struct crypto_key_t *key, /* Key */
92 byte iv[16], /* IV */
93 byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
94 int encrypt);
95
42/* crc.c */ 96/* crc.c */
43uint32_t crc(byte *data, int size); 97uint32_t crc(byte *data, int size);
44uint32_t crc_continue(uint32_t previous_crc, byte *data, int size); 98uint32_t crc_continue(uint32_t previous_crc, byte *data, int size);
@@ -56,3 +110,5 @@ void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data
56void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size); 110void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size);
57void sha_1_finish(struct sha_1_params_t *params); 111void sha_1_finish(struct sha_1_params_t *params);
58void sha_1_output(struct sha_1_params_t *params, byte *out); 112void sha_1_output(struct sha_1_params_t *params, byte *out);
113
114#endif /* __CRYPTO_H__ */
diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c
index 17b72417cf..5e65ba3261 100644
--- a/utils/sbtools/elftosb.c
+++ b/utils/sbtools/elftosb.c
@@ -21,13 +21,8 @@
21 21
22#define _ISOC99_SOURCE 22#define _ISOC99_SOURCE
23#include <stdio.h> 23#include <stdio.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <fcntl.h>
27#include <errno.h> 24#include <errno.h>
28#include <unistd.h>
29#include <stdlib.h> 25#include <stdlib.h>
30#include <inttypes.h>
31#include <string.h> 26#include <string.h>
32#include <ctype.h> 27#include <ctype.h>
33#include <time.h> 28#include <time.h>
@@ -39,143 +34,18 @@
39#include "elf.h" 34#include "elf.h"
40#include "sb.h" 35#include "sb.h"
41#include "dbparser.h" 36#include "dbparser.h"
37#include "misc.h"
42 38
43#define _STR(a) #a
44#define STR(a) _STR(a)
45
46#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0)
47#define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
48
49bool g_debug = false;
50char **g_extern; 39char **g_extern;
51int g_extern_count; 40int g_extern_count;
52 41
53#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) 42#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
54 43
55/** 44#define crypto_cbc(...) \
56 * Misc 45 do { int ret = crypto_cbc(__VA_ARGS__); \
57 */ 46 if(ret != CRYPTO_ERROR_SUCCESS) \
58 47 bug("crypto_cbc error: %d\n", ret); \
59char *s_getenv(const char *name) 48 }while(0)
60{
61 char *s = getenv(name);
62 return s ? s : "";
63}
64
65void generate_random_data(void *buf, size_t sz)
66{
67 static int rand_fd = -1;
68 if(rand_fd == -1)
69 rand_fd = open("/dev/urandom", O_RDONLY);
70 if(rand_fd == -1)
71 bugp("failed to open /dev/urandom");
72 if(read(rand_fd, buf, sz) != (ssize_t)sz)
73 bugp("failed to read /dev/urandom");
74}
75
76void *xmalloc(size_t s) /* malloc helper, used in elf.c */
77{
78 void * r = malloc(s);
79 if(!r) bugp("malloc");
80 return r;
81}
82
83int convxdigit(char digit, byte *val)
84{
85 if(digit >= '0' && digit <= '9')
86 {
87 *val = digit - '0';
88 return 0;
89 }
90 else if(digit >= 'A' && digit <= 'F')
91 {
92 *val = digit - 'A' + 10;
93 return 0;
94 }
95 else if(digit >= 'a' && digit <= 'f')
96 {
97 *val = digit - 'a' + 10;
98 return 0;
99 }
100 else
101 return 1;
102}
103
104/**
105 * Key file parsing
106 */
107
108typedef byte (*key_array_t)[16];
109
110int g_nr_keys;
111key_array_t g_key_array;
112
113static void add_keys(key_array_t ka, int kac)
114{
115 key_array_t new_ka = xmalloc((g_nr_keys + kac) * 16);
116 memcpy(new_ka, g_key_array, g_nr_keys * 16);
117 memcpy(new_ka + g_nr_keys, ka, kac * 16);
118 free(g_key_array);
119 g_key_array = new_ka;
120 g_nr_keys += kac;
121}
122
123static key_array_t read_keys(const char *key_file, int *num_keys)
124{
125 int size;
126 struct stat st;
127 int fd = open(key_file,O_RDONLY);
128 if(fd == -1)
129 bugp("opening key file failed");
130 if(fstat(fd,&st) == -1)
131 bugp("key file stat() failed");
132 size = st.st_size;
133 char *buf = xmalloc(size);
134 if(read(fd, buf, size) != (ssize_t)size)
135 bugp("reading key file");
136 close(fd);
137
138 if(g_debug)
139 printf("Parsing key file '%s'...\n", key_file);
140 *num_keys = size ? 1 : 0;
141 char *ptr = buf;
142 /* allow trailing newline at the end (but no space after it) */
143 while(ptr != buf + size && (ptr + 1) != buf + size)
144 {
145 if(*ptr++ == '\n')
146 (*num_keys)++;
147 }
148
149 key_array_t keys = xmalloc(sizeof(byte[16]) * *num_keys);
150 int pos = 0;
151 for(int i = 0; i < *num_keys; i++)
152 {
153 /* skip ws */
154 while(pos < size && isspace(buf[pos]))
155 pos++;
156 /* enough space ? */
157 if((pos + 32) > size)
158 bugp("invalid key file");
159 for(int j = 0; j < 16; j++)
160 {
161 byte a, b;
162 if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
163 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
164 keys[i][j] = (a << 4) | b;
165 }
166 if(g_debug)
167 {
168 printf("Add key: ");
169 for(int j = 0; j < 16; j++)
170 printf("%02x", keys[i][j]);
171 printf("\n");
172 }
173 pos += 32;
174 }
175 free(buf);
176
177 return keys;
178}
179 49
180/** 50/**
181 * command file to sb conversion 51 * command file to sb conversion
@@ -224,9 +94,9 @@ struct sb_file_t
224 94
225static bool elf_read(void *user, uint32_t addr, void *buf, size_t count) 95static bool elf_read(void *user, uint32_t addr, void *buf, size_t count)
226{ 96{
227 if(lseek(*(int *)user, addr, SEEK_SET) == (off_t)-1) 97 if(fseek((FILE *)user, addr, SEEK_SET) == -1)
228 return false; 98 return false;
229 return read(*(int *)user, buf, count) == (ssize_t)count; 99 return fread(buf, 1, count, (FILE *)user) == count;
230} 100}
231 101
232static void elf_printf(void *user, bool error, const char *fmt, ...) 102static void elf_printf(void *user, bool error, const char *fmt, ...)
@@ -264,14 +134,14 @@ static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
264 resolve_extern(src); 134 resolve_extern(src);
265 /* load it */ 135 /* load it */
266 src->type = CMD_SRC_ELF; 136 src->type = CMD_SRC_ELF;
267 int fd = open(src->filename, O_RDONLY); 137 FILE *fd = fopen(src->filename, "rb");
268 if(fd < 0) 138 if(fd == NULL)
269 bug("cannot open '%s' (id '%s')\n", src->filename, id); 139 bug("cannot open '%s' (id '%s')\n", src->filename, id);
270 if(g_debug) 140 if(g_debug)
271 printf("Loading ELF file '%s'...\n", src->filename); 141 printf("Loading ELF file '%s'...\n", src->filename);
272 elf_init(&src->elf); 142 elf_init(&src->elf);
273 src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, &fd); 143 src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, fd);
274 close(fd); 144 fclose(fd);
275 if(!src->loaded) 145 if(!src->loaded)
276 bug("error loading elf file '%s' (id '%s')\n", src->filename, id); 146 bug("error loading elf file '%s' (id '%s')\n", src->filename, id);
277 elf_translate_addresses(&src->elf); 147 elf_translate_addresses(&src->elf);
@@ -291,16 +161,17 @@ static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id)
291 resolve_extern(src); 161 resolve_extern(src);
292 /* load it */ 162 /* load it */
293 src->type = CMD_SRC_BIN; 163 src->type = CMD_SRC_BIN;
294 int fd = open(src->filename, O_RDONLY); 164 FILE *fd = fopen(src->filename, "rb");
295 if(fd < 0) 165 if(fd == NULL)
296 bug("cannot open '%s' (id '%s')\n", src->filename, id); 166 bug("cannot open '%s' (id '%s')\n", src->filename, id);
297 if(g_debug) 167 if(g_debug)
298 printf("Loading BIN file '%s'...\n", src->filename); 168 printf("Loading BIN file '%s'...\n", src->filename);
299 src->bin.size = lseek(fd, 0, SEEK_END); 169 fseek(fd, 0, SEEK_END);
300 lseek(fd, 0, SEEK_SET); 170 src->bin.size = ftell(fd);
171 fseek(fd, 0, SEEK_SET);
301 src->bin.data = xmalloc(src->bin.size); 172 src->bin.data = xmalloc(src->bin.size);
302 read(fd, src->bin.data, src->bin.size); 173 fread(src->bin.data, 1, src->bin.size, fd);
303 close(fd); 174 fclose(fd);
304 src->loaded = true; 175 src->loaded = true;
305} 176}
306 177
@@ -767,12 +638,12 @@ void produce_sb_instruction(struct sb_inst_t *inst,
767 638
768static void produce_sb_file(struct sb_file_t *sb, const char *filename) 639static void produce_sb_file(struct sb_file_t *sb, const char *filename)
769{ 640{
770 int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 641 FILE *fd = fopen(filename, "wb");
771 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 642 if(fd == NULL)
772 if(fd < 0)
773 bugp("cannot open output file"); 643 bugp("cannot open output file");
774 644
775 byte real_key[16]; 645 struct crypto_key_t real_key;
646 real_key.method = CRYPTO_KEY;
776 byte crypto_iv[16]; 647 byte crypto_iv[16];
777 byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys); 648 byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys);
778 /* init CBC-MACs */ 649 /* init CBC-MACs */
@@ -782,7 +653,7 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
782 fill_gaps(sb); 653 fill_gaps(sb);
783 compute_sb_offsets(sb); 654 compute_sb_offsets(sb);
784 655
785 generate_random_data(real_key, sizeof(real_key)); 656 generate_random_data(real_key.u.key, 16);
786 657
787 /* global SHA-1 */ 658 /* global SHA-1 */
788 struct sha_1_params_t file_sha1; 659 struct sha_1_params_t file_sha1;
@@ -791,13 +662,13 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
791 struct sb_header_t sb_hdr; 662 struct sb_header_t sb_hdr;
792 produce_sb_header(sb, &sb_hdr); 663 produce_sb_header(sb, &sb_hdr);
793 sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr)); 664 sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
794 write(fd, &sb_hdr, sizeof(sb_hdr)); 665 fwrite(&sb_hdr, 1, sizeof(sb_hdr), fd);
795 666
796 memcpy(crypto_iv, &sb_hdr, 16); 667 memcpy(crypto_iv, &sb_hdr, 16);
797 668
798 /* update CBC-MACs */ 669 /* update CBC-MACs */
799 for(int i = 0; i < g_nr_keys; i++) 670 for(int i = 0; i < g_nr_keys; i++)
800 cbc_mac((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, g_key_array[i], 671 crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i],
801 cbc_macs[i], &cbc_macs[i], 1); 672 cbc_macs[i], &cbc_macs[i], 1);
802 673
803 /* produce and write section headers */ 674 /* produce and write section headers */
@@ -806,21 +677,21 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
806 struct sb_section_header_t sb_sec_hdr; 677 struct sb_section_header_t sb_sec_hdr;
807 produce_sb_section_header(&sb->sections[i], &sb_sec_hdr); 678 produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
808 sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr)); 679 sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
809 write(fd, &sb_sec_hdr, sizeof(sb_sec_hdr)); 680 fwrite(&sb_sec_hdr, 1, sizeof(sb_sec_hdr), fd);
810 /* update CBC-MACs */ 681 /* update CBC-MACs */
811 for(int j = 0; j < g_nr_keys; j++) 682 for(int j = 0; j < g_nr_keys; j++)
812 cbc_mac((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE, 683 crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
813 g_key_array[j], cbc_macs[j], &cbc_macs[j], 1); 684 &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
814 } 685 }
815 /* produce key dictionary */ 686 /* produce key dictionary */
816 for(int i = 0; i < g_nr_keys; i++) 687 for(int i = 0; i < g_nr_keys; i++)
817 { 688 {
818 struct sb_key_dictionary_entry_t entry; 689 struct sb_key_dictionary_entry_t entry;
819 memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16); 690 memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16);
820 cbc_mac(real_key, entry.key, sizeof(real_key) / BLOCK_SIZE, g_key_array[i], 691 crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
821 crypto_iv, NULL, 1); 692 crypto_iv, NULL, 1);
822 693
823 write(fd, &entry, sizeof(entry)); 694 fwrite(&entry, 1, sizeof(entry), fd);
824 sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry)); 695 sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
825 } 696 }
826 697
@@ -836,7 +707,7 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
836 byte a, b; 707 byte a, b;
837 if(convxdigit(key[2 * i], &a) || convxdigit(key[2 * i + 1], &b)) 708 if(convxdigit(key[2 * i], &a) || convxdigit(key[2 * i + 1], &b))
838 bugp("Cannot override real key: key should be a 128-bit key written in hexadecimal\n"); 709 bugp("Cannot override real key: key should be a 128-bit key written in hexadecimal\n");
839 real_key[i] = (a << 4) | b; 710 real_key.u.key[i] = (a << 4) | b;
840 } 711 }
841 } 712 }
842 if(strlen(s_getenv("SB_OVERRIDE_IV")) != 0) 713 if(strlen(s_getenv("SB_OVERRIDE_IV")) != 0)
@@ -858,7 +729,7 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
858 { 729 {
859 printf("Real key: "); 730 printf("Real key: ");
860 for(int j = 0; j < 16; j++) 731 for(int j = 0; j < 16; j++)
861 printf("%02x", real_key[j]); 732 printf("%02x", real_key.u.key[j]);
862 printf("\n"); 733 printf("\n");
863 printf("IV : "); 734 printf("IV : ");
864 for(int j = 0; j < 16; j++) 735 for(int j = 0; j < 16; j++)
@@ -872,10 +743,10 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
872 struct sb_instruction_tag_t tag_cmd; 743 struct sb_instruction_tag_t tag_cmd;
873 produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections); 744 produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
874 if(g_nr_keys > 0) 745 if(g_nr_keys > 0)
875 cbc_mac((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE, 746 crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
876 real_key, crypto_iv, NULL, 1); 747 &real_key, crypto_iv, NULL, 1);
877 sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd)); 748 sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
878 write(fd, &tag_cmd, sizeof(tag_cmd)); 749 fwrite(&tag_cmd, 1, sizeof(tag_cmd), fd);
879 /* produce other commands */ 750 /* produce other commands */
880 byte cur_cbc_mac[16]; 751 byte cur_cbc_mac[16];
881 memcpy(cur_cbc_mac, crypto_iv, 16); 752 memcpy(cur_cbc_mac, crypto_iv, 16);
@@ -888,10 +759,10 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
888 struct sb_instruction_common_t cmd; 759 struct sb_instruction_common_t cmd;
889 produce_sb_instruction(inst, &cmd); 760 produce_sb_instruction(inst, &cmd);
890 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) 761 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
891 cbc_mac((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE, 762 crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
892 real_key, cur_cbc_mac, &cur_cbc_mac, 1); 763 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
893 sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); 764 sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
894 write(fd, &cmd, sizeof(cmd)); 765 fwrite(&cmd, 1, sizeof(cmd), fd);
895 } 766 }
896 /* data */ 767 /* data */
897 if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA) 768 if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
@@ -901,10 +772,10 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
901 memcpy(data, inst->data, inst->size); 772 memcpy(data, inst->data, inst->size);
902 memcpy(data + inst->size, inst->padding, inst->padding_size); 773 memcpy(data + inst->size, inst->padding, inst->padding_size);
903 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) 774 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
904 cbc_mac(data, data, sz / BLOCK_SIZE, 775 crypto_cbc(data, data, sz / BLOCK_SIZE,
905 real_key, cur_cbc_mac, &cur_cbc_mac, 1); 776 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
906 sha_1_update(&file_sha1, data, sz); 777 sha_1_update(&file_sha1, data, sz);
907 write(fd, data, sz); 778 fwrite(data, 1, sz, fd);
908 free(data); 779 free(data);
909 } 780 }
910 } 781 }
@@ -915,10 +786,10 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
915 sha_1_output(&file_sha1, final_sig); 786 sha_1_output(&file_sha1, final_sig);
916 generate_random_data(final_sig + 20, 12); 787 generate_random_data(final_sig + 20, 12);
917 if(g_nr_keys > 0) 788 if(g_nr_keys > 0)
918 cbc_mac(final_sig, final_sig, 2, real_key, crypto_iv, NULL, 1); 789 crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
919 write(fd, final_sig, 32); 790 fwrite(final_sig, 1, 32, fd);
920 791
921 close(fd); 792 fclose(fd);
922} 793}
923 794
924void usage(void) 795void usage(void)
@@ -931,10 +802,16 @@ void usage(void)
931 printf(" -d/--debug\tEnable debug output\n"); 802 printf(" -d/--debug\tEnable debug output\n");
932 printf(" -k <file>\tAdd key file\n"); 803 printf(" -k <file>\tAdd key file\n");
933 printf(" -z\t\tAdd zero key\n"); 804 printf(" -z\t\tAdd zero key\n");
805 printf(" --single-key <key>\tAdd single key\n");
806 printf(" --usb-otp <vid>:<pid>\tAdd USB OTP device\n");
934 exit(1); 807 exit(1);
935} 808}
936 809
937static byte g_zero_key[16] = {0}; 810static struct crypto_key_t g_zero_key =
811{
812 .method = CRYPTO_KEY,
813 .u.key = {0}
814};
938 815
939int main(int argc, char **argv) 816int main(int argc, char **argv)
940{ 817{
@@ -947,6 +824,8 @@ int main(int argc, char **argv)
947 { 824 {
948 {"help", no_argument, 0, '?'}, 825 {"help", no_argument, 0, '?'},
949 {"debug", no_argument, 0, 'd'}, 826 {"debug", no_argument, 0, 'd'},
827 {"single-key", required_argument, 0, 's'},
828 {"usb-otp", required_argument, 0, 'u'},
950 {0, 0, 0, 0} 829 {0, 0, 0, 0}
951 }; 830 };
952 831
@@ -979,6 +858,42 @@ int main(int argc, char **argv)
979 add_keys(&g_zero_key, 1); 858 add_keys(&g_zero_key, 1);
980 break; 859 break;
981 } 860 }
861 case 's':
862 {
863 struct crypto_key_t key;
864 key.method = CRYPTO_KEY;
865 if(strlen(optarg) != 32)
866 bug("The key given in argument is invalid");
867 for(int i = 0; i < 16; i++)
868 {
869 byte a, b;
870 if(convxdigit(optarg[2 * i], &a) || convxdigit(optarg[2 * i + 1], &b))
871 bugp("The key given in argument is invalid\n");
872 key.u.key[i] = (a << 4) | b;
873 }
874 add_keys(&key, 1);
875 break;
876 }
877 case 'u':
878 {
879 int vid, pid;
880 char *p = strchr(optarg, ':');
881 if(p == NULL)
882 bug("Invalid VID/PID\n");
883
884 char *end;
885 vid = strtol(optarg, &end, 16);
886 if(end != p)
887 bug("Invalid VID/PID\n");
888 pid = strtol(p + 1, &end, 16);
889 if(end != (optarg + strlen(optarg)))
890 bug("Invalid VID/PID\n");
891 struct crypto_key_t key;
892 key.method = CRYPTO_USBOTP;
893 key.u.vid_pid = vid << 16 | pid;
894 add_keys(&key, 1);
895 break;
896 }
982 default: 897 default:
983 abort(); 898 abort();
984 } 899 }
@@ -997,9 +912,8 @@ int main(int argc, char **argv)
997 printf("key: %d\n", g_nr_keys); 912 printf("key: %d\n", g_nr_keys);
998 for(int i = 0; i < g_nr_keys; i++) 913 for(int i = 0; i < g_nr_keys; i++)
999 { 914 {
1000 for(int j = 0; j < 16; j++) 915 printf(" ");
1001 printf(" %02x", g_key_array[i][j]); 916 print_key(&g_key_array[i], true);
1002 printf("\n");
1003 } 917 }
1004 918
1005 for(int i = 0; i < g_extern_count; i++) 919 for(int i = 0; i < g_extern_count; i++)
diff --git a/utils/sbtools/misc.c b/utils/sbtools/misc.c
new file mode 100644
index 0000000000..09a8919aef
--- /dev/null
+++ b/utils/sbtools/misc.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 <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
33char *s_getenv(const char *name)
34{
35 char *s = getenv(name);
36 return s ? s : "";
37}
38
39void generate_random_data(void *buf, size_t sz)
40{
41 FILE *rand_fd = fopen("/dev/urandom", "rb");
42 if(rand_fd == NULL)
43 bugp("failed to open /dev/urandom");
44 if(fread(buf, 1, sz, rand_fd) != sz)
45 bugp("failed to read /dev/urandom");
46 fclose(rand_fd);
47}
48
49void *xmalloc(size_t s)
50{
51 void * r = malloc(s);
52 if(!r) bugp("malloc");
53 return r;
54}
55
56int convxdigit(char digit, byte *val)
57{
58 if(digit >= '0' && digit <= '9')
59 {
60 *val = digit - '0';
61 return 0;
62 }
63 else if(digit >= 'A' && digit <= 'F')
64 {
65 *val = digit - 'A' + 10;
66 return 0;
67 }
68 else if(digit >= 'a' && digit <= 'f')
69 {
70 *val = digit - 'a' + 10;
71 return 0;
72 }
73 else
74 return 1;
75}
76
77/**
78 * Key file parsing
79 */
80int g_nr_keys;
81key_array_t g_key_array;
82
83void add_keys(key_array_t ka, int kac)
84{
85 key_array_t new_ka = xmalloc((g_nr_keys + kac) * sizeof(struct crypto_key_t));
86 memcpy(new_ka, g_key_array, g_nr_keys * sizeof(struct crypto_key_t));
87 memcpy(new_ka + g_nr_keys, ka, kac * sizeof(struct crypto_key_t));
88 free(g_key_array);
89 g_key_array = new_ka;
90 g_nr_keys += kac;
91}
92
93key_array_t read_keys(const char *key_file, int *num_keys)
94{
95 int size;
96 FILE *fd = fopen(key_file, "r");
97 if(fd == NULL)
98 bugp("opening key file failed");
99 fseek(fd, 0, SEEK_END);
100 size = ftell(fd);
101 fseek(fd, 0, SEEK_SET);
102 char *buf = xmalloc(size);
103 if(fread(buf, size, 1, fd) != (size_t)size)
104 bugp("reading key file");
105 fclose(fd);
106
107 if(g_debug)
108 printf("Parsing key file '%s'...\n", key_file);
109 *num_keys = size ? 1 : 0;
110 char *ptr = buf;
111 /* allow trailing newline at the end (but no space after it) */
112 while(ptr != buf + size && (ptr + 1) != buf + size)
113 {
114 if(*ptr++ == '\n')
115 (*num_keys)++;
116 }
117
118 key_array_t keys = xmalloc(sizeof(struct crypto_key_t) * *num_keys);
119 int pos = 0;
120 for(int i = 0; i < *num_keys; i++)
121 {
122 /* skip ws */
123 while(pos < size && isspace(buf[pos]))
124 pos++;
125 /* enough space ? */
126 if((pos + 32) > size)
127 bugp("invalid key file");
128 keys[i].method = CRYPTO_KEY;
129 for(int j = 0; j < 16; j++)
130 {
131 byte a, b;
132 if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
133 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
134 keys[i].u.key[j] = (a << 4) | b;
135 }
136 if(g_debug)
137 {
138 printf("Add key: ");
139 for(int j = 0; j < 16; j++)
140 printf("%02x", keys[i].u.key[j]);
141 printf("\n");
142 }
143 pos += 32;
144 }
145 free(buf);
146
147 return keys;
148}
149
150void print_hex(byte *data, int len, bool newline)
151{
152 for(int i = 0; i < len; i++)
153 printf("%02X ", data[i]);
154 if(newline)
155 printf("\n");
156}
157
158void print_key(struct crypto_key_t *key, bool newline)
159{
160 switch(key->method)
161 {
162 case CRYPTO_KEY:
163 print_hex(key->u.key, 16, false);
164 break;
165 case CRYPTO_USBOTP:
166 printf("USB-OTP(%04x:%04x)", key->u.vid_pid >> 16, key->u.vid_pid & 0xffff);
167 break;
168 case CRYPTO_NONE:
169 printf("none");
170 break;
171 }
172 if(newline)
173 printf("\n");
174}
diff --git a/utils/sbtools/misc.h b/utils/sbtools/misc.h
new file mode 100644
index 0000000000..545285eafc
--- /dev/null
+++ b/utils/sbtools/misc.h
@@ -0,0 +1,48 @@
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(a) do { perror("ERROR: "a); exit(1); } while(0)
32
33extern bool g_debug;
34
35typedef struct crypto_key_t *key_array_t;
36int g_nr_keys;
37key_array_t g_key_array;
38
39char *s_getenv(const char *name);
40void generate_random_data(void *buf, size_t sz);
41void *xmalloc(size_t s);
42int convxdigit(char digit, byte *val);
43void print_hex(byte *data, int len, bool newline);
44void add_keys(key_array_t ka, int kac);
45key_array_t read_keys(const char *key_file, int *num_keys);
46void print_key(struct crypto_key_t *key, bool newline);
47
48#endif /* __MISC_H__ */
diff --git a/utils/sbtools/sbtoelf.c b/utils/sbtools/sbtoelf.c
index fb4567bed9..3c1c750582 100644
--- a/utils/sbtools/sbtoelf.c
+++ b/utils/sbtools/sbtoelf.c
@@ -28,21 +28,19 @@
28 28
29#define _ISOC99_SOURCE /* snprintf() */ 29#define _ISOC99_SOURCE /* snprintf() */
30#include <stdio.h> 30#include <stdio.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <errno.h> 31#include <errno.h>
35#include <unistd.h>
36#include <stdlib.h> 32#include <stdlib.h>
37#include <inttypes.h>
38#include <string.h> 33#include <string.h>
39#include <ctype.h> 34#include <ctype.h>
40#include <time.h> 35#include <time.h>
36#include <stdarg.h>
41#include <strings.h> 37#include <strings.h>
38#include <getopt.h>
42 39
43#include "crypto.h" 40#include "crypto.h"
44#include "elf.h" 41#include "elf.h"
45#include "sb.h" 42#include "sb.h"
43#include "misc.h"
46 44
47#if 1 /* ANSI colors */ 45#if 1 /* ANSI colors */
48 46
@@ -60,104 +58,24 @@ char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
60# define color(a) 58# define color(a)
61#endif 59#endif
62 60
63#define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
64#define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
65
66/* all blocks are sized as a multiple of 0x1ff */ 61/* all blocks are sized as a multiple of 0x1ff */
67#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) 62#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
68 63
69/* If you find a firmware that breaks the known format ^^ */ 64/* If you find a firmware that breaks the known format ^^ */
70#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) 65#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)
71 66
67#define crypto_cbc(...) \
68 do { int ret = crypto_cbc(__VA_ARGS__); \
69 if(ret != CRYPTO_ERROR_SUCCESS) \
70 bug("crypto_cbc error: %d\n", ret); \
71 }while(0)
72
72/* globals */ 73/* globals */
73 74
74uint8_t *g_buf; /* file content */ 75uint8_t *g_buf; /* file content */
75#define PREFIX_SIZE 128 76char *g_out_prefix;
76char out_prefix[PREFIX_SIZE]; 77bool g_debug;
77const char *key_file; 78bool g_raw_mode;
78
79char *s_getenv(const char *name)
80{
81 char *s = getenv(name);
82 return s ? s : "";
83}
84
85void *xmalloc(size_t s) /* malloc helper, used in elf.c */
86{
87 void * r = malloc(s);
88 if(!r) bugp("malloc");
89 return r;
90}
91
92static void print_hex(byte *data, int len, bool newline)
93{
94 for(int i = 0; i < len; i++)
95 printf("%02X ", data[i]);
96 if(newline)
97 printf("\n");
98}
99
100static int convxdigit(char digit, byte *val)
101{
102 if(digit >= '0' && digit <= '9')
103 {
104 *val = digit - '0';
105 return 0;
106 }
107 else if(digit >= 'A' && digit <= 'F')
108 {
109 *val = digit - 'A' + 10;
110 return 0;
111 }
112 else if(digit >= 'a' && digit <= 'f')
113 {
114 *val = digit - 'a' + 10;
115 return 0;
116 }
117 else
118 return 1;
119}
120
121typedef byte (*key_array_t)[16];
122
123static key_array_t read_keys(int num_keys)
124{
125 int size;
126 struct stat st;
127 int fd = open(key_file,O_RDONLY);
128 if(fd == -1)
129 bugp("opening key file failed");
130 if(fstat(fd,&st) == -1)
131 bugp("key file stat() failed");
132 size = st.st_size;
133 char *buf = xmalloc(size);
134 if(read(fd, buf, size) != (ssize_t)size)
135 bugp("reading key file");
136 close(fd);
137
138 key_array_t keys = xmalloc(sizeof(byte[16]) * num_keys);
139 int pos = 0;
140 for(int i = 0; i < num_keys; i++)
141 {
142 /* skip ws */
143 while(pos < size && isspace(buf[pos]))
144 pos++;
145 /* enough space ? */
146 if((pos + 32) > size)
147 bugp("invalid key file (not enough keys)");
148 for(int j = 0; j < 16; j++)
149 {
150 byte a, b;
151 if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
152 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
153 keys[i][j] = (a << 4) | b;
154 }
155 pos += 32;
156 }
157 free(buf);
158
159 return keys;
160}
161 79
162#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) 80#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
163 81
@@ -195,17 +113,21 @@ static void extract_elf_section(struct elf_params_t *elf, int count, const char
195 113
196static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent) 114static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent)
197{ 115{
198 char filename[PREFIX_SIZE + 32]; 116 char *filename = xmalloc(strlen(g_out_prefix) + strlen(name) + 5);
199 snprintf(filename, sizeof filename, "%s%s.bin", out_prefix, name); 117 if(g_out_prefix)
200 FILE *fd = fopen(filename, "wb"); 118 {
201 if (fd != NULL) { 119 sprintf(filename, "%s%s.bin", g_out_prefix, name);
202 fwrite(buf, size, 1, fd); 120 FILE *fd = fopen(filename, "wb");
203 fclose(fd); 121 if (fd != NULL)
122 {
123 fwrite(buf, size, 1, fd);
124 fclose(fd);
125 }
204 } 126 }
205 if(data_sec) 127 if(data_sec)
206 return; 128 return;
207 129
208 snprintf(filename, sizeof filename, "%s%s", out_prefix, name); 130 sprintf(filename, "%s%s", g_out_prefix, name);
209 131
210 /* elf construction */ 132 /* elf construction */
211 struct elf_params_t elf; 133 struct elf_params_t elf;
@@ -484,19 +406,23 @@ static void extract(unsigned long filesize)
484 printf("0x%08x\n", sb_header->first_boot_sec_id); 406 printf("0x%08x\n", sb_header->first_boot_sec_id);
485 407
486 /* encryption cbc-mac */ 408 /* encryption cbc-mac */
487 key_array_t keys = NULL; /* array of 16-bytes keys */
488 byte real_key[16]; 409 byte real_key[16];
489 bool valid_key = false; /* false until a matching key was found */ 410 bool valid_key = false; /* false until a matching key was found */
490 if(sb_header->nr_keys > 0) 411 if(sb_header->nr_keys > 0)
491 { 412 {
492 keys = read_keys(sb_header->nr_keys); 413 if(sb_header->nr_keys > g_nr_keys)
414 {
415 color(GREY);
416 bug("SB file has %d keys but only %d were specified on command line\n",
417 sb_header->nr_keys, g_nr_keys);
418 }
493 color(BLUE); 419 color(BLUE);
494 printf("Encryption data\n"); 420 printf("Encryption data\n");
495 for(int i = 0; i < sb_header->nr_keys; i++) 421 for(int i = 0; i < sb_header->nr_keys; i++)
496 { 422 {
497 color(RED); 423 color(RED);
498 printf(" Key %d: ", i); 424 printf(" Key %d: ", i);
499 print_hex(keys[i], 16, true); 425 print_key(&g_key_array[i], true);
500 color(GREEN); 426 color(GREEN);
501 printf(" CBC-MAC of headers: "); 427 printf(" CBC-MAC of headers: ");
502 428
@@ -512,8 +438,8 @@ static void extract(unsigned long filesize)
512 byte computed_cbc_mac[16]; 438 byte computed_cbc_mac[16];
513 byte zero[16]; 439 byte zero[16];
514 memset(zero, 0, 16); 440 memset(zero, 0, 16);
515 cbc_mac(g_buf, NULL, sb_header->header_size + sb_header->nr_sections, 441 crypto_cbc(g_buf, NULL, sb_header->header_size + sb_header->nr_sections,
516 keys[i], zero, &computed_cbc_mac, 1); 442 &g_key_array[i], zero, &computed_cbc_mac, 1);
517 color(RED); 443 color(RED);
518 bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0; 444 bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0;
519 if(ok) 445 if(ok)
@@ -533,7 +459,7 @@ static void extract(unsigned long filesize)
533 byte decrypted_key[16]; 459 byte decrypted_key[16];
534 byte iv[16]; 460 byte iv[16];
535 memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ 461 memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
536 cbc_mac(dict_entry->key, decrypted_key, 1, keys[i], iv, NULL, 0); 462 crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0);
537 printf(" Decrypted key : "); 463 printf(" Decrypted key : ");
538 color(YELLOW); 464 color(YELLOW);
539 print_hex(decrypted_key, 16, false); 465 print_hex(decrypted_key, 16, false);
@@ -769,37 +695,127 @@ static void extract(unsigned long filesize)
769 printf(" Failed\n"); 695 printf(" Failed\n");
770} 696}
771 697
772int main(int argc, const char **argv) 698void usage(void)
773{ 699{
774 int fd; 700 printf("Usage: sbtoelf [options] sb-file\n");
775 struct stat st; 701 printf("Options:\n");
776 if(argc != 3 && argc != 4) 702 printf(" -?/--help\tDisplay this message\n");
777 { 703 printf(" -o <file>\tSet output prefix\n");
778 printf("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv); 704 printf(" -d/--debug\tEnable debug output\n");
779 printf("To use raw command mode, set environment variable SB_RAW_CMD to YES\n"); 705 printf(" -k <file>\tAdd key file\n");
780 return 1; 706 printf(" -z\t\tAdd zero key\n");
781 } 707 printf(" -r\t\tUse raw command mode\n");
708 printf(" --single-key <key>\tAdd single key\n");
709 printf(" --usb-otp <vid>:<pid>\tAdd USB OTP device\n");
710 exit(1);
711}
782 712
783 if(argc == 4) 713static struct crypto_key_t g_zero_key =
784 snprintf(out_prefix, PREFIX_SIZE, "%s", argv[3]); 714{
785 else 715 .method = CRYPTO_KEY,
786 strcpy(out_prefix, ""); 716 .u.key = {0}
717};
787 718
788 if( (fd = open(argv[1], O_RDONLY)) == -1 ) 719int main(int argc, char **argv)
789 bugp("opening firmware failed"); 720{
721 while(1)
722 {
723 static struct option long_options[] =
724 {
725 {"help", no_argument, 0, '?'},
726 {"debug", no_argument, 0, 'd'},
727 {"single-key", required_argument, 0, 's'},
728 {"usb-otp", required_argument, 0, 'u'},
729 {0, 0, 0, 0}
730 };
731
732 int c = getopt_long(argc, argv, "?do:k:zr", long_options, NULL);
733 if(c == -1)
734 break;
735 switch(c)
736 {
737 case -1:
738 break;
739 case 'd':
740 g_debug = true;
741 break;
742 case '?':
743 usage();
744 break;
745 case 'o':
746 g_out_prefix = optarg;
747 break;
748 case 'k':
749 {
750 int kac;
751 key_array_t ka = read_keys(optarg, &kac);
752 add_keys(ka, kac);
753 break;
754 }
755 case 'z':
756 {
757 add_keys(&g_zero_key, 1);
758 break;
759 }
760 case 's':
761 {
762 struct crypto_key_t key;
763 key.method = CRYPTO_KEY;
764 if(strlen(optarg) != 32)
765 bug("The key given in argument is invalid");
766 for(int i = 0; i < 16; i++)
767 {
768 byte a, b;
769 if(convxdigit(optarg[2 * i], &a) || convxdigit(optarg[2 * i + 1], &b))
770 bugp("The key given in argument is invalid\n");
771 key.u.key[i] = (a << 4) | b;
772 }
773 add_keys(&key, 1);
774 break;
775 }
776 case 'u':
777 {
778 int vid, pid;
779 char *p = strchr(optarg, ':');
780 if(p == NULL)
781 bug("Invalid VID/PID\n");
782
783 char *end;
784 vid = strtol(optarg, &end, 16);
785 if(end != p)
786 bug("Invalid VID/PID\n");
787 pid = strtol(p + 1, &end, 16);
788 if(end != (optarg + strlen(optarg)))
789 bug("Invalid VID/PID\n");
790 struct crypto_key_t key;
791 key.method = CRYPTO_USBOTP;
792 key.u.vid_pid = vid << 16 | pid;
793 add_keys(&key, 1);
794 break;
795 }
796 default:
797 abort();
798 }
799 }
790 800
791 key_file = argv[2]; 801 if(argc - optind != 1)
802 bug("Missing sb file or too many files after options\n");
792 803
793 if(fstat(fd, &st) == -1) 804 const char *sb_file = argv[optind];
794 bugp("firmware stat() failed"); 805 FILE *fd = fopen(sb_file, "rb");
806 if(fd == NULL)
807 bug("Cannot open input file\n");
808 fseek(fd, 0, SEEK_END);
809 size_t size = ftell(fd);
810 fseek(fd, 0, SEEK_SET);
795 811
796 g_buf = xmalloc(st.st_size); 812 g_buf = xmalloc(size);
797 if(read(fd, g_buf, st.st_size) != (ssize_t)st.st_size) /* load the whole file into memory */ 813 if(fread(g_buf, 1, size, fd) != size) /* load the whole file into memory */
798 bugp("reading firmware"); 814 bugp("reading firmware");
799 815
800 close(fd); 816 fclose(fd);
801 817
802 extract(st.st_size); 818 extract(size);
803 819
804 color(OFF); 820 color(OFF);
805 821