Skip to content

Commit 0f64197

Browse files
salomethirot-armutzig
authored andcommitted
boot: Add AES256 support for image encryption
Support only works when using mbedtls as the cryptographic library. Signed-off-by: Salome Thirot <salome.thirot@arm.com>
1 parent 9b97456 commit 0f64197

File tree

14 files changed

+95
-56
lines changed

14 files changed

+95
-56
lines changed

NOTICE

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ Portions of this software were developed at
88
Runtime Inc, copyright 2015.
99

1010
Portions of this software were developed at
11-
Arm Limited, copyright 2019-2020.
11+
Arm Limited, copyright 2019-2021.

boot/bootutil/include/bootutil/caps.h

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*
22
* Copyright (c) 2017 Linaro Limited
3+
* Copyright (c) 2021 Arm Limited
34
*
45
* Licensed under the Apache License, Version 2.0 (the "License");
56
* you may not use this file except in compliance with the License.
@@ -47,6 +48,7 @@ uint32_t bootutil_get_caps(void);
4748
#define BOOTUTIL_CAP_DOWNGRADE_PREVENTION (1<<12)
4849
#define BOOTUTIL_CAP_ENC_X25519 (1<<13)
4950
#define BOOTUTIL_CAP_BOOTSTRAP (1<<14)
51+
#define BOOTUTIL_CAP_AES256 (1<<15)
5052

5153
/*
5254
* Query the number of images this bootloader is configured for. This

boot/bootutil/include/bootutil/crypto/aes_ctr.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,15 @@
2121

2222
#if defined(MCUBOOT_USE_MBED_TLS)
2323
#include <mbedtls/aes.h>
24-
#define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE (16)
24+
#include "bootutil/enc_key_public.h"
25+
#define BOOTUTIL_CRYPTO_AES_CTR_KEY_SIZE BOOT_ENC_KEY_SIZE
2526
#define BOOTUTIL_CRYPTO_AES_CTR_BLOCK_SIZE (16)
2627
#endif /* MCUBOOT_USE_MBED_TLS */
2728

2829
#if defined(MCUBOOT_USE_TINYCRYPT)
30+
#if defined(MCUBOOT_AES_256)
31+
#error "Cannot use AES-256 for encryption with Tinycrypt library."
32+
#endif
2933
#include <string.h>
3034
#include <tinycrypt/aes.h>
3135
#include <tinycrypt/ctr_mode.h>

boot/bootutil/include/bootutil/crypto/aes_kw.h

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#endif /* MCUBOOT_USE_MBED_TLS */
2424

2525
#if defined(MCUBOOT_USE_TINYCRYPT)
26+
#if defined(MCUBOOT_AES_256)
27+
#error "Cannot use AES-256 for encryption with Tinycrypt library."
28+
#endif
2629
#include <tinycrypt/aes.h>
2730
#include <tinycrypt/constants.h>
2831
#endif /* MCUBOOT_USE_TINYCRYPT */

