imxtools/sbtools: rework cryptography
It was a mess, a mix of crypto_* and cbc_mac calls. I made everything call crypto functions, and also separate key setup from cryptographic operations, this will be useful to speed up the code in the upcoming commits. Drop support for "usbotp" key, since the crypto code for that was never mainlined and we can always get the keys from a device as long as we have code execution (using the DCP debug registers). Change-Id: I7aa24d12207ffb744225d1b9cc7cb1dc7281dd22
This commit is contained in:
parent
cb8a98e365
commit
2b20026dd7
10 changed files with 172 additions and 319 deletions
|
@ -14,7 +14,7 @@ CFLAGS += -std=gnu99 -g -O3
|
|||
OUTPUT = mkimxboot
|
||||
|
||||
# inputs for lib
|
||||
IMXTOOLS_SOURCES = misc.c sb.c crypto.c crc.c aes128.c sha1.c elf.c
|
||||
IMXTOOLS_SOURCES = misc.c sb.c crypto.cpp crc.c aes128.c sha1.c elf.c
|
||||
LIBSOURCES := dualboot.c mkimxboot.c md5.c \
|
||||
$(addprefix $(IMXTOOLS_DIR),$(IMXTOOLS_SOURCES))
|
||||
# inputs for binary only
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
DEFINES=-DCRYPTO_LIBUSB
|
||||
DEFINES=
|
||||
CC=gcc
|
||||
LD=gcc
|
||||
CFLAGS=-O3 -g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
|
||||
CXX=g++
|
||||
LD=g++
|
||||
CFLAGS=-O3 -g -std=c99 -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
|
||||
CXXFLAGS=-O3 -g -Wall $(DEFINES)
|
||||
LDFLAGS=`pkg-config --libs libusb-1.0`
|
||||
BINS=elftosb sbtoelf sbloader rsrctool elftosb1
|
||||
|
||||
|
@ -10,6 +12,9 @@ all: $(BINS)
|
|||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o xorcrypt.o dbparser.o elf.o misc.o sb.o sb1.o
|
||||
$(LD) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
|
|
|
@ -1,188 +0,0 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2010 Amaury Pouly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "crypto.h"
|
||||
#include <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);
|
||||
}
|
55
utils/imxtools/sbtools/crypto.cpp
Normal file
55
utils/imxtools/sbtools/crypto.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
/***************************************************************************
|
||||
* __________ __ ___.
|
||||
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||
* \/ \/ \/ \/ \/
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2016 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 "misc.h"
|
||||
|
||||
static enum crypto_method_t g_cur_method = CRYPTO_NONE;
|
||||
static byte g_key[16];
|
||||
|
||||
int crypto_setup(struct crypto_key_t *key)
|
||||
{
|
||||
g_cur_method = key->method;
|
||||
switch(g_cur_method)
|
||||
{
|
||||
case CRYPTO_KEY:
|
||||
memcpy(g_key, key->u.key, 16);
|
||||
return CRYPTO_ERROR_SUCCESS;
|
||||
default:
|
||||
return CRYPTO_ERROR_BADSETUP;
|
||||
}
|
||||
}
|
||||
|
||||
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) */
|
||||
bool encrypt)
|
||||
{
|
||||
if(g_cur_method == CRYPTO_KEY)
|
||||
{
|
||||
cbc_mac(in_data, out_data, nr_blocks, g_key, iv, out_cbc_mac, encrypt);
|
||||
return CRYPTO_ERROR_SUCCESS;
|
||||
}
|
||||
else
|
||||
return CRYPTO_ERROR_BADSETUP;
|
||||
}
|
|
@ -24,6 +24,11 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef uint8_t byte;
|
||||
|
||||
|
@ -48,32 +53,8 @@ enum crypto_method_t
|
|||
CRYPTO_NONE, /* disable */
|
||||
CRYPTO_KEY, /* key */
|
||||
CRYPTO_XOR_KEY, /* XOR key */
|
||||
CRYPTO_USBOTP, /* use usbotp device */
|
||||
};
|
||||
|
||||
/* parameter can be:
|
||||
* - CRYPTO_KEY: array of 16-bytes (the key)
|
||||
* - CRYPTO_USBOTP: 32-bit integer: vid << 16 | pid */
|
||||
void crypto_setup(enum crypto_method_t method, void *param);
|
||||
|
||||
#define CRYPTO_ERROR_SUCCESS 0
|
||||
#define CRYPTO_ERROR_BADSETUP -1 /* bad crypto setup */
|
||||
#define CRYPTO_ERROR_NODEVICE -2 /* no device with vid:pid */
|
||||
#define CRYPTO_ERROR_BADENDP -3 /* device doesn't have the required endpoints */
|
||||
#define CRYPTO_ERROR_CLAIMFAIL -4 /* device interface claim error */
|
||||
#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */
|
||||
#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */
|
||||
#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */
|
||||
#define CRYPTO_NUM_ERRORS 8
|
||||
/* return 0 on success, <0 on error */
|
||||
int crypto_apply(
|
||||
byte *in_data, /* Input data */
|
||||
byte *out_data, /* Output data (or NULL) */
|
||||
int nr_blocks, /* Number of blocks (one block=16 bytes) */
|
||||
byte iv[16], /* IV */
|
||||
byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
|
||||
int encrypt);
|
||||
|
||||
union xorcrypt_key_t
|
||||
{
|
||||
uint8_t key[64];
|
||||
|
@ -88,19 +69,25 @@ struct crypto_key_t
|
|||
{
|
||||
byte key[16];
|
||||
union xorcrypt_key_t xor_key[2];
|
||||
uint32_t vid_pid;
|
||||
byte param[0];
|
||||
}u;
|
||||
};
|
||||
|
||||
int crypto_cbc(
|
||||
#define CRYPTO_ERROR_SUCCESS 0
|
||||
#define CRYPTO_ERROR_BADSETUP -1
|
||||
|
||||
/* parameter can be:
|
||||
* - CRYPTO_KEY: array of 16-bytes (the key)
|
||||
* return 0 on success, <0 on error */
|
||||
int crypto_setup(struct crypto_key_t *key);
|
||||
|
||||
/* 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) */
|
||||
struct crypto_key_t *key, /* Key */
|
||||
byte iv[16], /* IV */
|
||||
byte (*out_cbc_mac)[16], /* CBC-MAC of the result (or NULL) */
|
||||
int encrypt);
|
||||
bool encrypt);
|
||||
|
||||
/* crc.c */
|
||||
uint32_t crc(byte *data, int size);
|
||||
|
@ -127,4 +114,8 @@ uint32_t xor_encrypt(union xorcrypt_key_t keys[2], void *data, int size);
|
|||
uint32_t xor_decrypt(union xorcrypt_key_t keys[2], void *data, int size);
|
||||
void xor_generate_key(uint32_t laserfuse[3], union xorcrypt_key_t key[2]);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CRYPTO_H__ */
|
||||
|
|
|
@ -118,7 +118,6 @@ bool parse_key(char **pstr, struct crypto_key_t *key)
|
|||
while(isspace(*str))
|
||||
str++;
|
||||
/* CRYPTO_KEY: 32 hex characters
|
||||
* CRYPTO_USBOTP: usbotp(vid:pid) where vid and pid are hex numbers
|
||||
* CRYPTO_XOR_KEY: 256 hex characters */
|
||||
if(isxdigit(str[0]) && strlen(str) >= 256 && isxdigit(str[32]))
|
||||
{
|
||||
|
@ -151,30 +150,7 @@ bool parse_key(char **pstr, struct crypto_key_t *key)
|
|||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *prefix = "usbotp(";
|
||||
if(strlen(str) < strlen(prefix))
|
||||
return false;
|
||||
if(strncmp(str, prefix, strlen(prefix)) != 0)
|
||||
return false;
|
||||
str += strlen(prefix);
|
||||
/* vid */
|
||||
long vid = strtol(str, &str, 16);
|
||||
if(vid < 0 || vid > 0xffff)
|
||||
return false;
|
||||
if(*str++ != ':')
|
||||
return false;
|
||||
/* pid */
|
||||
long pid = strtol(str, &str, 16);
|
||||
if(pid < 0 || pid > 0xffff)
|
||||
return false;
|
||||
if(*str++ != ')')
|
||||
return false;
|
||||
*pstr = str;
|
||||
key->method = CRYPTO_USBOTP;
|
||||
key->u.vid_pid = vid << 16 | pid;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void add_keys(key_array_t ka, int kac)
|
||||
|
@ -278,9 +254,6 @@ void print_key(void *user, misc_printf_t printf, struct crypto_key_t *key, bool
|
|||
case CRYPTO_KEY:
|
||||
print_hex(user, printf, key->u.key, 16, false);
|
||||
break;
|
||||
case CRYPTO_USBOTP:
|
||||
printf(user, "USB-OTP(%04x:%04x)", key->u.vid_pid >> 16, key->u.vid_pid & 0xffff);
|
||||
break;
|
||||
case CRYPTO_NONE:
|
||||
printf(user, "none");
|
||||
break;
|
||||
|
|
|
@ -73,8 +73,7 @@ enum rsrc_error_t
|
|||
RSRC_FORMAT_ERROR = -5,
|
||||
RSRC_CHECKSUM_ERROR = -6,
|
||||
RSRC_NO_VALID_KEY = -7,
|
||||
RSRC_FIRST_CRYPTO_ERROR = -8,
|
||||
RSRC_LAST_CRYPTO_ERROR = RSRC_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS,
|
||||
RSRC_CRYPTO_ERROR = -8,
|
||||
};
|
||||
|
||||
enum rsrc_error_t rsrc_write_file(struct rsrc_file_t *rsrc, const char *filename);
|
||||
|
|
|
@ -322,6 +322,12 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void *
|
|||
byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE);
|
||||
byte *buf_p = buf;
|
||||
#define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0)
|
||||
#define check_crypto(expr) \
|
||||
do { int err = expr; \
|
||||
if(err != CRYPTO_ERROR_SUCCESS) { \
|
||||
free(cbc_macs); \
|
||||
cprintf(u, true, GREY, "Crypto error: %d\n", err); \
|
||||
return SB_CRYPTO_ERROR; } } while(0)
|
||||
|
||||
sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
|
||||
write(&sb_hdr, sizeof(sb_hdr));
|
||||
|
@ -330,8 +336,11 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void *
|
|||
|
||||
/* update CBC-MACs */
|
||||
for(int i = 0; i < g_nr_keys; i++)
|
||||
crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i],
|
||||
cbc_macs[i], &cbc_macs[i], 1);
|
||||
{
|
||||
check_crypto(crypto_setup(&g_key_array[i]));
|
||||
check_crypto(crypto_apply((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE,
|
||||
cbc_macs[i], &cbc_macs[i], true));
|
||||
}
|
||||
|
||||
/* produce and write section headers */
|
||||
for(int i = 0; i < sb_hdr.nr_sections; i++)
|
||||
|
@ -342,23 +351,23 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void *
|
|||
write(&sb_sec_hdr, sizeof(sb_sec_hdr));
|
||||
/* update CBC-MACs */
|
||||
for(int j = 0; j < g_nr_keys; j++)
|
||||
crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
|
||||
&g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
|
||||
{
|
||||
check_crypto(crypto_setup(&g_key_array[j]));
|
||||
check_crypto(crypto_apply((byte *)&sb_sec_hdr, NULL,
|
||||
sizeof(sb_sec_hdr) / BLOCK_SIZE, cbc_macs[j], &cbc_macs[j], true));
|
||||
}
|
||||
}
|
||||
/* produce key dictionary */
|
||||
for(int i = 0; i < g_nr_keys; i++)
|
||||
{
|
||||
struct sb_key_dictionary_entry_t entry;
|
||||
memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16);
|
||||
crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
|
||||
crypto_iv, NULL, 1);
|
||||
|
||||
check_crypto(crypto_setup(&g_key_array[i]));
|
||||
check_crypto(crypto_apply(real_key.u.key, entry.key, 1, crypto_iv, NULL, true));
|
||||
write(&entry, sizeof(entry));
|
||||
sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
|
||||
}
|
||||
|
||||
free(cbc_macs);
|
||||
|
||||
/* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
|
||||
/* Image crafting, don't use it unless you understand what you do */
|
||||
if(sb->override_real_key)
|
||||
|
@ -388,6 +397,8 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void *
|
|||
write(data, init_gap);
|
||||
free(data);
|
||||
}
|
||||
/* setup real key */
|
||||
check_crypto(crypto_setup(&real_key));
|
||||
/* produce sections data */
|
||||
for(int i = 0; i< sb_hdr.nr_sections; i++)
|
||||
{
|
||||
|
@ -395,8 +406,10 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void *
|
|||
struct sb_instruction_tag_t tag_cmd;
|
||||
produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
|
||||
if(g_nr_keys > 0)
|
||||
crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
|
||||
&real_key, crypto_iv, NULL, 1);
|
||||
{
|
||||
check_crypto(crypto_apply((byte *)&tag_cmd, (byte *)&tag_cmd,
|
||||
sizeof(tag_cmd) / BLOCK_SIZE, crypto_iv, NULL, true));
|
||||
}
|
||||
sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
|
||||
write(&tag_cmd, sizeof(tag_cmd));
|
||||
/* produce other commands */
|
||||
|
@ -411,8 +424,10 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void *
|
|||
struct sb_instruction_common_t cmd;
|
||||
produce_sb_instruction(inst, &cmd, u, cprintf);
|
||||
if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
|
||||
crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
|
||||
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
|
||||
{
|
||||
check_crypto(crypto_apply((byte *)&cmd, (byte *)&cmd,
|
||||
sizeof(cmd) / BLOCK_SIZE, cur_cbc_mac, &cur_cbc_mac, true));
|
||||
}
|
||||
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
|
||||
write(&cmd, sizeof(cmd));
|
||||
}
|
||||
|
@ -424,8 +439,10 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void *
|
|||
memcpy(data, inst->data, inst->size);
|
||||
memcpy(data + inst->size, inst->padding, inst->padding_size);
|
||||
if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
|
||||
crypto_cbc(data, data, sz / BLOCK_SIZE,
|
||||
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
|
||||
{
|
||||
check_crypto(crypto_apply(data, data, sz / BLOCK_SIZE,
|
||||
cur_cbc_mac, &cur_cbc_mac, true));
|
||||
}
|
||||
sha_1_update(&file_sha1, data, sz);
|
||||
write(data, sz);
|
||||
free(data);
|
||||
|
@ -450,8 +467,10 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void *
|
|||
cmd.hdr.opcode = SB_INST_NOP;
|
||||
cmd.hdr.checksum = instruction_checksum(&cmd.hdr);
|
||||
if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
|
||||
crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
|
||||
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
|
||||
{
|
||||
check_crypto(crypto_apply((byte *)&cmd, (byte *)&cmd,
|
||||
sizeof(cmd) / BLOCK_SIZE, cur_cbc_mac, &cur_cbc_mac, true));
|
||||
}
|
||||
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
|
||||
write(&cmd, sizeof(cmd));
|
||||
}
|
||||
|
@ -463,28 +482,34 @@ enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename, void *
|
|||
sha_1_output(&file_sha1, final_sig);
|
||||
generate_random_data(final_sig + 20, 12);
|
||||
if(g_nr_keys > 0)
|
||||
crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
|
||||
check_crypto(crypto_apply(final_sig, final_sig, 2, crypto_iv, NULL, true));
|
||||
write(final_sig, 32);
|
||||
|
||||
free(cbc_macs);
|
||||
|
||||
if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE)
|
||||
{
|
||||
printf(GREY, "[ERROR][INTERNAL] SB image buffer was not entirely filled !\n");
|
||||
printf(GREY, "[ERROR][INTERNAL] expected %u blocks, got %u\n",
|
||||
free(buf);
|
||||
printf(GREY, "Internal error: SB image buffer was not entirely filled !\n");
|
||||
printf(GREY, "Internal error: expected %u blocks, got %u\n",
|
||||
(buf_p - buf) / BLOCK_SIZE, sb_hdr.image_size);
|
||||
cprintf(u, true, GREY, "Internal error\n");
|
||||
return SB_ERROR;
|
||||
}
|
||||
|
||||
FILE *fd = fopen(filename, "wb");
|
||||
if(fd == NULL)
|
||||
return SB_OPEN_ERROR;
|
||||
if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1)
|
||||
{
|
||||
free(buf);
|
||||
return SB_WRITE_ERROR;
|
||||
}
|
||||
fclose(fd);
|
||||
int cnt = fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd);
|
||||
if(cnt != 1)
|
||||
printf(GREY, "Write error: %m\n");
|
||||
free(buf);
|
||||
fclose(fd);
|
||||
if(cnt != 1)
|
||||
return SB_WRITE_ERROR;
|
||||
|
||||
return SB_SUCCESS;
|
||||
#undef check_crypto
|
||||
#undef printf
|
||||
}
|
||||
|
||||
|
@ -712,22 +737,28 @@ static void sb_printer(void *user, const char *fmt, ...)
|
|||
}
|
||||
|
||||
struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, void *u,
|
||||
generic_printf_t cprintf, enum sb_error_t *err)
|
||||
generic_printf_t cprintf, enum sb_error_t *out_err)
|
||||
{
|
||||
struct sb_file_t *sb_file = NULL;
|
||||
uint8_t *buf = _buf;
|
||||
|
||||
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
||||
#define fatal(e, ...) \
|
||||
do { if(err) *err = e; \
|
||||
do { if(out_err) *out_err = e; \
|
||||
cprintf(u, true, GREY, __VA_ARGS__); \
|
||||
free(cbcmacs); \
|
||||
sb_free(sb_file); \
|
||||
return NULL; } while(0)
|
||||
struct printer_t printer = {.user = u, .cprintf = cprintf, .color = OFF, .error = false };
|
||||
#define print_hex(c, p, len, nl) \
|
||||
do { printer.color = c; print_hex(&printer, sb_printer, p, len, nl); } while(0)
|
||||
#define check_crypto(expr) \
|
||||
do { int err = expr; \
|
||||
if(err != CRYPTO_ERROR_SUCCESS) \
|
||||
fatal(SB_CRYPTO_ERROR, "Crypto error: %d\n", err); } while(0)
|
||||
|
||||
struct sha_1_params_t sha_1_params;
|
||||
byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
|
||||
sb_file = xmalloc(sizeof(struct sb_file_t));
|
||||
memset(sb_file, 0, sizeof(struct sb_file_t));
|
||||
struct sb_header_t *sb_header = (struct sb_header_t *)buf;
|
||||
|
@ -826,12 +857,12 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id);
|
||||
|
||||
/* encryption cbc-mac */
|
||||
byte real_key[16];
|
||||
struct crypto_key_t real_key;
|
||||
real_key.method = CRYPTO_KEY;
|
||||
bool valid_key = false; /* false until a matching key was found */
|
||||
|
||||
if(sb_header->nr_keys > 0)
|
||||
{
|
||||
byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
|
||||
printf(BLUE, "Encryption keys\n");
|
||||
for(int i = 0; i < g_nr_keys; i++)
|
||||
{
|
||||
|
@ -843,13 +874,9 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
/* check it */
|
||||
byte zero[16];
|
||||
memset(zero, 0, 16);
|
||||
int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
|
||||
&g_key_array[i], zero, &cbcmacs[i], 1);
|
||||
if(ret != CRYPTO_ERROR_SUCCESS)
|
||||
{
|
||||
free(cbcmacs);
|
||||
fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret);
|
||||
}
|
||||
check_crypto(crypto_setup(&g_key_array[i]));
|
||||
check_crypto(crypto_apply(buf, NULL, sb_header->header_size +
|
||||
sb_header->nr_sections, zero, &cbcmacs[i], true));
|
||||
print_hex(YELLOW, cbcmacs[i], 16, true);
|
||||
}
|
||||
|
||||
|
@ -878,24 +905,20 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
byte decrypted_key[16];
|
||||
byte iv[16];
|
||||
memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
|
||||
int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0);
|
||||
if(ret != CRYPTO_ERROR_SUCCESS)
|
||||
{
|
||||
free(cbcmacs);
|
||||
fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret);
|
||||
}
|
||||
check_crypto(crypto_setup(&g_key_array[idx]));
|
||||
check_crypto(crypto_apply(dict_entry->key, decrypted_key, 1, iv, NULL, false));
|
||||
printf(GREEN, " Decrypted key: ");
|
||||
print_hex(YELLOW, decrypted_key, 16, false);
|
||||
if(valid_key)
|
||||
{
|
||||
if(memcmp(real_key, decrypted_key, 16) == 0)
|
||||
if(memcmp(real_key.u.key, decrypted_key, 16) == 0)
|
||||
printf(RED, " Cross-Check Ok");
|
||||
else
|
||||
printf(RED, " Cross-Check Failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(real_key, decrypted_key, 16);
|
||||
memcpy(real_key.u.key, decrypted_key, 16);
|
||||
valid_key = true;
|
||||
}
|
||||
printf(OFF, "\n");
|
||||
|
@ -904,8 +927,6 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
printf(RED, " Don't Match\n");
|
||||
}
|
||||
|
||||
free(cbcmacs);
|
||||
|
||||
if(!valid_key)
|
||||
{
|
||||
if(g_force)
|
||||
|
@ -916,11 +937,9 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
|
||||
if(getenv("SB_REAL_KEY") != 0)
|
||||
{
|
||||
struct crypto_key_t k;
|
||||
char *env = getenv("SB_REAL_KEY");
|
||||
if(!parse_key(&env, &k) || *env)
|
||||
if(!parse_key(&env, &real_key) || *env)
|
||||
fatal(SB_ERROR, "Invalid SB_REAL_KEY\n");
|
||||
memcpy(real_key, k.u.key, 16);
|
||||
/* assume the key is valid */
|
||||
if(valid_key)
|
||||
printf(GREY, " Overriding real key\n");
|
||||
|
@ -931,16 +950,17 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
|
||||
printf(RED, " Summary:\n");
|
||||
printf(GREEN, " Real key: ");
|
||||
print_hex(YELLOW, real_key, 16, true);
|
||||
print_hex(YELLOW, real_key.u.key, 16, true);
|
||||
printf(GREEN, " IV : ");
|
||||
print_hex(YELLOW, buf, 16, true);
|
||||
|
||||
memcpy(sb_file->real_key, real_key, 16);
|
||||
memcpy(sb_file->real_key, real_key.u.key, 16);
|
||||
memcpy(sb_file->crypto_iv, buf, 16);
|
||||
/* setup real key if needed */
|
||||
check_crypto(crypto_setup(&real_key));
|
||||
}
|
||||
else
|
||||
valid_key = true;
|
||||
|
||||
/* sections */
|
||||
if(!(flags & SB_RAW_MODE))
|
||||
{
|
||||
|
@ -986,12 +1006,13 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
/* save it */
|
||||
byte *sec = xmalloc(size);
|
||||
if(encrypted)
|
||||
cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
|
||||
check_crypto(crypto_apply(buf + pos, sec, size / BLOCK_SIZE, buf, NULL, false));
|
||||
else
|
||||
memcpy(sec, buf + pos, size);
|
||||
|
||||
struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
|
||||
sec, size, " ", u, cprintf, err);
|
||||
sec, size, " ", u, cprintf, out_err);
|
||||
free(sec);
|
||||
if(s)
|
||||
{
|
||||
s->other_flags = sec_hdr->flags & ~SECTION_STD_MASK;
|
||||
|
@ -1001,9 +1022,7 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
free(s);
|
||||
}
|
||||
else
|
||||
fatal(*err, "Error reading section\n");
|
||||
|
||||
free(sec);
|
||||
fatal(*out_err, "Error reading section\n");
|
||||
}
|
||||
}
|
||||
else if(valid_key)
|
||||
|
@ -1019,7 +1038,7 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
memcpy(iv, buf, 16);
|
||||
byte cmd[BLOCK_SIZE];
|
||||
if(sb_header->nr_keys > 0)
|
||||
cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0);
|
||||
check_crypto(crypto_apply(buf + offset, cmd, 1, iv, &iv, false));
|
||||
else
|
||||
memcpy(cmd, buf + offset, BLOCK_SIZE);
|
||||
struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd;
|
||||
|
@ -1077,12 +1096,13 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
/* save it */
|
||||
byte *sec = xmalloc(size);
|
||||
if(encrypted)
|
||||
cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
|
||||
check_crypto(crypto_apply(buf + pos, sec, size / BLOCK_SIZE, buf, NULL, false));
|
||||
else
|
||||
memcpy(sec, buf + pos, size);
|
||||
|
||||
struct sb_section_t *s = read_section(data_sec, tag->identifier,
|
||||
sec, size, " ", u, cprintf, err);
|
||||
sec, size, " ", u, cprintf, out_err);
|
||||
free(sec);
|
||||
if(s)
|
||||
{
|
||||
s->other_flags = tag->flags & ~SECTION_STD_MASK;
|
||||
|
@ -1094,8 +1114,7 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
free(s);
|
||||
}
|
||||
else
|
||||
fatal(*err, "Error reading section\n");
|
||||
free(sec);
|
||||
fatal(*out_err, "Error reading section\n");
|
||||
|
||||
/* last one ? */
|
||||
if(tag->hdr.flags & SB_INST_LAST_TAG)
|
||||
|
@ -1126,7 +1145,7 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
printf(OFF, " ");
|
||||
print_hex(YELLOW, encrypted_block + 16, 16, true);
|
||||
/* decrypt it */
|
||||
cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0);
|
||||
check_crypto(crypto_apply(encrypted_block, decrypted_block, 2, buf, NULL, false));
|
||||
}
|
||||
else
|
||||
memcpy(decrypted_block, &buf[filesize - 32], 32);
|
||||
|
@ -1153,6 +1172,7 @@ struct sb_file_t *sb_read_memory(void *_buf, size_t filesize, unsigned flags, vo
|
|||
fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n");
|
||||
}
|
||||
|
||||
free(cbcmacs);
|
||||
return sb_file;
|
||||
#undef printf
|
||||
#undef fatal
|
||||
|
|
|
@ -232,8 +232,7 @@ enum sb_error_t
|
|||
SB_FORMAT_ERROR = -5,
|
||||
SB_CHECKSUM_ERROR = -6,
|
||||
SB_NO_VALID_KEY = -7,
|
||||
SB_FIRST_CRYPTO_ERROR = -8,
|
||||
SB_LAST_CRYPTO_ERROR = SB_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS,
|
||||
SB_CRYPTO_ERROR = -8,
|
||||
};
|
||||
|
||||
#define SB_RAW_MODE (1 << 0) /* read image in raw mode (aka bootloader-like) */
|
||||
|
|
|
@ -139,8 +139,7 @@ enum sb1_error_t
|
|||
SB1_FORMAT_ERROR = -5,
|
||||
SB1_CHECKSUM_ERROR = -6,
|
||||
SB1_NO_VALID_KEY = -7,
|
||||
SB1_FIRST_CRYPTO_ERROR = -8,
|
||||
SB1_LAST_CRYPTO_ERROR = SB1_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS,
|
||||
SB1_CRYPTO_ERROR = -8,
|
||||
};
|
||||
|
||||
enum sb1_error_t sb1_write_file(struct sb1_file_t *sb, const char *filename);
|
||||
|
|
Loading…
Reference in a new issue