Add encrypted image support on sim

This adds new cargo features to allow running tests of encrypted
images with both RSA-OAEP and AES-128-KW.

When installing images on the simulated flash, both a plain and an
encrypted images are created. When encrypted image support is enabled,
verification of images in slot1 match against the encrypted image,
otherwise plain images are used.

PS: Also fixes ImageHeader to match bootutil definition.

Signed-off-by: Fabio Utzig <utzig@apache.org>
diff --git a/sim/Cargo.lock b/sim/Cargo.lock
index 8fa80f2..066f925 100644
--- a/sim/Cargo.lock
+++ b/sim/Cargo.lock
@@ -1,4 +1,35 @@
 [[package]]
+name = "aes-ctr"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "aes-soft"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "aesni"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "aho-corasick"
 version = "0.6.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -39,14 +70,33 @@
 ]
 
 [[package]]
+name = "base64"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "bitflags"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "block-cipher-trait"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "bootsim"
 version = "0.1.0"
 dependencies = [
+ "aes-ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -63,6 +113,11 @@
 ]
 
 [[package]]
+name = "byte-tools"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "byteorder"
 version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -87,6 +142,15 @@
 ]
 
 [[package]]
+name = "ctr"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "dbghelp-sys"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -159,6 +223,14 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [[package]]
+name = "generic-array"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "kernel32-sys"
 version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -215,6 +287,11 @@
 ]
 
 [[package]]
+name = "opaque-debug"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "pem"
 version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -337,6 +414,14 @@
 ]
 
 [[package]]
+name = "stream-cipher"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
 name = "strsim"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -369,6 +454,11 @@
 ]
 
 [[package]]
+name = "typenum"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
 name = "unicode-xid"
 version = "0.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -407,15 +497,22 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
 [metadata]
+"checksum aes-ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f65958ff3692041c36fc009261ccd63f24cd8e0dc1164266f068c2387e8b4e4f"
+"checksum aes-soft 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "67cc03b0a090a05cb01e96998a01905d7ceedce1bc23b756c0bb7faa0682ccb1"
+"checksum aesni 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6810b7fb9f2bb4f76f05ac1c170b8dde285b6308955dc3afd89710268c958d9e"
 "checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
 "checksum backtrace 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8709cc7ec06f6f0ae6c2c7e12f6ed41540781f72b488d83734978295ceae182e"
 "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
 "checksum base64 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c4a342b450b268e1be8036311e2c613d7f8a7ed31214dff1cc3b60852a3168d"
+"checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9"
 "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
+"checksum block-cipher-trait 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "370424437b9459f3dfd68428ed9376ddfe03d8b70ede29cc533b3557df186ab4"
+"checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40"
 "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23"
 "checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
 "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
 "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
+"checksum ctr 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50ac3add446ec1f8fe3dc007cd838f5b22bbf33186394feac505451ecc43c018"
 "checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
 "checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a"
 "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
@@ -425,6 +522,7 @@
 "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159"
 "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82"
 "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
+"checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d"
 "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
 "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
 "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
@@ -432,6 +530,7 @@
 "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
 "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
 "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
+"checksum opaque-debug 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d620c9c26834b34f039489ac0dfdb12c7ac15ccaf818350a64c9b5334a452ad7"
 "checksum pem 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97b2fe7dc63bbe9ad4cc7510f33b8ac45242c8032acaa460193c05d852aa74d8"
 "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
 "checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd"
@@ -446,10 +545,12 @@
 "checksum serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1c57ab4ec5fa85d08aaf8ed9245899d9bbdd66768945b21113b84d5f595cb6a1"
 "checksum serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "02c92ea07b6e49b959c1481804ebc9bfd92d3c459f1274c9a9546829e42a66ce"
 "checksum serde_derive_internals 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75c6aac7b99801a16db5b40b7bf0d7e4ba16e76fbf231e32a4677f271cac0603"
+"checksum stream-cipher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "30dc6118470d69ce0fdcf7e6f95e95853f7f4f72f80d835d4519577c323814ab"
 "checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
 "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
 "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
 "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
+"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
 "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
 "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
 "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae"
diff --git a/sim/Cargo.toml b/sim/Cargo.toml
index 29fb0d4..84fbabe 100644
--- a/sim/Cargo.toml
+++ b/sim/Cargo.toml
@@ -10,6 +10,8 @@
 sig-ecdsa = ["mcuboot-sys/sig-ecdsa"]
 overwrite-only = ["mcuboot-sys/overwrite-only"]
 validate-slot0 = ["mcuboot-sys/validate-slot0"]
+enc-rsa = ["mcuboot-sys/enc-rsa"]
+enc-kw = ["mcuboot-sys/enc-kw"]
 
 [build-dependencies]
 gcc = "0.3.54"
@@ -27,6 +29,8 @@
 ring = { version = "0.12.1", features = ["rsa_signing"] }
 untrusted = "0.5"
 pem = "0.5"
+aes-ctr = "0.1.0"
+base64 = "0.9.2"
 
 # The simulator runs very slowly without optimization.  A value of 1
 # compiles in about half the time, but runs about 5-6 times slower.  2
diff --git a/sim/mcuboot-sys/Cargo.toml b/sim/mcuboot-sys/Cargo.toml
index 7846875..25d5652 100644
--- a/sim/mcuboot-sys/Cargo.toml
+++ b/sim/mcuboot-sys/Cargo.toml
@@ -23,6 +23,12 @@
 # Disable validation of slot0
 validate-slot0 = []
 
+# Encrypt image in slot1 using RSA-OAEP-2048
+enc-rsa = []
+
+# Encrypt image in slot1 using AES-KW-128
+enc-kw = []
+
 [build-dependencies]
 gcc = "0.3.54"
 
diff --git a/sim/mcuboot-sys/build.rs b/sim/mcuboot-sys/build.rs
index 2c28dbb..ea958f6 100644
--- a/sim/mcuboot-sys/build.rs
+++ b/sim/mcuboot-sys/build.rs
@@ -13,6 +13,8 @@
     let sig_ecdsa = env::var("CARGO_FEATURE_SIG_ECDSA").is_ok();
     let overwrite_only = env::var("CARGO_FEATURE_OVERWRITE_ONLY").is_ok();
     let validate_slot0 = env::var("CARGO_FEATURE_VALIDATE_SLOT0").is_ok();
+    let enc_rsa = env::var("CARGO_FEATURE_ENC_RSA").is_ok();
+    let enc_kw = env::var("CARGO_FEATURE_ENC_KW").is_ok();
 
     let mut conf = gcc::Build::new();
     conf.define("__BOOTSIM__", None);
@@ -73,6 +75,49 @@
         conf.define("MCUBOOT_OVERWRITE_ONLY_FAST", None);
     }
 