boot/bootutil/include/bootutil/enc_key_public.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* SPDX-License-Identifier: Apache-2.0
33
*
44
* Copyright (c) 2018-2019 JUUL Labs
5-
* Copyright (c) 2019 Arm Limited
5+
* Copyright (c) 2019-2021 Arm Limited
66
* Copyright (c) 2021 Nordic Semiconductor ASA
77
*
88
* Original license:
@@ -32,12 +32,16 @@
3232
extern "C" {
3333
#endif
3434

35+
#ifdef MCUBOOT_AES_256
36+
#define BOOT_ENC_KEY_SIZE 32
37+
#else
3538
#define BOOT_ENC_KEY_SIZE 16
39+
#endif
3640

3741
#define TLV_ENC_RSA_SZ 256
38-
#define TLV_ENC_KW_SZ 24
39-
#define TLV_ENC_EC256_SZ (65 + 32 + 16)
40-
#define TLV_ENC_X25519_SZ (32 + 32 + 16)
42+
#define TLV_ENC_KW_SZ BOOT_ENC_KEY_SIZE + 8
43+
#define TLV_ENC_EC256_SZ (65 + 32 + BOOT_ENC_KEY_SIZE)
44+
#define TLV_ENC_X25519_SZ (32 + 32 + BOOT_ENC_KEY_SIZE)
4145

4246
#if defined(MCUBOOT_ENCRYPT_RSA)
4347
#define BOOT_ENC_TLV_SIZE TLV_ENC_RSA_SZ
@@ -53,4 +57,4 @@ extern "C" {
5357
}
5458
#endif
5559

56-
#endif /* BOOTUTIL_ENC_KEY_PUBLIC_H */
60+
#endif /* BOOTUTIL_ENC_KEY_PUBLIC_H */

boot/bootutil/include/bootutil/image.h

+6-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright (c) 2016-2019 Linaro LTD
55
* Copyright (c) 2016-2019 JUUL Labs
6-
* Copyright (c) 2019-2020 Arm Limited
6+
* Copyright (c) 2019-2021 Arm Limited
77
*
88
* Original license:
99
*
@@ -50,7 +50,8 @@ struct flash_area;
5050
* Image header flags.
5151
*/
5252
#define IMAGE_F_PIC 0x00000001 /* Not supported. */
53-
#define IMAGE_F_ENCRYPTED 0x00000004 /* Encrypted. */
53+
#define IMAGE_F_ENCRYPTED_AES128 0x00000004 /* Encrypted using AES128. */
54+
#define IMAGE_F_ENCRYPTED_AES256 0x00000008 /* Encrypted using AES256. */
5455
#define IMAGE_F_NON_BOOTABLE 0x00000010 /* Split image app. */
5556
/*
5657
* Indicates that this image should be loaded into RAM instead of run
@@ -89,7 +90,7 @@ struct flash_area;
8990
#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */
9091
#define IMAGE_TLV_ED25519 0x24 /* ed25519 of hash output */
9192
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
92-
#define IMAGE_TLV_ENC_KW128 0x31 /* Key encrypted with AES-KW-128 */
93+
#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW 128 or 256*/
9394
#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-EC256 */
9495
#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */
9596
#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */
@@ -148,7 +149,8 @@ struct image_tlv {
148149
uint16_t it_len; /* Data length (not including TLV header). */
149150
};
150151

151-
#define IS_ENCRYPTED(hdr) ((hdr)->ih_flags & IMAGE_F_ENCRYPTED)
152+
#define IS_ENCRYPTED(hdr) (((hdr)->ih_flags && IMAGE_F_ENCRYPTED_AES128) \
153+
|| ((hdr)->ih_flags && IMAGE_F_ENCRYPTED_AES256))
152154
#define MUST_DECRYPT(fap, idx, hdr) \
153155
((fap)->fa_id == FLASH_AREA_IMAGE_SECONDARY(idx) && IS_ENCRYPTED(hdr))
154156

boot/bootutil/src/caps.c

+4
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* SPDX-License-Identifier: Apache-2.0
33
*
44
* Copyright (c) 2017 Linaro Limited
5+
* Copyright (c) 2021 Arm Limited
56
*
67
* Licensed under the Apache License, Version 2.0 (the "License");
78
* you may not use this file except in compliance with the License.
@@ -68,6 +69,9 @@ uint32_t bootutil_get_caps(void)
6869
#if defined(MCUBOOT_BOOTSTRAP)
6970
res |= BOOTUTIL_CAP_BOOTSTRAP;
7071
#endif
72+
#if defined(MCUBOOT_AES_256)
73+
res |= BOOTUTIL_CAP_AES256;
74+
#endif
7175

7276
return res;
7377
}

boot/bootutil/src/encrypted.c

+8-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* SPDX-License-Identifier: Apache-2.0
33
*
44
* Copyright (c) 2018-2019 JUUL Labs
5-
* Copyright (c) 2019 Arm Limited
5+
* Copyright (c) 2019-2021 Arm Limited
66
*/
77

