Skip to content

Commit 18cbea5

Browse files
committed
Refactoring of IV handling to prevent reusing IVs
During fallback operations, use a different encryption IV than the one used to encrypt the backup during the update. This ensures that the same IV is never reused to encrypt different sectors.
1 parent 68d28fc commit 18cbea5

File tree

4 files changed

+149
-42
lines changed

4 files changed

+149
-42
lines changed

include/encrypt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,10 @@ void aes_set_iv(uint8_t *nonce, uint32_t address);
6969
int ext_flash_encrypt_write(uintptr_t address, const uint8_t *data, int len);
7070
int ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len);
7171

72+
#ifdef EXT_ENCRYPTED
73+
int wolfBoot_enable_fallback_iv(int enable);
74+
void wolfBoot_crypto_set_iv(const uint8_t *nonce, uint32_t iv_counter);
75+
#endif
76+
7277
#endif /* __WOLFBOOT || UNIT_TEST */
7378
#endif /* ENCRYPT_H_INCLUDED */

include/wolfboot/wolfboot.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,7 @@ int wolfBoot_get_partition_state(uint8_t part, uint8_t *st);
381381

382382
#ifdef EXT_ENCRYPTED
383383
/* Encryption support */
384+
384385
#if defined(ENCRYPT_WITH_CHACHA)
385386
#define ENCRYPT_BLOCK_SIZE 64
386387
#define ENCRYPT_KEY_SIZE 32 /* Chacha20 - 256bit */

src/libwolfboot.c

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,23 @@
6262

6363
#include <stddef.h> /* for size_t */
6464

65-
#if defined(EXT_ENCRYPTED)
65+
#if defined(EXT_ENCRYPTED) && (defined(__WOLFBOOT) || defined(UNIT_TEST))
66+
#include "encrypt.h"
6667
static int encrypt_initialized = 0;
6768

6869
static uint8_t encrypt_iv_nonce[ENCRYPT_NONCE_SIZE] XALIGNED(4);
69-
#if defined(__WOLFBOOT)
70-
#include "encrypt.h"
71-
#elif !defined(XMEMSET)
70+
static uint32_t encrypt_iv_offset = 0;
71+
72+
#define FALLBACK_IV_OFFSET 0x00100000U
73+
#if !defined(XMEMSET)
7274
#include <string.h>
7375
#define XMEMSET memset
7476
#define XMEMCPY memcpy
7577
#define XMEMCMP memcmp
7678
#endif
79+
#if defined(ENCRYPT_WITH_AES128) || defined(ENCRYPT_WITH_AES256)
80+
extern void aes_set_iv(uint8_t *nonce, uint32_t address);
81+
#endif
7782

7883
#if defined (__WOLFBOOT) || defined (UNIT_TEST)
7984
int wolfBoot_initialize_encryption(void)
@@ -1027,7 +1032,7 @@ static int decrypt_header(uint8_t *src)
10271032
uint32_t magic;
10281033
uint32_t len;
10291034
for (i = 0; i < IMAGE_HEADER_SIZE; i+=ENCRYPT_BLOCK_SIZE) {
1030-
crypto_set_iv(encrypt_iv_nonce, i / ENCRYPT_BLOCK_SIZE);
1035+
wolfBoot_crypto_set_iv(encrypt_iv_nonce, i / ENCRYPT_BLOCK_SIZE);
10311036
crypto_decrypt(dec_hdr + i, src + i, ENCRYPT_BLOCK_SIZE);
10321037
}
10331038
magic = *((uint32_t*)(dec_hdr));
@@ -1359,6 +1364,7 @@ int wolfBoot_fallback_is_possible(void)
13591364

13601365
#ifdef EXT_ENCRYPTED
13611366
#include "encrypt.h"
1367+
#include "string.h"
13621368