+    if enc_rsa {
+        conf.define("MCUBOOT_ENCRYPT_RSA", None);
+        conf.define("MCUBOOT_ENC_IMAGES", None);
+        conf.define("MCUBOOT_USE_MBED_TLS", None);
+        conf.define("MBEDTLS_CONFIG_FILE", Some("<config-rsa.h>"));
+
+        conf.file("../../boot/bootutil/src/encrypted.c");
+        conf.file("csupport/keys.c");
+
+        conf.include("mbedtls/include");
+        conf.file("mbedtls/library/sha256.c");
+
+        conf.file("mbedtls/library/platform.c");
+        conf.file("mbedtls/library/platform_util.c");
+        conf.file("mbedtls/library/rsa.c");
+        conf.file("mbedtls/library/rsa_internal.c");
+        conf.file("mbedtls/library/md.c");
+        conf.file("mbedtls/library/md_wrap.c");
+        conf.file("mbedtls/library/aes.c");
+        conf.file("mbedtls/library/bignum.c");
+        conf.file("mbedtls/library/asn1parse.c");
+    }
+
+    if enc_kw {
+        conf.define("MCUBOOT_ENCRYPT_KW", None);
+        conf.define("MCUBOOT_ENC_IMAGES", None);
+        conf.define("MCUBOOT_USE_MBED_TLS", None);
+        conf.define("MBEDTLS_CONFIG_FILE", Some("<config-kw.h>"));
+
+        conf.file("../../boot/bootutil/src/encrypted.c");
+        conf.file("csupport/keys.c");
+
+        conf.include("mbedtls/include");
+        conf.file("mbedtls/library/sha256.c");
+
+        conf.file("mbedtls/library/platform.c");
+        conf.file("mbedtls/library/platform_util.c");
+        conf.file("mbedtls/library/nist_kw.c");
+        conf.file("mbedtls/library/cipher.c");
+        conf.file("mbedtls/library/cipher_wrap.c");
+        conf.file("mbedtls/library/aes.c");
+    }
+
     conf.file("../../boot/bootutil/src/image_validate.c");
     if sig_rsa {
         conf.file("../../boot/bootutil/src/image_rsa.c");
diff --git a/sim/mcuboot-sys/csupport/keys.c b/sim/mcuboot-sys/csupport/keys.c
index aa8272f..6e4f3f5 100644
--- a/sim/mcuboot-sys/csupport/keys.c
+++ b/sim/mcuboot-sys/csupport/keys.c
@@ -65,8 +65,6 @@
     0x8b, 0x68, 0x34, 0xcc, 0x3a, 0x6a, 0xfc, 0x53,
     0x8e, 0xfa, 0xc1, };
 const unsigned int root_pub_der_len = 91;
-#else
-#error "No public key available for given signing algorithm."
 #endif
 
 #if defined(HAVE_KEYS)
@@ -78,3 +76,125 @@
 };
 const int bootutil_key_cnt = 1;
 #endif
