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);
 }