88
#include "mcuboot_config/mcuboot_config.h"
@@ -434,28 +434,28 @@ boot_enc_set_key(struct enc_key_data *enc_state, uint8_t slot,
434434
#if defined(MCUBOOT_ENCRYPT_RSA)
435435
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_RSA2048
436436
#elif defined(MCUBOOT_ENCRYPT_KW)
437-
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW128
437+
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_KW
438438
#elif defined(MCUBOOT_ENCRYPT_EC256)
439439
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_EC256
440440
# define EC_PUBK_INDEX (0)
441441
# define EC_TAG_INDEX (65)
442442
# define EC_CIPHERKEY_INDEX (65 + 32)
443-
_Static_assert(EC_CIPHERKEY_INDEX + 16 == EXPECTED_ENC_LEN,
443+
_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN,
444444
"Please fix ECIES-P256 component indexes");
445445
#elif defined(MCUBOOT_ENCRYPT_X25519)
446446
# define EXPECTED_ENC_TLV IMAGE_TLV_ENC_X25519
447447
# define EC_PUBK_INDEX (0)
448448
# define EC_TAG_INDEX (32)
449449
# define EC_CIPHERKEY_INDEX (32 + 32)
450-
_Static_assert(EC_CIPHERKEY_INDEX + 16 == EXPECTED_ENC_LEN,
450+
_Static_assert(EC_CIPHERKEY_INDEX + BOOT_ENC_KEY_SIZE == EXPECTED_ENC_LEN,
451451
"Please fix ECIES-X25519 component indexes");
452452
#endif
453453

454454
/*
455455
* Decrypt an encryption key TLV.
456456
*
457457
* @param buf An encryption TLV read from flash (build time fixed length)
458-
* @param enckey An AES-128 key sized buffer to store to plain key.
458+
* @param enckey An AES-128 or AES-256 key sized buffer to store to plain key.
459459
*/
460460
int
461461
boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey)
@@ -507,7 +507,7 @@ boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey)
507507

508508
#if defined(MCUBOOT_ENCRYPT_KW)
509509

510-
assert(*bootutil_enc_key.len == 16);
510+
assert(*bootutil_enc_key.len == BOOT_ENC_KEY_SIZE);
511511
rc = key_unwrap(buf, enckey);
512512

513513
#endif /* defined(MCUBOOT_ENCRYPT_KW) */
@@ -586,13 +586,13 @@ boot_enc_decrypt(const uint8_t *buf, uint8_t *enckey)
586586

587587
bootutil_hmac_sha256_init(&hmac);
588588

589-
rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[16], 32);
589+
rc = bootutil_hmac_sha256_set_key(&hmac, &derived_key[BOOT_ENC_KEY_SIZE], 32);
590590
if (rc != 0) {
591591
(void)bootutil_hmac_sha256_drop(&hmac);
592592
return -1;
593593
}
594594