+
+#if defined(MCUBOOT_ENCRYPT_RSA)
+unsigned char enc_key[] = {
+  0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
+  0xb4, 0x26, 0x14, 0x49, 0x3d, 0x16, 0x13, 0x3a, 0x6d, 0x9c, 0x84, 0xa9,
+  0x8b, 0x6a, 0x10, 0x20, 0x61, 0xef, 0x48, 0x04, 0xa4, 0x4b, 0x24, 0xf3,
+  0x00, 0x32, 0xac, 0x22, 0xe0, 0x30, 0x27, 0x70, 0x18, 0xe5, 0x55, 0xc8,
+  0xb8, 0x05, 0x34, 0x03, 0xb0, 0xf8, 0xa5, 0x96, 0xd2, 0x48, 0x58, 0xef,
+  0x70, 0xb0, 0x09, 0xdb, 0xe3, 0x58, 0x62, 0xef, 0x99, 0x63, 0x01, 0xb2,
+  0x89, 0xc4, 0xb3, 0xf6, 0x9e, 0x62, 0xbf, 0x4d, 0xc2, 0x8a, 0xd0, 0xc9,
+  0x4d, 0x43, 0xa3, 0xd8, 0xe5, 0x1d, 0xec, 0x62, 0x63, 0x08, 0xe2, 0x20,
+  0xa5, 0xfc, 0x78, 0xd0, 0x3e, 0x74, 0xc8, 0xa4, 0x1b, 0x36, 0xad, 0x7b,
+  0xf5, 0x06, 0xae, 0x4d, 0x51, 0x9b, 0x40, 0xce, 0x30, 0x4f, 0x6c, 0xea,
+  0xf9, 0xe9, 0x74, 0xea, 0x06, 0xee, 0x9c, 0xe4, 0x14, 0x68, 0x20, 0xb9,
+  0x3d, 0xe7, 0x11, 0x14, 0x8b, 0x25, 0xa3, 0xff, 0x4c, 0x8a, 0xf3, 0x53,
+  0xee, 0x6b, 0x3e, 0xef, 0x34, 0xcd, 0x6a, 0x3f, 0x62, 0x68, 0xc0, 0xff,
+  0x78, 0x4c, 0xb0, 0xc3, 0xe6, 0x96, 0x61, 0xfc, 0x1f, 0x18, 0xf1, 0x7a,
+  0x82, 0xe2, 0x8f, 0x35, 0xa8, 0x2b, 0x86, 0x16, 0xa4, 0x46, 0xfb, 0xac,
+  0x7e, 0x41, 0xdb, 0x02, 0x05, 0x91, 0x6d, 0xdf, 0xc1, 0xde, 0x13, 0x95,
+  0x9c, 0xf9, 0x9e, 0x5e, 0x72, 0xba, 0xa7, 0x25, 0x93, 0xfb, 0xdc, 0xe8,
+  0xab, 0x86, 0x45, 0x88, 0x47, 0x2d, 0xed, 0xee, 0xee, 0x97, 0x9e, 0xce,
+  0x5d, 0x9b, 0x04, 0x04, 0x40, 0x7c, 0xcb, 0x7c, 0x3d, 0x2c, 0x74, 0xab,
+  0xa4, 0xcc, 0x64, 0xa3, 0x5c, 0x95, 0x3d, 0xd4, 0xa2, 0xdc, 0x92, 0xb2,
+  0xc8, 0x18, 0xcb, 0xf9, 0x00, 0x39, 0x81, 0x8f, 0x8f, 0x40, 0xc2, 0xdf,
+  0x99, 0x29, 0xac, 0x8a, 0xc2, 0x3b, 0xd8, 0xa4, 0xf2, 0xad, 0xaf, 0x74,
+  0xc0, 0x11, 0xc7, 0x99, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
+  0x00, 0x42, 0x47, 0x80, 0x4f, 0x31, 0xda, 0x5d, 0x58, 0xb1, 0xdb, 0x54,
+  0x33, 0xcc, 0xc7, 0x49, 0x07, 0xa1, 0x00, 0x98, 0x4e, 0x9c, 0xe3, 0xc8,
+  0xc4, 0x5e, 0xde, 0x45, 0xd6, 0xcf, 0x04, 0xe8, 0x7d, 0xa5, 0xab, 0x3a,
+  0xd4, 0x8e, 0x5f, 0xdb, 0xb3, 0x3f, 0xf9, 0x3b, 0x73, 0x32, 0x0a, 0xcc,
+  0x2d, 0xcc, 0x17, 0xf8, 0x88, 0x9e, 0x2c, 0x76, 0xba, 0x10, 0x85, 0x0c,
+  0xaa, 0xd3, 0x65, 0x3b, 0x91, 0x10, 0xd4, 0xe3, 0xed, 0x88, 0x15, 0xea,
+  0x9b, 0x25, 0x82, 0x2d, 0x56, 0x2f, 0x75, 0xc2, 0xf2, 0xaf, 0xdd, 0x24,
+  0xd5, 0x3e, 0x3c, 0x95, 0x76, 0x88, 0x84, 0x0f, 0x0d, 0xd1, 0xb5, 0x5c,
+  0x3e, 0xae, 0xf7, 0xb6, 0x49, 0x5c, 0x2c, 0xf2, 0xba, 0xe9, 0xab, 0x4f,
+  0x37, 0x64, 0x9b, 0x30, 0x18, 0xaa, 0x54, 0x40, 0x04, 0xea, 0x3d, 0x25,
+  0x4d, 0x02, 0x29, 0x71, 0x6f, 0x4d, 0x82, 0x9b, 0xc3, 0x44, 0x2a, 0x9d,
+  0x0c, 0x98, 0xd3, 0xc8, 0x15, 0x0d, 0x04, 0x93, 0x60, 0x30, 0xc7, 0x5e,
+  0x79, 0xea, 0x53, 0x9d, 0xc0, 0x0e, 0x81, 0xac, 0x90, 0xbc, 0x9e, 0x1e,
+  0xd2, 0x28, 0x0f, 0x10, 0xf5, 0x1f, 0xdf, 0x38, 0x7f, 0x8a, 0x90, 0x8d,
+  0x49, 0x07, 0x7d, 0x78, 0xcb, 0xa7, 0xef, 0x92, 0x6d, 0x3b, 0x13, 0x95,
+  0x9b, 0xba, 0x83, 0xc6, 0xb3, 0x71, 0x25, 0x27, 0x07, 0x99, 0x54, 0x82,
+  0x3d, 0xec, 0xc5, 0xf8, 0xb4, 0xa0, 0x38, 0x7a, 0x59, 0x6a, 0x0b, 0xca,
+  0x69, 0x6c, 0x17, 0xa4, 0x18, 0xe0, 0xb4, 0xaa, 0x89, 0x99, 0x8f, 0xcb,
+  0x71, 0x34, 0x09, 0x1b, 0x6e, 0xe6, 0x87, 0x00, 0xb5, 0xba, 0x70, 0x8a,
+  0x29, 0x3d, 0x9a, 0x06, 0x18, 0x2d, 0x66, 0x5e, 0x61, 0x37, 0xeb, 0xdd,
+  0x5e, 0xc8, 0x28, 0x92, 0x05, 0x30, 0xfd, 0xb8, 0x65, 0xb1, 0x7f, 0xbf,
+  0x2d, 0x55, 0x12, 0x91, 0xc1, 0x02, 0x81, 0x81, 0x00, 0xda, 0x65, 0xda,
+  0x38, 0x7c, 0x18, 0xfb, 0x00, 0x11, 0x60, 0xeb, 0x37, 0x65, 0xb8, 0x83,
+  0x62, 0x88, 0xc4, 0x3a, 0x4e, 0x64, 0x6a, 0xf3, 0x3e, 0x4e, 0xc0, 0x34,
+  0x19, 0x8a, 0xcb, 0x4a, 0xca, 0x2f, 0x5d, 0x50, 0x7a, 0xac, 0xf7, 0x9e,
+  0x87, 0x5a, 0xfc, 0x4d, 0x49, 0xd7, 0xf9, 0x21, 0xf5, 0x0b, 0x6f, 0x57,
+  0x41, 0x3d, 0x8f, 0xb8, 0xec, 0x7f, 0xcc, 0x92, 0x09, 0xbe, 0xd3, 0xa4,
+  0xc3, 0x14, 0x85, 0x21, 0x5d, 0x05, 0xa3, 0xaa, 0x20, 0xf6, 0x62, 0x44,
+  0x50, 0x03, 0x5e, 0x53, 0x4a, 0xcd, 0x6a, 0xb6, 0x65, 0x8e, 0x4e, 0x4b,
+  0x3f, 0x25, 0xc6, 0x16, 0x31, 0xf5, 0x99, 0x13, 0x77, 0x42, 0xda, 0xdc,
+  0x70, 0x4d, 0x65, 0xb0, 0x99, 0x0f, 0xdf, 0x5a, 0xb1, 0x45, 0xf0, 0xb9,
+  0x8e, 0xa0, 0xae, 0x4f, 0x4d, 0x65, 0x09, 0x84, 0xb5, 0x38, 0x29, 0xbf,
+  0x69, 0xe0, 0x88, 0x1f, 0x27, 0x02, 0x81, 0x81, 0x00, 0xd3, 0x2a, 0x59,
+  0xec, 0x28, 0xc3, 0x0d, 0x4f, 0x92, 0x96, 0xca, 0x67, 0x94, 0xfc, 0x2e,
+  0xa6, 0x86, 0x68, 0x45, 0x53, 0x92, 0xcc, 0x86, 0x7f, 0x8a, 0xe1, 0x5d,
+  0xe8, 0x1d, 0x9e, 0xbb, 0x1e, 0x00, 0x26, 0x1d, 0x80, 0x12, 0xff, 0x9c,
+  0x11, 0x0a, 0xbd, 0xa6, 0xc3, 0x8d, 0x48, 0xda, 0xfc, 0x10, 0xf7, 0x7a,
+  0x16, 0x07, 0x15, 0xa0, 0x3a, 0xd3, 0x94, 0xfb, 0x52, 0x87, 0x39, 0xee,
+  0xe7, 0xc4, 0x26, 0x49, 0x16, 0xc6, 0xc0, 0x83, 0x25, 0xbf, 0x6a, 0x4e,
+  0x8c, 0x0b, 0x10, 0x85, 0x66, 0xab, 0x7e, 0xae, 0xac, 0x4c, 0x69, 0x3c,
+  0x44, 0xeb, 0xcd, 0xe9, 0xf6, 0x64, 0x8b, 0x4a, 0xd8, 0x6a, 0x4d, 0x6d,
+  0x47, 0xa9, 0xb8, 0x55, 0x72, 0xc1, 0xfd, 0xf4, 0x81, 0x4c, 0x66, 0xbe,
+  0x49, 0xf2, 0x75, 0x4f, 0x80, 0xf1, 0x20, 0x38, 0xb8, 0x6a, 0x1b, 0x75,
+  0x41, 0x30, 0x0f, 0x1b, 0x3f, 0x02, 0x81, 0x80, 0x09, 0x35, 0xfa, 0x7a,
+  0x1f, 0x61, 0xbe, 0x54, 0x46, 0x67, 0x5c, 0x04, 0x3e, 0x1a, 0x06, 0x10,
+  0x85, 0xcc, 0x20, 0xd9, 0x65, 0x8a, 0xcd, 0x2f, 0x77, 0x8a, 0xcb, 0xa7,
+  0xb8, 0x1e, 0xd2, 0xcc, 0xac, 0x2a, 0xb7, 0x56, 0x35, 0x2d, 0x4c, 0x56,
+  0x51, 0x14, 0x0a, 0xfe, 0x6e, 0x49, 0x67, 0x91, 0x3a, 0x26, 0x3b, 0xfb,
+  0xd8, 0x68, 0xd3, 0x57, 0xc6, 0x1c, 0x0e, 0x9c, 0xb2, 0x9b, 0xa2, 0x7b,
+  0x47, 0xc6, 0x45, 0x9d, 0xf2, 0xba, 0xf0, 0x55, 0xeb, 0x8e, 0x41, 0x6b,
+  0x4e, 0x79, 0x0f, 0xf2, 0x3b, 0xaf, 0xa0, 0x79, 0xb0, 0x02, 0xc5, 0x51,
+  0xa8, 0x7a, 0x2e, 0x3d, 0x75, 0x2a, 0x3b, 0x93, 0xf0, 0x11, 0xe2, 0xf2,
+  0x29, 0x91, 0x7c, 0x5d, 0x38, 0x3a, 0x27, 0x4d, 0x0a, 0xb2, 0x18, 0x61,
+  0x57, 0x8d, 0x82, 0x72, 0xb5, 0x2c, 0x2d, 0x98, 0xa7, 0x01, 0xbb, 0xbc,
+  0xef, 0x67, 0x4e, 0x49, 0x02, 0x81, 0x81, 0x00, 0xb2, 0x70, 0x53, 0x54,
+  0x70, 0x8d, 0x82, 0xad, 0xff, 0x1d, 0x55, 0x24, 0x7a, 0x8d, 0x2f, 0x8e,
+  0xa0, 0x7d, 0x74, 0x37, 0xcf, 0x10, 0xed, 0x86, 0xd1, 0x80, 0xe7, 0xad,
+  0xc1, 0x79, 0xe4, 0x7c, 0xd1, 0x7b, 0x63, 0xea, 0x5a, 0x23, 0x8d, 0x6a,
+  0x09, 0x3d, 0x81, 0xb2, 0x35, 0xad, 0x9e, 0xfe, 0xea, 0x07, 0x76, 0x2f,
+  0x2f, 0x05, 0x63, 0x44, 0xd2, 0x8e, 0x4e, 0x61, 0xca, 0xcb, 0x75, 0xca,
+  0x7b, 0xc2, 0x2e, 0x79, 0x04, 0xb2, 0xa1, 0x20, 0x40, 0xc4, 0x40, 0x63,
+  0xae, 0xe5, 0xe3, 0x14, 0x83, 0x4e, 0xa5, 0xa4, 0x0b, 0x5d, 0xd2, 0x04,
+  0x1b, 0x8f, 0x01, 0x69, 0xa8, 0x44, 0xdc, 0x96, 0x4c, 0x1d, 0xe9, 0x7e,
+  0x69, 0x38, 0xcf, 0x5c, 0x0d, 0xf9, 0xdf, 0xa7, 0x73, 0x3c, 0x4f, 0x08,
+  0x85, 0xce, 0x03, 0xc4, 0xdd, 0xfd, 0x70, 0x70, 0xc5, 0x99, 0x36, 0x58,
+  0x43, 0x98, 0x40, 0x59, 0x02, 0x81, 0x81, 0x00, 0xd5, 0xaa, 0xfb, 0xec,
+  0x8d, 0xc6, 0xdd, 0xfa, 0x2b, 0x5a, 0x24, 0xd0, 0xda, 0x58, 0xbd, 0x87,
+  0x92, 0x1a, 0x29, 0x62, 0x13, 0x1d, 0x4b, 0x79, 0x1b, 0xbe, 0x79, 0x7d,
+  0xad, 0x79, 0xca, 0x17, 0x75, 0xda, 0xe8, 0x32, 0xe8, 0xa0, 0x9e, 0xa8,
+  0x77, 0x53, 0xac, 0x38, 0xd6, 0xeb, 0xe6, 0x22, 0x65, 0xc4, 0xaa, 0x4c,
+  0xc8, 0xd0, 0x33, 0x1a, 0x1e, 0xbe, 0xbd, 0x73, 0x09, 0x4a, 0xfa, 0x85,
+  0x5c, 0xf3, 0x0c, 0x9c, 0x81, 0x56, 0x30, 0xa7, 0xf7, 0x9b, 0xf4, 0x92,
+  0x9c, 0x6b, 0x93, 0x6a, 0x00, 0x33, 0xdc, 0x2f, 0x54, 0x1e, 0x78, 0xd4,
+  0x97, 0xec, 0x24, 0xa2, 0xdb, 0x3d, 0x03, 0x33, 0x09, 0xb2, 0x2c, 0x03,
+  0x05, 0x40, 0xde, 0x52, 0xf2, 0x9b, 0xfa, 0x00, 0x8d, 0x4b, 0xfe, 0x5b,
+  0x9b, 0x9c, 0x73, 0xad, 0xfb, 0x7a, 0x00, 0x42, 0x62, 0x9e, 0xa0, 0x95,
+  0x55, 0x50, 0x32, 0x87
+};
+static unsigned int enc_key_len = 1192;
+const struct bootutil_key bootutil_enc_key = {
+    .key = enc_key,
+    .len = &enc_key_len,
+};
+#endif
+
+#if defined(MCUBOOT_ENCRYPT_KW)
+unsigned char enc_key[] = {
+  0xd1, 0x5a, 0x04, 0x95, 0xc4, 0xc2, 0xa8, 0xff, 0x30, 0x78, 0xce, 0x49,
+  0xb5, 0xfc, 0xb2, 0xdd
+};
+static unsigned int enc_key_len = 16;
+const struct bootutil_key bootutil_enc_key = {
+    .key = enc_key,
+    .len = &enc_key_len,
+};
+#endif
diff --git a/sim/mcuboot-sys/csupport/run.c b/sim/mcuboot-sys/csupport/run.c
index 17a10f1..f8aaccd 100644
--- a/sim/mcuboot-sys/csupport/run.c
+++ b/sim/mcuboot-sys/csupport/run.c
@@ -17,6 +17,15 @@
 #include "../../../ext/tinycrypt/lib/include/tinycrypt/ecc_dsa.h"
 #endif
 
