[PATCH 3/9] boot: image: add FIT decrypt-to-buffer helper
James Hilliard
james.hilliard1 at gmail.com
Thu Jul 2 03:46:53 CEST 2026
FIT cipher support currently allocates the output buffer inside the AES
helper. SPL often needs to decrypt directly into a caller-selected buffer,
for example a load buffer or a scratch buffer used before decompression.
Add a decrypt_to callback to the FIT cipher algorithm and wire it up for
AES. The existing allocating decrypt path becomes a wrapper around the new
helper.
When DM_AES is enabled, try the first UCLASS_AES provider before using the
software AES fallback in U-Boot proper. Return AES device errors to the
caller instead of hiding them with a software fallback after the device has
accepted the operation.
Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
boot/image-cipher.c | 38 +++++++++++++++--
boot/image-fit.c | 7 +++-
include/image.h | 39 +++++++++++++++--
include/u-boot/aes.h | 10 +++++
lib/Makefile | 2 +-
lib/aes/aes-decrypt.c | 98 ++++++++++++++++++++++++++++++++++++-------
6 files changed, 170 insertions(+), 24 deletions(-)
diff --git a/boot/image-cipher.c b/boot/image-cipher.c
index 9d389f26cea..93b3dd3c637 100644
--- a/boot/image-cipher.c
+++ b/boot/image-cipher.c
@@ -25,6 +25,7 @@ struct cipher_algo cipher_algos[] = {
#endif
.encrypt = image_aes_encrypt,
.decrypt = image_aes_decrypt,
+ .decrypt_to = image_aes_decrypt_to,
.add_cipher_data = image_aes_add_cipher_data
},
{
@@ -36,6 +37,7 @@ struct cipher_algo cipher_algos[] = {
#endif
.encrypt = image_aes_encrypt,
.decrypt = image_aes_decrypt,
+ .decrypt_to = image_aes_decrypt_to,
.add_cipher_data = image_aes_add_cipher_data
},
{
@@ -47,6 +49,7 @@ struct cipher_algo cipher_algos[] = {
#endif
.encrypt = image_aes_encrypt,
.decrypt = image_aes_decrypt,
+ .decrypt_to = image_aes_decrypt_to,
.add_cipher_data = image_aes_add_cipher_data
}
};
@@ -70,6 +73,7 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info,
int cipher_noffset)
{
const void *fdt = gd_fdt_blob();
+ int key_len, iv_len;
const char *node_name;
char node_path[128];
int noffset;
@@ -94,7 +98,7 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info,
return -1;
}
- info->iv = fdt_getprop(fit, cipher_noffset, "iv", NULL);
+ info->iv = fdt_getprop(fit, cipher_noffset, "iv", &iv_len);
info->ivname = fdt_getprop(fit, cipher_noffset, "iv-name-hint", NULL);
if (!info->iv && !info->ivname) {
@@ -136,20 +140,28 @@ static int fit_image_setup_decrypt(struct image_cipher_info *info,
}
/* read key */
- info->key = fdt_getprop(fdt, noffset, "key", NULL);
+ info->key = fdt_getprop(fdt, noffset, "key", &key_len);
if (!info->key) {
printf("Can't get key in cipher node '%s'\n", node_path);
return -1;
}
+ if (key_len != info->cipher->key_len) {
+ printf("Bad key length in cipher node '%s'\n", node_path);
+ return -1;
+ }
/* read iv */
if (!info->iv) {
- info->iv = fdt_getprop(fdt, noffset, "iv", NULL);
+ info->iv = fdt_getprop(fdt, noffset, "iv", &iv_len);
if (!info->iv) {
printf("Can't get IV in cipher node '%s'\n", node_path);
return -1;
}
}
+ if (iv_len != info->cipher->iv_len) {
+ printf("Bad IV length for cipher in image '%s'\n", node_name);
+ return -1;
+ }
return 0;
}
@@ -173,3 +185,23 @@ int fit_image_decrypt_data(const void *fit,
out:
return ret;
}
+
+int fit_image_decrypt_data_to(const void *fit,
+ int image_noffset, int cipher_noffset,
+ const void *data_ciphered, size_t size_ciphered,
+ void *data_unciphered, size_t *size_unciphered)
+{
+ struct image_cipher_info info;
+ int ret;
+
+ ret = fit_image_setup_decrypt(&info, fit, image_noffset,
+ cipher_noffset);
+ if (ret < 0)
+ return ret;
+
+ if (!info.cipher->decrypt_to)
+ return -ENOSYS;
+
+ return info.cipher->decrypt_to(&info, data_ciphered, size_ciphered,
+ data_unciphered, size_unciphered);
+}
diff --git a/boot/image-fit.c b/boot/image-fit.c
index 044a40e1910..dac8b35f338 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -1030,7 +1030,7 @@ int fit_image_get_data_size(const void *fit, int noffset, int *data_size)
*
* @fit: pointer to the FIT image header
* @noffset: component image node offset
- * @data_size: holds the data-size property
+ * @data_size: holds the data-size-unciphered property
*
* returns:
* 0, on success
@@ -1040,10 +1040,13 @@ int fit_image_get_data_size_unciphered(const void *fit, int noffset,
size_t *data_size)
{
const fdt32_t *val;
+ int len;
- val = fdt_getprop(fit, noffset, "data-size-unciphered", NULL);
+ val = fdt_getprop(fit, noffset, "data-size-unciphered", &len);
if (!val)
return -ENOENT;
+ if (len != sizeof(*val))
+ return -EINVAL;
*data_size = (size_t)fdt32_to_cpu(*val);
diff --git a/include/image.h b/include/image.h
index 9c8a746d576..5edbf8fdc33 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1862,11 +1862,40 @@ int fit_image_check_sig(const void *fit, int noffset, const void *data,
size_t size, const void *key_blob, int required_keynode,
char **err_msgp);
-int fit_image_decrypt_data(const void *fit,
- int image_noffset, int cipher_noffset,
- const void *data, size_t size,
+/**
+ * fit_image_decrypt_data() - Decrypt a FIT image payload
+ *
+ * @fit: FIT image
+ * @image_noffset: Offset of the image node to decrypt
+ * @cipher_noffset: Offset of the cipher node for the image
+ * @data: Encrypted image payload
+ * @size: Size of encrypted image payload
+ * @data_unciphered: Returns allocated decrypted payload
+ * @size_unciphered: Returns size of decrypted payload
+ * Return: 0 on success, <0 on error
+ */
+int fit_image_decrypt_data(const void *fit, int image_noffset,
+ int cipher_noffset, const void *data, size_t size,
void **data_unciphered, size_t *size_unciphered);
+/**
+ * fit_image_decrypt_data_to() - Decrypt a FIT image payload to a buffer
+ *
+ * @fit: FIT image
+ * @image_noffset: Offset of the image node to decrypt
+ * @cipher_noffset: Offset of the cipher node for the image
+ * @data: Encrypted image payload
+ * @size: Size of encrypted image payload
+ * @data_unciphered: Destination buffer for decrypted payload. The caller
+ * must provide at least @size bytes.
+ * @size_unciphered: Returns size of decrypted payload
+ * Return: 0 on success, <0 on error
+ */
+int fit_image_decrypt_data_to(const void *fit,
+ int image_noffset, int cipher_noffset,
+ const void *data, size_t size,
+ void *data_unciphered, size_t *size_unciphered);
+
/**
* fit_region_make_list() - Make a list of regions to hash
*
@@ -1960,6 +1989,10 @@ struct cipher_algo {
int (*decrypt)(struct image_cipher_info *info,
const void *cipher, size_t cipher_len,
void **data, size_t *data_len);
+
+ int (*decrypt_to)(struct image_cipher_info *info,
+ const void *cipher, size_t cipher_len,
+ void *data, size_t *data_len);
};
int fit_image_cipher_get_algo(const void *fit, int noffset, char **algo);
diff --git a/include/u-boot/aes.h b/include/u-boot/aes.h
index acbc50b9e6f..6d81af3780d 100644
--- a/include/u-boot/aes.h
+++ b/include/u-boot/aes.h
@@ -34,6 +34,9 @@ int image_aes_add_cipher_data(struct image_cipher_info *info, void *keydest,
int image_aes_decrypt(struct image_cipher_info *info,
const void *cipher, size_t cipher_len,
void **data, size_t *size);
+int image_aes_decrypt_to(struct image_cipher_info *info,
+ const void *cipher, size_t cipher_len,
+ void *data, size_t *size);
#else
int image_aes_decrypt(struct image_cipher_info *info,
const void *cipher, size_t cipher_len,
@@ -41,6 +44,13 @@ int image_aes_decrypt(struct image_cipher_info *info,
{
return -ENXIO;
}
+
+int image_aes_decrypt_to(struct image_cipher_info *info,
+ const void *cipher, size_t cipher_len,
+ void *data, size_t *size)
+{
+ return -ENXIO;
+}
#endif /* IMAGE_ENABLE_DECRYPT */
#endif
diff --git a/lib/Makefile b/lib/Makefile
index d0ffabc2b47..c69a928e6d8 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_ARCH_AT91) += at91/
obj-$(CONFIG_OPTEE_LIB) += optee/
obj-$(CONFIG_AES) += aes.o
-obj-$(CONFIG_AES) += aes/
obj-$(CONFIG_$(PHASE_)BINMAN_FDT) += binman.o
obj-$(CONFIG_FW_LOADER) += fw_loader.o
@@ -88,6 +87,7 @@ obj-$(CONFIG_$(PHASE_)ASN1_DECODER_LEGACY) += asn1_decoder.o
obj-$(CONFIG_$(PHASE_)ZLIB) += zlib/
obj-$(CONFIG_$(PHASE_)ZSTD) += zstd/
+obj-$(CONFIG_$(PHASE_)FIT_CIPHER) += aes/
obj-$(CONFIG_$(PHASE_)GZIP) += gunzip.o
obj-$(CONFIG_$(PHASE_)LZO) += lzo/
obj-$(CONFIG_$(PHASE_)LZMA) += lzma/
diff --git a/lib/aes/aes-decrypt.c b/lib/aes/aes-decrypt.c
index 741102a4723..84e7a5bf3e5 100644
--- a/lib/aes/aes-decrypt.c
+++ b/lib/aes/aes-decrypt.c
@@ -4,37 +4,105 @@
*/
#ifndef USE_HOSTCC
+#include <dm.h>
#include <malloc.h>
#endif
#include <image.h>
#include <uboot_aes.h>
+#ifndef USE_HOSTCC
+static int image_aes_validate_lengths(struct image_cipher_info *info,
+ size_t cipher_len)
+{
+ if (!cipher_len || cipher_len % AES_BLOCK_LENGTH ||
+ info->size_unciphered > cipher_len)
+ return -EINVAL;
+
+ return 0;
+}
+#endif
+
+int image_aes_decrypt_to(struct image_cipher_info *info,
+ const void *cipher, size_t cipher_len,
+ void *data, size_t *size)
+{
+#ifndef USE_HOSTCC
+ unsigned int aes_blocks, key_len = info->cipher->key_len;
+ int ret = -ENOSYS;
+
+ ret = image_aes_validate_lengths(info, cipher_len);
+ if (ret)
+ return ret;
+
+ *size = info->size_unciphered;
+
+ if (CONFIG_IS_ENABLED(DM_AES)) {
+ struct udevice *dev;
+
+ ret = uclass_first_device_err(UCLASS_AES, &dev);
+ if (!ret) {
+ ret = dm_aes_set_key_for_key_slot(dev, key_len * 8,
+ (u8 *)info->key, 0);
+ if (ret)
+ return ret;
+
+ ret = dm_aes_select_key_slot(dev, key_len * 8, 0);
+ if (ret)
+ return ret;
+
+ aes_blocks = cipher_len / AES_BLOCK_LENGTH;
+
+ return dm_aes_cbc_decrypt(dev, (u8 *)info->iv,
+ (u8 *)cipher, data,
+ aes_blocks);
+ }
+ }
+
+ if (!IS_ENABLED(CONFIG_XPL_BUILD)) {
+ unsigned char key_exp[AES256_EXPAND_KEY_LENGTH];
+
+ /* First we expand the key. */
+ aes_expand_key((u8 *)info->key, key_len, key_exp);
+
+ /* Calculate the number of AES blocks to decrypt. */
+ aes_blocks = cipher_len / AES_BLOCK_LENGTH;
+
+ aes_cbc_decrypt_blocks(key_len, key_exp, (u8 *)info->iv,
+ (u8 *)cipher, data, aes_blocks);
+ return 0;
+ }
+
+ return ret;
+#endif
+
+ return 0;
+}
+
int image_aes_decrypt(struct image_cipher_info *info,
const void *cipher, size_t cipher_len,
void **data, size_t *size)
{
-#ifndef USE_HOSTCC
- unsigned char key_exp[AES256_EXPAND_KEY_LENGTH];
- unsigned int aes_blocks, key_len = info->cipher->key_len;
+#ifdef USE_HOSTCC
+ return 0;
+#else
+ int ret;
+
+ ret = image_aes_validate_lengths(info, cipher_len);
+ if (ret)
+ return ret;
*data = malloc(cipher_len);
if (!*data) {
printf("Can't allocate memory to decrypt\n");
return -ENOMEM;
}
- *size = info->size_unciphered;
- memcpy(&key_exp[0], info->key, key_len);
-
- /* First we expand the key. */
- aes_expand_key((u8 *)info->key, key_len, key_exp);
-
- /* Calculate the number of AES blocks to encrypt. */
- aes_blocks = DIV_ROUND_UP(cipher_len, AES_BLOCK_LENGTH);
+ ret = image_aes_decrypt_to(info, cipher, cipher_len, *data, size);
+ if (ret) {
+ free(*data);
+ *data = NULL;
+ }
- aes_cbc_decrypt_blocks(key_len, key_exp, (u8 *)info->iv,
- (u8 *)cipher, *data, aes_blocks);
+ return ret;
#endif
-
- return 0;
}
--
2.53.0
More information about the U-Boot
mailing list