Implement new swap scheme for devices with large erase size using scratch with status area
diff --git a/boot/bootutil/src/encrypted.c b/boot/bootutil/src/encrypted.c
index d14855b..12c0a9c 100644
--- a/boot/bootutil/src/encrypted.c
+++ b/boot/bootutil/src/encrypted.c
@@ -297,15 +297,16 @@
* @param ikm_len Length of the input data.
* @param info An information tag.
* @param info_len Length of the information tag.
+ * @param salt An salt tag.
+ * @param salt_len Length of the salt tag.
* @param okm Output of the KDF computation.
* @param okm_len On input the requested length; on output the generated length
*/
static int
-hkdf(uint8_t *ikm, uint16_t ikm_len, uint8_t *info, uint16_t info_len,
- uint8_t *okm, uint16_t *okm_len)
+hkdf(const uint8_t *ikm, uint16_t ikm_len, const uint8_t *info, uint16_t info_len,
+ const uint8_t *salt, uint16_t salt_len, uint8_t *okm, uint16_t *okm_len)
{
bootutil_hmac_sha256_context hmac;
- uint8_t salt[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t prk[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t T[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint16_t off;
@@ -324,8 +325,7 @@
bootutil_hmac_sha256_init(&hmac);
- memset(salt, 0, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
- rc = bootutil_hmac_sha256_set_key(&hmac, salt, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
+ rc = bootutil_hmac_sha256_set_key(&hmac, salt, salt_len);
if (rc != 0) {
goto error;
}
@@ -429,21 +429,25 @@
return 0;
}
-#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE
+#define EXPECTED_ENC_LEN BOOT_ENC_TLV_SIZE
#if defined(MCUBOOT_ENCRYPT_RSA)
-# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048
+# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048
+# define EXPECTED_ENC_EXT_LEN EXPECTED_ENC_TLV
#elif defined(MCUBOOT_ENCRYPT_KW)
-# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW128
+# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW128
+# define EXPECTED_ENC_EXT_LEN EXPECTED_ENC_TLV
#elif defined(MCUBOOT_ENCRYPT_EC256)
-# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256
+# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256
+# define EXPECTED_ENC_EXT_LEN (EXPECTED_ENC_LEN + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)
# define EC_PUBK_INDEX (0)
# define EC_TAG_INDEX (65)
# define EC_CIPHERKEY_INDEX (65 + 32)
_Static_assert(EC_CIPHERKEY_INDEX + 16 == EXPECTED_ENC_LEN,
"Please fix ECIES-P256 component indexes");
#elif defined(MCUBOOT_ENCRYPT_X25519)
-# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519
+# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519
+# define EXPECTED_ENC_EXT_LEN EXPECTED_ENC_TLV
# define EC_PUBK_INDEX (0)
# define EC_TAG_INDEX (32)
# define EC_CIPHERKEY_INDEX (32 + 32)
@@ -451,14 +455,19 @@
"Please fix ECIES-X25519 component indexes");
#endif
+#ifndef EXPECTED_ENC_EXT_LEN
+#define EXPECTED_ENC_EXT_LEN EXPECTED_ENC_LEN
+#endif
+
/*
* Decrypt an encryption key TLV.
*
- * @param buf An encryption TLV read from flash (build time fixed length)
+ * @param buf An encryption TLV buffer red from flash
+ * @param sz An encryption TLV buffer data size
* @param enckey An AES-128 key sized buffer to store to plain key.
*/
int
-boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey)
+boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey, uint32_t sz, uint8_t *enciv)
{
#if defined(MCUBOOT_ENCRYPT_RSA)
mbedtls_rsa_context rsa;
@@ -475,14 +484,22 @@
#if defined(MCUBOOT_ENCRYPT_EC256) || defined(MCUBOOT_ENCRYPT_X25519)
bootutil_hmac_sha256_context hmac;
bootutil_aes_ctr_context aes_ctr;
+ uint8_t salt[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t tag[BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
uint8_t shared[SHARED_KEY_LEN];
- uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
+ uint8_t derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE + BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE * 2];
uint8_t *cp;
uint8_t *cpend;
uint8_t private_key[PRIV_KEY_LEN];
uint8_t counter[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
uint16_t len;
+ uint16_t out_len;
+ const uint8_t *my_salt = salt;
+ uint8_t *my_key_iv = counter;
+ uint8_t *my_counter = counter;
+#else
+ (void)sz;
+ (void)enciv;
#endif
int rc = -1;
@@ -532,6 +549,7 @@
bootutil_ecdh_p256_init(&ecdh_p256);
rc = bootutil_ecdh_p256_shared_secret(&ecdh_p256, &buf[EC_PUBK_INDEX], private_key, shared);
+
bootutil_ecdh_p256_drop(&ecdh_p256);
if (rc != 0) {
return -1;
@@ -573,10 +591,31 @@
* Expand shared secret to create keys for AES-128-CTR + HMAC-SHA256
*/
+ /* Prepare for default encryption scheme with zero salt and AES IVs */
+ memset(counter, 0, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
+ memset(salt, 0, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
+
len = BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE;
- rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", 16,
- derived_key, &len);
- if (rc != 0 || len != (BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE + BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE)) {
+
+ if (sz > EXPECTED_ENC_LEN) {
+ /* Use new enhanced encryption scheme with randomly generated salt and AES IVs */
+ len += BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE * 2;
+
+ my_salt = &buf[EXPECTED_ENC_LEN];
+
+ my_key_iv = &derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE +
+ BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE];
+
+ my_counter = &derived_key[BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE +
+ BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE +
+ BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE];
+ }
+
+ out_len = len;
+ rc = hkdf(shared, SHARED_KEY_LEN, (uint8_t *)"MCUBoot_ECIES_v1", BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE,
+ my_salt, BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE, derived_key, &out_len);
+
+ if (rc != 0 || len != out_len) {
return -1;
}
@@ -586,13 +625,13 @@
bootutil_hmac_sha256_init(&hmac);
- rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[16], 32);
+ rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE], BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE);
if (rc != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
- rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], 16);
+ rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
if (rc != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
@@ -605,22 +644,20 @@
return -1;
}
- if (bootutil_constant_time_compare(tag, &buf[EC_TAG_INDEX], 32) != 0) {
+ if (bootutil_constant_time_compare(tag, &buf[EC_TAG_INDEX], BOOTUTIL_CRYPTO_SHA256_DIGEST_SIZE) != 0) {
(void)bootutil_hmac_sha256_drop(&hmac);
return -1;
}
bootutil_hmac_sha256_drop(&hmac);
+ (void)memcpy(enciv, my_counter, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
+
/*
* Finally decrypt the received ciphered key
*/
bootutil_aes_ctr_init(&aes_ctr);
- if (rc != 0) {
- bootutil_aes_ctr_drop(&aes_ctr);
- return -1;
- }
rc = bootutil_aes_ctr_set_key(&aes_ctr, derived_key);
if (rc != 0) {
@@ -628,8 +665,7 @@
return -1;
}
- memset(counter, 0, BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE);
- rc = bootutil_aes_ctr_decrypt(&aes_ctr, counter, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, 0, enckey);
+ rc = bootutil_aes_ctr_decrypt(&aes_ctr, my_key_iv, &buf[EC_CIPHERKEY_INDEX], BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE, 0, enckey);
if (rc != 0) {
bootutil_aes_ctr_drop(&aes_ctr);
return -1;
@@ -658,7 +694,7 @@
#if MCUBOOT_SWAP_SAVE_ENCTLV
uint8_t *buf;
#else
- uint8_t buf[EXPECTED_ENC_LEN];
+ uint8_t buf[EXPECTED_ENC_EXT_LEN];
#endif
uint8_t slot;
int rc;
@@ -687,7 +723,7 @@
return rc;
}
- if (len != EXPECTED_ENC_LEN) {
+ if ((len < EXPECTED_ENC_LEN) || (len > EXPECTED_ENC_EXT_LEN)) {
return -1;
}
@@ -696,12 +732,12 @@
memset(buf, 0xff, BOOT_ENC_TLV_ALIGN_SIZE);
#endif
- rc = flash_area_read(fap, off, buf, EXPECTED_ENC_LEN);
+ rc = flash_area_read(fap, off, buf, len);
if (rc) {
return -1;
}
- return boot_enc_decrypt(buf, bs->enckey[slot]);
+ return (boot_enc_decrypt(buf, bs->enckey[slot], len, enc_state[slot].aes_iv));
}
bool
@@ -726,7 +762,7 @@
uint32_t blk_off, uint8_t *buf)
{
struct enc_key_data *enc;
- uint8_t nonce[16];
+ uint8_t *nonce;
int rc;
/* boot_copy_region will call boot_encrypt with sz = 0 when skipping over
@@ -735,13 +771,6 @@
return;
}
- memset(nonce, 0, 12);
- off >>= 4;
- nonce[12] = (uint8_t)(off >> 24);
- nonce[13] = (uint8_t)(off >> 16);
- nonce[14] = (uint8_t)(off >> 8);
- nonce[15] = (uint8_t)off;
-
rc = flash_area_id_to_multi_image_slot(image_index, fap->fa_id);
if (rc < 0) {
assert(0);
@@ -750,6 +779,15 @@
enc = &enc_state[rc];
assert(enc->valid == 1);
+
+ nonce = enc->aes_iv;
+
+ off >>= 4;
+ nonce[12] = (uint8_t)(off >> 24);
+ nonce[13] = (uint8_t)(off >> 16);
+ nonce[14] = (uint8_t)(off >> 8);
+ nonce[15] = (uint8_t)off;
+
bootutil_aes_ctr_encrypt(&enc->aes_ctr, nonce, buf, sz, blk_off, buf);
}