+#ifdef MCUBOOT_ENCRYPT_RSA
+#include "mbedtls/rsa.h"
+#include "mbedtls/asn1.h"
+#endif
+
+#ifdef MCUBOOT_ENCRYPT_KW
+#include "mbedtls/nist_kw.h"
+#endif
+
 #define BOOT_LOG_LEVEL BOOT_LOG_LEVEL_ERROR
 #include <bootutil/bootutil_log.h>
 
@@ -45,6 +54,155 @@
 #endif
 }
 
+#ifdef MCUBOOT_ENCRYPT_RSA
+static int
+parse_pubkey(mbedtls_rsa_context *ctx, uint8_t **p, uint8_t *end)
+{
+    int rc;
+    size_t len;
+
+    if ((rc = mbedtls_asn1_get_tag(p, end, &len,
+                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
+        return -1;
+    }
+
+    if (*p + len != end) {
+        return -2;
+    }
+
+    if ((rc = mbedtls_asn1_get_tag(p, end, &len,
+                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
+        return -3;
+    }
+
+    *p += len;
+
+    if ((rc = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_BIT_STRING)) != 0) {
+        return -4;
+    }
+
+    if (**p != MBEDTLS_ASN1_PRIMITIVE) {
+        return -5;
+    }
+
+    *p += 1;
+
+    if ((rc = mbedtls_asn1_get_tag(p, end, &len,
+                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
+        return -6;
+    }
+
+    if (mbedtls_asn1_get_mpi(p, end, &ctx->N) != 0) {
+        return -7;
+    }
+
+    if (mbedtls_asn1_get_mpi(p, end, &ctx->E) != 0) {
+        return -8;
+    }
+
+    ctx->len = mbedtls_mpi_size(&ctx->N);
+
+    if (*p != end) {
+        return -9;
+    }
+
+    if (mbedtls_rsa_check_pubkey(ctx) != 0) {
+        return -10;
+    }
+
+    return 0;
+}
+
+static int
+fake_rng(void *p_rng, unsigned char *output, size_t len)
+{
+    size_t i;
+
+    (void)p_rng;
+    for (i = 0; i < len; i++) {
+        output[i] = (char)i;
+    }
+
+    return 0;
+}
+#endif
+
+int mbedtls_platform_set_calloc_free(void * (*calloc_func)(size_t, size_t),
+                                     void (*free_func)(void *));
+
+int rsa_oaep_encrypt_(const uint8_t *pubkey, unsigned pubkey_len,
+                      const uint8_t *seckey, unsigned seckey_len,
+                      uint8_t *encbuf)
+{
+#ifdef MCUBOOT_ENCRYPT_RSA
+    mbedtls_rsa_context ctx;
+    uint8_t *cp;
+    uint8_t *cpend;
+    int rc;
+
+    mbedtls_platform_set_calloc_free(calloc, free);
+
+    mbedtls_rsa_init(&ctx, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
+
+    cp = (uint8_t *)pubkey;
+    cpend = cp + pubkey_len;
+
+    rc = parse_pubkey(&ctx, &cp, cpend);
+    if (rc) {
+        goto done;
+    }
+
+    rc = mbedtls_rsa_rsaes_oaep_encrypt(&ctx, fake_rng, NULL, MBEDTLS_RSA_PUBLIC,
+            NULL, 0, seckey_len, seckey, encbuf);
+    if (rc) {
+        goto done;
+    }
+
+done:
+    mbedtls_rsa_free(&ctx);
+    return rc;
+
+#else
+    (void)pubkey;
+    (void)pubkey_len;
+    (void)seckey;
+    (void)seckey_len;
+    (void)encbuf;
+    return 0;
+#endif
+}
+
+int kw_encrypt_(const uint8_t *kek, const uint8_t *seckey, uint8_t *encbuf)
+{
+#ifdef MCUBOOT_ENCRYPT_KW
+    mbedtls_nist_kw_context kw;
+    size_t olen;
+    int rc;
+
+    mbedtls_platform_set_calloc_free(calloc, free);
+
+    mbedtls_nist_kw_init(&kw);
+
+    rc = mbedtls_nist_kw_setkey(&kw, MBEDTLS_CIPHER_ID_AES, kek, 128, 1);
+    if (rc) {
+        goto done;
+    }
+
+    rc = mbedtls_nist_kw_wrap(&kw, MBEDTLS_KW_MODE_KW, seckey, 16, encbuf,
+            &olen, 24);
+
+done:
+    mbedtls_nist_kw_free(&kw);
+    return rc;
+
+#else
+    (void)kek;
+    (void)seckey;
+    (void)encbuf;
+    return 0;
+#endif
+}
+
 uint8_t sim_flash_align = 1;
 uint8_t flash_area_align(const struct flash_area *area)
 {
@@ -73,17 +231,12 @@
 
 static struct area_desc *flash_areas;
 
-#ifdef MCUBOOT_SIGN_RSA
-int mbedtls_platform_set_calloc_free(void * (*calloc_func)(size_t, size_t),
-                                     void (*free_func)(void *));
-#endif
-
 int invoke_boot_go(struct area_desc *adesc)
 {
     int res;
     struct boot_rsp rsp;
 
-#ifdef MCUBOOT_SIGN_RSA
+#if defined(MCUBOOT_SIGN_RSA)
     mbedtls_platform_set_calloc_free(calloc, free);
 #endif
 
diff --git a/sim/mcuboot-sys/src/c.rs b/sim/mcuboot-sys/src/c.rs
index 3b944c6..45624ed 100644
--- a/sim/mcuboot-sys/src/c.rs
+++ b/sim/mcuboot-sys/src/c.rs
@@ -60,6 +60,28 @@
     }
 }
 
+pub fn rsa_oaep_encrypt(pubkey: &[u8], seckey: &[u8]) -> Result<[u8; 256], &'static str> {
+    unsafe {
+        let mut encbuf: [u8; 256] = [0; 256];
+        if raw::rsa_oaep_encrypt_(pubkey.as_ptr(), pubkey.len() as u32,
+                                  seckey.as_ptr(), seckey.len() as u32,
+                                  encbuf.as_mut_ptr()) == 0 {
+            return Ok(encbuf);
+        }
+        return Err("Failed to encrypt buffer");
+    }
+}
+
+pub fn kw_encrypt(kek: &[u8], seckey: &[u8]) -> Result<[u8; 24], &'static str> {
+    unsafe {
+        let mut encbuf = [0u8; 24];
+        if raw::kw_encrypt_(kek.as_ptr(), seckey.as_ptr(), encbuf.as_mut_ptr()) == 0 {
+            return Ok(encbuf);
+        }
+        return Err("Failed to encrypt buffer");
+    }
+}
+
 mod raw {
     use area::CAreaDesc;
     use libc;
@@ -83,5 +105,12 @@
         pub fn ecdsa256_sign_(privkey: *const u8, hash: *const u8,
                               hash_len: libc::c_uint,
                               signature: *mut u8) -> libc::c_int;
+
+        pub fn rsa_oaep_encrypt_(pubkey: *const u8, pubkey_len: libc::c_uint,
+                                 seckey: *const u8, seckey_len: libc::c_uint,
+                                 encbuf: *mut u8) -> libc::c_int;
+
+        pub fn kw_encrypt_(kek: *const u8, seckey: *const u8,
+                           encbuf: *mut u8) -> libc::c_int;
     }
 }
diff --git a/sim/src/lib.rs b/sim/src/lib.rs
index 1e8ba8a..e7ad671 100644
--- a/sim/src/lib.rs
+++ b/sim/src/lib.rs
@@ -1,5 +1,7 @@
 #[macro_use] extern crate log;
 extern crate ring;
+extern crate aes_ctr;
+extern crate base64;
 extern crate env_logger;
 extern crate docopt;
 extern crate libc;
@@ -18,6 +20,9 @@
 use std::mem;
 use std::process;
 use std::slice;
+use aes_ctr::Aes128Ctr;
+use aes_ctr::stream_cipher::generic_array::GenericArray;
+use aes_ctr::stream_cipher::{NewFixStreamCipher, StreamCipherCore};
 
 mod caps;
 mod tlv;
@@ -26,7 +31,7 @@
 use simflash::{Flash, SimFlash};
 use mcuboot_sys::{c, AreaDesc, FlashId};
 use caps::Caps;
-use tlv::TlvGen;
+use tlv::{TlvGen, TlvFlags, AES_SEC_KEY};
 
 const USAGE: &'static str = "
 Mcuboot simulator
@@ -183,12 +188,14 @@
         let slot0 = SlotInfo {
             base_off: slot0_base as usize,
             trailer_off: slot1_base - offset_from_end,
+            len: slot0_len as usize,
         };
 
         // And an upgrade image.
         let slot1 = SlotInfo {
             base_off: slot1_base as usize,
             trailer_off: scratch_base - offset_from_end,
+            len: slot1_len as usize,
         };
 
         Run {
@@ -216,15 +223,14 @@
     /// Construct an `Images` that doesn't expect an upgrade to happen.
     pub fn make_no_upgrade_image(&self) -> Images {
         let mut flash = self.flash.clone();
-        let primary = install_image(&mut flash, self.slots[0].base_off, 32784, false);
-        let upgrade = install_image(&mut flash, self.slots[1].base_off, 41928, false);
+        let primaries = install_image(&mut flash, &self.slots, 0, 32784, false);
+        let upgrades = install_image(&mut flash, &self.slots, 1, 41928, false);
         Images {
             flash: flash,
             areadesc: self.areadesc.clone(),
-            slot0: self.slots[0].clone(),
-            slot1: self.slots[1].clone(),
-            primary: primary,
-            upgrade: upgrade,
+            slots: [self.slots[0].clone(), self.slots[1].clone()],
+            primaries: primaries,
+            upgrades: upgrades,
             total_count: None,
             align: self.align,
             erased_val: self.erased_val,
@@ -234,7 +240,7 @@
     /// Construct an `Images` for normal testing.
     pub fn make_image(&self) -> Images {
         let mut images = self.make_no_upgrade_image();
-        mark_upgrade(&mut images.flash, &images.slot1);
+        mark_upgrade(&mut images.flash, &images.slots[1]);
 
         // upgrades without fails, counts number of flash operations
         let total_count = match images.run_basic_upgrade() {
@@ -250,15 +256,14 @@
 
     pub fn make_bad_slot1_image(&self) -> Images {
         let mut bad_flash = self.flash.clone();
-        let primary = install_image(&mut bad_flash, self.slots[0].base_off, 32784, false);
-        let upgrade = install_image(&mut bad_flash, self.slots[1].base_off, 41928, true);
+        let primaries = install_image(&mut bad_flash, &self.slots, 0, 32784, false);
+        let upgrades = install_image(&mut bad_flash, &self.slots, 1, 41928, true);
         Images {
             flash: bad_flash,
             areadesc: self.areadesc.clone(),
-            slot0: self.slots[0].clone(),
-            slot1: self.slots[1].clone(),
-            primary: primary,
-            upgrade: upgrade,
+            slots: [self.slots[0].clone(), self.slots[1].clone()],
+            primaries: primaries,
+            upgrades: upgrades,
             total_count: None,
             align: self.align,
             erased_val: self.erased_val,
@@ -380,7 +385,7 @@
         let (fl, total_count) = try_upgrade(&self.flash, &self, None);
         info!("Total flash operation count={}", total_count);
 
-        if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
+        if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
             warn!("Image mismatch after first boot");
             Err(())
         } else {
@@ -402,7 +407,7 @@
             for count in 2 .. 5 {
                 info!("Try revert: {}", count);
                 let fl = try_revert(&self.flash, &self.areadesc, count, self.align);
-                if !verify_image(&fl, self.slot0.base_off, &self.primary) {
+                if !verify_image(&fl, &self.slots, 0, &self.primaries) {
                     error!("Revert failure on count {}", count);
                     fails += 1;
                 }
@@ -421,25 +426,25 @@
             info!("Try interruption at {}", i);
             let (fl, count) = try_upgrade(&self.flash, &self, Some(i));
             info!("Second boot, count={}", count);
-            if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
+            if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
                 warn!("FAIL at step {} of {}", i, total_flash_ops);
                 fails += 1;
             }
 
-            if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+            if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                                BOOT_FLAG_SET, BOOT_FLAG_SET) {
                 warn!("Mismatched trailer for Slot 0");
                 fails += 1;
             }
 
-            if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
+            if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
                                BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
                 warn!("Mismatched trailer for Slot 1");
                 fails += 1;
             }
 
             if Caps::SwapUpgrade.present() {
-                if !verify_image(&fl, self.slot1.base_off, &self.primary) {
+                if !verify_image(&fl, &self.slots, 1, &self.primaries) {
                     warn!("Slot 1 FAIL at step {} of {}", i, total_flash_ops);
                     fails += 1;
                 }
@@ -465,9 +470,9 @@
                                                   total_flash_ops, total_fails);
         info!("Random interruptions at reset points={:?}", total_counts);
 
-        let slot0_ok = verify_image(&fl, self.slot0.base_off, &self.upgrade);
+        let slot0_ok = verify_image(&fl, &self.slots, 0, &self.upgrades);
         let slot1_ok = if Caps::SwapUpgrade.present() {
-            verify_image(&fl, self.slot1.base_off, &self.primary)
+            verify_image(&fl, &self.slots, 1, &self.primaries)
         } else {
             true
         };
@@ -477,12 +482,12 @@
                    if slot1_ok { "ok" } else { "fail" });
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+        if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                            BOOT_FLAG_SET, BOOT_FLAG_SET) {
             error!("Mismatched trailer for Slot 0");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
+        if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
                            BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             error!("Mismatched trailer for Slot 1");
             fails += 1;
@@ -539,25 +544,25 @@
         //FIXME: copy_done is written by boot_go, is it ok if no copy
         //       was ever done?
 
-        if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
+        if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
             warn!("Slot 0 image verification FAIL");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+        if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                            BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
+        if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
                            BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 1");
             fails += 1;
         }
 
         // Marks image in slot0 as permanent, no revert should happen...
-        mark_permanent_upgrade(&mut fl, &self.slot0, self.align, self.erased_val);
+        mark_permanent_upgrade(&mut fl, &self.slots[0], self.align, self.erased_val);
 
-        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+        if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                            BOOT_FLAG_SET, BOOT_FLAG_SET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
@@ -569,12 +574,12 @@
             fails += 1;
         }
 
-        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+        if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                            BOOT_FLAG_SET, BOOT_FLAG_SET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
-        if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
+        if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
             warn!("Failed image verification");
             fails += 1;
         }
@@ -594,10 +599,10 @@
 
         info!("Try non-revert on imgtool generated image");
 
-        mark_upgrade(&mut fl, &self.slot0);
+        mark_upgrade(&mut fl, &self.slots[0]);
 
         // This simulates writing an image created by imgtool to Slot 0
-        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+        if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                            BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
@@ -611,16 +616,16 @@
         }
 
         // State should not have changed
-        if !verify_image(&fl, self.slot0.base_off, &self.primary) {
+        if !verify_image(&fl, &self.slots, 0, &self.primaries) {
             warn!("Failed image verification");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+        if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                            BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot1.trailer_off, BOOT_MAGIC_UNSET,
+        if !verify_trailer(&fl, self.slots[1].trailer_off, BOOT_MAGIC_UNSET,
                            BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 1");
             fails += 1;
@@ -641,11 +646,11 @@
 
         info!("Try upgrade image with bad signature");
 
-        mark_upgrade(&mut fl, &self.slot0);
-        mark_permanent_upgrade(&mut fl, &self.slot0, self.align, self.erased_val);
-        mark_upgrade(&mut fl, &self.slot1);
+        mark_upgrade(&mut fl, &self.slots[0]);
+        mark_permanent_upgrade(&mut fl, &self.slots[0], self.align, self.erased_val);
+        mark_upgrade(&mut fl, &self.slots[1]);
 
-        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+        if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                            BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
@@ -659,11 +664,11 @@
         }
 
         // State should not have changed
-        if !verify_image(&fl, self.slot0.base_off, &self.primary) {
+        if !verify_image(&fl, &self.slots, 0, &self.primaries) {
             warn!("Failed image verification");
             fails += 1;
         }
-        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+        if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                            BOOT_FLAG_SET, BOOT_FLAG_UNSET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
@@ -683,10 +688,22 @@
 
     // FIXME: could get status sz from bootloader
     #[cfg(not(feature = "overwrite-only"))]
+    #[cfg(not(feature = "enc-rsa"))]
+    #[cfg(not(feature = "enc-kw"))]
     fn status_sz(&self) -> usize {
         self.trailer_sz() - (16 + 24)
     }
 
+    #[cfg(feature = "enc-rsa")]
+    fn status_sz(&self) -> usize {
+        self.trailer_sz() - (16 + 24 + 32)
+    }
+
+    #[cfg(feature = "enc-kw")]
+    fn status_sz(&self) -> usize {
+        self.trailer_sz() - (16 + 24 + 32)
+    }
+
     /// This test runs a simple upgrade with no fails in the images, but
     /// allowing for fails in the status area. This should run to the end
     /// and warn that write fails were detected...
@@ -700,9 +717,9 @@
 
         info!("Try swap with status fails");
 
-        mark_permanent_upgrade(&mut fl, &self.slot1, self.align, self.erased_val);
+        mark_permanent_upgrade(&mut fl, &self.slots[1], self.align, self.erased_val);
 
-        let status_off = self.slot1.base_off - self.trailer_sz();
+        let status_off = self.slots[1].base_off - self.trailer_sz();
 
         // Always fail writes to status area...
         let _ = fl.add_bad_region(status_off, self.status_sz(), 1.0);
@@ -720,13 +737,13 @@
             fails += 1;
         }
 
-        if !verify_trailer(&fl, self.slot0.trailer_off, BOOT_MAGIC_GOOD,
+        if !verify_trailer(&fl, self.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                            BOOT_FLAG_SET, BOOT_FLAG_SET) {
             warn!("Mismatched trailer for Slot 0");
             fails += 1;
         }
 
-        if !verify_image(&fl, self.slot0.base_off, &self.upgrade) {
+        if !verify_image(&fl, &self.slots, 0, &self.upgrades) {
             warn!("Failed image verification");
             fails += 1;
         }
@@ -758,9 +775,9 @@
 
         info!("Try interrupted swap with status fails");
 
-        mark_permanent_upgrade(&mut fl, &self.slot1, self.align, self.erased_val);
+        mark_permanent_upgrade(&mut fl, &self.slots[1], self.align, self.erased_val);
 
-        let status_off = self.slot1.base_off - self.trailer_sz();
+        let status_off = self.slots[1].base_off - self.trailer_sz();
 
         // Mark the status area as a bad area
         let _ = fl.add_bad_region(status_off, self.status_sz(), 0.5);
@@ -805,9 +822,9 @@
 
         info!("Try interrupted swap with status fails");
 
-        mark_permanent_upgrade(&mut fl, &self.slot1, self.align, self.erased_val);
+        mark_permanent_upgrade(&mut fl, &self.slots[1], self.align, self.erased_val);
 
-        let status_off = self.slot1.base_off - self.trailer_sz();
+        let status_off = self.slots[1].base_off - self.trailer_sz();
 
         // Mark the status area as a bad area
         let _ = fl.add_bad_region(status_off, self.status_sz(), 1.0);
@@ -835,7 +852,7 @@
     // Clone the flash to have a new copy.
     let mut fl = flash.clone();
 
-    mark_permanent_upgrade(&mut fl, &images.slot1, images.align, images.erased_val);
+    mark_permanent_upgrade(&mut fl, &images.slots[1], images.align, images.erased_val);
 
     let mut counter = stop.unwrap_or(0);
 
@@ -883,7 +900,7 @@
         fails += 1;
     }
 
-    if !verify_trailer(&fl, images.slot0.trailer_off, None, None, BOOT_FLAG_UNSET) {
+    if !verify_trailer(&fl, images.slots[0].trailer_off, None, None, BOOT_FLAG_UNSET) {
         warn!("copy_done should be unset");
         fails += 1;
     }
@@ -894,20 +911,20 @@
         fails += 1;
     }
 
-    if !verify_image(&fl, images.slot0.base_off, &images.upgrade) {
+    if !verify_image(&fl, &images.slots, 0, &images.upgrades) {
         warn!("Image in slot 0 before revert is invalid at stop={}", stop);
         fails += 1;
     }
-    if !verify_image(&fl, images.slot1.base_off, &images.primary) {
+    if !verify_image(&fl, &images.slots, 1, &images.primaries) {
         warn!("Image in slot 1 before revert is invalid at stop={}", stop);
         fails += 1;
     }
-    if !verify_trailer(&fl, images.slot0.trailer_off, BOOT_MAGIC_GOOD,
+    if !verify_trailer(&fl, images.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                        BOOT_FLAG_UNSET, BOOT_FLAG_SET) {
         warn!("Mismatched trailer for Slot 0 before revert");
         fails += 1;
     }
-    if !verify_trailer(&fl, images.slot1.trailer_off, BOOT_MAGIC_UNSET,
+    if !verify_trailer(&fl, images.slots[1].trailer_off, BOOT_MAGIC_UNSET,
                        BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
         warn!("Mismatched trailer for Slot 1 before revert");
         fails += 1;
@@ -920,20 +937,20 @@
         fails += 1;
     }
 
-    if !verify_image(&fl, images.slot0.base_off, &images.primary) {
+    if !verify_image(&fl, &images.slots, 0, &images.primaries) {
         warn!("Image in slot 0 after revert is invalid at stop={}", stop);
         fails += 1;
     }
-    if !verify_image(&fl, images.slot1.base_off, &images.upgrade) {
+    if !verify_image(&fl, &images.slots, 1, &images.upgrades) {
         warn!("Image in slot 1 after revert is invalid at stop={}", stop);
         fails += 1;
     }
-    if !verify_trailer(&fl, images.slot0.trailer_off, BOOT_MAGIC_GOOD,
+    if !verify_trailer(&fl, images.slots[0].trailer_off, BOOT_MAGIC_GOOD,
                        BOOT_FLAG_SET, BOOT_FLAG_SET) {
         warn!("Mismatched trailer for Slot 1 after revert");
         fails += 1;
     }
-    if !verify_trailer(&fl, images.slot1.trailer_off, BOOT_MAGIC_UNSET,
+    if !verify_trailer(&fl, images.slots[1].trailer_off, BOOT_MAGIC_UNSET,
                        BOOT_FLAG_UNSET, BOOT_FLAG_UNSET) {
         warn!("Mismatched trailer for Slot 1 after revert");
         fails += 1;
@@ -946,7 +963,7 @@
                     total_ops: i32,  count: usize) -> (SimFlash, Vec<i32>) {
     let mut fl = flash.clone();
 
-    mark_permanent_upgrade(&mut fl, &images.slot1, images.align, images.erased_val);
+    mark_permanent_upgrade(&mut fl, &images.slots[1], images.align, images.erased_val);
 
     let mut rng = rand::thread_rng();
     let mut resets = vec![0i32; count];
@@ -985,20 +1002,19 @@
 
 /// Install a "program" into the given image.  This fakes the image header, or at least all of the
 /// fields used by the given code.  Returns a copy of the image that was written.
-fn install_image(flash: &mut Flash, offset: usize, len: usize,
-                 bad_sig: bool) -> Vec<u8> {
-    let offset0 = offset;
+fn install_image(flash: &mut Flash, slots: &[SlotInfo], slot: usize, len: usize,
+                 bad_sig: bool) -> [Option<Vec<u8>>; 2] {
+    let offset = slots[slot].base_off;
+    let slot_len = slots[slot].len;
 
     let mut tlv = make_tlv();
 
     // Generate a boot header.  Note that the size doesn't include the header.
     let header = ImageHeader {
         magic: 0x96f3b83d,
-        tlv_size: tlv.get_size(),
-        _pad1: 0,
+        load_addr: 0,
         hdr_size: 32,
-        key_id: 0,
-        _pad2: 0,
+        _pad1: 0,
         img_size: len as u32,
         flags: tlv.get_flags(),
         ver: ImageVersion {
@@ -1007,7 +1023,7 @@
             revision: 1,
             build_num: offset as u32,
         },
-        _pad3: 0,
+        _pad2: 0,
     };
 
     let b_header = header.as_raw();
@@ -1017,35 +1033,106 @@
                                                   mem::size_of::<ImageHeader>()) };
                                                   */
     assert_eq!(b_header.len(), 32);
-    flash.write(offset, &b_header).unwrap();
-    let offset = offset + b_header.len();
 
     // The core of the image itself is just pseudorandom data.
-    let mut buf = vec![0; len];
-    splat(&mut buf, offset);
-    tlv.add_bytes(&buf);
+    let mut b_img = vec![0; len];
+    splat(&mut b_img, offset);
 
-    // Get and append the TLV itself.
-    if bad_sig {
-        let good_sig = &mut tlv.make_tlv();
-        buf.append(&mut vec![0; good_sig.len()]);
-    } else {
-        buf.append(&mut tlv.make_tlv());
+    // TLV signatures work over plain image
+    tlv.add_bytes(&b_img);
+
+    // Generate encrypted images
+    let flag = TlvFlags::ENCRYPTED as u32;
+    let is_encrypted = (tlv.get_flags() & flag) == flag;
+    let mut b_encimg = vec![];
+    if is_encrypted {
+        let key = GenericArray::from_slice(AES_SEC_KEY);
+        let nonce = GenericArray::from_slice(&[0; 16]);
+        let mut cipher = Aes128Ctr::new(&key, &nonce);
+        b_encimg = b_img.clone();
+        cipher.apply_keystream(&mut b_encimg);
     }
 
+    // Build the TLV itself.
+    let mut b_tlv = if bad_sig {
+        let good_sig = &mut tlv.make_tlv();
+        vec![0; good_sig.len()]
+    } else {
+        tlv.make_tlv()
+    };
+
     // Pad the block to a flash alignment (8 bytes).
-    while buf.len() % 8 != 0 {
-        buf.push(0xFF);
+    while b_tlv.len() % 8 != 0 {
+        //FIXME: should be erase_val?
+        b_tlv.push(0xFF);
     }
 
-    flash.write(offset, &buf).unwrap();
-    let offset = offset + buf.len();
+    let mut buf = vec![];
+    buf.append(&mut b_header.to_vec());
+    buf.append(&mut b_img);
+    buf.append(&mut b_tlv.clone());
 
-    // Copy out the image so that we can verify that the image was installed correctly later.
-    let mut copy = vec![0u8; offset - offset0];
-    flash.read(offset0, &mut copy).unwrap();
+    let mut encbuf = vec![];
+    if is_encrypted {
+        encbuf.append(&mut b_header.to_vec());
+        encbuf.append(&mut b_encimg);
+        encbuf.append(&mut b_tlv);
+    }
 
-    copy
+    let result: [Option<Vec<u8>>; 2];
+
+    // Since images are always non-encrypted in slot0, we first write an
+    // encrypted image, re-read to use for verification, erase + flash
+    // un-encrypted. In slot1 the image is written un-encrypted, and if
+    // encryption is requested, it follows an erase + flash encrypted.
+
+    if slot == 0 {
+        let enc_copy: Option<Vec<u8>>;
+
+        if is_encrypted {
+            flash.write(offset, &encbuf).unwrap();
+
+            let mut enc = vec![0u8; encbuf.len()];
+            flash.read(offset, &mut enc).unwrap();
+
+            enc_copy = Some(enc);
+
+            flash.erase(offset, slot_len).unwrap();
+        } else {
+            enc_copy = None;
+        }
+
+        flash.write(offset, &buf).unwrap();
+
+        let mut copy = vec![0u8; buf.len()];
+        flash.read(offset, &mut copy).unwrap();
+
+        result = [Some(copy), enc_copy];
+    } else {
+        flash.write(offset, &buf).unwrap();
+
+        let mut copy = vec![0u8; buf.len()];
+        flash.read(offset, &mut copy).unwrap();
+
+        let enc_copy: Option<Vec<u8>>;
+
+        if is_encrypted {
+            flash.erase(offset, slot_len).unwrap();
+
+            flash.write(offset, &encbuf).unwrap();
+
+            let mut enc = vec![0u8; encbuf.len()];
+            flash.read(offset, &mut enc).unwrap();
+
+            enc_copy = Some(enc);
+        } else {
+            enc_copy = None;
+        }
+
+        result = [Some(copy), enc_copy];
+    }
+
+    result
 }
 
 // The TLV in use depends on what kind of signature we are verifying.
@@ -1059,21 +1146,64 @@
     TlvGen::new_ecdsa()
 }
 
+#[cfg(feature = "enc-rsa")]
+fn make_tlv() -> TlvGen {
+    TlvGen::new_enc_rsa()
+}
+
+#[cfg(feature = "enc-kw")]
+fn make_tlv() -> TlvGen {
+    TlvGen::new_enc_kw()
+}
+
 #[cfg(not(feature = "sig-rsa"))]
 #[cfg(not(feature = "sig-ecdsa"))]
+#[cfg(not(feature = "enc-rsa"))]
+#[cfg(not(feature = "enc-kw"))]
 fn make_tlv() -> TlvGen {
     TlvGen::new_hash_only()
 }
 
+#[cfg(feature = "enc-rsa")]
+fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
+    match &images[slot] {
+        Some(image) => return image,
+        None => panic!("Invalid image"),
+    }
+}
+
+#[cfg(feature = "enc-kw")]
+fn find_image(images: &[Option<Vec<u8>>; 2], slot: usize) -> &Vec<u8> {
+    match &images[slot] {
+        Some(image) => return image,
+        None => panic!("Invalid image"),
+    }
+}
+
+#[cfg(not(feature = "enc-rsa"))]
+#[cfg(not(feature = "enc-kw"))]
+fn find_image(images: &[Option<Vec<u8>>; 2], _slot: usize) -> &Vec<u8> {
+    match &images[0] {
+        Some(image) => return image,
+        None => panic!("Invalid image"),
+    }
+}
+
 /// Verify that given image is present in the flash at the given offset.
-fn verify_image(flash: &Flash, offset: usize, buf: &[u8]) -> bool {
+fn verify_image(flash: &Flash, slots: &[SlotInfo], slot: usize,
+                images: &[Option<Vec<u8>>; 2]) -> bool {
+    let image = find_image(images, slot);
+    let buf = image.as_slice();
+
     let mut copy = vec![0u8; buf.len()];
+    let offset = slots[slot].base_off;
     flash.read(offset, &mut copy).unwrap();
 
     if buf != &copy[..] {
         for i in 0 .. buf.len() {
             if buf[i] != copy[i] {
-                info!("First failure at {:#x}", offset + i);
+                info!("First failure for slot{} at {:#x} {:#x}!={:#x}",
+                      slot, offset + i, buf[i], copy[i]);
                 break;
             }
         }
@@ -1153,15 +1283,13 @@
 #[repr(C)]
 pub struct ImageHeader {
     magic: u32,
-    tlv_size: u16,
-    key_id: u8,
-    _pad1: u8,
+    load_addr: u32,
     hdr_size: u16,
-    _pad2: u16,
+    _pad1: u16,
     img_size: u32,
     flags: u32,
     ver: ImageVersion,
-    _pad3: u32,
+    _pad2: u32,
 }
 
 impl AsRaw for ImageHeader {}
@@ -1178,15 +1306,15 @@
 struct SlotInfo {
     base_off: usize,
     trailer_off: usize,
+    len: usize,
 }
 
 pub struct Images {
     flash: SimFlash,
     areadesc: AreaDesc,
-    slot0: SlotInfo,
-    slot1: SlotInfo,
-    primary: Vec<u8>,
-    upgrade: Vec<u8>,
+    slots: [SlotInfo; 2],
+    primaries: [Option<Vec<u8>>; 2],
+    upgrades: [Option<Vec<u8>>; 2],
     total_count: Option<i32>,
     align: u8,
     erased_val: u8,
diff --git a/sim/src/tlv.rs b/sim/src/tlv.rs
index 79e89fd..7878dd2 100644
--- a/sim/src/tlv.rs
+++ b/sim/src/tlv.rs
@@ -10,6 +10,7 @@
 
 use std::sync::Arc;
 use pem;
+use base64;
 use ring::{digest, rand, signature};
 use untrusted;
 use mcuboot_sys::c;
@@ -23,6 +24,16 @@
     RSA2048 = 0x20,
     ECDSA224 = 0x21,
     ECDSA256 = 0x22,
+    ENCRSA2048 = 0x30,
+    ENCKW128 = 0x31,
+}
+
+#[allow(dead_code, non_camel_case_types)]
+pub enum TlvFlags {
+    PIC = 0x01,
+    NON_BOOTABLE = 0x02,
+    ENCRYPTED = 0x04,
+    RAM_LOAD = 0x20,
 }
 
 pub struct TlvGen {
@@ -32,6 +43,8 @@
     payload: Vec<u8>,
 }
 
+pub const AES_SEC_KEY: &[u8; 16] = b"0123456789ABCDEF";
+
 impl TlvGen {
     /// Construct a new tlv generator that will only contain a hash of the data.
     #[allow(dead_code)]
@@ -64,6 +77,26 @@
         }
     }
 
+    #[allow(dead_code)]
+    pub fn new_enc_rsa() -> TlvGen {
+        TlvGen {
+            flags: TlvFlags::ENCRYPTED as u32,
+            kinds: vec![TlvKinds::SHA256, TlvKinds::ENCRSA2048],
+            size: 4 + 32 + 4 + 256,
+            payload: vec![],
+        }
+    }
+
+    #[allow(dead_code)]
+    pub fn new_enc_kw() -> TlvGen {
+        TlvGen {
+            flags: TlvFlags::ENCRYPTED as u32,
+            kinds: vec![TlvKinds::SHA256, TlvKinds::ENCKW128],
+            size: 4 + 32 + 4 + 24,
+            payload: vec![],
+        }
+    }
+
     /// Retrieve the header flags for this configuration.  This can be called at any time.
     pub fn get_flags(&self) -> u32 {
         self.flags
@@ -212,6 +245,41 @@
             result.extend(der);
         }
 
+        if self.kinds.contains(&TlvKinds::ENCRSA2048) {
+            let key_bytes = pem::parse(include_bytes!("../../enc-rsa2048-pub.pem")
+                                       .as_ref()).unwrap();
+            assert_eq!(key_bytes.tag, "PUBLIC KEY");
+
+            let encbuf = match c::rsa_oaep_encrypt(&key_bytes.contents, AES_SEC_KEY) {
+                Ok(v) => v,
+                Err(_) => panic!("Failed to encrypt secret key"),
+            };
+
+            assert!(encbuf.len() == 256);
+            result.push(TlvKinds::ENCRSA2048 as u8);
+            result.push(0);
+            result.push(0);
+            result.push(1);
+            result.extend_from_slice(&encbuf);
+        }
+
+        if self.kinds.contains(&TlvKinds::ENCKW128) {
+            let key_bytes = base64::decode(
+                include_str!("../../enc-aes128kw.b64").trim()).unwrap();
+
+            let encbuf = match c::kw_encrypt(&key_bytes, AES_SEC_KEY) {
+                Ok(v) => v,
+                Err(_) => panic!("Failed to encrypt secret key"),
+            };
+
+            assert!(encbuf.len() == 24);
+            result.push(TlvKinds::ENCKW128 as u8);
+            result.push(0);
+            result.push(24);
+            result.push(0);
+            result.extend_from_slice(&encbuf);
+        }
+
         result
     }
 }