13631369
#if defined(WOLFBOOT_RENESAS_TSIP)
13641370
#include "wolfssl/wolfcrypt/port/Renesas/renesas-tsip-crypt.h"
@@ -1388,6 +1394,39 @@ int wolfBoot_fallback_is_possible(void)
13881394
static uint8_t ENCRYPT_KEY[ENCRYPT_KEY_SIZE + ENCRYPT_NONCE_SIZE];
13891395
#endif
13901396

1397+
#if defined(EXT_ENCRYPTED) && defined(__WOLFBOOT)
1398+
int RAMFUNCTION wolfBoot_enable_fallback_iv(int enable)
1399+
{
1400+
int prev = 0;
1401+
if (encrypt_iv_offset != 0)
1402+
prev = 1;
1403+
1404+
if (enable)
1405+
encrypt_iv_offset = FALLBACK_IV_OFFSET;
1406+
else
1407+
encrypt_iv_offset = 0;
1408+
1409+
return prev;
1410+
}
1411+
1412+
void RAMFUNCTION wolfBoot_crypto_set_iv(const uint8_t *nonce, uint32_t iv_counter)
1413+
{
1414+
#if defined(ENCRYPT_WITH_CHACHA)
1415+
crypto_set_iv((uint8_t *)nonce, iv_counter + encrypt_iv_offset);
1416+
#elif defined(ENCRYPT_WITH_AES128) || defined(ENCRYPT_WITH_AES256)
1417+
uint8_t local_nonce[ENCRYPT_NONCE_SIZE];
1418+
XMEMCPY(local_nonce, nonce, ENCRYPT_NONCE_SIZE);
1419+
crypto_set_iv(local_nonce, iv_counter + encrypt_iv_offset);
1420+
#else
1421+
(void)nonce;
1422+
(void)iv_counter;
1423+
#endif
1424+
1425+
/* Fallback IV offset is single-use; clear it once applied. */
1426+
encrypt_iv_offset = 0;
1427+
}
1428+
#endif /* EXT_ENCRYPTED && __WOLFBOOT */
1429+
13911430
static int RAMFUNCTION hal_set_key(const uint8_t *k, const uint8_t *nonce)
13921431
{
13931432
#ifdef WOLFBOOT_RENESAS_TSIP
@@ -1808,8 +1847,7 @@ int RAMFUNCTION ext_flash_encrypt_write(uintptr_t address, const uint8_t *data,
18081847
}
18091848
if (wolfBoot_initialize_encryption() < 0)
18101849
return -1;
1811-
1812-
crypto_set_iv(encrypt_iv_nonce, iv_counter);
1850+
wolfBoot_crypto_set_iv(encrypt_iv_nonce, iv_counter);
18131851
break;
18141852
case PART_SWAP:
18151853
/* data is coming from update and is already encrypted */
@@ -1892,7 +1930,7 @@ int RAMFUNCTION ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len
18921930
return -1;
18931931
}
18941932
}
1895-
crypto_set_iv(encrypt_iv_nonce, iv_counter);
1933+
wolfBoot_crypto_set_iv(encrypt_iv_nonce, iv_counter);
18961934
break;
18971935
case PART_SWAP:
18981936
break;
@@ -1988,7 +2026,7 @@ int wolfBoot_ram_decrypt(uint8_t *src, uint8_t *dst)
19882026

