summaryrefslogtreecommitdiffstats
path: root/utils
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 /utils
parentb7547e58680c32879392e424bdd70d1719d384b9 (diff)
downloadrockbox-9fe029b12a0828b247718fc89b08547b1ab916b5.tar.gz
rockbox-9fe029b12a0828b247718fc89b08547b1ab916b5.tar.bz2
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
Diffstat (limited to 'utils')
-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 @@
+DEFINES=-DCRYPTO_LIBUSB
+CC=gcc
+LD=gcc
+CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
+LDFLAGS=`pkg-config --libs libusb-1.0`
+
all: elftosb sbtoelf
-sbtoelf: sbtoelf.c crc.c crypto.h aes128.c sha1.c elf.c sb.h
- gcc -g -std=c99 -o $@ -W -Wall $^
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o
+ $(LD) $(LDFLAGS) -o $@ $^
-elftosb: elftosb.c crc.c crypto.h aes128.c sha1.c elf.c sb.h dbparser.h dbparser.c
- gcc -g -std=c99 -o $@ -W -Wall $^
+elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o
+ $(LD) $(LDFLAGS) -o $@ $^
clean:
- rm -fr elftosb sbtoelf
+ rm -fr *.o
+
+veryclean:
+ 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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "crypto.h"
+#include <stdio.h>
+#include <stdbool.h>
+#ifdef CRYPTO_LIBUSB
+#include "libusb.h"
+#endif
+#include "misc.h"
+
+static enum crypto_method_t cur_method = CRYPTO_NONE;
+static byte key[16];
+static uint16_t usb_vid, usb_pid;
+
+void crypto_setup(enum crypto_method_t method, void *param)
+{
+ cur_method = method;
+ switch(method)
+ {
+ case CRYPTO_KEY:
+ memcpy(key, param, sizeof(key));
+ break;
+ case CRYPTO_USBOTP:
+ {
+ uint32_t value = *(uint32_t *)param;
+ usb_vid = value >> 16;
+ usb_pid = value & 0xffff;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+int crypto_apply(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks (one block=16 bytes) */
+ byte iv[16], /* Key */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt)
+{
+ if(cur_method == CRYPTO_KEY)
+ {
+ cbc_mac(in_data, out_data, nr_blocks, key, iv, out_cbc_mac, encrypt);
+ return CRYPTO_ERROR_SUCCESS;
+ }
+ #ifdef CRYPTO_LIBUSB
+ else if(cur_method == CRYPTO_USBOTP)
+ {
+ if(out_cbc_mac && !encrypt)
+ memcpy(*out_cbc_mac, in_data + 16 * (nr_blocks - 1), 16);
+
+ libusb_device_handle *handle = NULL;
+ libusb_context *ctx;
+ /* init library */
+ libusb_init(&ctx);
+ libusb_set_debug(NULL,3);
+ /* open device */
+ handle = libusb_open_device_with_vid_pid(ctx, usb_vid, usb_pid);
+ if(handle == NULL)
+ {
+ printf("usbotp: cannot open device %04x:%04x\n", usb_vid, usb_pid);
+ return CRYPTO_ERROR_NODEVICE;
+ }
+ /* get device pointer */
+ libusb_device *mydev = libusb_get_device(handle);
+ if(g_debug)
+ printf("usbotp: device found at %d:%d\n", libusb_get_bus_number(mydev),
+ libusb_get_device_address(mydev));
+ int config_id;
+ /* explore configuration */
+ libusb_get_configuration(handle, &config_id);
+ struct libusb_config_descriptor *config;
+ libusb_get_active_config_descriptor(mydev, &config);
+
+ if(g_debug)
+ {
+ printf("usbotp: configuration: %d\n", config_id);
+ printf("usbotp: interfaces: %d\n", config->bNumInterfaces);
+ }
+
+ const struct libusb_endpoint_descriptor *endp = NULL;
+ int intf, intf_alt;
+ for(intf = 0; intf < config->bNumInterfaces; intf++)
+ for(intf_alt = 0; intf_alt < config->interface[intf].num_altsetting; intf_alt++)
+ for(int ep = 0; ep < config->interface[intf].altsetting[intf_alt].bNumEndpoints; ep++)
+ {
+ endp = &config->interface[intf].altsetting[intf_alt].endpoint[ep];
+ if((endp->bmAttributes & LIBUSB_TRANSFER_TYPE_MASK) == LIBUSB_TRANSFER_TYPE_INTERRUPT &&
+ (endp->bEndpointAddress & LIBUSB_ENDPOINT_DIR_MASK) == LIBUSB_ENDPOINT_IN)
+ goto Lfound;
+ }
+ libusb_close(handle);
+ printf("usbotp: No suitable endpoint found\n");
+ return CRYPTO_ERROR_BADENDP;
+
+ if(g_debug)
+ {
+ printf("usbotp: use interface %d, alt %d\n", intf, intf_alt);
+ printf("usbotp: use endpoint %d\n", endp->bEndpointAddress);
+ }
+ Lfound:
+ if(libusb_claim_interface(handle, intf) != 0)
+ {
+ if(g_debug)
+ printf("usbotp: claim error\n");
+ return CRYPTO_ERROR_CLAIMFAIL;
+ }
+
+ int buffer_size = 16 + 16 * nr_blocks;
+ unsigned char *buffer = xmalloc(buffer_size);
+ memcpy(buffer, iv, 16);
+ memcpy(buffer + 16, in_data, 16 * nr_blocks);
+ int ret = libusb_control_transfer(handle,
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
+ 0xaa, encrypt ? 0xeeee : 0xdddd, 0, buffer, buffer_size, 1000);
+ if(ret < 0)
+ {
+ if(g_debug)
+ printf("usbotp: control transfer failed: %d\n", ret);
+ libusb_release_interface(handle, intf);
+ libusb_close(handle);
+ return CRYPTO_ERROR_DEVREJECT;
+ }
+
+ int recv_size;
+ ret = libusb_interrupt_transfer(handle, endp->bEndpointAddress, buffer,
+ buffer_size, &recv_size, 1000);
+ libusb_release_interface(handle, intf);
+ libusb_close(handle);
+
+ if(ret < 0)
+ {
+ if(g_debug)
+ printf("usbotp: interrupt transfer failed: %d\n", ret);
+ return CRYPTO_ERROR_DEVSILENT;
+ }
+ if(recv_size != buffer_size)
+ {
+ if(g_debug)
+ printf("usbotp: device returned %d bytes, expected %d\n", recv_size,
+ buffer_size);
+ return CRYPTO_ERROR_DEVERR;
+ }
+
+ if(out_data)
+ memcpy(out_data, buffer + 16, 16 * nr_blocks);
+ if(out_cbc_mac && encrypt)
+ memcpy(*out_cbc_mac, buffer + buffer_size - 16, 16);
+
+ return CRYPTO_ERROR_SUCCESS;
+ }
+ #endif
+ else
+ return CRYPTO_ERROR_BADSETUP;
+}
+
+int crypto_cbc(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks (one block=16 bytes) */
+ struct crypto_key_t *key, /* Key */
+ byte iv[16], /* IV */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt)
+{
+ crypto_setup(key->method, (void *)key->u.param);
+ return crypto_apply(in_data, out_data, nr_blocks, iv, out_cbc_mac, encrypt);
+}
diff --git a/utils/sbtools/crypto.h b/utils/sbtools/crypto.h
index 0662ef8587..51f44406db 100644
--- a/utils/sbtools/crypto.h
+++ b/utils/sbtools/crypto.h
@@ -18,6 +18,9 @@
* KIND, either express or implied.
*
****************************************************************************/
+#ifndef __CRYPTO_H__
+#define __CRYPTO_H__
+
#include <stdio.h>
#include <stdint.h>
#include <string.h>
@@ -39,6 +42,57 @@ void cbc_mac(
int encrypt /* 1 to encrypt, 0 to decrypt */
);
+/* crypto.c */
+enum crypto_method_t
+{
+ CRYPTO_NONE, /* disable */
+ CRYPTO_KEY, /* key */
+ CRYPTO_USBOTP, /* use usbotp device */
+};
+
+/* parameter can be:
+ * - CRYPTO_KEY: array of 16-bytes (the key)
+ * - CRYPTO_USBOTP: 32-bit integer: vid << 16 | pid */
+void crypto_setup(enum crypto_method_t method, void *param);
+
+#define CRYPTO_ERROR_SUCCESS 0
+#define CRYPTO_ERROR_BADSETUP -1 /* bad crypto setup */
+#define CRYPTO_ERROR_NODEVICE -2 /* no device with vid:pid */
+#define CRYPTO_ERROR_BADENDP -3 /* device doesn't have the required endpoints */
+#define CRYPTO_ERROR_CLAIMFAIL -4 /* device interface claim error */
+#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */
+#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */
+#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */
+/* return 0 on success, <0 on error */
+int crypto_apply(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks (one block=16 bytes) */
+ byte iv[16], /* IV */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt);
+
+/* all-in-one function */
+struct crypto_key_t
+{
+ enum crypto_method_t method;
+ union
+ {
+ byte key[16];
+ uint32_t vid_pid;
+ byte param[0];
+ }u;
+};
+
+int crypto_cbc(
+ byte *in_data, /* Input data */
+ byte *out_data, /* Output data (or NULL) */
+ int nr_blocks, /* Number of blocks (one block=16 bytes) */
+ struct crypto_key_t *key, /* Key */
+ byte iv[16], /* IV */
+ byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
+ int encrypt);
+
/* crc.c */
uint32_t crc(byte *data, int size);
uint32_t crc_continue(uint32_t previous_crc, byte *data, int size);
@@ -56,3 +110,5 @@ void sha_1_block(struct sha_1_params_t *params, uint32_t cur_hash[5], byte *data
void sha_1_update(struct sha_1_params_t *params, byte *buffer, int size);
void sha_1_finish(struct sha_1_params_t *params);
void sha_1_output(struct sha_1_params_t *params, byte *out);
+
+#endif /* __CRYPTO_H__ */
diff --git a/utils/sbtools/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 @@
#define _ISOC99_SOURCE
#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <inttypes.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
@@ -39,143 +34,18 @@
#include "elf.h"
#include "sb.h"
#include "dbparser.h"
+#include "misc.h"
-#define _STR(a) #a
-#define STR(a) _STR(a)
-
-#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0)
-#define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
-
-bool g_debug = false;
char **g_extern;
int g_extern_count;
#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
-/**
- * Misc
- */
-
-char *s_getenv(const char *name)
-{
- char *s = getenv(name);
- return s ? s : "";
-}
-
-void generate_random_data(void *buf, size_t sz)
-{
- static int rand_fd = -1;
- if(rand_fd == -1)
- rand_fd = open("/dev/urandom", O_RDONLY);
- if(rand_fd == -1)
- bugp("failed to open /dev/urandom");
- if(read(rand_fd, buf, sz) != (ssize_t)sz)
- bugp("failed to read /dev/urandom");
-}
-
-void *xmalloc(size_t s) /* malloc helper, used in elf.c */
-{
- void * r = malloc(s);
- if(!r) bugp("malloc");
- return r;
-}
-
-int convxdigit(char digit, byte *val)
-{
- if(digit >= '0' && digit <= '9')
- {
- *val = digit - '0';
- return 0;
- }
- else if(digit >= 'A' && digit <= 'F')
- {
- *val = digit - 'A' + 10;
- return 0;
- }
- else if(digit >= 'a' && digit <= 'f')
- {
- *val = digit - 'a' + 10;
- return 0;
- }
- else
- return 1;
-}
-
-/**
- * Key file parsing
- */
-
-typedef byte (*key_array_t)[16];
-
-int g_nr_keys;
-key_array_t g_key_array;
-
-static void add_keys(key_array_t ka, int kac)
-{
- key_array_t new_ka = xmalloc((g_nr_keys + kac) * 16);
- memcpy(new_ka, g_key_array, g_nr_keys * 16);
- memcpy(new_ka + g_nr_keys, ka, kac * 16);
- free(g_key_array);
- g_key_array = new_ka;
- g_nr_keys += kac;
-}
-
-static key_array_t read_keys(const char *key_file, int *num_keys)
-{
- int size;
- struct stat st;
- int fd = open(key_file,O_RDONLY);
- if(fd == -1)
- bugp("opening key file failed");
- if(fstat(fd,&st) == -1)
- bugp("key file stat() failed");
- size = st.st_size;
- char *buf = xmalloc(size);
- if(read(fd, buf, size) != (ssize_t)size)
- bugp("reading key file");
- close(fd);
-
- if(g_debug)
- printf("Parsing key file '%s'...\n", key_file);
- *num_keys = size ? 1 : 0;
- char *ptr = buf;
- /* allow trailing newline at the end (but no space after it) */
- while(ptr != buf + size && (ptr + 1) != buf + size)
- {
- if(*ptr++ == '\n')
- (*num_keys)++;
- }
-
- key_array_t keys = xmalloc(sizeof(byte[16]) * *num_keys);
- int pos = 0;
- for(int i = 0; i < *num_keys; i++)
- {
- /* skip ws */
- while(pos < size && isspace(buf[pos]))
- pos++;
- /* enough space ? */
- if((pos + 32) > size)
- bugp("invalid key file");
- for(int j = 0; j < 16; j++)
- {
- byte a, b;
- if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
- bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
- keys[i][j] = (a << 4) | b;
- }
- if(g_debug)
- {
- printf("Add key: ");
- for(int j = 0; j < 16; j++)
- printf("%02x", keys[i][j]);
- printf("\n");
- }
- pos += 32;
- }
- free(buf);
-
- return keys;
-}
+#define crypto_cbc(...) \
+ do { int ret = crypto_cbc(__VA_ARGS__); \
+ if(ret != CRYPTO_ERROR_SUCCESS) \
+ bug("crypto_cbc error: %d\n", ret); \
+ }while(0)
/**
* command file to sb conversion
@@ -224,9 +94,9 @@ struct sb_file_t
static bool elf_read(void *user, uint32_t addr, void *buf, size_t count)
{
- if(lseek(*(int *)user, addr, SEEK_SET) == (off_t)-1)
+ if(fseek((FILE *)user, addr, SEEK_SET) == -1)
return false;
- return read(*(int *)user, buf, count) == (ssize_t)count;
+ return fread(buf, 1, count, (FILE *)user) == count;
}
static 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)
resolve_extern(src);
/* load it */
src->type = CMD_SRC_ELF;
- int fd = open(src->filename, O_RDONLY);
- if(fd < 0)
+ FILE *fd = fopen(src->filename, "rb");
+ if(fd == NULL)
bug("cannot open '%s' (id '%s')\n", src->filename, id);
if(g_debug)
printf("Loading ELF file '%s'...\n", src->filename);
elf_init(&src->elf);
- src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, &fd);
- close(fd);
+ src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, fd);
+ fclose(fd);
if(!src->loaded)
bug("error loading elf file '%s' (id '%s')\n", src->filename, id);
elf_translate_addresses(&src->elf);
@@ -291,16 +161,17 @@ static void load_bin_by_id(struct cmd_file_t *cmd_file, const char *id)
resolve_extern(src);
/* load it */
src->type = CMD_SRC_BIN;
- int fd = open(src->filename, O_RDONLY);
- if(fd < 0)
+ FILE *fd = fopen(src->filename, "rb");
+ if(fd == NULL)
bug("cannot open '%s' (id '%s')\n", src->filename, id);
if(g_debug)
printf("Loading BIN file '%s'...\n", src->filename);
- src->bin.size = lseek(fd, 0, SEEK_END);
- lseek(fd, 0, SEEK_SET);
+ fseek(fd, 0, SEEK_END);
+ src->bin.size = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
src->bin.data = xmalloc(src->bin.size);
- read(fd, src->bin.data, src->bin.size);
- close(fd);
+ fread(src->bin.data, 1, src->bin.size, fd);
+ fclose(fd);
src->loaded = true;
}
@@ -767,12 +638,12 @@ void produce_sb_instruction(struct sb_inst_t *inst,
static void produce_sb_file(struct sb_file_t *sb, const char *filename)
{
- int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
- if(fd < 0)
+ FILE *fd = fopen(filename, "wb");
+ if(fd == NULL)
bugp("cannot open output file");
- byte real_key[16];
+ struct crypto_key_t real_key;
+ real_key.method = CRYPTO_KEY;
byte crypto_iv[16];
byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys);
/* init CBC-MACs */
@@ -782,7 +653,7 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
fill_gaps(sb);
compute_sb_offsets(sb);
- generate_random_data(real_key, sizeof(real_key));
+ generate_random_data(real_key.u.key, 16);
/* global SHA-1 */
struct sha_1_params_t file_sha1;
@@ -791,13 +662,13 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
struct sb_header_t sb_hdr;
produce_sb_header(sb, &sb_hdr);
sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
- write(fd, &sb_hdr, sizeof(sb_hdr));
+ fwrite(&sb_hdr, 1, sizeof(sb_hdr), fd);
memcpy(crypto_iv, &sb_hdr, 16);
/* update CBC-MACs */
for(int i = 0; i < g_nr_keys; i++)
- cbc_mac((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, g_key_array[i],
+ crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i],
cbc_macs[i], &cbc_macs[i], 1);
/* produce and write section headers */
@@ -806,21 +677,21 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
struct sb_section_header_t sb_sec_hdr;
produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
- write(fd, &sb_sec_hdr, sizeof(sb_sec_hdr));
+ fwrite(&sb_sec_hdr, 1, sizeof(sb_sec_hdr), fd);
/* update CBC-MACs */
for(int j = 0; j < g_nr_keys; j++)
- cbc_mac((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
- g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
+ crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
+ &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
}
/* produce key dictionary */
for(int i = 0; i < g_nr_keys; i++)
{
struct sb_key_dictionary_entry_t entry;
memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16);
- cbc_mac(real_key, entry.key, sizeof(real_key) / BLOCK_SIZE, g_key_array[i],
+ crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
crypto_iv, NULL, 1);
- write(fd, &entry, sizeof(entry));
+ fwrite(&entry, 1, sizeof(entry), fd);
sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
}
@@ -836,7 +707,7 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
byte a, b;
if(convxdigit(key[2 * i], &a) || convxdigit(key[2 * i + 1], &b))
bugp("Cannot override real key: key should be a 128-bit key written in hexadecimal\n");
- real_key[i] = (a << 4) | b;
+ real_key.u.key[i] = (a << 4) | b;
}
}
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)
{
printf("Real key: ");
for(int j = 0; j < 16; j++)
- printf("%02x", real_key[j]);
+ printf("%02x", real_key.u.key[j]);
printf("\n");
printf("IV : ");
for(int j = 0; j < 16; j++)
@@ -872,10 +743,10 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
struct sb_instruction_tag_t tag_cmd;
produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
if(g_nr_keys > 0)
- cbc_mac((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
- real_key, crypto_iv, NULL, 1);
+ crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
+ &real_key, crypto_iv, NULL, 1);
sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
- write(fd, &tag_cmd, sizeof(tag_cmd));
+ fwrite(&tag_cmd, 1, sizeof(tag_cmd), fd);
/* produce other commands */
byte cur_cbc_mac[16];
memcpy(cur_cbc_mac, crypto_iv, 16);
@@ -888,10 +759,10 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
struct sb_instruction_common_t cmd;
produce_sb_instruction(inst, &cmd);
if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
- cbc_mac((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
- real_key, cur_cbc_mac, &cur_cbc_mac, 1);
+ crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
+ &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
- write(fd, &cmd, sizeof(cmd));
+ fwrite(&cmd, 1, sizeof(cmd), fd);
}
/* data */
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)
memcpy(data, inst->data, inst->size);
memcpy(data + inst->size, inst->padding, inst->padding_size);
if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
- cbc_mac(data, data, sz / BLOCK_SIZE,
- real_key, cur_cbc_mac, &cur_cbc_mac, 1);
+ crypto_cbc(data, data, sz / BLOCK_SIZE,
+ &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
sha_1_update(&file_sha1, data, sz);
- write(fd, data, sz);
+ fwrite(data, 1, sz, fd);
free(data);
}
}
@@ -915,10 +786,10 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
sha_1_output(&file_sha1, final_sig);
generate_random_data(final_sig + 20, 12);
if(g_nr_keys > 0)
- cbc_mac(final_sig, final_sig, 2, real_key, crypto_iv, NULL, 1);
- write(fd, final_sig, 32);
+ crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
+ fwrite(final_sig, 1, 32, fd);
- close(fd);
+ fclose(fd);
}
void usage(void)
@@ -931,10 +802,16 @@ void usage(void)
printf(" -d/--debug\tEnable debug output\n");
printf(" -k <file>\tAdd key file\n");
printf(" -z\t\tAdd zero key\n");
+ printf(" --single-key <key>\tAdd single key\n");
+ printf(" --usb-otp <vid>:<pid>\tAdd USB OTP device\n");
exit(1);
}
-static byte g_zero_key[16] = {0};
+static struct crypto_key_t g_zero_key =
+{
+ .method = CRYPTO_KEY,
+ .u.key = {0}
+};
int main(int argc, char **argv)
{
@@ -947,6 +824,8 @@ int main(int argc, char **argv)
{
{"help", no_argument, 0, '?'},
{"debug", no_argument, 0, 'd'},
+ {"single-key", required_argument, 0, 's'},
+ {"usb-otp", required_argument, 0, 'u'},
{0, 0, 0, 0}
};
@@ -979,6 +858,42 @@ int main(int argc, char **argv)
add_keys(&g_zero_key, 1);
break;
}
+ case 's':
+ {
+ struct crypto_key_t key;
+ key.method = CRYPTO_KEY;
+ if(strlen(optarg) != 32)
+ bug("The key given in argument is invalid");
+ for(int i = 0; i < 16; i++)
+ {
+ byte a, b;
+ if(convxdigit(optarg[2 * i], &a) || convxdigit(optarg[2 * i + 1], &b))
+ bugp("The key given in argument is invalid\n");
+ key.u.key[i] = (a << 4) | b;
+ }
+ add_keys(&key, 1);
+ break;
+ }
+ case 'u':
+ {
+ int vid, pid;
+ char *p = strchr(optarg, ':');
+ if(p == NULL)
+ bug("Invalid VID/PID\n");
+
+ char *end;
+ vid = strtol(optarg, &end, 16);
+ if(end != p)
+ bug("Invalid VID/PID\n");
+ pid = strtol(p + 1, &end, 16);
+ if(end != (optarg + strlen(optarg)))
+ bug("Invalid VID/PID\n");
+ struct crypto_key_t key;
+ key.method = CRYPTO_USBOTP;
+ key.u.vid_pid = vid << 16 | pid;
+ add_keys(&key, 1);
+ break;
+ }
default:
abort();
}
@@ -997,9 +912,8 @@ int main(int argc, char **argv)
printf("key: %d\n", g_nr_keys);
for(int i = 0; i < g_nr_keys; i++)
{
- for(int j = 0; j < 16; j++)
- printf(" %02x", g_key_array[i][j]);
- printf("\n");
+ printf(" ");
+ print_key(&g_key_array[i], true);
}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <ctype.h>
+#include "misc.h"
+
+bool g_debug = false;
+
+/**
+ * Misc
+ */
+
+char *s_getenv(const char *name)
+{
+ char *s = getenv(name);
+ return s ? s : "";
+}
+
+void generate_random_data(void *buf, size_t sz)
+{
+ FILE *rand_fd = fopen("/dev/urandom", "rb");
+ if(rand_fd == NULL)
+ bugp("failed to open /dev/urandom");
+ if(fread(buf, 1, sz, rand_fd) != sz)
+ bugp("failed to read /dev/urandom");
+ fclose(rand_fd);
+}
+
+void *xmalloc(size_t s)
+{
+ void * r = malloc(s);
+ if(!r) bugp("malloc");
+ return r;
+}
+
+int convxdigit(char digit, byte *val)
+{
+ if(digit >= '0' && digit <= '9')
+ {
+ *val = digit - '0';
+ return 0;
+ }
+ else if(digit >= 'A' && digit <= 'F')
+ {
+ *val = digit - 'A' + 10;
+ return 0;
+ }
+ else if(digit >= 'a' && digit <= 'f')
+ {
+ *val = digit - 'a' + 10;
+ return 0;
+ }
+ else
+ return 1;
+}
+
+/**
+ * Key file parsing
+ */
+int g_nr_keys;
+key_array_t g_key_array;
+
+void add_keys(key_array_t ka, int kac)
+{
+ key_array_t new_ka = xmalloc((g_nr_keys + kac) * sizeof(struct crypto_key_t));
+ memcpy(new_ka, g_key_array, g_nr_keys * sizeof(struct crypto_key_t));
+ memcpy(new_ka + g_nr_keys, ka, kac * sizeof(struct crypto_key_t));
+ free(g_key_array);
+ g_key_array = new_ka;
+ g_nr_keys += kac;
+}
+
+key_array_t read_keys(const char *key_file, int *num_keys)
+{
+ int size;
+ FILE *fd = fopen(key_file, "r");
+ if(fd == NULL)
+ bugp("opening key file failed");
+ fseek(fd, 0, SEEK_END);
+ size = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
+ char *buf = xmalloc(size);
+ if(fread(buf, size, 1, fd) != (size_t)size)
+ bugp("reading key file");
+ fclose(fd);
+
+ if(g_debug)
+ printf("Parsing key file '%s'...\n", key_file);
+ *num_keys = size ? 1 : 0;
+ char *ptr = buf;
+ /* allow trailing newline at the end (but no space after it) */
+ while(ptr != buf + size && (ptr + 1) != buf + size)
+ {
+ if(*ptr++ == '\n')
+ (*num_keys)++;
+ }
+
+ key_array_t keys = xmalloc(sizeof(struct crypto_key_t) * *num_keys);
+ int pos = 0;
+ for(int i = 0; i < *num_keys; i++)
+ {
+ /* skip ws */
+ while(pos < size && isspace(buf[pos]))
+ pos++;
+ /* enough space ? */
+ if((pos + 32) > size)
+ bugp("invalid key file");
+ keys[i].method = CRYPTO_KEY;
+ for(int j = 0; j < 16; j++)
+ {
+ byte a, b;
+ if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
+ bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
+ keys[i].u.key[j] = (a << 4) | b;
+ }
+ if(g_debug)
+ {
+ printf("Add key: ");
+ for(int j = 0; j < 16; j++)
+ printf("%02x", keys[i].u.key[j]);
+ printf("\n");
+ }
+ pos += 32;
+ }
+ free(buf);
+
+ return keys;
+}
+
+void print_hex(byte *data, int len, bool newline)
+{
+ for(int i = 0; i < len; i++)
+ printf("%02X ", data[i]);
+ if(newline)
+ printf("\n");
+}
+
+void print_key(struct crypto_key_t *key, bool newline)
+{
+ switch(key->method)
+ {
+ case CRYPTO_KEY:
+ print_hex(key->u.key, 16, false);
+ break;
+ case CRYPTO_USBOTP:
+ printf("USB-OTP(%04x:%04x)", key->u.vid_pid >> 16, key->u.vid_pid & 0xffff);
+ break;
+ case CRYPTO_NONE:
+ printf("none");
+ break;
+ }
+ if(newline)
+ printf("\n");
+}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __MISC_H__
+#define __MISC_H__
+
+#include <stdbool.h>
+#include "crypto.h"
+
+#define _STR(a) #a
+#define STR(a) _STR(a)
+
+#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0)
+#define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
+
+extern bool g_debug;
+
+typedef struct crypto_key_t *key_array_t;
+int g_nr_keys;
+key_array_t g_key_array;
+
+char *s_getenv(const char *name);
+void generate_random_data(void *buf, size_t sz);
+void *xmalloc(size_t s);
+int convxdigit(char digit, byte *val);
+void print_hex(byte *data, int len, bool newline);
+void add_keys(key_array_t ka, int kac);
+key_array_t read_keys(const char *key_file, int *num_keys);
+void print_key(struct crypto_key_t *key, bool newline);
+
+#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 @@
#define _ISOC99_SOURCE /* snprintf() */
#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
-#include <unistd.h>
#include <stdlib.h>
-#include <inttypes.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
+#include <stdarg.h>
#include <strings.h>
+#include <getopt.h>
#include "crypto.h"
#include "elf.h"
#include "sb.h"
+#include "misc.h"
#if 1 /* ANSI colors */
@@ -60,104 +58,24 @@ char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
# define color(a)
#endif
-#define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
-#define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
-
/* all blocks are sized as a multiple of 0x1ff */
#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
/* If you find a firmware that breaks the known format ^^ */
#define assert(a) do { if(!(a)) { fprintf(stderr,"Assertion \"%s\" failed in %s() line %d!\n\nPlease send us your firmware!\n",#a,__func__,__LINE__); exit(1); } } while(0)
+#define crypto_cbc(...) \
+ do { int ret = crypto_cbc(__VA_ARGS__); \
+ if(ret != CRYPTO_ERROR_SUCCESS) \
+ bug("crypto_cbc error: %d\n", ret); \
+ }while(0)
+
/* globals */
uint8_t *g_buf; /* file content */
-#define PREFIX_SIZE 128
-char out_prefix[PREFIX_SIZE];
-const char *key_file;
-
-char *s_getenv(const char *name)
-{
- char *s = getenv(name);
- return s ? s : "";
-}
-
-void *xmalloc(size_t s) /* malloc helper, used in elf.c */
-{
- void * r = malloc(s);
- if(!r) bugp("malloc");
- return r;
-}
-
-static void print_hex(byte *data, int len, bool newline)
-{
- for(int i = 0; i < len; i++)
- printf("%02X ", data[i]);
- if(newline)
- printf("\n");
-}
-
-static int convxdigit(char digit, byte *val)
-{
- if(digit >= '0' && digit <= '9')
- {
- *val = digit - '0';
- return 0;
- }
- else if(digit >= 'A' && digit <= 'F')
- {
- *val = digit - 'A' + 10;
- return 0;
- }
- else if(digit >= 'a' && digit <= 'f')
- {
- *val = digit - 'a' + 10;
- return 0;
- }
- else
- return 1;
-}
-
-typedef byte (*key_array_t)[16];
-
-static key_array_t read_keys(int num_keys)
-{
- int size;
- struct stat st;
- int fd = open(key_file,O_RDONLY);
- if(fd == -1)
- bugp("opening key file failed");
- if(fstat(fd,&st) == -1)
- bugp("key file stat() failed");
- size = st.st_size;
- char *buf = xmalloc(size);
- if(read(fd, buf, size) != (ssize_t)size)
- bugp("reading key file");
- close(fd);
-
- key_array_t keys = xmalloc(sizeof(byte[16]) * num_keys);
- int pos = 0;
- for(int i = 0; i < num_keys; i++)
- {
- /* skip ws */
- while(pos < size && isspace(buf[pos]))
- pos++;
- /* enough space ? */
- if((pos + 32) > size)
- bugp("invalid key file (not enough keys)");
- for(int j = 0; j < 16; j++)
- {
- byte a, b;
- if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
- bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
- keys[i][j] = (a << 4) | b;
- }
- pos += 32;
- }
- free(buf);
-
- return keys;
-}
+char *g_out_prefix;
+bool g_debug;
+bool g_raw_mode;
#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
@@ -195,17 +113,21 @@ static void extract_elf_section(struct elf_params_t *elf, int count, const char
static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent)
{
- char filename[PREFIX_SIZE + 32];
- snprintf(filename, sizeof filename, "%s%s.bin", out_prefix, name);
- FILE *fd = fopen(filename, "wb");
- if (fd != NULL) {
- fwrite(buf, size, 1, fd);
- fclose(fd);
+ char *filename = xmalloc(strlen(g_out_prefix) + strlen(name) + 5);
+ if(g_out_prefix)
+ {
+ sprintf(filename, "%s%s.bin", g_out_prefix, name);
+ FILE *fd = fopen(filename, "wb");
+ if (fd != NULL)
+ {
+ fwrite(buf, size, 1, fd);
+ fclose(fd);
+ }
}
if(data_sec)
return;
- snprintf(filename, sizeof filename, "%s%s", out_prefix, name);
+ sprintf(filename, "%s%s", g_out_prefix, name);
/* elf construction */
struct elf_params_t elf;
@@ -484,19 +406,23 @@ static void extract(unsigned long filesize)
printf("0x%08x\n", sb_header->first_boot_sec_id);
/* encryption cbc-mac */
- key_array_t keys = NULL; /* array of 16-bytes keys */
byte real_key[16];
bool valid_key = false; /* false until a matching key was found */
if(sb_header->nr_keys > 0)
{
- keys = read_keys(sb_header->nr_keys);
+ if(sb_header->nr_keys > g_nr_keys)
+ {
+ color(GREY);
+ bug("SB file has %d keys but only %d were specified on command line\n",
+ sb_header->nr_keys, g_nr_keys);
+ }
color(BLUE);
printf("Encryption data\n");
for(int i = 0; i < sb_header->nr_keys; i++)
{
color(RED);
printf(" Key %d: ", i);
- print_hex(keys[i], 16, true);
+ print_key(&g_key_array[i], true);
color(GREEN);
printf(" CBC-MAC of headers: ");
@@ -512,8 +438,8 @@ static void extract(unsigned long filesize)
byte computed_cbc_mac[16];
byte zero[16];
memset(zero, 0, 16);
- cbc_mac(g_buf, NULL, sb_header->header_size + sb_header->nr_sections,
- keys[i], zero, &computed_cbc_mac, 1);
+ crypto_cbc(g_buf, NULL, sb_header->header_size + sb_header->nr_sections,
+ &g_key_array[i], zero, &computed_cbc_mac, 1);
color(RED);
bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0;
if(ok)
@@ -533,7 +459,7 @@ static void extract(unsigned long filesize)
byte decrypted_key[16];
byte iv[16];
memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
- cbc_mac(dict_entry->key, decrypted_key, 1, keys[i], iv, NULL, 0);
+ crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0);
printf(" Decrypted key : ");
color(YELLOW);
print_hex(decrypted_key, 16, false);
@@ -769,37 +695,127 @@ static void extract(unsigned long filesize)
printf(" Failed\n");
}
-int main(int argc, const char **argv)
+void usage(void)
{
- int fd;
- struct stat st;
- if(argc != 3 && argc != 4)
- {
- printf("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv);
- printf("To use raw command mode, set environment variable SB_RAW_CMD to YES\n");
- return 1;
- }
+ printf("Usage: sbtoelf [options] sb-file\n");
+ printf("Options:\n");
+ printf(" -?/--help\tDisplay this message\n");
+ printf(" -o <file>\tSet output prefix\n");
+ printf(" -d/--debug\tEnable debug output\n");
+ printf(" -k <file>\tAdd key file\n");
+ printf(" -z\t\tAdd zero key\n");
+ printf(" -r\t\tUse raw command mode\n");
+ printf(" --single-key <key>\tAdd single key\n");
+ printf(" --usb-otp <vid>:<pid>\tAdd USB OTP device\n");
+ exit(1);
+}
- if(argc == 4)
- snprintf(out_prefix, PREFIX_SIZE, "%s", argv[3]);
- else
- strcpy(out_prefix, "");
+static struct crypto_key_t g_zero_key =
+{
+ .method = CRYPTO_KEY,
+ .u.key = {0}
+};
- if( (fd = open(argv[1], O_RDONLY)) == -1 )
- bugp("opening firmware failed");
+int main(int argc, char **argv)
+{
+ while(1)
+ {
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, '?'},
+ {"debug", no_argument, 0, 'd'},
+ {"single-key", required_argument, 0, 's'},
+ {"usb-otp", required_argument, 0, 'u'},
+ {0, 0, 0, 0}
+ };
+
+ int c = getopt_long(argc, argv, "?do:k:zr", long_options, NULL);
+ if(c == -1)
+ break;
+ switch(c)
+ {
+ case -1:
+ break;
+ case 'd':
+ g_debug = true;
+ break;
+ case '?':
+ usage();
+ break;
+ case 'o':
+ g_out_prefix = optarg;
+ break;
+ case 'k':
+ {
+ int kac;
+ key_array_t ka = read_keys(optarg, &kac);
+ add_keys(ka, kac);
+ break;
+ }
+ case 'z':
+ {
+ add_keys(&g_zero_key, 1);
+ break;
+ }
+ case 's':
+ {
+ struct crypto_key_t key;
+ key.method = CRYPTO_KEY;
+ if(strlen(optarg) != 32)
+ bug("The key given in argument is invalid");
+ for(int i = 0; i < 16; i++)
+ {
+ byte a, b;
+ if(convxdigit(optarg[2 * i], &a) || convxdigit(optarg[2 * i + 1], &b))
+ bugp("The key given in argument is invalid\n");
+ key.u.key[i] = (a << 4) | b;
+ }
+ add_keys(&key, 1);
+ break;
+ }
+ case 'u':
+ {
+ int vid, pid;
+ char *p = strchr(optarg, ':');
+ if(p == NULL)
+ bug("Invalid VID/PID\n");
+
+ char *end;
+ vid = strtol(optarg, &end, 16);
+ if(end != p)
+ bug("Invalid VID/PID\n");
+ pid = strtol(p + 1, &end, 16);
+ if(end != (optarg + strlen(optarg)))
+ bug("Invalid VID/PID\n");
+ struct crypto_key_t key;
+ key.method = CRYPTO_USBOTP;
+ key.u.vid_pid = vid << 16 | pid;
+ add_keys(&key, 1);
+ break;
+ }
+ default:
+ abort();
+ }
+ }
- key_file = argv[2];
+ if(argc - optind != 1)
+ bug("Missing sb file or too many files after options\n");
- if(fstat(fd, &st) == -1)
- bugp("firmware stat() failed");
+ const char *sb_file = argv[optind];
+ FILE *fd = fopen(sb_file, "rb");
+ if(fd == NULL)
+ bug("Cannot open input file\n");
+ fseek(fd, 0, SEEK_END);
+ size_t size = ftell(fd);
+ fseek(fd, 0, SEEK_SET);
- g_buf = xmalloc(st.st_size);
- if(read(fd, g_buf, st.st_size) != (ssize_t)st.st_size) /* load the whole file into memory */
+ g_buf = xmalloc(size);
+ if(fread(g_buf, 1, size, fd) != size) /* load the whole file into memory */
bugp("reading firmware");
- close(fd);
+ fclose(fd);
- extract(st.st_size);
+ extract(size);
color(OFF);