Merge pull request #167 from danielinux/aes-encryption

Add AES encryption support
pull/178/head
David Garske 2022-02-09 10:55:51 -08:00 committed by GitHub
commit 262a5b0a78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 501 additions and 92 deletions

View File

@ -0,0 +1,30 @@
ARCH?=ARM
TARGET?=stm32wb
SIGN?=ECC256
HASH?=SHA256
DEBUG?=0
VTOR?=1
CORTEX_M0?=0
NO_ASM?=0
EXT_FLASH?=1
SPI_FLASH?=0
NO_XIP?=0
UART_FLASH?=1
ALLOW_DOWNGRADE?=0
NVM_FLASH_WRITEONCE?=1
WOLFBOOT_VERSION?=0
V?=0
NO_MPU?=0
SPMATH?=1
RAM_CODE?=0
DUALBANK_SWAP?=0
IMAGE_HEADER_SIZE?=256
PKA?=0
ENCRYPT=1
ENCRYPT_WITH_AES128=1
WOLFTPM?=0
WOLFBOOT_PARTITION_SIZE?=0x20000
WOLFBOOT_SECTOR_SIZE?=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08010000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x20000

View File

@ -0,0 +1,30 @@
ARCH?=ARM
TARGET?=stm32wb
SIGN?=ECC256
HASH?=SHA256
DEBUG?=0
VTOR?=1
CORTEX_M0?=0
NO_ASM?=0
EXT_FLASH?=1
SPI_FLASH?=0
NO_XIP?=0
UART_FLASH?=1
ALLOW_DOWNGRADE?=0
NVM_FLASH_WRITEONCE?=1
WOLFBOOT_VERSION?=0
V?=0
NO_MPU?=0
SPMATH?=1
RAM_CODE?=0
DUALBANK_SWAP?=0
IMAGE_HEADER_SIZE?=256
PKA?=0
ENCRYPT=1
ENCRYPT_WITH_AES256=1
WOLFTPM?=0
WOLFBOOT_PARTITION_SIZE?=0x20000
WOLFBOOT_SECTOR_SIZE?=0x1000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x08010000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x0
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x20000

View File

@ -21,6 +21,7 @@ DUALBANK_SWAP?=0
IMAGE_HEADER_SIZE?=256
PKA?=0
ENCRYPT=1
ENCRYPT_WITH_CHACHA=1
WOLFTPM?=0
WOLFBOOT_PARTITION_SIZE?=0x20000
WOLFBOOT_SECTOR_SIZE?=0x1000

View File

@ -57,18 +57,27 @@ reboot.
### Symmetric encryption algorithm
The algorithm currently used to encrypt and decrypt data in external partitions
The default algorithm used to encrypt and decrypt data in external partitions
is Chacha20-256.
- The `key` provided to `wolfBoot_set_encrypt_key()` must be exactly 32 Bytes long.
- The `nonce` argument must be a 96-bit (12 Bytes) randomly generated buffer, to be used as IV for encryption and decryption.
AES-128 and AES-256 are also supported. AES is used in counter mode. AES-128 and AES-256 have a key length of 16 and 32 bytes
respectively, and the IV size is 16 bytes long in both cases.
## Example usage
### Signing and encrypting the update bundle
To compile wolfBoot with encryption support, use the option `ENCRYPT=1`.
By default, this also selects `ENCRYPT_WITH_CHACHA=1`. To use AES encryption instead,
select `ENCRYPT_WITH_AES128=1` or `ENCRYPT_WITH_AES256=1`.
### Signing and encrypting the update bundle with ChaCha20-256
The `sign.py` tool can sign and encrypt the image with a single command.
The encryption secret is provided in a binary file that should contain a concatenation of
In case of chacha20, the encryption secret is provided in a binary file that should contain a concatenation of
a 32B ChaCha-256 key and a 12B nonce.
In the examples provided, the test application uses the following parameters:
@ -94,6 +103,34 @@ secret file:
which will produce as output the file `test-app/image_v24_signed_and_encrypted.bin`, that can be transferred to the target's external device.
### Signing and encrypting the update bundle with AES-256
In case of AES-256, the encryption secret is provided in a binary file that should contain a concatenation of
a 32B key and a 16B IV.
In the examples provided, the test application uses the following parameters:
```
key = "0123456789abcdef0123456789abcdef"
iv = "0123456789abcdef"
```
So it is easy to prepare the encryption secret in the test scripts or from the command line using:
```
echo -n "0123456789abcdef0123456789abcdef0123456789abcdef" > enc_key.der
```
The `sign.py` script can now be invoked to produce a signed+encrypted image, by using the extra argument `--encrypt` followed by the
secret file. To select AES-256, use the `--aes256` option.
```
./tools/keytools/sign.py --aes256 --encrypt enc_key.der test-app/image.bin ecc256.der 24
```
which will produce as output the file `test-app/image_v24_signed_and_encrypted.bin`, that can be transferred to the target's external device.
### API usage in the application

View File

