1
0
Fork 0
forked from len0rd/rockbox

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
This commit is contained in:
Amaury Pouly 2011-10-29 14:22:17 +00:00
parent b7547e5868
commit 9fe029b12a
7 changed files with 720 additions and 312 deletions

View file

@ -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 all: elftosb sbtoelf
sbtoelf: sbtoelf.c crc.c crypto.h aes128.c sha1.c elf.c sb.h %.o: %.c
gcc -g -std=c99 -o $@ -W -Wall $^ $(CC) $(CFLAGS) -c -o $@ $<
elftosb: elftosb.c crc.c crypto.h aes128.c sha1.c elf.c sb.h dbparser.h dbparser.c sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o
gcc -g -std=c99 -o $@ -W -Wall $^ $(LD) $(LDFLAGS) -o $@ $^
elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o
$(LD) $(LDFLAGS) -o $@ $^
clean: clean:
rm -fr elftosb sbtoelf rm -fr *.o
veryclean:
rm -rf sbtoelf elftosb

188
utils/sbtools/crypto.c Normal file
View file

@ -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);
}

View file

@ -18,6 +18,9 @@
* KIND, either express or implied. * KIND, either express or implied.
* *
****************************************************************************/ ****************************************************************************/
#ifndef __CRYPTO_H__
#define __CRYPTO_H__
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -39,6 +42,57 @@ void cbc_mac(
int encrypt /* 1 to encrypt, 0 to decrypt */ 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 */ /* crc.c */
uint32_t crc(byte *data, int size); uint32_t crc(byte *data, int size);
uint32_t crc_continue(uint32_t previous_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_update(struct sha_1_params_t *params, byte *buffer, int size);
void sha_1_finish(struct sha_1_params_t *params); void sha_1_finish(struct sha_1_params_t *params);
void sha_1_output(struct sha_1_params_t *params, byte *out); void sha_1_output(struct sha_1_params_t *params, byte *out);
#endif /* __CRYPTO_H__ */

View file

@ -21,13 +21,8 @@
#define _ISOC99_SOURCE #define _ISOC99_SOURCE
#include <stdio.h> #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
@ -39,143 +34,18 @@
#include "elf.h" #include "elf.h"
#include "sb.h" #include "sb.h"
#include "dbparser.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; char **g_extern;
int g_extern_count; int g_extern_count;
#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
/** #define crypto_cbc(...) \
* Misc do { int ret = crypto_cbc(__VA_ARGS__); \
*/ if(ret != CRYPTO_ERROR_SUCCESS) \
bug("crypto_cbc error: %d\n", ret); \
char *s_getenv(const char *name) }while(0)
{
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;
}
/** /**
* command file to sb conversion * 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) 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 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, ...) 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); resolve_extern(src);
/* load it */ /* load it */
src->type = CMD_SRC_ELF; src->type = CMD_SRC_ELF;
int fd = open(src->filename, O_RDONLY); FILE *fd = fopen(src->filename, "rb");
if(fd < 0) if(fd == NULL)
bug("cannot open '%s' (id '%s')\n", src->filename, id); bug("cannot open '%s' (id '%s')\n", src->filename, id);
if(g_debug) if(g_debug)
printf("Loading ELF file '%s'...\n", src->filename); printf("Loading ELF file '%s'...\n", src->filename);
elf_init(&src->elf); elf_init(&src->elf);
src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, &fd); src->loaded = elf_read_file(&src->elf, elf_read, elf_printf, fd);
close(fd); fclose(fd);
if(!src->loaded) if(!src->loaded)
bug("error loading elf file '%s' (id '%s')\n", src->filename, id); bug("error loading elf file '%s' (id '%s')\n", src->filename, id);
elf_translate_addresses(&src->elf); 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); resolve_extern(src);
/* load it */ /* load it */
src->type = CMD_SRC_BIN; src->type = CMD_SRC_BIN;
int fd = open(src->filename, O_RDONLY); FILE *fd = fopen(src->filename, "rb");
if(fd < 0) if(fd == NULL)
bug("cannot open '%s' (id '%s')\n", src->filename, id); bug("cannot open '%s' (id '%s')\n", src->filename, id);
if(g_debug) if(g_debug)
printf("Loading BIN file '%s'...\n", src->filename); printf("Loading BIN file '%s'...\n", src->filename);
src->bin.size = lseek(fd, 0, SEEK_END); fseek(fd, 0, SEEK_END);
lseek(fd, 0, SEEK_SET); src->bin.size = ftell(fd);
fseek(fd, 0, SEEK_SET);
src->bin.data = xmalloc(src->bin.size); src->bin.data = xmalloc(src->bin.size);
read(fd, src->bin.data, src->bin.size); fread(src->bin.data, 1, src->bin.size, fd);
close(fd); fclose(fd);
src->loaded = true; 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) static void produce_sb_file(struct sb_file_t *sb, const char *filename)
{ {
int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, FILE *fd = fopen(filename, "wb");
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if(fd == NULL)
if(fd < 0)
bugp("cannot open output file"); 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 crypto_iv[16];
byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys); byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys);
/* init CBC-MACs */ /* init CBC-MACs */
@ -782,7 +653,7 @@ static void produce_sb_file(struct sb_file_t *sb, const char *filename)
fill_gaps(sb); fill_gaps(sb);
compute_sb_offsets(sb); compute_sb_offsets(sb);
generate_random_data(real_key, sizeof(real_key)); generate_random_data(real_key.u.key, 16);
/* global SHA-1 */ /* global SHA-1 */
struct sha_1_params_t file_sha1; 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; struct sb_header_t sb_hdr;
produce_sb_header(sb, &sb_hdr); produce_sb_header(sb, &sb_hdr);
sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(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); memcpy(crypto_iv, &sb_hdr, 16);
/* update CBC-MACs */ /* update CBC-MACs */
for(int i = 0; i < g_nr_keys; i++) 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); cbc_macs[i], &cbc_macs[i], 1);
/* produce and write section headers */ /* 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; struct sb_section_header_t sb_sec_hdr;
produce_sb_section_header(&sb->sections[i], &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)); 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 */ /* update CBC-MACs */
for(int j = 0; j < g_nr_keys; j++) for(int j = 0; j < g_nr_keys; j++)
cbc_mac((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE, crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
g_key_array[j], cbc_macs[j], &cbc_macs[j], 1); &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
} }
/* produce key dictionary */ /* produce key dictionary */
for(int i = 0; i < g_nr_keys; i++) for(int i = 0; i < g_nr_keys; i++)
{ {
struct sb_key_dictionary_entry_t entry; struct sb_key_dictionary_entry_t entry;
memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16); 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); crypto_iv, NULL, 1);
write(fd, &entry, sizeof(entry)); fwrite(&entry, 1, sizeof(entry), fd);
sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry)); 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; byte a, b;
if(convxdigit(key[2 * i], &a) || convxdigit(key[2 * i + 1], &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"); 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) 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: "); printf("Real key: ");
for(int j = 0; j < 16; j++) for(int j = 0; j < 16; j++)
printf("%02x", real_key[j]); printf("%02x", real_key.u.key[j]);
printf("\n"); printf("\n");
printf("IV : "); printf("IV : ");
for(int j = 0; j < 16; j++) 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; struct sb_instruction_tag_t tag_cmd;
produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections); produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
if(g_nr_keys > 0) if(g_nr_keys > 0)
cbc_mac((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE, crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
real_key, crypto_iv, NULL, 1); &real_key, crypto_iv, NULL, 1);
sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd)); 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 */ /* produce other commands */
byte cur_cbc_mac[16]; byte cur_cbc_mac[16];
memcpy(cur_cbc_mac, crypto_iv, 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; struct sb_instruction_common_t cmd;
produce_sb_instruction(inst, &cmd); produce_sb_instruction(inst, &cmd);
if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
cbc_mac((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE, crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
real_key, cur_cbc_mac, &cur_cbc_mac, 1); &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd)); sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
write(fd, &cmd, sizeof(cmd)); fwrite(&cmd, 1, sizeof(cmd), fd);
} }
/* data */ /* data */
if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_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->data, inst->size);
memcpy(data + inst->size, inst->padding, inst->padding_size); memcpy(data + inst->size, inst->padding, inst->padding_size);
if(g_nr_keys > 0 && !sb->sections[i].is_cleartext) if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
cbc_mac(data, data, sz / BLOCK_SIZE, crypto_cbc(data, data, sz / BLOCK_SIZE,
real_key, cur_cbc_mac, &cur_cbc_mac, 1); &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
sha_1_update(&file_sha1, data, sz); sha_1_update(&file_sha1, data, sz);
write(fd, data, sz); fwrite(data, 1, sz, fd);
free(data); 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); sha_1_output(&file_sha1, final_sig);
generate_random_data(final_sig + 20, 12); generate_random_data(final_sig + 20, 12);
if(g_nr_keys > 0) if(g_nr_keys > 0)
cbc_mac(final_sig, final_sig, 2, real_key, crypto_iv, NULL, 1); crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
write(fd, final_sig, 32); fwrite(final_sig, 1, 32, fd);
close(fd); fclose(fd);
} }
void usage(void) void usage(void)
@ -931,10 +802,16 @@ void usage(void)
printf(" -d/--debug\tEnable debug output\n"); printf(" -d/--debug\tEnable debug output\n");
printf(" -k <file>\tAdd key file\n"); printf(" -k <file>\tAdd key file\n");
printf(" -z\t\tAdd zero key\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); 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) int main(int argc, char **argv)
{ {
@ -947,6 +824,8 @@ int main(int argc, char **argv)
{ {
{"help", no_argument, 0, '?'}, {"help", no_argument, 0, '?'},
{"debug", no_argument, 0, 'd'}, {"debug", no_argument, 0, 'd'},
{"single-key", required_argument, 0, 's'},
{"usb-otp", required_argument, 0, 'u'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@ -979,6 +858,42 @@ int main(int argc, char **argv)
add_keys(&g_zero_key, 1); add_keys(&g_zero_key, 1);
break; 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: default:
abort(); abort();
} }
@ -997,9 +912,8 @@ int main(int argc, char **argv)
printf("key: %d\n", g_nr_keys); printf("key: %d\n", g_nr_keys);
for(int i = 0; i < g_nr_keys; i++) for(int i = 0; i < g_nr_keys; i++)
{ {
for(int j = 0; j < 16; j++) printf(" ");
printf(" %02x", g_key_array[i][j]); print_key(&g_key_array[i], true);
printf("\n");
} }
for(int i = 0; i < g_extern_count; i++) for(int i = 0; i < g_extern_count; i++)

174
utils/sbtools/misc.c Normal file
View file

@ -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");
}

48
utils/sbtools/misc.h Normal file
View file

@ -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__ */

View file

@ -28,21 +28,19 @@
#define _ISOC99_SOURCE /* snprintf() */ #define _ISOC99_SOURCE /* snprintf() */
#include <stdio.h> #include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h> #include <errno.h>
#include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include <stdarg.h>
#include <strings.h> #include <strings.h>
#include <getopt.h>
#include "crypto.h" #include "crypto.h"
#include "elf.h" #include "elf.h"
#include "sb.h" #include "sb.h"
#include "misc.h"
#if 1 /* ANSI colors */ #if 1 /* ANSI colors */
@ -60,104 +58,24 @@ char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
# define color(a) # define color(a)
#endif #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 */ /* all blocks are sized as a multiple of 0x1ff */
#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) #define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
/* If you find a firmware that breaks the known format ^^ */ /* 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 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 */ /* globals */
uint8_t *g_buf; /* file content */ uint8_t *g_buf; /* file content */
#define PREFIX_SIZE 128 char *g_out_prefix;
char out_prefix[PREFIX_SIZE]; bool g_debug;
const char *key_file; bool g_raw_mode;
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;
}
#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) #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) static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent)
{ {
char filename[PREFIX_SIZE + 32]; char *filename = xmalloc(strlen(g_out_prefix) + strlen(name) + 5);
snprintf(filename, sizeof filename, "%s%s.bin", out_prefix, name); if(g_out_prefix)
FILE *fd = fopen(filename, "wb"); {
if (fd != NULL) { sprintf(filename, "%s%s.bin", g_out_prefix, name);
fwrite(buf, size, 1, fd); FILE *fd = fopen(filename, "wb");
fclose(fd); if (fd != NULL)
{
fwrite(buf, size, 1, fd);
fclose(fd);
}
} }
if(data_sec) if(data_sec)
return; return;
snprintf(filename, sizeof filename, "%s%s", out_prefix, name); sprintf(filename, "%s%s", g_out_prefix, name);
/* elf construction */ /* elf construction */
struct elf_params_t elf; 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); printf("0x%08x\n", sb_header->first_boot_sec_id);
/* encryption cbc-mac */ /* encryption cbc-mac */
key_array_t keys = NULL; /* array of 16-bytes keys */
byte real_key[16]; byte real_key[16];
bool valid_key = false; /* false until a matching key was found */ bool valid_key = false; /* false until a matching key was found */
if(sb_header->nr_keys > 0) 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); color(BLUE);
printf("Encryption data\n"); printf("Encryption data\n");
for(int i = 0; i < sb_header->nr_keys; i++) for(int i = 0; i < sb_header->nr_keys; i++)
{ {
color(RED); color(RED);
printf(" Key %d: ", i); printf(" Key %d: ", i);
print_hex(keys[i], 16, true); print_key(&g_key_array[i], true);
color(GREEN); color(GREEN);
printf(" CBC-MAC of headers: "); printf(" CBC-MAC of headers: ");
@ -512,8 +438,8 @@ static void extract(unsigned long filesize)
byte computed_cbc_mac[16]; byte computed_cbc_mac[16];
byte zero[16]; byte zero[16];
memset(zero, 0, 16); memset(zero, 0, 16);
cbc_mac(g_buf, NULL, sb_header->header_size + sb_header->nr_sections, crypto_cbc(g_buf, NULL, sb_header->header_size + sb_header->nr_sections,
keys[i], zero, &computed_cbc_mac, 1); &g_key_array[i], zero, &computed_cbc_mac, 1);
color(RED); color(RED);
bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0; bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0;
if(ok) if(ok)
@ -533,7 +459,7 @@ static void extract(unsigned long filesize)
byte decrypted_key[16]; byte decrypted_key[16];
byte iv[16]; byte iv[16];
memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ 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 : "); printf(" Decrypted key : ");
color(YELLOW); color(YELLOW);
print_hex(decrypted_key, 16, false); print_hex(decrypted_key, 16, false);
@ -769,37 +695,127 @@ static void extract(unsigned long filesize)
printf(" Failed\n"); printf(" Failed\n");
} }
int main(int argc, const char **argv) void usage(void)
{ {
int fd; printf("Usage: sbtoelf [options] sb-file\n");
struct stat st; printf("Options:\n");
if(argc != 3 && argc != 4) 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);
}
static struct crypto_key_t g_zero_key =
{
.method = CRYPTO_KEY,
.u.key = {0}
};
int main(int argc, char **argv)
{
while(1)
{ {
printf("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv); static struct option long_options[] =
printf("To use raw command mode, set environment variable SB_RAW_CMD to YES\n"); {
return 1; {"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();
}
} }
if(argc == 4) if(argc - optind != 1)
snprintf(out_prefix, PREFIX_SIZE, "%s", argv[3]); bug("Missing sb file or too many files after options\n");
else
strcpy(out_prefix, "");
if( (fd = open(argv[1], O_RDONLY)) == -1 ) const char *sb_file = argv[optind];
bugp("opening firmware failed"); 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);
key_file = argv[2]; g_buf = xmalloc(size);
if(fread(g_buf, 1, size, fd) != size) /* load the whole file into memory */
if(fstat(fd, &st) == -1)
bugp("firmware stat() failed");
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 */
bugp("reading firmware"); bugp("reading firmware");
close(fd); fclose(fd);
extract(st.st_size); extract(size);
color(OFF); color(OFF);