19892027
/* decrypt content */
19902028
while (dst_offset < (len + IMAGE_HEADER_SIZE)) {
1991-
crypto_set_iv(encrypt_iv_nonce, iv_counter);
2029+
wolfBoot_crypto_set_iv(encrypt_iv_nonce, iv_counter);
19922030
crypto_decrypt(dec_block, row_address, ENCRYPT_BLOCK_SIZE);
19932031
XMEMCPY(dst + dst_offset, dec_block, ENCRYPT_BLOCK_SIZE);
19942032
row_address += ENCRYPT_BLOCK_SIZE;
@@ -2035,4 +2073,3 @@ int wolfBoot_nsc_write_update(uint32_t address, const uint8_t *buf, uint32_t len
20352073
}
20362074

20372075
#endif
2038-

src/update_flash.c

Lines changed: 96 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@
3939
int WP11_Library_Init(void);
4040
#endif
4141

42+
#ifdef EXT_ENCRYPTED
43+
#include "encrypt.h"
44+
#endif /* EXT_ENCRYPTED */
45+
4246
#ifdef RAM_CODE
4347
#ifndef TARGET_rp2350
4448
extern unsigned int _start_text;
@@ -55,9 +59,6 @@ static uint8_t buffer[FLASHBUFFER_SIZE] XALIGNED(4);
5559
# endif
5660
#endif
5761

58-
#ifdef EXT_ENCRYPTED
59-
#include "encrypt.h"
60-
#endif
6162

6263
static void RAMFUNCTION wolfBoot_erase_bootloader(void)
6364
{
@@ -136,6 +137,7 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
136137
uint32_t src_sector_offset = (sector * WOLFBOOT_SECTOR_SIZE);
137138
uint32_t dst_sector_offset = src_sector_offset;
138139
#ifdef EXT_ENCRYPTED
140+
uint32_t i;
139141
uint8_t key[ENCRYPT_KEY_SIZE];
140142
uint8_t nonce[ENCRYPT_NONCE_SIZE];
141143
uint32_t iv_counter;
@@ -153,19 +155,21 @@ static int RAMFUNCTION wolfBoot_copy_sector(struct wolfBoot_image *src,
153155
dst_sector_offset = 0;
154156

155157
#ifdef EXT_ENCRYPTED
156-
if (wolfBoot_initialize_encryption() < 0) {
158+
if (wolfBoot_initialize_encryption() < 0)
157159
return -1;
158-
}
159-
wolfBoot_get_encrypt_key(key, nonce);
160160

161+
wolfBoot_get_encrypt_key(key, nonce);
161162
if (src->part == PART_SWAP)
162163
iv_counter = dst_sector_offset;
163164
else
165+
/*
166+
* Always re-derive the IV starting from the source address.
167+
* This guarantees we do not reuse the same IV in the SWAP partition.
168+
*/
164169
iv_counter = src_sector_offset;
165-
166170
iv_counter /= ENCRYPT_BLOCK_SIZE;
167-
crypto_set_iv(nonce, iv_counter);
168-
#endif
171+
wolfBoot_crypto_set_iv(nonce, iv_counter);
172+
#endif /* EXT_ENCRYPTED */
169173

170174
#ifdef EXT_FLASH
171175
if (PART_IS_EXT(src)) {
@@ -222,7 +226,6 @@ static int RAMFUNCTION wolfBoot_backup_last_boot_sector(uint32_t sector)
222226
wolfBoot_open_image(src, PART_BOOT);
223227
wolfBoot_open_image(dst, PART_SWAP);
224228

225-
226229
wolfBoot_printf("Copy sector %d (part %d->%d)\n",
227230
sector, src->part, dst->part);
228231

@@ -234,7 +237,12 @@ static int RAMFUNCTION wolfBoot_backup_last_boot_sector(uint32_t sector)
234237
iv_counter /= ENCRYPT_BLOCK_SIZE;
235238
if (wolfBoot_initialize_encryption() < 0)
236239
return -1;
237-
crypto_set_iv(nonce, iv_counter);
240+
/*
241+
* Preserve the IV sequence used by the source sector so that the staging
242+
* copy in SWAP can be decrypted with exactly the same keystream when it is
243+
* restored to BOOT.
244+
*/
245+
wolfBoot_crypto_set_iv(nonce, iv_counter);
238246

239247
/* Erase swap space */
240248
wb_flash_erase(dst, dst_sector_offset, WOLFBOOT_SECTOR_SIZE);
@@ -523,7 +531,7 @@ static int wolfBoot_delta_update(struct wolfBoot_image *boot,
523531
}
524532
iv_counter /= ENCRYPT_BLOCK_SIZE;
525533
/* Encrypt + send */
526-
crypto_set_iv(nonce, iv_counter);
534+
wolfBoot_crypto_set_iv(nonce, iv_counter);
527535
crypto_encrypt(enc_blk, delta_blk, ret);
528536
wr_ret = ext_flash_write(
529537
(uint32_t)(WOLFBOOT_PARTITION_SWAP_ADDRESS + len),
@@ -659,26 +667,54 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
659667
uint16_t update_type;
660668
uint32_t fw_size;
661669
uint32_t size;
670+
int inverse = 0;
671+
int fallback_image = 0;
662672
#if defined(DISABLE_BACKUP) && defined(EXT_ENCRYPTED)
663673
uint8_t key[ENCRYPT_KEY_SIZE];
664674
uint8_t nonce[ENCRYPT_NONCE_SIZE];
665675
#endif
666676
#ifdef DELTA_UPDATES
667677
uint8_t st;
668-
int inverse = 0;
669678
int resume = 0;
670679
int stateRet = -1;
671-
uint32_t cur_v;
672-
uint32_t up_v;
673680
#endif
674681
uint32_t cur_ver, upd_ver;
675682

676683
wolfBoot_printf("Staring Update (fallback allowed %d)\n", fallback_allowed);
677684

678685
/* No Safety check on open: we might be in the middle of a broken update */
679-
wolfBoot_open_image(&update, PART_UPDATE);
680-
wolfBoot_open_image(&boot, PART_BOOT);
681-
wolfBoot_open_image(&swap, PART_SWAP);
686+
{
687+
int update_open;
688+
#ifdef EXT_ENCRYPTED
689+
/* Start with the standard IV mapping for every fresh update attempt. */
690+
wolfBoot_enable_fallback_iv(0);
691+
#endif
692+
update_open = wolfBoot_open_image(&update, PART_UPDATE);
693+
#ifdef EXT_ENCRYPTED
694+
if (update_open < 0) {
695+
int prev = wolfBoot_enable_fallback_iv(1);
696+
(void)prev;
697+
update_open = wolfBoot_open_image(&update, PART_UPDATE);
698+
if (update_open < 0) {
699+
wolfBoot_enable_fallback_iv(0);
700+
return -1;
701+
}
702+
fallback_image = 1;
703+
}
704+
wolfBoot_enable_fallback_iv(fallback_image);
705+
#else
706+
if (update_open < 0)
707+
return -1;
708+
#endif
709+
wolfBoot_open_image(&boot, PART_BOOT);
710+
wolfBoot_open_image(&swap, PART_SWAP);
711+
712+
#ifdef EXT_ENCRYPTED
713+
wolfBoot_printf("Update partition fallback image: %d\n", fallback_image);
714+
if (fallback_image)
715+
inverse = 1;
716+
#endif
717+
}
682718

683719
/* get total size */
684720
total_size = wolfBoot_get_total_size(&boot, &update);
@@ -705,12 +741,23 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
705741
wolfBoot_printf("Invalid update size %u\n", update.fw_size);
706742
return -1;
707743
}
708-
if (!update.hdr_ok
709-
|| (wolfBoot_verify_integrity(&update) < 0)
710-
|| (wolfBoot_verify_authenticity(&update) < 0)) {
711-
wolfBoot_printf("Update verify failed: Hdr %d, Hash %d, Sig %d\n",
712-
update.hdr_ok, update.sha_ok, update.signature_ok);
713-
return -1;
744+
if (!fallback_image) {
745+
if (!update.hdr_ok
746+
|| (wolfBoot_verify_integrity(&update) < 0)
747+
|| (wolfBoot_verify_authenticity(&update) < 0)) {
748+
wolfBoot_printf("Update verify failed: Hdr %d, Hash %d, Sig %d\n",
749+
update.hdr_ok, update.sha_ok, update.signature_ok);
750+
return -1;
751+
}
752+
} else {
753+
/*
754+
* When we recover an already-encrypted fallback image, the
755+
* manifest still contains hashes computed with the original IV
756+
* stream. Skip the redundant integrity/authenticity checks here
757+
* and let the bootloader verify the restored image after the swap.
758+
*/
759+
update.sha_ok = 1;
760+
update.signature_ok = 1;
714761
}
715762
PART_SANITY_CHECK(&update);
716763

@@ -731,12 +778,11 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
731778
}
732779
#endif
733780
}
781+
if (cur_ver > upd_ver)
782+
inverse = 1;
734783

735784
#ifdef DELTA_UPDATES
736785
if ((update_type & 0x00F0) == HDR_IMG_TYPE_DIFF) {
737-
cur_v = wolfBoot_current_firmware_version();
738-
up_v = wolfBoot_update_firmware_version();
739-
inverse = cur_v >= up_v;
740786
/* if magic isn't set stateRet will be -1 but that means we're on a
741787
* fresh partition and aren't resuming */
742788
stateRet = wolfBoot_get_partition_state(PART_UPDATE, &st);
@@ -745,7 +791,7 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
745791
* header we can't determine the direction by version numbers. instead
746792
* use the update partition state, updating means regular, new means
747793
* reverting */
748-
if ((stateRet == 0) && ((flag != SECT_FLAG_NEW) || (cur_v == 0))) {
794+
if ((stateRet == 0) && ((flag != SECT_FLAG_NEW) || (cur_ver == 0))) {
749795
resume = 1;
750796
if (st == IMG_STATE_UPDATING) {
751797
inverse = 0;
@@ -780,7 +826,6 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
780826
#ifdef EXT_FLASH
781827
ext_flash_unlock();
782828
#endif
783-
784829
/* Interruptible swap
785830
* The status is saved in the sector flags of the update partition.
786831
* If something goes wrong, the operation will be resumed upon reboot.
@@ -800,7 +845,22 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
800845
if (size > sector_size)
801846
size = sector_size;
802847
flag = SECT_FLAG_BACKUP;
803-
wolfBoot_copy_sector(&boot, &update, sector);
848+
{
849+
#ifdef EXT_ENCRYPTED
850+
/*
851+
* When we are performing a fallback, force the alternate
852+
* IV offset only for the segment copied from BOOT into
853+
* UPDATE. All other copies see the offset that was
854+
* active beforehand (0 for the normal path, fallback
855+
* offset for the recovery path).
856+
*/
857+
int prev_iv = wolfBoot_enable_fallback_iv(1);
858+
#endif
859+
wolfBoot_copy_sector(&boot, &update, sector);
860+
#ifdef EXT_ENCRYPTED
861+
wolfBoot_enable_fallback_iv(prev_iv);
862+
#endif
863+
}
804864
if (((sector + 1) * sector_size) < WOLFBOOT_PARTITION_SIZE)
805865
wolfBoot_set_update_sector_flag(sector, flag);
806866
/* FALL THROUGH */
@@ -945,10 +1005,14 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
9451005
hal_flash_lock();
9461006

9471007
/* Save the encryption key after swapping */
948-
#ifdef EXT_ENCRYPTED
1008+
#ifdef EXT_ENCRYPTED
9491009
wolfBoot_set_encrypt_key(key, nonce);
950-
#endif
1010+
#endif
9511011
#endif /* DISABLE_BACKUP */
1012+
#ifdef EXT_ENCRYPTED
1013+
/* Make sure we leave the global IV offset in its normal state. */
1014+
wolfBoot_enable_fallback_iv(0);
1015+
#endif
9521016
return 0;
9531017
}
9541018

0 commit comments

Comments
 (0)