@ -31,9 +31,37 @@
#include "target.h"
#include "wolfboot/wolfboot.h"
#ifdef ENCRYPT_WITH_CHACHA
#include <wolfssl/wolfcrypt/chacha.h>
#else
#include <wolfssl/wolfcrypt/aes.h>
#endif
#include <wolfssl/wolfcrypt/pwdbased.h>
#ifdef ENCRYPT_WITH_CHACHA
extern ChaCha chacha;
#define crypto_init() chacha_init()
#define crypto_encrypt(eb,b,sz) wc_Chacha_Process(&chacha, eb, b, sz)
#define crypto_decrypt(db,b,sz) wc_Chacha_Process(&chacha, db, b, sz)
#define crypto_set_iv(n, iv) wc_Chacha_SetIV(&chacha, n, iv)
int chacha_init(void);
#elif defined(ENCRYPT_WITH_AES128) || defined(ENCRYPT_WITH_AES256)
extern Aes aes_dec, aes_enc;
#define crypto_init() aes_init()
#define crypto_encrypt(eb,b,sz) wc_AesCtrEncrypt(&aes_enc, eb, b, sz)
#define crypto_decrypt(db,b,sz) wc_AesCtrEncrypt(&aes_dec, db, b, sz)
#define crypto_set_iv(n,a) aes_set_iv(n, a)
int aes_init(void);
void aes_set_iv(uint8_t *nonce, uint32_t address);
#endif /* ENCRYPT_WITH_CHACHA */
/* Internal read/write functions (not exported in the libwolfboot API) */
int ext_flash_encrypt_write(uintptr_t address, const uint8_t *data, int len);

View File

@ -144,7 +144,6 @@
#endif
#ifdef EXT_ENCRYPTED
# define HAVE_CHACHA
# define HAVE_PWDBASED
#else
# define NO_PWDBASED
@ -152,7 +151,9 @@
/* Disables - For minimum wolfCrypt build */
#ifndef WOLFBOOT_TPM
# if !defined(ENCRYPT_WITH_AES128) && !defined(ENCRYPT_WITH_AES256)
# define NO_AES
# endif
# define NO_HMAC
#endif

View File

@ -131,7 +131,7 @@ int wolfBoot_dualboot_candidate(void);
/* Hashing function configuration */
#if defined(WOLFBOOT_HASH_SHA256)
# define WOLFBOOT_SHA_BLOCK_SIZE (16)
# define WOLFBOOT_SHA_BLOCK_SIZE (256)
# define WOLFBOOT_SHA_HDR HDR_SHA256
# define WOLFBOOT_SHA_DIGEST_SIZE (32)
# define image_hash image_sha256
@ -146,10 +146,26 @@ int wolfBoot_dualboot_candidate(void);
# error "No valid hash algorithm defined!"
#endif
#ifdef EXT_ENCRYPTED
/* Encryption support */
#define ENCRYPT_BLOCK_SIZE 16
#define ENCRYPT_KEY_SIZE 32 /* Chacha20 - 256bit */
#define ENCRYPT_NONCE_SIZE 12 /* 96 bit*/
#if defined(ENCRYPT_WITH_CHACHA)
#define ENCRYPT_BLOCK_SIZE 64
#define ENCRYPT_KEY_SIZE 32 /* Chacha20 - 256bit */
#define ENCRYPT_NONCE_SIZE 12 /* 96 bit*/
#elif defined(ENCRYPT_WITH_AES128)
#define ENCRYPT_BLOCK_SIZE 16
#define ENCRYPT_KEY_SIZE 16 /* AES128 */
#define ENCRYPT_NONCE_SIZE 16 /* AES IV size */
#elif defined(ENCRYPT_WITH_AES256)
#define ENCRYPT_BLOCK_SIZE 16
#define ENCRYPT_KEY_SIZE 32 /* AES256 */
#define ENCRYPT_NONCE_SIZE 16 /* AES IV size */
#else
# error "Encryption ON, but no encryption algorithm selected."
#endif
#endif /* EXT_ENCRYPTED */
#ifdef DELTA_UPDATES
int wolfBoot_get_diffbase_hdr(uint8_t part, uint8_t **ptr);
@ -158,4 +174,5 @@ int wolfBoot_get_diffbase_hdr(uint8_t part, uint8_t **ptr);
int wolfBoot_set_encrypt_key(const uint8_t *key, const uint8_t *nonce);
int wolfBoot_get_encrypt_key(uint8_t *key, uint8_t *nonce);
int wolfBoot_erase_encrypt_key(void);
#endif /* !WOLFBOOT_H */

View File

@ -178,7 +178,19 @@ endif
ifeq ($(ENCRYPT),1)
CFLAGS+=-D"EXT_ENCRYPTED=1"
ifeq ($(ENCRYPT_WITH_AES128),1)
CFLAGS+=-DWOLFSSL_AES_COUNTER -DWOLFSSL_AES_DIRECT
CFLAGS+=-DENCRYPT_WITH_AES128 -DWOLFSSL_AES_128
WOLFCRYPT_OBJS+=./lib/wolfssl/wolfcrypt/src/aes.o
else ifeq ($(ENCRYPT_WITH_AES256),1)
CFLAGS+=-DWOLFSSL_AES_COUNTER -DWOLFSSL_AES_DIRECT
CFLAGS+=-DENCRYPT_WITH_AES256 -DWOLFSSL_AES_256
WOLFCRYPT_OBJS+=./lib/wolfssl/wolfcrypt/src/aes.o
else
ENCRYPT_WITH_CHACHA=1
WOLFCRYPT_OBJS+=./lib/wolfssl/wolfcrypt/src/chacha.o
CFLAGS+=-DENCRYPT_WITH_CHACHA -DHAVE_CHACHA
endif
endif
ifeq ($(EXT_FLASH),1)