595-
rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], 16);
595+
rc = bootutil_hmac_sha256_update(&hmac, &buf[EC_CIPHERKEY_INDEX], BOOT_ENC_KEY_SIZE);
596596
if (rc != 0) {
597597
(void)bootutil_hmac_sha256_drop(&hmac);
598598
return -1;

docs/design.md

+6-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
44
- Copyright (c) 2017-2020 Linaro LTD
55
- Copyright (c) 2017-2019 JUUL Labs
6-
- Copyright (c) 2019-2020 Arm Limited
6+
- Copyright (c) 2019-2021 Arm Limited
77
88
- Original license:
99
@@ -96,6 +96,8 @@ struct image_tlv {
9696
* Image header flags.
9797
*/
9898
#define IMAGE_F_PIC 0x00000001 /* Not supported. */
99+
#define IMAGE_F_ENCRYPTED_AES128 0x00000004 /* Encrypted using AES128. */
100+
#define IMAGE_F_ENCRYPTED_AES256 0x00000008 /* Encrypted using AES256. */
99101
#define IMAGE_F_NON_BOOTABLE 0x00000010 /* Split image app. */
100102
#define IMAGE_F_RAM_LOAD 0x00000020
101103

@@ -110,7 +112,8 @@ struct image_tlv {
110112
#define IMAGE_TLV_RSA3072_PSS 0x23 /* RSA3072 of hash output */
111113
#define IMAGE_TLV_ED25519 0x24 /* ED25519 of hash output */
112114
#define IMAGE_TLV_ENC_RSA2048 0x30 /* Key encrypted with RSA-OAEP-2048 */
113-
#define IMAGE_TLV_ENC_KW128 0x31 /* Key encrypted with AES-KW-128 */
115+
#define IMAGE_TLV_ENC_KW 0x31 /* Key encrypted with AES-KW-128 or
116+
256 */
114117
#define IMAGE_TLV_ENC_EC256 0x32 /* Key encrypted with ECIES-P256 */
115118
#define IMAGE_TLV_ENC_X25519 0x33 /* Key encrypted with ECIES-X25519 */
116119
#define IMAGE_TLV_DEPENDENCY 0x40 /* Image depends on other image */
@@ -1285,4 +1288,4 @@ done:
12851288
the shell returns, and it is possible to investigate the results. It is also
12861289
possible to stop the test with _Ctrl+c_. The parameters to the
12871290
`execute_test.sh` are `SKIP_SIZE`, `BUILD_TYPE`, `DAMAGE_TYPE`, `FIH_LEVEL` in
1288-
order.
1291+
order.

docs/encrypted_images.md

+17-15
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ applied over the un-encrypted data. Validation on encrypted images, checks
5959
that the encrypted flag is set and TLV data is OK, then it decrypts each
6060
image block before sending the data to the hash routines.
6161

62-
The image is encrypted using AES-CTR-128, with a counter that starts
63-
from zero (over the payload blocks) and increments by 1 for each 16-byte
64-
block. AES-CTR-128 was chosen for speed/simplicity and allowing for any
62+
The image is encrypted using AES-CTR-128 or AES-CTR-256, with a counter
63+
that starts from zero (over the payload blocks) and increments by 1 for each
64+
16-byte block. AES-CTR was chosen for speed/simplicity and allowing for any
6565
block to be encrypted/decrypted without requiring knowledge of any other
6666
block (allowing for simple resume operations on swap interruptions).
6767

@@ -70,14 +70,15 @@ The key used is a randomized when creating a new image, by `imgtool` or
7070
but randomizing a 16-byte block with a TRNG should make it highly
7171
improbable that duplicates ever happen.
7272

73-
To distribute this AES-CTR-128 key, new TLVs were defined. The key can be
74-
encrypted using either RSA-OAEP, AES-KW-128, ECIES-P256 or ECIES-X25519.
73+
To distribute this AES-CTR key, new TLVs were defined. The key can be
74+
encrypted using either RSA-OAEP, AES-KW (128 or 256 bits depending on the
75+
AES-CTR key length), ECIES-P256 or ECIES-X25519.
7576

7677
For RSA-OAEP a new TLV with value `0x30` is added to the image, for
77-
AES-KW-128 a new TLV with value `0x31` is added to the image, for
78+
AES-KW a new TLV with value `0x31` is added to the image, for
7879
ECIES-P256 a new TLV with value `0x32` is added, and for ECIES-X25519 a
7980
newt TLV with value `0x33` is added. The contents of those TLVs
80-
are the results of applying the given operations over the AES-CTR-128 key.
81+
are the results of applying the given operations over the AES-CTR key.
8182

8283
## [ECIES encryption](#ecies-encryption)
8384

@@ -94,17 +95,17 @@ libraries. The whole key encryption can be summarized as:
9495
* Derive the new keys from the secret using HKDF (built on HMAC-SHA256). We
9596
are not using a `salt` and using an `info` of `MCUBoot_ECIES_v1`, generating
9697
48 bytes of key material.
97-
* A new random encryption key of 16 bytes is generated (for AES-128). This is
98+
* A new random encryption key is generated (for AES). This is
9899
the AES key used to encrypt the images.
99-
* The key is encrypted with AES-128-CTR and a `nonce` of 0 using the first
100-
16 bytes of key material generated previously by the HKDF.
100+
* The key is encrypted with AES-128-CTR or AES-256-CTR and a `nonce` of 0 using
101+
the first 16 bytes of key material generated previously by the HKDF.
101102
* The encrypted key now goes through a HMAC-SHA256 using the remaining 32
102103
bytes of key material from the HKDF.
103104

104105
The final TLV is built from the 65 bytes for ECIES-P256 or 32 bytes for
105106
ECIES-X25519, which correspond to the ephemeral public key, followed by the
106-
32 bytes of MAC tag and the 16 bytes of the encrypted key, resulting in a TLV
107-
of 113 bytes for ECIES-P256 or 80 bytes for ECIES-X25519.
107+
32 bytes of MAC tag and the 16 or 32 bytes of the encrypted key, resulting in
108+
a TLV of 113 or 129 bytes for ECIES-P256 and 80 or 96 bytes for ECIES-X25519.
108109

109110
The implemenation of ECIES-P256 is named ENC_EC256 in the source code and
110111
artifacts while ECIES-X25519 is named ENC_X25519.
@@ -149,7 +150,7 @@ To extract the public key in source file form, use
149150
`imgtool getpub -k <input.pem> -l <lang>`, where lang can be one of `c` or
150151
`rust` (defaults to `c`).
151152

152-
If using AES-KW-128, follow the steps in the next section to generate the
153+
If using AES-KW, follow the steps in the next section to generate the
153154
required keys.
154155

155156
## [Creating your keys with Unix tooling](#creating-your-keys-with-unix-tooling)
@@ -161,5 +162,6 @@ required keys.
161162
* If using ECIES-X25519, generate a private key passing the option `-t x25519`
162163
to `imgtool keygen` command. To generate public key PEM file the following
163164
command can be used: `openssl pkey -in <generated-private-key.pem> -pubout`
164-
* If using AES-KW-128 (`newt` only), the `kek` can be generated with a
165-
command like `dd if=/dev/urandom bs=1 count=16 | base64 > my_kek.b64`
165+
* If using AES-KW (`newt` only), the `kek` can be generated with a
166+
command like (change count to 32 for a 256 bit key)
167+
`dd if=/dev/urandom bs=1 count=16 | base64 > my_kek.b64`

enc-aes256kw.b64

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
5FxRRtIcgjXMGhmvofKqIMiMf0Bs2yKqarXLqvixW7Q=

scripts/imgtool/image.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Copyright 2018 Nordic Semiconductor ASA
22
# Copyright 2017-2020 Linaro Limited
3-
# Copyright 2019-2020 Arm Limited
3+
# Copyright 2019-2021 Arm Limited
44
#
55
# SPDX-License-Identifier: Apache-2.0
66
#
@@ -51,7 +51,8 @@
5151
# Image header flags.
5252
IMAGE_F = {
5353
'PIC': 0x0000001,
54-
'ENCRYPTED': 0x0000004,
54+
'ENCRYPTED_AES128': 0x0000004,
55+
'ENCRYPTED_AES256': 0x0000008,
5556
'NON_BOOTABLE': 0x0000010,
5657
'RAM_LOAD': 0x0000020,
5758
'ROM_FIXED': 0x0000100,
@@ -67,7 +68,7 @@
6768
'RSA3072': 0x23,
6869
'ED25519': 0x24,
6970
'ENCRSA2048': 0x30,
70-
'ENCKW128': 0x31,
71+
'ENCKW': 0x31,
7172
'ENCEC256': 0x32,
7273
'ENCX25519': 0x33,
7374
'DEPENDENCY': 0x40,
@@ -288,7 +289,7 @@ def ecies_hkdf(self, enckey, plainkey):
288289
return cipherkey, ciphermac, pubk
289290

290291
def create(self, key, public_key_format, enckey, dependencies=None,
291-
sw_type=None, custom_tlvs=None):
292+
sw_type=None, custom_tlvs=None, encrypt_keylen=128):
292293
self.enckey = enckey
293294

294295
# Calculate the hash of the public key
@@ -361,7 +362,10 @@ def create(self, key, public_key_format, enckey, dependencies=None,
361362
self.payload.extend(pad)
362363

363364
# This adds the header to the payload as well
364-
self.add_header(enckey, protected_tlv_size)
365+
if encrypt_keylen == 256:
366+
self.add_header(enckey, protected_tlv_size, 256)
367+
else:
368+
self.add_header(enckey, protected_tlv_size)
365369

366370
prot_tlv = TLV(self.endian, TLV_PROT_INFO_MAGIC)
367371

@@ -429,7 +433,10 @@ def create(self, key, public_key_format, enckey, dependencies=None,
429433
self.payload = self.payload[:protected_tlv_off]
430434

431435
if enckey is not None:
432-
plainkey = os.urandom(16)
436+
if encrypt_keylen == 256:
437+
plainkey = os.urandom(32)
438+
else:
439+
plainkey = os.urandom(16)
433440

434441
if isinstance(enckey, rsa.RSAPublic):
435442
cipherkey = enckey._get_public().encrypt(
@@ -462,12 +469,15 @@ def create(self, key, public_key_format, enckey, dependencies=None,
462469

463470
self.check_trailer()
464471

465-
def add_header(self, enckey, protected_tlv_size):
472+
def add_header(self, enckey, protected_tlv_size, aes_length=128):
466473
"""Install the image header."""
467474

468475
flags = 0
469476
if enckey is not None:
470-
flags |= IMAGE_F['ENCRYPTED']
477+
if aes_length == 128:
478+
flags |= IMAGE_F['ENCRYPTED_AES128']
479+
else:
480+
flags |= IMAGE_F['ENCRYPTED_AES256']
471481
if self.load_addr != 0:
472482
# Indicates that this image should be loaded into RAM
473483
# instead of run directly from flash.

0 commit comments

Comments
 (0)