diff --git a/config/examples/stm32wb-uart-flash-encryption-aes128.config b/config/examples/stm32wb-uart-flash-encryption-aes128.config new file mode 100644 index 00000000..4c9733ea --- /dev/null +++ b/config/examples/stm32wb-uart-flash-encryption-aes128.config @@ -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 diff --git a/config/examples/stm32wb-uart-flash-encryption-aes256.config b/config/examples/stm32wb-uart-flash-encryption-aes256.config new file mode 100644 index 00000000..ec2676c8 --- /dev/null +++ b/config/examples/stm32wb-uart-flash-encryption-aes256.config @@ -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 diff --git a/config/examples/stm32wb-uart-flash-encryption.config b/config/examples/stm32wb-uart-flash-encryption.config index bef5700f..4b130939 100644 --- a/config/examples/stm32wb-uart-flash-encryption.config +++ b/config/examples/stm32wb-uart-flash-encryption.config @@ -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 diff --git a/docs/encrypted_partitions.md b/docs/encrypted_partitions.md index 33718e1b..0be3d5bc 100644 --- a/docs/encrypted_partitions.md +++ b/docs/encrypted_partitions.md @@ -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 diff --git a/include/encrypt.h b/include/encrypt.h index 97f97075..0ce389cc 100644 --- a/include/encrypt.h +++ b/include/encrypt.h @@ -31,9 +31,37 @@ #include "target.h" #include "wolfboot/wolfboot.h" +#ifdef ENCRYPT_WITH_CHACHA #include +#else +#include +#endif + #include +#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); diff --git a/include/user_settings.h b/include/user_settings.h index 3ffa0c3c..6673250d 100644 --- a/include/user_settings.h +++ b/include/user_settings.h @@ -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 -# define NO_AES +# if !defined(ENCRYPT_WITH_AES128) && !defined(ENCRYPT_WITH_AES256) +# define NO_AES +# endif # define NO_HMAC #endif diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index 3d781184..5f7f487d 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -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 */ diff --git a/options.mk b/options.mk index 164f573f..652c5ea8 100644 --- a/options.mk +++ b/options.mk @@ -178,7 +178,19 @@ endif ifeq ($(ENCRYPT),1) CFLAGS+=-D"EXT_ENCRYPTED=1" - WOLFCRYPT_OBJS+=./lib/wolfssl/wolfcrypt/src/chacha.o + 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) diff --git a/src/libwolfboot.c b/src/libwolfboot.c index f0812627..adf7c35b 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -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 + +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; diff --git a/src/update_flash.c b/src/update_flash.c index 20fddf0f..952524b2 100644 --- a/src/update_flash.c +++ b/src/update_flash.c @@ -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; } diff --git a/test-app/app_stm32wb.c b/test-app/app_stm32wb.c index 753a8692..0772cd38 100644 --- a/test-app/app_stm32wb.c +++ b/test-app/app_stm32wb.c @@ -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) { diff --git a/tools/config.mk b/tools/config.mk index b8bc11f0..0de0e4fe 100644 --- a/tools/config.mk +++ b/tools/config.mk @@ -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 diff --git a/tools/keytools/Makefile b/tools/keytools/Makefile index b1c510e9..fcbe0813 100644 --- a/tools/keytools/Makefile +++ b/tools/keytools/Makefile @@ -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 \ diff --git a/tools/keytools/sign.c b/tools/keytools/sign.c index 416a4cad..713f2f56 100755 --- a/tools/keytools/sign.c +++ b/tools/keytools/sign.c @@ -56,11 +56,13 @@ #include #include +#include #ifdef HAVE_CHACHA #include #endif + #ifndef NO_RSA #include #endif @@ -86,7 +88,7 @@ #endif #if defined(_WIN32) && !defined(PATH_MAX) - #define PATH_MAX 256 + #define PATH_MAX 256 #endif #ifndef IMAGE_HEADER_SIZE @@ -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,16 +768,40 @@ 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 */ - wc_Chacha_SetKey(&cha, key, sizeof(key)); - 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; + 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_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); } - wc_Chacha_SetIV(&cha, iv, (pos >> 4)); - wc_Chacha_Process(&cha, enc_buf, buf, fread_retval); - fwrite(enc_buf, 1, fread_retval, fef); } fclose(fef); } @@ -757,7 +809,6 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz, cons 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; } diff --git a/tools/keytools/sign.py b/tools/keytools/sign.py index 62f65ce4..43af5f33 100755 --- a/tools/keytools/sign.py +++ b/tools/keytools/sign.py @@ -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') - 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) - buf = outfile.read(16) - if len(buf) == 0: - break - enc_outfile.write(cha.encrypt(buf)) - off += 1 + if chacha: + key = ekeyfile.read(32) + iv_nonce = ekeyfile.read(12) + cha = ciphers.ChaCha(key, 32) + cha.set_iv(iv_nonce, 0) + while True: + buf = outfile.read(16) + if len(buf) == 0: + break + enc_outfile.write(cha.encrypt(buf)) + 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() diff --git a/tools/keytools/user_settings.h b/tools/keytools/user_settings.h index 7d73512d..921dc1b8 100755 --- a/tools/keytools/user_settings.h +++ b/tools/keytools/user_settings.h @@ -68,7 +68,6 @@ #define HAVE_CHACHA /* Disables */ -#define NO_AES #define NO_CMAC #define NO_HMAC #define NO_RC4 diff --git a/tools/test-enc.mk b/tools/test-enc.mk index 5b737c67..9af90240 100644 --- a/tools/test-enc.mk +++ b/tools/test-enc.mk @@ -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"