View File

@ -759,11 +759,14 @@ int RAMFUNCTION wolfBoot_erase_encrypt_key(void)
#ifdef __WOLFBOOT
static ChaCha chacha;
static int chacha_initialized = 0;
static uint8_t chacha_iv_nonce[ENCRYPT_NONCE_SIZE];
static int encrypt_initialized = 0;
static uint8_t encrypt_iv_nonce[ENCRYPT_NONCE_SIZE];
static int chacha_init(void)
#ifdef ENCRYPT_WITH_CHACHA
ChaCha chacha;
int chacha_init(void)
{
uint8_t *key = (uint8_t *)(WOLFBOOT_PARTITION_BOOT_ADDRESS + ENCRYPT_TMP_SECRET_OFFSET);
uint8_t ff[ENCRYPT_KEY_SIZE];
@ -777,12 +780,77 @@ static int chacha_init(void)
if (XMEMCMP(key, ff, ENCRYPT_KEY_SIZE) == 0)
return -1;
XMEMCPY(chacha_iv_nonce, stored_nonce, ENCRYPT_NONCE_SIZE);
XMEMCPY(encrypt_iv_nonce, stored_nonce, ENCRYPT_NONCE_SIZE);
wc_Chacha_SetKey(&chacha, key, ENCRYPT_KEY_SIZE);
chacha_initialized = 1;
encrypt_initialized = 1;
return 0;
}
#elif defined(ENCRYPT_WITH_AES128) || defined(ENCRYPT_WITH_AES256)
/* Inline use of ByteReverseWord32 */
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
Aes aes_dec, aes_enc;
int aes_init(void)
{
uint8_t *key = (uint8_t *)(WOLFBOOT_PARTITION_BOOT_ADDRESS + ENCRYPT_TMP_SECRET_OFFSET);
uint8_t ff[ENCRYPT_KEY_SIZE];
uint8_t iv_buf[ENCRYPT_BLOCK_SIZE];
uint8_t *stored_nonce = key + ENCRYPT_KEY_SIZE;
wc_AesInit(&aes_enc, NULL, 0);
wc_AesInit(&aes_dec, NULL, 0);
/* Check against 'all 0xff' or 'all zero' cases */
XMEMSET(ff, 0xFF, ENCRYPT_KEY_SIZE);
if (XMEMCMP(key, ff, ENCRYPT_KEY_SIZE) == 0)
return -1;
XMEMSET(ff, 0x00, ENCRYPT_KEY_SIZE);
if (XMEMCMP(key, ff, ENCRYPT_KEY_SIZE) == 0)
return -1;
XMEMCPY(encrypt_iv_nonce, stored_nonce, ENCRYPT_NONCE_SIZE);
XMEMCPY(iv_buf, stored_nonce, ENCRYPT_NONCE_SIZE);
/* AES_ENCRYPTION is used for both directions in CTR */
wc_AesSetKeyDirect(&aes_enc, key, ENCRYPT_KEY_SIZE, iv_buf, AES_ENCRYPTION);
wc_AesSetKeyDirect(&aes_dec, key, ENCRYPT_KEY_SIZE, iv_buf, AES_ENCRYPTION);
encrypt_initialized = 1;
return 0;
}
void aes_set_iv(uint8_t *nonce, uint32_t iv_ctr)
{
uint32_t iv_buf[ENCRYPT_BLOCK_SIZE / sizeof(uint32_t)];
uint32_t iv_local_ctr;
int i;
XMEMCPY(iv_buf, nonce, ENCRYPT_NONCE_SIZE);
#ifndef BIG_ENDIAN_ORDER
for (i = 0; i < 4; i++) {
iv_buf[i] = ByteReverseWord32(iv_buf[i]);
}
#endif
iv_buf[3] += iv_ctr;
if(iv_buf[3] < iv_ctr) { /* overflow */
for (i = 2; i >= 0; i--) {
iv_buf[i]++;
if (iv_buf[i] != 0)
break;
}
}
#ifndef BIG_ENDIAN_ORDER
for (i = 0; i < 4; i++) {
iv_buf[i] = ByteReverseWord32(iv_buf[i]);
}
#endif
wc_AesSetIV(&aes_enc, (byte *)iv_buf);
wc_AesSetIV(&aes_dec, (byte *)iv_buf);
}
#endif
static inline uint8_t part_address(uintptr_t a)
{
@ -790,20 +858,19 @@ static inline uint8_t part_address(uintptr_t a)
#if WOLFBOOT_PARTITION_UPDATE_ADDRESS != 0
(a >= WOLFBOOT_PARTITION_UPDATE_ADDRESS) &&
#endif
(a <= WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE))
(a < WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE))
return PART_UPDATE;
if ( 1 &&
#if WOLFBOOT_PARTITION_SWAP_ADDRESS != 0
(a >= WOLFBOOT_PARTITION_SWAP_ADDRESS) &&
#endif
(a <= WOLFBOOT_PARTITION_SWAP_ADDRESS + WOLFBOOT_SECTOR_SIZE))
(a < WOLFBOOT_PARTITION_SWAP_ADDRESS + WOLFBOOT_SECTOR_SIZE))
return PART_SWAP;
return PART_NONE;
}
int ext_flash_encrypt_write(uintptr_t address, const uint8_t *data, int len)
{
uint32_t iv_counter;
uint8_t block[ENCRYPT_BLOCK_SIZE];
uint8_t part;
int sz = len;
@ -818,25 +885,20 @@ int ext_flash_encrypt_write(uintptr_t address, const uint8_t *data, int len)
if (sz < ENCRYPT_BLOCK_SIZE) {
sz = ENCRYPT_BLOCK_SIZE;
}
if (!chacha_initialized)
if (chacha_init() < 0)
if (!encrypt_initialized)
if (crypto_init() < 0)
return -1;
part = part_address(address);
switch(part) {
case PART_UPDATE:
iv_counter = (address - WOLFBOOT_PARTITION_UPDATE_ADDRESS) / ENCRYPT_BLOCK_SIZE;
/* Do not encrypt last sectors */
if (iv_counter >= (START_FLAGS_OFFSET - ENCRYPT_BLOCK_SIZE) / ENCRYPT_BLOCK_SIZE) {
/* do not encrypt flag sector */
if (address - WOLFBOOT_PARTITION_UPDATE_ADDRESS >= START_FLAGS_OFFSET) {
return ext_flash_write(address, data, len);
}
break;
case PART_SWAP:
{
uint32_t row_number;
row_number = (address - WOLFBOOT_PARTITION_SWAP_ADDRESS) / ENCRYPT_BLOCK_SIZE;
iv_counter = row_number;
break;
}
/* data is coming from update and is already encrypted */
return ext_flash_write(address, data, len);
default:
return -1;
}
@ -845,19 +907,15 @@ int ext_flash_encrypt_write(uintptr_t address, const uint8_t *data, int len)
if (ext_flash_read(row_address, block, ENCRYPT_BLOCK_SIZE) != ENCRYPT_BLOCK_SIZE)
return -1;
XMEMCPY(block + row_offset, data, step);
wc_Chacha_SetIV(&chacha, chacha_iv_nonce, iv_counter);
wc_Chacha_Process(&chacha, enc_block, block, ENCRYPT_BLOCK_SIZE);
crypto_encrypt(enc_block, block, ENCRYPT_BLOCK_SIZE);
ext_flash_write(row_address, enc_block, ENCRYPT_BLOCK_SIZE);
address += step;
data += step;
sz -= step;
iv_counter++;
}
for (i = 0; i < sz / ENCRYPT_BLOCK_SIZE; i++) {
wc_Chacha_SetIV(&chacha, chacha_iv_nonce, iv_counter);
XMEMCPY(block, data + (ENCRYPT_BLOCK_SIZE * i), ENCRYPT_BLOCK_SIZE);
wc_Chacha_Process(&chacha, ENCRYPT_CACHE + (ENCRYPT_BLOCK_SIZE * i), block, ENCRYPT_BLOCK_SIZE);
iv_counter++;
crypto_encrypt(ENCRYPT_CACHE + (ENCRYPT_BLOCK_SIZE * i), block, ENCRYPT_BLOCK_SIZE);
}
return ext_flash_write(address, ENCRYPT_CACHE, len);
}
@ -879,8 +937,8 @@ int ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len)
if (sz < ENCRYPT_BLOCK_SIZE) {
sz = ENCRYPT_BLOCK_SIZE;
}
if (!chacha_initialized)
if (chacha_init() < 0)
if (!encrypt_initialized)
if (crypto_init() < 0)
return -1;
part = part_address(row_address);
switch(part) {
@ -890,12 +948,10 @@ int ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len)
if (iv_counter >= (START_FLAGS_OFFSET - ENCRYPT_BLOCK_SIZE) / ENCRYPT_BLOCK_SIZE) {
return ext_flash_read(address, data, len);
}
crypto_set_iv(encrypt_iv_nonce, iv_counter);
break;
case PART_SWAP:
{
uint32_t row_number;
row_number = (address - WOLFBOOT_PARTITION_SWAP_ADDRESS) / ENCRYPT_BLOCK_SIZE;
iv_counter = row_number;
break;
}
default:
@ -906,8 +962,7 @@ int ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len)
int step = ENCRYPT_BLOCK_SIZE - row_offset;
if (ext_flash_read(row_address, block, ENCRYPT_BLOCK_SIZE) != ENCRYPT_BLOCK_SIZE)
return -1;
wc_Chacha_SetIV(&chacha, chacha_iv_nonce, iv_counter);
wc_Chacha_Process(&chacha, dec_block, block, ENCRYPT_BLOCK_SIZE);
crypto_decrypt(dec_block, block, ENCRYPT_BLOCK_SIZE);
XMEMCPY(data, dec_block + row_offset, step);
address += step;
data += step;
@ -917,9 +972,8 @@ int ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len)
if (ext_flash_read(address, data, sz) != sz)
return -1;
for (i = 0; i < sz / ENCRYPT_BLOCK_SIZE; i++) {
wc_Chacha_SetIV(&chacha, chacha_iv_nonce, iv_counter);
XMEMCPY(block, data + (ENCRYPT_BLOCK_SIZE * i), ENCRYPT_BLOCK_SIZE);
wc_Chacha_Process(&chacha, data + (ENCRYPT_BLOCK_SIZE * i), block, ENCRYPT_BLOCK_SIZE);
crypto_decrypt(data + (ENCRYPT_BLOCK_SIZE * i), block, ENCRYPT_BLOCK_SIZE);
iv_counter++;
}
return len;

View File

@ -42,6 +42,10 @@ static uint8_t buffer[FLASHBUFFER_SIZE];
# endif
#endif
#ifdef EXT_ENCRYPTED
#include "encrypt.h"
#endif
static void RAMFUNCTION wolfBoot_erase_bootloader(void)
{
uint32_t *start = (uint32_t *)&_start_text;
@ -116,6 +120,12 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src, struct w
uint32_t pos = 0;
uint32_t src_sector_offset = (sector * WOLFBOOT_SECTOR_SIZE);
uint32_t dst_sector_offset = (sector * WOLFBOOT_SECTOR_SIZE);
#ifdef EXT_ENCRYPTED
uint8_t key[ENCRYPT_KEY_SIZE];
uint8_t nonce[ENCRYPT_NONCE_SIZE];
uint32_t iv_counter;
#endif
if (src == dst)
return 0;
@ -123,6 +133,18 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src, struct w
src_sector_offset = 0;
if (dst->part == PART_SWAP)
dst_sector_offset = 0;
#ifdef EXT_ENCRYPTED
wolfBoot_get_encrypt_key(key, nonce);
if(src->part == PART_SWAP)
iv_counter = dst_sector_offset;
else
iv_counter = src_sector_offset;
iv_counter /= ENCRYPT_BLOCK_SIZE;
crypto_set_iv(nonce, iv_counter);
#endif
#ifdef EXT_FLASH
if (PART_IS_EXT(src)) {
#ifndef BUFFER_DECLARED
@ -131,9 +153,20 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src, struct w
#endif
wb_flash_erase(dst, dst_sector_offset, WOLFBOOT_SECTOR_SIZE);
while (pos < WOLFBOOT_SECTOR_SIZE) {
if (src_sector_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
ext_flash_check_read((uintptr_t)(src->hdr) + src_sector_offset + pos, (void *)buffer, FLASHBUFFER_SIZE);
wb_flash_write(dst, dst_sector_offset + pos, buffer, FLASHBUFFER_SIZE);
if (src_sector_offset + pos <
(src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) {
/* bypass decryption, copy encrypted data into swap */
if (dst->part == PART_SWAP) {
ext_flash_read((uintptr_t)(src->hdr) + src_sector_offset + pos,
(void *)buffer, FLASHBUFFER_SIZE);
} else {
ext_flash_check_read((uintptr_t)(src->hdr) + src_sector_offset +
pos,
(void *)buffer, FLASHBUFFER_SIZE);
}
wb_flash_write(dst,
dst_sector_offset + pos, buffer, FLASHBUFFER_SIZE);
}
pos += FLASHBUFFER_SIZE;
}

View File

@ -30,8 +30,15 @@
#include "uart_drv.h"
#ifdef PLATFORM_stm32wb
char enc_key[] = "0123456789abcdef0123456789abcdef" /* ChaCha key (256 bit) */
"0123456789ab"; /* IV nonce (96 bit) */
/* Matches all keys:
* - chacha (32 + 12)
* - aes128 (16 + 16)
* - aes256 (32 + 16)
*/
/* Longest key possible: AES256 (32 key + 16 IV = 48) */
char enc_key[] = "0123456789abcdef0123456789abcdef"
"0123456789abcdef";
volatile uint32_t time_elapsed = 0;
void main(void) {

View File

@ -28,6 +28,9 @@ ifeq ($(ARCH),)
V?=0
NO_MPU?=0
ENCRYPT?=0
ENCRYPT_WITH_CHACHA?=0
ENCRYPT_WITH_AES128?=0
ENCRYPT_WITH_AES256?=0
FLAGS_HOME?=0
FLAGS_INVERT?=0
SPMATH?=1
@ -61,5 +64,6 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO_DRIVERS
WOLFBOOT_PARTITION_BOOT_ADDRESS WOLFBOOT_PARTITION_UPDATE_ADDRESS \
WOLFBOOT_PARTITION_SWAP_ADDRESS WOLFBOOT_LOAD_ADDRESS \
WOLFBOOT_LOAD_DTS_ADDRESS WOLFBOOT_DTS_BOOT_ADDRESS WOLFBOOT_DTS_UPDATE_ADDRESS \
WOLFBOOT_SMALL_STACK DELTA_UPDATES DELTA_BLOCK_SIZE
WOLFBOOT_SMALL_STACK DELTA_UPDATES DELTA_BLOCK_SIZE \
ENCRYPT_WITH_CHAHA ENCRYPT_WITH_AES128 ENCRYPT_WITH_AES256

View File

@ -11,11 +11,11 @@ CC = gcc
WOLFBOOTDIR = ../..
WOLFDIR = $(WOLFBOOTDIR)/lib/wolfssl/
CFLAGS = -Wall -Wextra -Werror
CFLAGS += -I. -DWOLFSSL_USER_SETTINGS -I$(WOLFDIR) -I$(WOLFBOOTDIR)/include
CFLAGS += -I. -DWOLFSSL_USER_SETTINGS -I$(WOLFDIR) -I$(WOLFBOOTDIR)/include -DWOLFBOOT_KEYTOOLS -DWOLFSSL_AES_DIRECT -DWOLFSSL_AES_COUNTER
# option variables
DEBUG_FLAGS = -g -DDEBUG -DDEBUG_SIGNTOOL -DDEBUG_WOLFSSL -DDEBUG_WOLFSSL_VERBOSE
OPTIMIZE = -Os
OPTIMIZE = -O2
# Options
#CFLAGS+=$(DEBUG_FLAGS)
@ -29,6 +29,7 @@ CFLAGS+=-DIMAGE_HEADER_SIZE=$(IMAGE_HEADER_SIZE)
# Sources
SRC=$(WOLFDIR)wolfcrypt/src/asn.c \
$(WOLFDIR)wolfcrypt/src/aes.c \
$(WOLFDIR)wolfcrypt/src/ecc.c \
$(WOLFDIR)wolfcrypt/src/coding.c \
$(WOLFDIR)wolfcrypt/src/chacha.c \

View File

@ -56,11 +56,13 @@
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/asn.h>
#include <wolfssl/wolfcrypt/aes.h>
#ifdef HAVE_CHACHA
#include <wolfssl/wolfcrypt/chacha.h>
#endif
#ifndef NO_RSA
#include <wolfssl/wolfcrypt/rsa.h>
#endif
@ -136,7 +138,15 @@
#define SIGN_RSA4096 HDR_IMG_TYPE_AUTH_RSA4096
#define SIGN_ED448 HDR_IMG_TYPE_AUTH_ED448
#define ENC_OFF 0
#define ENC_CHACHA 1
#define ENC_AES128 2
#define ENC_AES256 3
#define ENC_BLOCK_SIZE 16
#define ENC_MAX_KEY_SZ 32
#define ENC_MAX_IV_SZ 16
static void header_append_u32(uint8_t* header, uint32_t* idx, uint32_t tmp32)
{
@ -202,6 +212,7 @@ struct cmd_options {
static struct cmd_options CMD = {
.sign = SIGN_AUTO,
.encrypt = ENC_OFF,
.hash_algo = HASH_SHA256,
.header_sz = IMAGE_HEADER_SIZE
};
@ -710,28 +721,45 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz, cons
pos += read_sz;
}
if (CMD.encrypt && CMD.encrypt_key_file) {
uint8_t key[CHACHA_MAX_KEY_SZ], iv[CHACHA_IV_BYTES];
if ((CMD.encrypt != ENC_OFF) && CMD.encrypt_key_file) {
uint8_t key[ENC_MAX_KEY_SZ], iv[ENC_MAX_IV_SZ];
uint8_t enc_buf[ENC_BLOCK_SIZE];
int ivSz, keySz;
uint32_t fsize = 0;
ChaCha cha;
#ifndef HAVE_CHACHA
fprintf(stderr, "Encryption not supported: chacha support not found in wolfssl configuration.\n");
exit(100);
#endif
switch (CMD.encrypt) {
case ENC_CHACHA:
ivSz = CHACHA_IV_BYTES;
keySz = CHACHA_MAX_KEY_SZ;
break;
case ENC_AES128:
ivSz = 16;
keySz = 16;
break;
case ENC_AES256:
ivSz = 16;
keySz = 32;
break;
default:
printf("No valid encryption mode selected\n");
goto failure;
}
fek = fopen(CMD.encrypt_key_file, "rb");
if (fek == NULL) {
fprintf(stderr, "Open encryption key file %s: %s\n", CMD.encrypt_key_file, strerror(errno));
exit(1);
}
keySz = fread(key, 1, sizeof(key), fek);
ivSz = fread(iv, 1, sizeof(iv), fek);
fclose(fek);
if (keySz != sizeof(key) || ivSz != sizeof(iv)) {
fprintf(stderr, "Error reading key and iv from %s\n", CMD.encrypt_key_file);
ret = fread(key, 1, keySz, fek);
if (ret != keySz) {
fprintf(stderr, "Error reading key from %s\n", CMD.encrypt_key_file);
exit(1);
}
ret = fread(iv, 1, ivSz, fek);
if (ret != ivSz) {
fprintf(stderr, "Error reading IV from %s\n", CMD.encrypt_key_file);
exit(1);
}
fclose(fek);
fef = fopen(CMD.output_encrypted_image_file, "wb");
if (!fef) {
@ -740,24 +768,47 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz, cons
fsize = ftell(f);
fseek(f, 0, SEEK_SET); /* restart the _signed file from 0 */
if (CMD.encrypt == ENC_CHACHA) {
ChaCha cha;
#ifndef HAVE_CHACHA
fprintf(stderr, "Encryption not supported: chacha support not found in wolfssl configuration.\n");
exit(100);
#endif
wc_Chacha_SetKey(&cha, key, sizeof(key));
wc_Chacha_SetIV(&cha, iv, 0);
for (pos = 0; pos < fsize; pos += ENC_BLOCK_SIZE) {
int fread_retval;
fread_retval = fread(buf, 1, ENC_BLOCK_SIZE, f);
if ((fread_retval == 0) && feof(f)) {
break;
}
wc_Chacha_SetIV(&cha, iv, (pos >> 4));
wc_Chacha_Process(&cha, enc_buf, buf, fread_retval);
fwrite(enc_buf, 1, fread_retval, fef);
}
} else if ((CMD.encrypt == ENC_AES128) || (CMD.encrypt == ENC_AES256)) {
Aes aes_e;
wc_AesInit(&aes_e, NULL, 0);
wc_AesSetKeyDirect(&aes_e, key, keySz, iv, AES_ENCRYPTION);
for (pos = 0; pos < fsize; pos += ENC_BLOCK_SIZE) {
int fread_retval;
fread_retval = fread(buf, 1, ENC_BLOCK_SIZE, f);
if ((fread_retval == 0) && feof(f)) {
break;
}
/* Pad with FF if input is too short */
while((fread_retval % ENC_BLOCK_SIZE) != 0) {
buf[fread_retval++] = 0xFF;
}
wc_AesCtrEncrypt(&aes_e, enc_buf, buf, fread_retval);
fwrite(enc_buf, 1, fread_retval, fef);
}
}
fclose(fef);
}
printf("Output image(s) successfully created.\n");
ret = 0;
fclose(f2);
fclose(f);
failure:
if (header)
free(header);
@ -1012,7 +1063,7 @@ int main(int argc, char** argv)
/* Check arguments and print usage */
if (argc < 4 || argc > 10) {
printf("Usage: %s [--ed25519 | --ed447 | --ecc256 | --rsa2048 | --rsa2048enc | --rsa4096 | --rsa4096enc | --no-CMD.sign] [--sha256 | --sha3] [--wolfboot-update] [--encrypt enc_key.bin] [--delta image_vX_signed.bin] image key.der fw_version\n", argv[0]);
printf("Usage: %s [--ed25519 | --ed447 | --ecc256 | --rsa2048 | --rsa2048enc | --rsa4096 | --rsa4096enc | --no-CMD.sign] [--sha256 | --sha3] [--wolfboot-update] [--encrypt enc_key.bin] [--chacha | --aes128 | --aes256] [--delta image_vX_signed.bin] image key.der fw_version\n", argv[0]);
printf(" - or - ");
printf(" %s [--sha256 | --sha3] [--sha-only] [--wolfboot-update] image pub_key.der fw_version\n", argv[0]);
printf(" - or - ");
@ -1072,12 +1123,24 @@ int main(int argc, char** argv)
CMD.manual_sign = 1;
}
else if (strcmp(argv[i], "--encrypt") == 0) {
CMD.encrypt = 1;
if (CMD.encrypt == ENC_OFF)
CMD.encrypt = ENC_CHACHA;
CMD.encrypt_key_file = argv[++i];
} else if (strcmp(argv[i], "--delta") == 0) {
}
else if (strcmp(argv[i], "--aes128") == 0) {
CMD.encrypt = ENC_AES128;
}
else if (strcmp(argv[i], "--aes256") == 0) {
CMD.encrypt = ENC_AES256;
}
else if (strcmp(argv[i], "--chacha") == 0) {
CMD.encrypt = ENC_CHACHA;
}
else if (strcmp(argv[i], "--delta") == 0) {
CMD.delta = 1;
CMD.delta_base_file = argv[++i];
} else {
}
else {
i--;
break;
}

View File

@ -66,6 +66,9 @@ self_update=False
sha_only=False
manual_sign=False
encrypt=False
chacha=True
aes128=False
aes256=False
delta=False
encrypt_key_file=None
delta_base_file=None
@ -249,7 +252,7 @@ if (argc < 4) or (argc > 10):
print(" - or - ")
print(" %s [--sha256 | --sha3] [--sha-only] [--wolfboot-update] [--encrypt key.bin] [--delta base_file.bin] image pub_key.der fw_version\n" % sys.argv[0])
print(" - or - ")
print(" %s [--ed25519 | --ed448 | --ecc256 | --rsa2048 | --rsa4096 ] [--sha256 | --sha3] [--manual-sign] [--encrypt key.bin] [--delta base_file.bin] image pub_key.der fw_version signature.sig\n" % sys.argv[0])
print(" %s [--ed25519 | --ed448 | --ecc256 | --rsa2048 | --rsa4096 ] [--sha256 | --sha3] [--manual-sign] [--chacha | --aes128 | --aes256 ] [--encrypt key.bin] [--delta base_file.bin] image pub_key.der fw_version signature.sig\n" % sys.argv[0])
sys.exit(1)
i = 1
@ -280,6 +283,16 @@ while (i < len(argv)):
encrypt = True
i += 1
encrypt_key_file = argv[i]
elif (argv[i] == '--chacha'):
encrypt = True
elif (argv[i] == '--aes128'):
encrypt = True
chacha = False
aes128 = True
elif (argv[i] == '--aes256'):
encrypt = True
chacha = False
aes256 = True
elif (argv[i] == '--delta'):
delta = True
i += 1
@ -552,17 +565,39 @@ if (encrypt):
off = 0
outfile = open(output_image_file, 'rb')
ekeyfile = open(encrypt_key_file, 'rb')
enc_outfile = open(encrypted_output_image_file, 'wb')
if chacha:
key = ekeyfile.read(32)
iv_nonce = ekeyfile.read(12)
enc_outfile = open(encrypted_output_image_file, 'wb')
cha = ciphers.ChaCha(key, 32)
while(True):
cha.set_iv(iv_nonce, off)
cha.set_iv(iv_nonce, 0)
while True:
buf = outfile.read(16)
if len(buf) == 0:
break
enc_outfile.write(cha.encrypt(buf))
off += 1
elif aes128:
key = ekeyfile.read(16)
iv = ekeyfile.read(16)
aesctr = ciphers.Aes(key, ciphers.MODE_CTR, iv)
while True:
buf = outfile.read(16)
if len(buf) == 0:
break
while (len(buf) % 16) != 0:
buf += struct.pack('B', HDR_PADDING)
enc_outfile.write(aesctr.encrypt(buf))
elif aes256:
key = ekeyfile.read(32)
iv = ekeyfile.read(16)
aesctr = ciphers.Aes(key, ciphers.MODE_CTR, iv)
while True:
buf = outfile.read(16)
if len(buf) == 0:
break
while (len(buf) % 16) != 0:
buf += struct.pack('B', HDR_PADDING)
enc_outfile.write(aesctr.encrypt(buf))
outfile.close()
ekeyfile.close()
enc_outfile.close()

View File

@ -68,7 +68,6 @@
#define HAVE_CHACHA
/* Disables */
#define NO_AES
#define NO_CMAC
#define NO_HMAC
#define NO_RC4

View File

@ -4,6 +4,18 @@ test-enc-update:SIGN_ENC_ARGS?=--ecc256 --encrypt /tmp/enc_key.der
test-enc-update:USBTTY?=/dev/ttyACM0
test-enc-update:TIMEOUT?=60
test-enc-aes128-update:ENC_TEST_UPDATE_VERSION?=2
test-enc-aes128-update:SIGN_ARGS?=--ecc256
test-enc-aes128-update:SIGN_ENC_ARGS?=--ecc256 --aes128 --encrypt /tmp/enc_key.der
test-enc-aes128-update:USBTTY?=/dev/ttyACM0
test-enc-aes128-update:TIMEOUT?=60
test-enc-aes256-update:ENC_TEST_UPDATE_VERSION?=2
test-enc-aes256-update:SIGN_ARGS?=--ecc256
test-enc-aes256-update:SIGN_ENC_ARGS?=--ecc256 --aes256 --encrypt /tmp/enc_key.der
test-enc-aes256-update:USBTTY?=/dev/ttyACM0
test-enc-aes256-update:TIMEOUT?=60
tools/uart-flash-server/ufserver: FORCE
@make -C `dirname $@`
@rm -f src/libwolfboot.o
@ -32,3 +44,48 @@ test-enc-update: factory.bin test-app/image.bin tools/uart-flash-server/ufserver
@rm boot.bin boot_full.bin
@echo "TEST SUCCESSFUL"
test-enc-aes128-update: factory.bin test-app/image.bin tools/uart-flash-server/ufserver
@diff .config config/examples/stm32wb-uart-flash-encryption-aes128.config || (echo "\n\n*** Error: please copy config/examples/stm32wb-uart-flash-encryption-aes128.config to .config to run this test\n\n" && exit 1)
@printf "0123456789abcdef0123456789abcdef" > /tmp/enc_key.der
@$(SIGN_TOOL) $(SIGN_ARGS) test-app/image.bin $(PRIVATE_KEY) $(ENC_TEST_UPDATE_VERSION)
@$(SIGN_TOOL) $(SIGN_ENC_ARGS) test-app/image.bin $(PRIVATE_KEY) $(ENC_TEST_UPDATE_VERSION)
@(tools/uart-flash-server/ufserver test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed_and_encrypted.bin $(USBTTY))&
@st-flash erase
@st-flash write factory.bin 0x08000000
@sleep 3
@sync
@st-flash reset
@sync
@sleep $(TIMEOUT)
@st-flash reset
@sleep 3
@killall ufserver
@st-flash read boot_full.bin 0x08010000 0x8000
@SIZE=`wc -c test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin | cut -d" " -f 1`; \
dd if=boot_full.bin of=boot.bin bs=1 count=$$SIZE
@diff boot.bin test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin || (echo "TEST FAILED" && exit 1)
@rm boot.bin boot_full.bin
@echo "TEST SUCCESSFUL"
test-enc-aes256-update: factory.bin test-app/image.bin tools/uart-flash-server/ufserver
@diff .config config/examples/stm32wb-uart-flash-encryption-aes256.config || (echo "\n\n*** Error: please copy config/examples/stm32wb-uart-flash-encryption-aes256.config to .config to run this test\n\n" && exit 1)
@printf "0123456789abcdef0123456789abcdef0123456789abcdef" > /tmp/enc_key.der
@$(SIGN_TOOL) $(SIGN_ARGS) test-app/image.bin $(PRIVATE_KEY) $(ENC_TEST_UPDATE_VERSION)
@$(SIGN_TOOL) $(SIGN_ENC_ARGS) test-app/image.bin $(PRIVATE_KEY) $(ENC_TEST_UPDATE_VERSION)
@(tools/uart-flash-server/ufserver test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed_and_encrypted.bin $(USBTTY))&
@st-flash erase
@st-flash write factory.bin 0x08000000
@sleep 3
@sync
@st-flash reset
@sync
@sleep $(TIMEOUT)
@st-flash reset
@sleep 3
@killall ufserver
@st-flash read boot_full.bin 0x08010000 0x8000
@SIZE=`wc -c test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin | cut -d" " -f 1`; \
dd if=boot_full.bin of=boot.bin bs=1 count=$$SIZE
@diff boot.bin test-app/image_v$(ENC_TEST_UPDATE_VERSION)_signed.bin || (echo "TEST FAILED" && exit 1)
@rm boot.bin boot_full.bin
@echo "TEST SUCCESSFUL"