[PATCH v5 00/16] Add support for asymmetric decryption

64 views
Skip to first unread message

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:15 AM (7 days ago) Sep 4
to swup...@googlegroups.com
Hi everyone,

I’ve just updated the long-pending Asymmetric Decryption feature.
Now that Stefano has finished the crypto rework, there shouldn’t be any
blockers left.

The first few patch files are basically independent of the OpenSSL CMS part and
could already be merged.

Thanks a lot for your feedback and please test it thoroughly.

Best regards,
Michael

Michael Glembotzki (12):
openssl_DECRYPT_init: Fix error message on missing iv
swupdate.c: Abort if no key for encrypted sw-description is provided
swupdate: Add -K / --decryption-key param and decryption-key-file config
parser: Read aes-key from sw-description into struct img_type
Add openssl cms decryption functions for asymmetric decryption
util.h: Propagate cipher and image aes key to copy pipeline
stream_interface.c: Force opensslCMS as crypto lib for sw-description
cpio_utils.c: use per-image AES key / iv from sw-description
decrypt_keys: make ivt dynamically allocated
cpio_utils: handle -EAGAIN and set eof only on success
crypto: store cipher in decryption_key and use default key only if it matches
doc: Add documentation for asymmetric decryption

Stefano Babic (4):
core: don't check for writen output to terminate
crypto: prepare to support multiple cipher
Move accessors for keys in own file
decrypt_keys.c: Store key filename for opensslCMS decryption

core/Makefile | 1 +
core/cpio_utils.c | 34 +++++++++++--
core/crypto.c | 4 +-
core/decrypt_keys.c | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
core/installer.c | 2 +
core/stream_interface.c | 39 ++++++++++-----
core/swupdate.c | 15 ++++--
core/util.c | 134 -------------------------------------------------
crypto/Kconfig | 18 +++++++
crypto/Makefile | 1 +
crypto/swupdate_decrypt_mbedtls.c | 7 ++-
crypto/swupdate_decrypt_openssl.c | 7 ++-
crypto/swupdate_decrypt_openssl_cms.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
crypto/swupdate_decrypt_wolfssl.c | 6 ++-
crypto/swupdate_openssl.h | 3 ++
doc/source/asym_encrypted_images.rst | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
doc/source/encrypted_images.rst | 2 +
doc/source/index.rst | 1 +
doc/source/sw-description.rst | 25 +++++++---
include/swupdate_aes.h | 55 ++++++++++++++++++++
include/swupdate_crypto.h | 5 +-
include/swupdate_image.h | 3 ++
include/util.h | 9 +++-
parser/parser.c | 35 ++++++++++++-
24 files changed, 789 insertions(+), 172 deletions(-)



Michael Glembotzki

unread,
Sep 4, 2025, 7:57:16 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
crypto/swupdate_decrypt_mbedtls.c | 2 +-
crypto/swupdate_decrypt_openssl.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/crypto/swupdate_decrypt_mbedtls.c b/crypto/swupdate_decrypt_mbedtls.c
index ce96966d..c87a2c3d 100644
--- a/crypto/swupdate_decrypt_mbedtls.c
+++ b/crypto/swupdate_decrypt_mbedtls.c
@@ -21,7 +21,7 @@ static void *mbedtls_DECRYPT_init(unsigned char *key, char keylen, unsigned char
int error;

if ((key == NULL) || (iv == NULL)) {
- ERROR("no key provided for decryption!");
+ ERROR("no key or iv provided for decryption!");
return NULL;
}

diff --git a/crypto/swupdate_decrypt_openssl.c b/crypto/swupdate_decrypt_openssl.c
index 6eb933df..3f632d6d 100644
--- a/crypto/swupdate_decrypt_openssl.c
+++ b/crypto/swupdate_decrypt_openssl.c
@@ -29,7 +29,7 @@ static void *openssl_DECRYPT_init(unsigned char *key, char keylen, unsigned char
int ret;

if ((key == NULL) || (iv == NULL)) {
- ERROR("no key provided for decryption!");
+ ERROR("no key or iv provided for decryption!");
return NULL;
}

--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:17 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
core/swupdate.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/core/swupdate.c b/core/swupdate.c
index 4f013945..41e498c8 100644
--- a/core/swupdate.c
+++ b/core/swupdate.c
@@ -109,6 +109,7 @@ static struct option long_options[] = {
#endif
#ifdef CONFIG_ENCRYPTED_IMAGES
{"key-aes", required_argument, NULL, 'K'},
+ {"decryption-key", required_argument, NULL, 'K'},
{"decrypt-provider", required_argument, NULL, '8'},
#endif
#ifdef CONFIG_HASH_VERIFY
@@ -179,8 +180,8 @@ static void usage(char *programname)
#endif
#endif
#ifdef CONFIG_ENCRYPTED_IMAGES
- " -K, --key-aes <key file> : the file contains the symmetric key to be used\n"
- " to decrypt images\n"
+ " -K, --key-aes <key file> : the file contains the decryption key to be used\n"
+ " --decryption-key <key file>: to decrypt images\n"
" -8, --decrypt-provider <string>: the provider used for decryption\n"
#endif
#ifdef CONFIG_HASH_VERIFY
@@ -383,6 +384,8 @@ static int read_globals_settings(void *elem, void *data)
"ca-path", sw->publickeyfname);
GET_FIELD_STRING(LIBCFG_PARSER, elem,
"aes-key-file", sw->aeskeyfname);
+ GET_FIELD_STRING(LIBCFG_PARSER, elem,
+ "decryption-key-file", sw->aeskeyfname);
GET_FIELD_STRING(LIBCFG_PARSER, elem,
"mtd-blacklist", sw->mtdblacklist);
GET_FIELD_STRING(LIBCFG_PARSER, elem,
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:17 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
core/swupdate.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/core/swupdate.c b/core/swupdate.c
index eca29846..4f013945 100644
--- a/core/swupdate.c
+++ b/core/swupdate.c
@@ -1057,7 +1057,13 @@ int main(int argc, char **argv)
* If an AES key is passed, load it to allow
* to decrypt images
*/
- if (strlen(swcfg.aeskeyfname)) {
+ if (!strlen(swcfg.aeskeyfname)) {
+#ifdef CONFIG_ENCRYPTED_SW_DESCRIPTION
+ fprintf(stderr,
+ "Error: Encrypted sw-description expected, but no key provided.\n");
+ exit(EXIT_FAILURE);
+#endif
+ } else {
if (load_decryption_key(swcfg.aeskeyfname)) {
fprintf(stderr,
"Error: Key file does not contain a valid AES key.\n");
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:18 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Stefano Babic
From: Stefano Babic <stefan...@swupdate.org>

commit 9e0bcaad2 and 744def043e are thought to fix the decryption of a
short artifact of one AES block. However, check is done on both input
and output data, but just checking if there are still data in the
incoming buffer is enough. This allows a crypto module to postpone the
decryption and to collect data - some algorithms are not able to work on
stream of data, and they need to have the full crypto message in memory.

Signed-off-by: Stefano Babic <stefan...@swupdate.org>
---
core/cpio_utils.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 30259e27..10a39914 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -312,7 +312,7 @@ static int decrypt_step(void *state, void *buffer, size_t size)
ret = swupdate_DECRYPT_update(s->dcrypt,
s->output, &s->outlen, s->input, inlen);
}
- if (inlen == 0 || s->outlen == 0) {
+ if (inlen == 0) {
/*
* Finalise the decryption. Further plaintext bytes may
* be written at this stage.
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:18 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Stefano Babic
From: Stefano Babic <stefan...@swupdate.org>

This is a preparation to introduce other cipher than aes-cbc.

Signed-off-by: Stefano Babic <stefan...@swupdate.org>
---
core/cpio_utils.c | 2 +-
core/crypto.c | 4 +--
crypto/swupdate_decrypt_mbedtls.c | 5 ++-
crypto/swupdate_decrypt_openssl.c | 5 ++-
crypto/swupdate_decrypt_wolfssl.c | 6 +++-
include/swupdate_aes.h | 54 +++++++++++++++++++++++++++++++
include/swupdate_crypto.h | 5 +--
include/swupdate_image.h | 2 ++
parser/parser.c | 12 +++++--
9 files changed, 85 insertions(+), 10 deletions(-)
create mode 100644 include/swupdate_aes.h

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 10a39914..0768998a 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -617,7 +617,7 @@ int copyfile(struct swupdate_copy *args)
ivt = ivtbuf;
} else
ivt = get_aes_ivt();
- decrypt_state.dcrypt = swupdate_DECRYPT_init(aes_key, get_aes_keylen(), ivt);
+ decrypt_state.dcrypt = swupdate_DECRYPT_init(aes_key, get_aes_keylen(), ivt, AES_CBC);
if (!decrypt_state.dcrypt) {
ERROR("decrypt initialization failure, aborting");
ret = -EFAULT;
diff --git a/core/crypto.c b/core/crypto.c
index b41c477c..62deac9d 100644
--- a/core/crypto.c
+++ b/core/crypto.c
@@ -139,14 +139,14 @@ void print_registered_cryptolib(void)
}
}

-void *swupdate_DECRYPT_init(unsigned char *key, char keylen, unsigned char *iv)
+void *swupdate_DECRYPT_init(unsigned char *key, char keylen, unsigned char *iv, cipher_t cipher)
{
swupdate_decrypt_lib *lib;
if (!get_cryptolib())
return NULL;

lib = (swupdate_decrypt_lib *)current[DECRYPTLIB]->lib;
- return lib->DECRYPT_init(key, keylen, iv);
+ return lib->DECRYPT_init(key, keylen, iv, cipher);
}

int swupdate_DECRYPT_update(void *dgst, unsigned char *buf,
diff --git a/crypto/swupdate_decrypt_mbedtls.c b/crypto/swupdate_decrypt_mbedtls.c
index c87a2c3d..abff9cec 100644
--- a/crypto/swupdate_decrypt_mbedtls.c
+++ b/crypto/swupdate_decrypt_mbedtls.c
@@ -12,7 +12,7 @@

static swupdate_decrypt_lib mbedtls;

-static void *mbedtls_DECRYPT_init(unsigned char *key, char keylen, unsigned char *iv)
+static void *mbedtls_DECRYPT_init(unsigned char *key, char keylen, unsigned char *iv, cipher_t cipher)
{
struct mbedtls_digest *dgst;
mbedtls_cipher_type_t cipher_type;
@@ -20,6 +20,9 @@ static void *mbedtls_DECRYPT_init(unsigned char *key, char keylen, unsigned char
int key_bitlen;
int error;

+ /* Temporary to remove warning */
+ cipher = cipher;
+
if ((key == NULL) || (iv == NULL)) {
ERROR("no key or iv provided for decryption!");
return NULL;
diff --git a/crypto/swupdate_decrypt_openssl.c b/crypto/swupdate_decrypt_openssl.c
index 3f632d6d..e6ea3ffd 100644
--- a/crypto/swupdate_decrypt_openssl.c
+++ b/crypto/swupdate_decrypt_openssl.c
@@ -22,12 +22,15 @@
static void openssl_probe(void);

static swupdate_decrypt_lib openssl;
-static void *openssl_DECRYPT_init(unsigned char *key, char keylen, unsigned char *iv)
+static void *openssl_DECRYPT_init(unsigned char *key, char keylen, unsigned char *iv, cipher_t reqcipher)
{
struct openssl_digest *dgst;
const EVP_CIPHER *cipher;
int ret;

+ /* Temporary to remove warning */
+ reqcipher = reqcipher;
+
if ((key == NULL) || (iv == NULL)) {
ERROR("no key or iv provided for decryption!");
return NULL;
diff --git a/crypto/swupdate_decrypt_wolfssl.c b/crypto/swupdate_decrypt_wolfssl.c
index e63eed02..015fcd3c 100644
--- a/crypto/swupdate_decrypt_wolfssl.c
+++ b/crypto/swupdate_decrypt_wolfssl.c
@@ -26,7 +26,8 @@ static void wolfssl_debug(int __attribute__ ((__unused__)) level, const char *co
#endif

static void *wolfssl_DECRYPT_init(unsigned char *key,
- char __attribute__ ((__unused__)) keylen, unsigned char *iv)
+ char __attribute__ ((__unused__)) keylen, unsigned char *iv,
+ cipher_t cipher)
{
struct wolfssl_digest *dgst;
const char *library;
@@ -43,6 +44,9 @@ static void *wolfssl_DECRYPT_init(unsigned char *key,
return NULL;
}

+ /* Temporary to remove warning */
+ cipher = cipher;
+
dgst = calloc(1, sizeof(*dgst));
if (!dgst) {
return NULL;
diff --git a/include/swupdate_aes.h b/include/swupdate_aes.h
new file mode 100644
index 00000000..acb69573
--- /dev/null
+++ b/include/swupdate_aes.h
@@ -0,0 +1,54 @@
+/*
+ * (C) Copyright 2025
+ * Stefano Babic, stefan...@swupdate.org.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#pragma once
+#include <stdbool.h>
+#include <string.h>
+
+/*
+ * Add global definitions to set the cipher.
+ * Each implementation must map the generic enum
+ * to the library specific code
+ */
+
+typedef enum {
+ AES_CBC,
+ AES_CBC_128,
+ AES_CBC_192,
+ AES_CBC_256,
+ AES_CTR,
+ AES_CTR_128,
+ AES_CTR_192,
+ AES_CTR_256,
+ AES_UNKNOWN
+} cipher_t;
+
+typedef struct {
+ cipher_t cipher;
+ const char *ciphername;
+} map_cipher_t;
+
+static map_cipher_t map_cipher[] = {
+ {AES_CBC, "aes-cbc"},
+ {AES_CBC_128, "aes-cbc-128"},
+ {AES_CBC_192, "aes-cbc-192"},
+ {AES_CBC_256, "aes-cbc-256"},
+ {AES_CBC_128, "aes-cbc-128"},
+ {AES_CTR_128, "aes-ctr-128"},
+ {AES_CTR_192, "aes-ctr-192"},
+ {AES_CTR_256, "aes-ctr-256"},
+ {AES_CTR_128, "aes-ctr-128"}
+};
+
+static inline cipher_t map_name_cipher (const char *name) {
+ for (int count = 0; count < sizeof(map_cipher)/sizeof(map_cipher_t); count++) {
+ if (!strcmp(map_cipher[count].ciphername, name))
+ return map_cipher[count].cipher;
+ }
+ return AES_UNKNOWN;
+}
diff --git a/include/swupdate_crypto.h b/include/swupdate_crypto.h
index 243b6068..aa9da964 100644
--- a/include/swupdate_crypto.h
+++ b/include/swupdate_crypto.h
@@ -8,6 +8,7 @@

#pragma once
#include <stdbool.h>
+#include <swupdate_aes.h>

#define SHA_DEFAULT "sha256"

@@ -37,7 +38,7 @@ typedef enum {
} ssl_cert_purpose_t;

typedef struct {
- void *(*DECRYPT_init)(unsigned char *key, char keylen, unsigned char *iv);
+ void *(*DECRYPT_init)(unsigned char *key, char keylen, unsigned char *iv, cipher_t cipher);
int (*DECRYPT_update)(void *ctx, unsigned char *buf,
int *outlen, const unsigned char *cryptbuf, int inlen);

@@ -116,7 +117,7 @@ int swupdate_verify_file(void *ctx, const char *sigfile,
const char *file, const char *signer_name);
int swupdate_HASH_compare(const unsigned char *hash1, const unsigned char *hash2);

-void *swupdate_DECRYPT_init(unsigned char *key, char keylen, unsigned char *iv);
+void *swupdate_DECRYPT_init(unsigned char *key, char keylen, unsigned char *iv, cipher_t cipher);
int swupdate_DECRYPT_update(void *ctx, unsigned char *buf,
int *outlen, const unsigned char *cryptbuf, int inlen);
int swupdate_DECRYPT_final(void *ctx, unsigned char *buf,
diff --git a/include/swupdate_image.h b/include/swupdate_image.h
index 26ace794..8c58a40c 100644
--- a/include/swupdate_image.h
+++ b/include/swupdate_image.h
@@ -13,6 +13,7 @@
#include "globals.h"
#include "swupdate_dict.h"
#include "lua_util.h"
+#include "swupdate_aes.h"

typedef enum {
FLASH,
@@ -56,6 +57,7 @@ struct img_type {
int compressed;
bool preserve_attributes; /* whether to preserve attributes in archives */
bool is_encrypted;
+ cipher_t cipher;
char ivt_ascii[33];
bool install_directly;
int is_script;
diff --git a/parser/parser.c b/parser/parser.c
index 72868cb1..a2d8ff51 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -24,6 +24,7 @@
#include "parselib.h"
#include "parsers.h"
#include "swupdate_dict.h"
+#include "swupdate_aes.h"
#include "lua_util.h"

#define MODULE_NAME "PARSER"
@@ -439,7 +440,7 @@ static void get_ivt_value(parsertype p, void *elem, char *ivt_ascii)
static int parse_common_attributes(parsertype p, void *elem, struct img_type *image, struct swupdate_cfg *cfg)
{
char seek_str[MAX_SEEK_STRING_SIZE];
- const char* compressed;
+ const char *compressed, *encrypted;
unsigned long offset = 0;

/*
@@ -498,7 +499,14 @@ static int parse_common_attributes(parsertype p, void *elem, struct img_type *im
GET_FIELD_BOOL(p, elem, "preserve-attributes", &image->preserve_attributes);
GET_FIELD_BOOL(p, elem, "install-if-different", &image->id.install_if_different);
GET_FIELD_BOOL(p, elem, "install-if-higher", &image->id.install_if_higher);
- GET_FIELD_BOOL(p, elem, "encrypted", &image->is_encrypted);
+
+ if ((encrypted = get_field_string(p, elem, "encrypted")) != NULL) {
+ image->is_encrypted = true;
+ image->cipher = map_name_cipher(encrypted);
+ } else {
+ GET_FIELD_BOOL(p, elem, "encrypted", &image->is_encrypted);
+ image->cipher = AES_CBC;
+ }
get_ivt_value(p, elem, image->ivt_ascii);

if (is_image_installed(&cfg->installed_sw_list, image)) {
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:19 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Stefano Babic
From: Stefano Babic <stefan...@swupdate.org>

Signed-off-by: Stefano Babic <stefan...@swupdate.org>
---
core/Makefile | 1 +
core/cpio_utils.c | 4 +-
core/decrypt_keys.c | 150 ++++++++++++++++++++++++++++++++++++++++++++
core/util.c | 134 ---------------------------------------
include/util.h | 4 +-
5 files changed, 155 insertions(+), 138 deletions(-)
create mode 100644 core/decrypt_keys.c

diff --git a/core/Makefile b/core/Makefile
index 1ef31136..2840f993 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -11,6 +11,7 @@
obj-y += swupdate.o \
cpio_utils.o \
crypto.o \
+ decrypt_keys.o \
notifier.o \
handler.o \
bootloader.o \
diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 0768998a..e3a94c50 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -608,7 +608,7 @@ int copyfile(struct swupdate_copy *args)
}

if (args->encrypted) {
- aes_key = (unsigned char *)get_aes_key();
+ aes_key = (unsigned char *)swupdate_get_decrypt_key();
if (args->imgivt && strlen(args->imgivt)) {
if (!is_hex_str(args->imgivt) || ascii_to_bin(ivtbuf, sizeof(ivtbuf), args->imgivt)) {
ERROR("Invalid image ivt");
@@ -617,7 +617,7 @@ int copyfile(struct swupdate_copy *args)
ivt = ivtbuf;
} else
ivt = get_aes_ivt();
- decrypt_state.dcrypt = swupdate_DECRYPT_init(aes_key, get_aes_keylen(), ivt, AES_CBC);
+ decrypt_state.dcrypt = swupdate_DECRYPT_init(aes_key, swupdate_get_decrypt_keylen(), ivt, AES_CBC);
if (!decrypt_state.dcrypt) {
ERROR("decrypt initialization failure, aborting");
ret = -EFAULT;
diff --git a/core/decrypt_keys.c b/core/decrypt_keys.c
new file mode 100644
index 00000000..f5b6296d
--- /dev/null
+++ b/core/decrypt_keys.c
@@ -0,0 +1,150 @@
+/*
+ * (C) Copyright 2025
+ * Stefano Babic, stefan...@swupdate.org.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "util.h"
+#include "generated/autoconf.h"
+
+/*
+ * key is 256 bit for max aes_256
+ * or is a pkcs#11 URL
+ * keylen is the actual aes key length
+ * ivt is 128 bit
+ */
+struct decryption_key {
+ char *key;
+ char keylen;
+ unsigned char ivt[AES_BLK_SIZE];
+};
+
+static struct decryption_key *decrypt_keys = NULL;
+
+int set_aes_key(const char *key, const char *ivt)
+{
+ int ret;
+ size_t keylen;
+ bool is_pkcs11 = false;
+
+ /*
+ * Allocates the global structure just once
+ */
+ if (!decrypt_keys) {
+ decrypt_keys = (struct decryption_key *)calloc(1, sizeof(*decrypt_keys));
+ if (!decrypt_keys)
+ return -ENOMEM;
+ }
+
+ if (strlen(ivt) != (AES_BLK_SIZE*2) || !is_hex_str(ivt)) {
+ ERROR("Invalid ivt");
+ return -EINVAL;
+ }
+
+ ret = ascii_to_bin(decrypt_keys->ivt, sizeof(decrypt_keys->ivt), ivt);
+ keylen = strlen(key);
+
+ if (!strcmp("pkcs11", key)) {
+ is_pkcs11 = true;
+ decrypt_keys->keylen = keylen;
+
+ } else {
+ switch (keylen) {
+ case AES_128_KEY_LEN * 2:
+ case AES_192_KEY_LEN * 2:
+ case AES_256_KEY_LEN * 2:
+ // valid hex string size for AES 128/192/256
+ decrypt_keys->keylen = keylen / 2;
+ break;
+ default:
+ ERROR("Invalid decrypt_keys length");
+ return -EINVAL;
+ }
+ }
+
+ if (decrypt_keys->key)
+ free(decrypt_keys->key);
+
+ decrypt_keys->key = calloc(1, keylen + 1);
+ if (!decrypt_keys->key)
+ return -ENOMEM;
+
+ if (is_pkcs11) {
+ strncpy(decrypt_keys->key, key, keylen);
+ } else {
+ ret |= !is_hex_str(key);
+ ret |= ascii_to_bin((unsigned char *)decrypt_keys->key, decrypt_keys->keylen, key);
+ }
+
+ if (ret) {
+ ERROR("Invalid decrypt_keys");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int load_decryption_key(char *fname)
+{
+ FILE *fp;
+ char *b1 = NULL, *b2 = NULL;
+ int ret;
+
+ fp = fopen(fname, "r");
+ if (!fp)
+ return -EBADF;
+
+ ret = fscanf(fp, "%ms %ms", &b1, &b2);
+ switch (ret) {
+ case 2:
+ DEBUG("Read decryption key and initialization vector from file %s.", fname);
+ break;
+ default:
+ if (b1 != NULL)
+ free(b1);
+ fprintf(stderr, "File with decryption key is not in the format <key> <ivt>\n");
+ fclose(fp);
+ return -EINVAL;
+ }
+ fclose(fp);
+
+ ret = set_aes_key(b1, b2);
+
+ if (b1 != NULL)
+ free(b1);
+ if (b2 != NULL)
+ free(b2);
+
+ if (ret) {
+ fprintf(stderr, "Keys are invalid\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+char *swupdate_get_decrypt_key(void) {
+ if (!decrypt_keys)
+ return NULL;
+ return decrypt_keys->key;
+}
+
+char swupdate_get_decrypt_keylen(void) {
+ if (!decrypt_keys)
+ return -1;
+ return decrypt_keys->keylen;
+}
+
+unsigned char *get_aes_ivt(void) {
+ if (!decrypt_keys)
+ return NULL;
+ return decrypt_keys->ivt;
+}
diff --git a/core/util.c b/core/util.c
index 9d87e04c..2534da31 100644
--- a/core/util.c
+++ b/core/util.c
@@ -37,20 +37,6 @@
#include "util.h"
#include "generated/autoconf.h"

-/*
- * key is 256 bit for max aes_256
- * or is a pkcs#11 URL
- * keylen is the actual aes key length
- * ivt is 128 bit
- */
-struct decryption_key {
- char *key;
- char keylen;
- unsigned char ivt[AES_BLK_SIZE];
-};
-
-static struct decryption_key *aes_key = NULL;
-
/*
* Configuration file for fw_env.config
*/
@@ -506,63 +492,6 @@ int count_elem_list(struct imglist *list)
return count;
}

-int load_decryption_key(char *fname)
-{
- FILE *fp;
- char *b1 = NULL, *b2 = NULL;
- int ret;
-
- fp = fopen(fname, "r");
- if (!fp)
- return -EBADF;
-
- ret = fscanf(fp, "%ms %ms", &b1, &b2);
- switch (ret) {
- case 2:
- DEBUG("Read decryption key and initialization vector from file %s.", fname);
- break;
- default:
- if (b1 != NULL)
- free(b1);
- fprintf(stderr, "File with decryption key is not in the format <key> <ivt>\n");
- fclose(fp);
- return -EINVAL;
- }
- fclose(fp);
-
- ret = set_aes_key(b1, b2);
-
- if (b1 != NULL)
- free(b1);
- if (b2 != NULL)
- free(b2);
-
- if (ret) {
- fprintf(stderr, "Keys are invalid\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-char *get_aes_key(void) {
- if (!aes_key)
- return NULL;
- return aes_key->key;
-}
-
-char get_aes_keylen(void) {
- if (!aes_key)
- return -1;
- return aes_key->keylen;
-}
-
-unsigned char *get_aes_ivt(void) {
- if (!aes_key)
- return NULL;
- return aes_key->ivt;
-}
-
bool is_hex_str(const char *ascii) {
unsigned int i, size;

@@ -580,69 +509,6 @@ bool is_hex_str(const char *ascii) {
return true;
}

-int set_aes_key(const char *key, const char *ivt)
-{
- int ret;
- size_t keylen;
- bool is_pkcs11 = false;
-
- /*
- * Allocates the global structure just once
- */
- if (!aes_key) {
- aes_key = (struct decryption_key *)calloc(1, sizeof(*aes_key));
- if (!aes_key)
- return -ENOMEM;
- }
-
- if (strlen(ivt) != (AES_BLK_SIZE*2) || !is_hex_str(ivt)) {
- ERROR("Invalid ivt");
- return -EINVAL;
- }
-
- ret = ascii_to_bin(aes_key->ivt, sizeof(aes_key->ivt), ivt);
- keylen = strlen(key);
-
- if (!strcmp("pkcs11", key)) {
- is_pkcs11 = true;
- aes_key->keylen = keylen;
-
- } else {
- switch (keylen) {
- case AES_128_KEY_LEN * 2:
- case AES_192_KEY_LEN * 2:
- case AES_256_KEY_LEN * 2:
- // valid hex string size for AES 128/192/256
- aes_key->keylen = keylen / 2;
- break;
- default:
- ERROR("Invalid aes_key length");
- return -EINVAL;
- }
- }
-
- if (aes_key->key)
- free(aes_key->key);
-
- aes_key->key = calloc(1, keylen + 1);
- if (!aes_key->key)
- return -ENOMEM;
-
- if (is_pkcs11) {
- strncpy(aes_key->key, key, keylen);
- } else {
- ret |= !is_hex_str(key);
- ret |= ascii_to_bin((unsigned char *)aes_key->key, aes_key->keylen, key);
- }
-
- if (ret) {
- ERROR("Invalid aes_key");
- return -EINVAL;
- }
-
- return 0;
-}
-
const char *get_fwenv_config(void) {
if (!fwenv_config)
#if defined(CONFIG_UBOOT)
diff --git a/include/util.h b/include/util.h
index 008ad79f..36c68b9d 100644
--- a/include/util.h
+++ b/include/util.h
@@ -289,8 +289,8 @@ void set_fwenv_config(const char *fname);

/* Decryption key functions */
int load_decryption_key(char *fname);
-char *get_aes_key(void);
-char get_aes_keylen(void);
+char *swupdate_get_decrypt_key(void);
+char swupdate_get_decrypt_keylen(void);
unsigned char *get_aes_ivt(void);
int set_aes_key(const char *key, const char *ivt);

--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:20 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
include/swupdate_image.h | 1 +
parser/parser.c | 23 +++++++++++++++++++++++
2 files changed, 24 insertions(+)

diff --git a/include/swupdate_image.h b/include/swupdate_image.h
index 8c58a40c..1bb37dc8 100644
--- a/include/swupdate_image.h
+++ b/include/swupdate_image.h
@@ -59,6 +59,7 @@ struct img_type {
bool is_encrypted;
cipher_t cipher;
char ivt_ascii[33];
+ char aes_ascii[65]; /* AES_256_KEY_LEN*2+1 */
bool install_directly;
int is_script;
int is_partitioner;
diff --git a/parser/parser.c b/parser/parser.c
index a2d8ff51..84bf036c 100644
--- a/parser/parser.c
+++ b/parser/parser.c
@@ -437,6 +437,28 @@ static void get_ivt_value(parsertype p, void *elem, char *ivt_ascii)
}
}

+static void get_aes_value(parsertype p, void *elem, char *aes_ascii)
+{
+ size_t keylen;
+ const char *s = NULL;
+ s = get_field_string(p, elem, "aes-key");
+ if (s) {
+ keylen = strnlen(s, SWUPDATE_GENERAL_STRING_SIZE);
+
+ switch (keylen) {
+ case AES_128_KEY_LEN * 2:
+ case AES_192_KEY_LEN * 2:
+ case AES_256_KEY_LEN * 2:
+ // valid hex string size for AES 128/192/256
+ break;
+ default:
+ ERROR("Invalid aes-key length");
+ return;
+ }
+ get_field_string_with_size(p, elem, "aes-key", aes_ascii, keylen);
+ }
+}
+
static int parse_common_attributes(parsertype p, void *elem, struct img_type *image, struct swupdate_cfg *cfg)
{
char seek_str[MAX_SEEK_STRING_SIZE];
@@ -508,6 +530,7 @@ static int parse_common_attributes(parsertype p, void *elem, struct img_type *im
image->cipher = AES_CBC;
}
get_ivt_value(p, elem, image->ivt_ascii);
+ get_aes_value(p, elem, image->aes_ascii);

if (is_image_installed(&cfg->installed_sw_list, image)) {
image->skip = SKIP_SAME;
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:20 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki, Stefano Babic
Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
Signed-off-by: Stefano Babic <stefan...@swupdate.org>
---
crypto/Kconfig | 18 +++
crypto/Makefile | 1 +
crypto/swupdate_decrypt_openssl_cms.c | 202 ++++++++++++++++++++++++++
crypto/swupdate_openssl.h | 3 +
include/swupdate_aes.h | 1 +
5 files changed, 225 insertions(+)
create mode 100644 crypto/swupdate_decrypt_openssl_cms.c

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 93b39778..4b9db821 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -94,6 +94,24 @@ config ENCRYPTED_SW_DESCRIPTION
if this is set. It is a compile time option, and mix of plain and
encrypted sw-descriptions is not possible.

+config ASYM_ENCRYPTED_SW_DESCRIPTION
+ bool "Asymmetrical encrypted sw-description"
+ depends on ENCRYPTED_SW_DESCRIPTION
+ select SIGALG_ASYM_DEC_CMS
+ default n
+ help
+ This option enables support for asymmetrical encrypted sw-description,
+ making it possible to decrypt images device specific.
+
+menu "Asymmetric decryption algorithm"
+ depends on ASYM_ENCRYPTED_SW_DESCRIPTION
+
+ config SIGALG_ASYM_DEC_CMS
+ bool "Cryptographic Message Syntax (CMS) / PKCS#7"
+ default n
+ depends on SSL_IMPL_OPENSSL
+endmenu
+
config ENCRYPTED_IMAGES_HARDEN_LOGGING
bool "Harden logging for encrypted images"
default n
diff --git a/crypto/Makefile b/crypto/Makefile
index 4d06bec0..25ab3ab7 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_SIGALG_RAWRSA) += swupdate_rsa_verify_openssl.o
obj-$(CONFIG_SIGALG_RSAPSS) += swupdate_rsa_verify_openssl.o
obj-$(CONFIG_SIGALG_CMS) += swupdate_cms_verify_openssl.o
obj-$(CONFIG_ENCRYPTED_IMAGES) += swupdate_decrypt_openssl.o
+obj-$(CONFIG_SIGALG_ASYM_DEC_CMS) += swupdate_decrypt_openssl_cms.o
endif

ifeq ($(CONFIG_SSL_IMPL_WOLFSSL),y)
diff --git a/crypto/swupdate_decrypt_openssl_cms.c b/crypto/swupdate_decrypt_openssl_cms.c
new file mode 100644
index 00000000..b7e76d26
--- /dev/null
+++ b/crypto/swupdate_decrypt_openssl_cms.c
@@ -0,0 +1,202 @@
+/*
+ * (C) Copyright 2024-2025
+ * Michael Glembotzki, iris-GmbH infrared & intelligent sensors, michael.g...@iris-sensing.com
+ *
+ * (C) Copyright 2025
+ * Stefano Babic, stefan...@swupdate.org.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ * Code mostly taken from openssl examples
+ */
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include "swupdate.h"
+#include "util.h"
+#include "swupdate_crypto.h"
+#include "swupdate_openssl.h"
+
+static void openssl_cms_probe(void);
+static swupdate_decrypt_lib opensslCMS;
+
+//int swupdate_dgst_add_asym_keypair(struct swupdate_cfg *sw, const char *keypair_file)
+static void *openssl_CMS_DECRYPT_init(unsigned char *key,
+ __attribute__ ((__unused__)) char keylen,
+ __attribute__ ((__unused__)) unsigned char *iv,
+ __attribute__ ((__unused__)) cipher_t cipher)
+{
+ struct openssl_digest *dgst = NULL;
+ X509 *decrypt_cert = NULL;
+ EVP_PKEY *pkey = NULL;
+ BIO *tbio = NULL;
+ const char *keypair_file = (const char *)key;
+
+ if (!keypair_file) {
+ ERROR("A PEM private key is not given !");
+ return NULL;
+ }
+
+ tbio = BIO_new_file(keypair_file, "r");
+ if (!tbio) {
+ ERROR("%s cannot be opened", keypair_file);
+ goto err;
+ }
+
+ dgst = calloc(1, sizeof(*dgst));
+ if (!dgst) {
+ ERROR("OOM, Cannot create internal crypto structure");
+ goto err;
+ }
+
+ dgst->cryptbuf = BIO_new(BIO_s_mem());
+ if (!dgst->cryptbuf) {
+ ERROR("Cannot create openSSL BIO buffer");
+ goto err;
+ }
+
+
+ pkey = PEM_read_bio_PrivateKey(tbio, NULL, 0, NULL);
+ if (!pkey) {
+ ERROR("Decryption key not found");
+ goto err;
+ }
+ dgst->pkey = pkey;
+ BIO_reset(tbio);
+
+ /*
+ * Cert is optional, but helps OpenSSL find the right key faster in
+ * large CMS recipient lists.
+ */
+ decrypt_cert = PEM_read_bio_X509(tbio, NULL, 0, NULL);
+ if (!decrypt_cert) {
+ WARN("Decryption cert not found");
+ } else {
+ dgst->decrypt_cert = decrypt_cert;
+ }
+ BIO_free(tbio);
+
+ return (dgst);
+
+err:
+ if (tbio)
+ BIO_free(tbio);
+ if (dgst) {
+ if (dgst->cryptbuf)
+ BIO_free(dgst->cryptbuf);
+ free (dgst);
+ }
+
+ return NULL;
+}
+
+/*
+ * Decrypting CMS requires that the encrypted message is in memory.
+ * So store the crypted message, and really do the decryption in the final callback
+ */
+static int openssl_CMS_DECRYPT_update(void *ctx,
+ __attribute__ ((__unused__)) unsigned char *buf,
+ int *outlen,
+ const unsigned char *cryptbuf,
+ int inlen)
+{
+ struct openssl_digest *dgst = (struct openssl_digest *)ctx;
+
+ if (BIO_write(dgst->cryptbuf, cryptbuf, inlen) < 0) {
+ return -EFAULT;
+ }
+
+ /*
+ * important: no plaintext is passed to buf during update()
+ */
+ *outlen = 0;
+
+ /*
+ * Return -EAGAIN instead of 0:
+ * 0 would signal EOF and stop the loop, so final() would never be called.
+ * -EAGAIN means: no plaintext yet, try again to fill the dgst->cryptbuf.
+ */
+ return -EAGAIN;
+}
+
+#define BUFSIZE 16384
+static int openssl_CMS_DECRYPT_final(void *ctx, unsigned char *buf,
+ int *outlen)
+{
+ struct openssl_digest *dgst = (struct openssl_digest *)ctx;
+
+ /* Decrypt only once and buffer the result in the internal plain BIO. */
+ if (!dgst->plain) {
+ CMS_ContentInfo *cms = NULL;
+ BIO *out = BIO_new(BIO_s_mem());
+ if (!out) {
+ ERROR("Cannot create openSSL BIO output buffer");
+ return -ENOMEM;
+ }
+
+ /* Parse message */
+ cms = d2i_CMS_bio(dgst->cryptbuf, NULL);
+ if (!cms) {
+ ERROR("Cannot parse as DER-encoded CMS blob");
+ BIO_free(out);
+ return -EFAULT;
+ }
+
+ if (!CMS_decrypt(cms, dgst->pkey, dgst->decrypt_cert, NULL, out, 0)) {
+ ERROR("Decrypting failed");
+ CMS_ContentInfo_free(cms);
+ BIO_free(out);
+ return -EFAULT;
+ }
+ CMS_ContentInfo_free(cms);
+ BIO_free(dgst->cryptbuf);
+ dgst->cryptbuf = NULL;
+ dgst->plain = out;
+ }
+
+ int n = BIO_read(dgst->plain, buf, BUFSIZE);
+ if (n < 0) {
+ ERROR("Reading from plain BIO failed");
+ return -EFAULT;
+ }
+ *outlen = n;
+
+ if (BIO_pending(dgst->plain) > 0) {
+ /* more plain data is pending, let decrypt_step call final() again */
+ return -EAGAIN;
+ }
+
+ BIO_free(dgst->plain);
+ dgst->plain = NULL;
+ return 0;
+}
+
+static void openssl_CMS_DECRYPT_cleanup(void *ctx)
+{
+ struct openssl_digest *dgst = (struct openssl_digest *)ctx;
+ if (dgst) {
+ EVP_CIPHER_CTX_free(SSL_GET_CTXDEC(dgst));
+ if (dgst->cryptbuf)
+ BIO_free(dgst->cryptbuf);
+ if (dgst->plain)
+ BIO_free(dgst->plain);
+ free(dgst);
+ }
+
+ dgst = NULL;
+
+ return;
+}
+
+__attribute__((constructor))
+static void openssl_cms_probe(void)
+{
+ opensslCMS.DECRYPT_init = openssl_CMS_DECRYPT_init;
+ opensslCMS.DECRYPT_update = openssl_CMS_DECRYPT_update;
+ opensslCMS.DECRYPT_final = openssl_CMS_DECRYPT_final;
+ opensslCMS.DECRYPT_cleanup = openssl_CMS_DECRYPT_cleanup;
+ (void)register_cryptolib("opensslCMS", &opensslCMS);
+}
diff --git a/crypto/swupdate_openssl.h b/crypto/swupdate_openssl.h
index 4dc79503..2773cbc8 100644
--- a/crypto/swupdate_openssl.h
+++ b/crypto/swupdate_openssl.h
@@ -35,12 +35,15 @@ struct openssl_digest {
EVP_PKEY *pkey; /* this is used for RSA key */
EVP_PKEY_CTX *ckey; /* this is used for RSA key */
X509_STORE *certs; /* this is used if CMS is set */
+ X509 *decrypt_cert;
EVP_MD_CTX *ctx;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
EVP_CIPHER_CTX ctxdec;
#else
EVP_CIPHER_CTX *ctxdec;
#endif
+ BIO *cryptbuf;
+ BIO *plain;
};

#if OPENSSL_VERSION_NUMBER < 0x10100000L
diff --git a/include/swupdate_aes.h b/include/swupdate_aes.h
index acb69573..b019f8cd 100644
--- a/include/swupdate_aes.h
+++ b/include/swupdate_aes.h
@@ -25,6 +25,7 @@ typedef enum {
AES_CTR_128,
AES_CTR_192,
AES_CTR_256,
+ CMS,
AES_UNKNOWN
} cipher_t;

--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:21 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
core/cpio_utils.c | 2 ++
core/installer.c | 2 ++
core/stream_interface.c | 2 ++
include/util.h | 3 +++
4 files changed, 9 insertions(+)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index e3a94c50..6fb7a984 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -801,6 +801,8 @@ int copyimage(void *out, struct img_type *img, writeimage callback)
.hash = img->sha256,
.encrypted = img->is_encrypted,
.imgivt = img->ivt_ascii,
+ .imgaes = img->aes_ascii,
+ .cipher = img->cipher,
};
return copyfile(&copy);
}
diff --git a/core/installer.c b/core/installer.c
index da063938..8cba1790 100644
--- a/core/installer.c
+++ b/core/installer.c
@@ -157,6 +157,8 @@ static int extract_scripts(struct imglist *head)
.hash = script->sha256,
.encrypted = script->is_encrypted,
.imgivt = script->ivt_ascii,
+ .imgaes = script->aes_ascii,
+ .cipher = script->cipher,
};
ret = copyfile(&copy);
close(fdin);
diff --git a/core/stream_interface.c b/core/stream_interface.c
index 10359c30..ba6fb8a4 100644
--- a/core/stream_interface.c
+++ b/core/stream_interface.c
@@ -91,6 +91,7 @@ static int extract_file_to_tmp(int fd, const char *fname, unsigned long *poffs,
int fdout;
uint32_t checksum;
const char* TMPDIR = get_tmpdir();
+ cipher_t cipher = AES_CBC;

if (extract_cpio_header(fd, &fdh, poffs)) {
return -1;
@@ -126,6 +127,7 @@ static int extract_file_to_tmp(int fd, const char *fname, unsigned long *poffs,
.offs = poffs,
.checksum = &checksum,
.encrypted = encrypted,
+ .cipher = cipher,
};
if (copyfile(&copy) < 0) {
close(fdout);
diff --git a/include/util.h b/include/util.h
index 36c68b9d..e9704743 100644
--- a/include/util.h
+++ b/include/util.h
@@ -23,6 +23,7 @@
#include "swupdate_status.h"
#include "swupdate_dict.h"
#include "compat.h"
+#include "swupdate_aes.h"

#define NOTIFY_BUF_SIZE 2048
#define ENOMEM_ASPRINTF -1
@@ -92,6 +93,8 @@ struct swupdate_copy {
/* encryption */
bool encrypted;
const char *imgivt;
+ const char *imgaes;
+ cipher_t cipher;
};

/*
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:21 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
.. if CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION is enabled.

Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
core/stream_interface.c | 37 +++++++++++++++++++++++++------------
1 file changed, 25 insertions(+), 12 deletions(-)

diff --git a/core/stream_interface.c b/core/stream_interface.c
index ba6fb8a4..1472d0e9 100644
--- a/core/stream_interface.c
+++ b/core/stream_interface.c
@@ -45,6 +45,7 @@
#include "state.h"
#include "bootloader.h"
#include "hw-compatibility.h"
+#include "swupdate_crypto.h"

#define BUFF_SIZE 4096
#define PERCENT_LB_INDEX 4
@@ -92,25 +93,33 @@ static int extract_file_to_tmp(int fd, const char *fname, unsigned long *poffs,
uint32_t checksum;
const char* TMPDIR = get_tmpdir();
cipher_t cipher = AES_CBC;
+ int ret = -1;
+
+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+ const char *cryptolib = get_cryptolib();
+ cipher = CMS;
+ if (encrypted)
+ set_cryptolib("opensslCMS");
+#endif

if (extract_cpio_header(fd, &fdh, poffs)) {
- return -1;
+ goto err;
}
if (strcmp(fdh.filename, fname)) {
TRACE("description file name not the first of the list: %s instead of %s",
fdh.filename,
fname);
- return -1;
+ goto err;
}
if (snprintf(output_file, sizeof(output_file), "%s%s", TMPDIR,
fdh.filename) >= (int)sizeof(output_file)) {
ERROR("Path too long: %s%s", TMPDIR, fdh.filename);
- return -1;
+ goto err;
}
if (max_size && fdh.size >= max_size) {
ERROR("%s size (%ld) exceeds configured max of %d, aborting",
fdh.filename, fdh.size, max_size);
- return -1;
+ goto err;
}
TRACE("Found file");
TRACE("\tfilename %s", fdh.filename);
@@ -118,7 +127,7 @@ static int extract_file_to_tmp(int fd, const char *fname, unsigned long *poffs,

fdout = openfileoutput(output_file);
if (fdout < 0)
- return -1;
+ goto err;

struct swupdate_copy copy = {
.fdin = fd,
@@ -130,16 +139,20 @@ static int extract_file_to_tmp(int fd, const char *fname, unsigned long *poffs,
.cipher = cipher,
};
if (copyfile(&copy) < 0) {
- close(fdout);
- return -1;
+ goto err;
}
if (!swupdate_verify_chksum(checksum, &fdh)) {
- close(fdout);
- return -1;
+ goto err;
}
- close(fdout);
-
- return 0;
+ ret = 0;
+err:
+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+ if (encrypted)
+ set_cryptolib(cryptolib);
+#endif
+ if (fdout >= 0)
+ close(fdout);
+ return ret;
}

static bool update_transaction_state(struct swupdate_cfg *software, update_state_t newstate)
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:22 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
core/cpio_utils.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 6fb7a984..aff7a4bb 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -532,6 +532,8 @@ int copyfile(struct swupdate_copy *args)
unsigned char *aes_key = NULL;
unsigned char *ivt = NULL;
unsigned char ivtbuf[AES_BLK_SIZE];
+ unsigned char aesbuf[AES_256_KEY_LEN];
+ char keylen = 0;

struct InputState input_state = {
.fdin = args->fdin,
@@ -608,7 +610,6 @@ int copyfile(struct swupdate_copy *args)
}

if (args->encrypted) {
- aes_key = (unsigned char *)swupdate_get_decrypt_key();
if (args->imgivt && strlen(args->imgivt)) {
if (!is_hex_str(args->imgivt) || ascii_to_bin(ivtbuf, sizeof(ivtbuf), args->imgivt)) {
ERROR("Invalid image ivt");
@@ -617,7 +618,20 @@ int copyfile(struct swupdate_copy *args)
ivt = ivtbuf;
} else
ivt = get_aes_ivt();
- decrypt_state.dcrypt = swupdate_DECRYPT_init(aes_key, swupdate_get_decrypt_keylen(), ivt, AES_CBC);
+
+ if (args->imgaes && strlen(args->imgaes)) {
+ if (!is_hex_str(args->imgaes) || ascii_to_bin(aesbuf, sizeof(aesbuf), args->imgaes)) {
+ ERROR("Invalid image aes-key");
+ return -EINVAL;
+ }
+ aes_key = aesbuf;
+ keylen = strlen(args->imgaes) / 2;
+ } else {
+ aes_key = (unsigned char *)swupdate_get_decrypt_key();
+ keylen = swupdate_get_decrypt_keylen();
+ }
+
+ decrypt_state.dcrypt = swupdate_DECRYPT_init(aes_key, keylen, ivt, args->cipher);
if (!decrypt_state.dcrypt) {
ERROR("decrypt initialization failure, aborting");
ret = -EFAULT;
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:23 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
Use NULL to detect unset iv instead of relying on a zero buffer.

Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
core/decrypt_keys.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/core/decrypt_keys.c b/core/decrypt_keys.c
index 969a3cdc..25beb08a 100644
--- a/core/decrypt_keys.c
+++ b/core/decrypt_keys.c
@@ -25,7 +25,7 @@
struct decryption_key {
char *key;
char keylen;
- unsigned char ivt[AES_BLK_SIZE];
+ unsigned char *ivt;
};

static struct decryption_key *decrypt_keys = NULL;
@@ -72,7 +72,14 @@ int set_aes_key(const char *key, const char *ivt)
return -EINVAL;
}

- ret = ascii_to_bin(decrypt_keys->ivt, sizeof(decrypt_keys->ivt), ivt);
+ if (decrypt_keys->ivt)
+ free(decrypt_keys->ivt);
+
+ decrypt_keys->ivt = calloc(1, AES_BLK_SIZE);
+ if (!decrypt_keys->ivt)
+ return -ENOMEM;
+
+ ret = ascii_to_bin(decrypt_keys->ivt, AES_BLK_SIZE, ivt);
keylen = strlen(key);

if (!strcmp("pkcs11", key)) {
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:23 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Stefano Babic, Michael Glembotzki
From: Stefano Babic <stefan...@swupdate.org>

For asymmetric encrypted sw-description with OpenSSL CMS, the decryption
key is now stored as the provided filename instead of parsing the key in
advance. This lets the openssl_CMS_DECRYPT_init() handle key loading
directly from the file.

Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
core/decrypt_keys.c | 29 ++++++++++++++++++++++++++++-
include/util.h | 1 +
2 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/core/decrypt_keys.c b/core/decrypt_keys.c
index f5b6296d..969a3cdc 100644
--- a/core/decrypt_keys.c
+++ b/core/decrypt_keys.c
@@ -17,7 +17,8 @@

/*
* key is 256 bit for max aes_256
- * or is a pkcs#11 URL
+ * or is a pkcs#11 URL
+ * or a cms key file name
* keylen is the actual aes key length
* ivt is 128 bit
*/
@@ -29,6 +30,28 @@ struct decryption_key {

static struct decryption_key *decrypt_keys = NULL;

+int set_filename_as_key(const char *fname)
+{
+ size_t len;
+ if (!decrypt_keys) {
+ decrypt_keys = (struct decryption_key *)calloc(1, sizeof(*decrypt_keys));
+ if (!decrypt_keys)
+ return -ENOMEM;
+ }
+ len = strlen(fname);
+
+ if (decrypt_keys->key)
+ free(decrypt_keys->key);
+
+ decrypt_keys->key = calloc(1, len + 1);
+ if (!decrypt_keys->key)
+ return -ENOMEM;
+
+ decrypt_keys->keylen = len;
+ strncpy(decrypt_keys->key, fname, len);
+ return 0;
+}
+
int set_aes_key(const char *key, const char *ivt)
{
int ret;
@@ -98,6 +121,10 @@ int load_decryption_key(char *fname)
char *b1 = NULL, *b2 = NULL;
int ret;

+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+ return set_filename_as_key(fname);
+#endif
+
fp = fopen(fname, "r");
if (!fp)
return -EBADF;
diff --git a/include/util.h b/include/util.h
index e9704743..b3121ddb 100644
--- a/include/util.h
+++ b/include/util.h
@@ -296,6 +296,7 @@ char *swupdate_get_decrypt_key(void);
char swupdate_get_decrypt_keylen(void);
unsigned char *get_aes_ivt(void);
int set_aes_key(const char *key, const char *ivt);
+int set_filename_as_key(const char *fname);

/* Getting global information */
int get_install_info(char *buf, size_t len);
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:25 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
doc/source/asym_encrypted_images.rst | 159 +++++++++++++++++++++++++++
doc/source/encrypted_images.rst | 2 +
doc/source/index.rst | 1 +
doc/source/sw-description.rst | 25 ++++-
4 files changed, 181 insertions(+), 6 deletions(-)
create mode 100644 doc/source/asym_encrypted_images.rst

diff --git a/doc/source/asym_encrypted_images.rst b/doc/source/asym_encrypted_images.rst
new file mode 100644
index 00000000..7b217fbd
--- /dev/null
+++ b/doc/source/asym_encrypted_images.rst
@@ -0,0 +1,159 @@
+.. SPDX-FileCopyrightText: 2025 Michael Glembotzki <michael.g...@iris-sensing.com>
+.. SPDX-License-Identifier: GPL-2.0-only
+
+Asymmetrically Encrypted Update Images
+======================================
+
+Asymmetrically encrypted update images are realized by an asymmetrical
+encrypted sw-description, making it possible to decrypt images device specific.
+The artifacts themselves are still encrypted symmetrically. An AES key must be
+provided in the sw-description. At the moment only Cryptographic Message Syntax
+(CMS) is available for asymmetic decryption.
+
+
+Use Cases
+---------
+
+- Asymmetrically encrypted update images, with individual device key pairs, are
+ inherently more secure than a purely symmetrical solution, because one
+ compromised private device key does not affect the security of the others.
+- If ``CONFIG_SIGNED_IMAGES`` is enabled too and a device's private key is
+ compromised, the key pair can be excluded from the list of eligible devices
+ for receiving new update images.
+- The AES key can be securely **exchanged** with each new update image, as it is
+ part of the sw-description, even in the absence of direct access to the
+ device.
+
+
+Create a Self-Signed Device Key Pair
+------------------------------------
+
+As an example, an elliptic curve key pair (PEM) is generated for a single
+device. These steps must be repeated for all other devices. An RSA key pair
+could be used in the same way.
+
+::
+
+ # Create a private key and a self-signed certificate
+ openssl ecparam -name secp521r1 -genkey -noout -out device-key-001.pem
+ openssl req -new -x509 -key device-key-001.pem -out device-cert-001.pem -subj "/O=SWUpdate /CN=target"
+
+ # Combine the private key and the certificate into a single file
+ # Note: The certificate is optional, but it speeds up key matching,
+ # especially when there are many different device keys.
+ cat device-key-001.pem device-cert-001.pem > device-001.pem
+
+
+Symmetric Encryption of Artifacts
+---------------------------------
+
+Generate an AES key and IV, as familiar from
+:ref:`symmetric image encryption <sym-encrypted-images>`. The encryption
+process for the artifacts remains unchanged.
+
+
+Encryption of sw-description for Multiple Devices
+-------------------------------------------------
+
+All device certificates togther are used for encryption.
+
+::
+
+ # Encrypt sw-description for multiple devices
+ openssl cms -encrypt -aes-256-cbc -in <INFILE> -out <OUTFILE> -outform DER -recip <CERT_1> <CERT_2> <CERT_X>
+
+Replace ``<INFILE>`` with the plain `sw-description` (e.g.
+`sw-description.in`) and the encrypted ``<OUTFILE>`` with `sw-description`.
+``<CERT_1>``, ``<CERT_2>``, [...] ``<CERT_X>`` constitute the comprehensive
+list of devices intended for encryption.
+
+
+Decryption of sw-description for a Single Device
+------------------------------------------------
+
+The combined key pair (private key and certificate) is used for decryption.
+SWUpdate handles the decryption process autonomously. Manually executing this
+step is not necessary and is provided here solely for development purposes.
+
+::
+
+ # Decrypt sw-description for a single device
+ openssl cms -decrypt -in <INFILE> -out ``<OUTFILE>`` -inform DER -inkey <PRIVATE_KEY_1> -recip <CERT_1>
+
+Replace the encrypted ``<INFILE>`` with `sw-description` and the
+``<OUTFILE>`` with plain `sw-description` (e.g. `sw-description.in`).
+``<PRIVATE_KEY_1>`` and ``<CERT_1>`` are used for the decryption.
+
+
+Example Asymmetrically Encrypted Image
+--------------------------------------
+
+The image artifacts should be symmetrically encrypted and signed in advance.
+Now, create a plain `sw-description.in` file. The attributes: ``encrypted``,
+``aes-key`` and ``ivt`` are necessary for artifact decryption. It is okay that
+the AES key is included here, because the sw-description file will be encrypted
+afterwards.
+
+::
+
+ software =
+ {
+ version = "1.0.0";
+ images: ({
+ filename = "rootfs.ext4.enc";
+ device = "/dev/mmcblk0p3";
+ sha256 = "131159df3a4efaa890ff80173664a125c496c458dd432a8a6acae18872e35822";
+ encrypted = "aes-cbc"; // former: encrypted = true;
+ aes-key = "ed73b9d3bf9c655d5a0b04836d8be48660a4a4bb6f4aa07c6778e00e342881ac";
+ ivt = "ea34a55a0c3476ed78f238ac87a7970c";
+ });
+ }
+
+
+Asymmetrically encrypt the `sw-description` for multiple devices:
+::
+
+ openssl cms -encrypt -aes-256-cbc -in sw-description.in -out sw-description -outform DER -recip device-cert-001.pem device-cert-002.pem device-cert-003.pem
+
+
+Create the new update image (SWU):
+
+::
+
+ #!/bin/sh
+
+ FILES="sw-description sw-description.sig rootfs.ext4.enc"
+
+ for i in $FILES; do
+ echo $i;done | cpio -ov -H crc > firmware.swu
+
+
+Running SWUpdate with Asymmetrically Encrypted Images
+-----------------------------------------------------
+
+Asymmetric encryption support can be enabled by configuring the compile-time
+option ``CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION``, which depends on
+``CONFIG_ENCRYPTED_SW_DESCRIPTION``. To pass the combined key pair
+(PEM) generated earlier to SWUpdate, use the ``-K`` argument. Alternatively,
+use the ``decryption-key`` parameter in the ``swupdate.cfg``.
+
+
+Security Considerations
+-----------------------
+- Ideally, generate the private key on the device during factory provisioning,
+ ensuring it never leaves the device. Only the public certificate leaves the
+ device for encrypting future update packages.
+- This feature should be used in conjunction with signature verification
+ (``CONFIG_SIGNED_IMAGES``) to ensure data integrity. In principle, anyone
+ with the corresponding device certificate can create update packages.
+- As a side effect, the size of the update package may significantly increase
+ in a large-scale deployment. To enhance scalability, consider using group
+ keys. Smaller groups should be preferred over larger ones. For example,
+ 1000 device keys (using secp521r1) increase the sw-description size to
+ 0.35 MB. This means that by forming groups of 1000, it is possible to support
+ 1 million devices. Alternatively, groups of 100 increase the sw-description
+ size to 3.5 MB accordingly.
+- Exchange the AES key in the sw-description with each update package.
+- Avoid encrypting new update packages for compromised devices, if there is no
+ direct access to the device or if unauthorized users have access to new update
+ packages.
diff --git a/doc/source/encrypted_images.rst b/doc/source/encrypted_images.rst
index c70ed784..7c96e40a 100644
--- a/doc/source/encrypted_images.rst
+++ b/doc/source/encrypted_images.rst
@@ -1,6 +1,8 @@
.. SPDX-FileCopyrightText: 2013-2021 Stefano Babic <stefan...@swupdate.org>
.. SPDX-License-Identifier: GPL-2.0-only

+.. _sym-encrypted-images:
+
Symmetrically Encrypted Update Images
=====================================

diff --git a/doc/source/index.rst b/doc/source/index.rst
index 67c376c0..77b3e0f0 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -41,6 +41,7 @@ SWUpdate Documentation
sw-description.rst
signed_images.rst
encrypted_images.rst
+ asym_encrypted_images.rst
handlers.rst
mongoose.rst
suricatta.rst
diff --git a/doc/source/sw-description.rst b/doc/source/sw-description.rst
index f90a0cfa..2150dcc0 100644
--- a/doc/source/sw-description.rst
+++ b/doc/source/sw-description.rst
@@ -1511,13 +1511,26 @@ There are 4 main sections inside sw-description:
| | | | compared with the entries in |
| | | | sw-versions |
+-------------+----------+------------+---------------------------------------+
- | encrypted | bool | images | flag |
- | | | files | if set, file is encrypted |
- | | | scripts | and must be decrypted before |
- | | | | installing. |
+ | encrypted | string | images | string to indicate the artefact is |
+ | | | files | encrypted with this cipher. |
+ | | | scripts | e.g 'encrypted = "aes-cbc"'. |
+ | | | | See swupdate_aes.h for supported |
+ | | | | values. |
+-------------+----------+------------+---------------------------------------+
- | ivt | string | images | IVT in case of encrypted artefact |
- | | | files | It has no value if "encrypted" is not |
+ | encrypted | bool | images | Use the string form, if the key is |
+ | | | files | provided within the sw-description. |
+ | | | scripts | true is equal to |
+ | | | | 'encrypted = "aes-cbc"'. |
+ +-------------+----------+------------+---------------------------------------+
+ | aes-key | string | images | AES key for encrypted artifacts |
+ | | | files | Note: This key should only be used if |
+ | | | scripts | sw-description is encrypted |
+ | | | | (symmetrically or asymmetrically). It |
+ | | | | must be provided as an ASCII hex |
+ | | | | string of 16, 24, or 32 characters. |
+ +-------------+----------+------------+---------------------------------------+
+ | ivt | string | images | Optional IVT for encrypted artefacts. |
+ | | | files | It has no effect if "encrypted" is not|
| | | scripts | set. Each artefact can have an own |
| | | | IVT to avoid attacker can guess the |
| | | | the key. |
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:25 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
copyfile continues on -EAGAIN instead of failing
decrypt_step sets eof only if final returned 0

Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
core/cpio_utils.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index aff7a4bb..6ef38c15 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -319,7 +319,9 @@ static int decrypt_step(void *state, void *buffer, size_t size)
*/
ret = swupdate_DECRYPT_final(s->dcrypt,
s->output, &s->outlen);
- s->eof = true;
+ if (ret == 0) {
+ s->eof = true;
+ }
}
if (ret < 0) {
return ret;
@@ -728,6 +730,9 @@ int copyfile(struct swupdate_copy *args)

for (;;) {
ret = step(state, buffer, sizeof buffer);
+ if (ret == -EAGAIN) {
+ continue;
+ }
if (ret < 0) {
goto copyfile_exit;
}
--
2.50.1

Michael Glembotzki

unread,
Sep 4, 2025, 7:57:25 AM (7 days ago) Sep 4
to swup...@googlegroups.com, Michael Glembotzki
Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
core/cpio_utils.c | 9 +++++++--
core/decrypt_keys.c | 14 ++++++++++++--
include/util.h | 3 ++-
3 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 6ef38c15..cb291d3b 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -629,8 +629,13 @@ int copyfile(struct swupdate_copy *args)
aes_key = aesbuf;
keylen = strlen(args->imgaes) / 2;
} else {
- aes_key = (unsigned char *)swupdate_get_decrypt_key();
- keylen = swupdate_get_decrypt_keylen();
+ /*
+ * Only fall back to the default decryption key if the requested cipher matches.
+ */
+ if (swupdate_get_decrypt_cipher() == args->cipher) {
+ aes_key = (unsigned char *)swupdate_get_decrypt_key();
+ keylen = swupdate_get_decrypt_keylen();
+ }
}

decrypt_state.dcrypt = swupdate_DECRYPT_init(aes_key, keylen, ivt, args->cipher);
diff --git a/core/decrypt_keys.c b/core/decrypt_keys.c
index 25beb08a..95c7c13b 100644
--- a/core/decrypt_keys.c
+++ b/core/decrypt_keys.c
@@ -26,11 +26,12 @@ struct decryption_key {
char *key;
char keylen;
unsigned char *ivt;
+ cipher_t cipher;
};

static struct decryption_key *decrypt_keys = NULL;

-int set_filename_as_key(const char *fname)
+int set_filename_as_key(const char *fname, cipher_t cipher)
{
size_t len;
if (!decrypt_keys) {
@@ -49,6 +50,7 @@ int set_filename_as_key(const char *fname)

decrypt_keys->keylen = len;
strncpy(decrypt_keys->key, fname, len);
+ decrypt_keys->cipher = cipher;
return 0;
}

@@ -100,6 +102,8 @@ int set_aes_key(const char *key, const char *ivt)
}
}

+ decrypt_keys->cipher = AES_CBC;
+
if (decrypt_keys->key)
free(decrypt_keys->key);

@@ -129,7 +133,7 @@ int load_decryption_key(char *fname)
int ret;

#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
- return set_filename_as_key(fname);
+ return set_filename_as_key(fname, CMS);
#endif

fp = fopen(fname, "r");
@@ -182,3 +186,9 @@ unsigned char *get_aes_ivt(void) {
return NULL;
return decrypt_keys->ivt;
}
+
+cipher_t swupdate_get_decrypt_cipher(void) {
+ if (!decrypt_keys)
+ return AES_UNKNOWN;
+ return decrypt_keys->cipher;
+}
diff --git a/include/util.h b/include/util.h
index b3121ddb..52fff11a 100644
--- a/include/util.h
+++ b/include/util.h
@@ -296,7 +296,8 @@ char *swupdate_get_decrypt_key(void);
char swupdate_get_decrypt_keylen(void);
unsigned char *get_aes_ivt(void);
int set_aes_key(const char *key, const char *ivt);
-int set_filename_as_key(const char *fname);
+int set_filename_as_key(const char *fname, cipher_t cipher);
+cipher_t swupdate_get_decrypt_cipher(void);

Michael Glembotzki

unread,
Sep 5, 2025, 4:47:32 AM (6 days ago) Sep 5
to swup...@googlegroups.com, Michael Glembotzki
Fixes: c9641aca

Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
test/test_crypt.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/test/test_crypt.c b/test/test_crypt.c
index 6c49a8e8..a52edec9 100644
--- a/test/test_crypt.c
+++ b/test/test_crypt.c
@@ -33,6 +33,7 @@ struct cryptdata {
unsigned char *key;
unsigned char *iv;
unsigned char *crypttext;
+ cipher_t cipher;
};

static void hex2bin(unsigned char *dest, const unsigned char *source)
@@ -47,7 +48,7 @@ static void hex2bin(unsigned char *dest, const unsigned char *source)
static void do_crypt(struct cryptdata *crypt, char keylen, unsigned char *CRYPTTEXT, unsigned char *PLAINTEXT)
{
int len;
- void *dcrypt = swupdate_DECRYPT_init(crypt->key, keylen, crypt->iv);
+ void *dcrypt = swupdate_DECRYPT_init(crypt->key, keylen, crypt->iv, crypt->cipher);
assert_non_null(dcrypt);

unsigned char *buffer = calloc(1, strlen((const char *)CRYPTTEXT) + EVP_MAX_BLOCK_LENGTH);
@@ -75,6 +76,7 @@ static void test_crypt_128(void **state)
hex2bin((crypt.key = calloc(1, strlen((const char *)KEY))), KEY);
hex2bin((crypt.iv = calloc(1, strlen((const char *)IV))), IV);
hex2bin((crypt.crypttext = calloc(1, strlen((const char *)CRYPTTEXT))), CRYPTTEXT);
+ crypt.cipher = AES_CBC_128;

do_crypt(&crypt, 16, &CRYPTTEXT[0], &PLAINTEXT[0]);

@@ -96,6 +98,7 @@ static void test_crypt_192(void **state)
hex2bin((crypt.key = calloc(1, strlen((const char *)KEY))), KEY);
hex2bin((crypt.iv = calloc(1, strlen((const char *)IV))), IV);
hex2bin((crypt.crypttext = calloc(1, strlen((const char *)CRYPTTEXT))), CRYPTTEXT);
+ crypt.cipher = AES_CBC_192;

do_crypt(&crypt, 24, &CRYPTTEXT[0], &PLAINTEXT[0]);

@@ -117,6 +120,7 @@ static void test_crypt_256(void **state)
hex2bin((crypt.key = calloc(1, strlen((const char *)KEY))), KEY);
hex2bin((crypt.iv = calloc(1, strlen((const char *)IV))), IV);
hex2bin((crypt.crypttext = calloc(1, strlen((const char *)CRYPTTEXT))), CRYPTTEXT);
+ crypt.cipher = AES_CBC; // AES_CBC_256

do_crypt(&crypt, 32, &CRYPTTEXT[0], &PLAINTEXT[0]);

@@ -137,9 +141,10 @@ static void test_crypt_failure(void **state)
hex2bin((crypt.key = calloc(1, strlen((const char *)KEY))), KEY);
hex2bin((crypt.iv = calloc(1, strlen((const char *)IV))), IV);
hex2bin((crypt.crypttext = calloc(1, strlen((const char *)CRYPTTEXT))), CRYPTTEXT);
+ crypt.cipher = AES_CBC;

int len;
- void *dcrypt = swupdate_DECRYPT_init(crypt.key, 32, crypt.iv);
+ void *dcrypt = swupdate_DECRYPT_init(crypt.key, 32, crypt.iv, crypt.cipher);
assert_non_null(dcrypt);

unsigned char *buffer = calloc(1, strlen((const char *)CRYPTTEXT) + EVP_MAX_BLOCK_LENGTH);
--
2.50.1

Michael Glembotzki

unread,
Sep 5, 2025, 4:47:33 AM (6 days ago) Sep 5
to swup...@googlegroups.com, Michael Glembotzki
Fixes: 9c9aa3ca
Fixes: 82e825c7

Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>
---
corelib/lua_interface.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/corelib/lua_interface.c b/corelib/lua_interface.c
index 1ff3e5e4..6543dff7 100644
--- a/corelib/lua_interface.c
+++ b/corelib/lua_interface.c
@@ -330,7 +330,9 @@ static void lua_string_to_img(struct img_type *img, const char *key,
if (!strcmp(key, "ivt"))
strncpy(img->ivt_ascii, value,
sizeof(img->ivt_ascii));
-
+ if (!strcmp(key, "aes-key"))
+ strncpy(img->aes_ascii, value,
+ sizeof(img->aes_ascii));
if (!strncmp(key, offset, sizeof(offset))) {
strncpy(seek_str, value,
sizeof(seek_str));
@@ -514,6 +516,7 @@ static void update_table(lua_State* L, struct img_type *img)
LUA_PUSH_IMG_STRING(img, "data", type_data);
LUA_PUSH_IMG_STRING(img, "filesystem", filesystem);
LUA_PUSH_IMG_STRING(img, "ivt", ivt_ascii);
+ LUA_PUSH_IMG_STRING(img, "aes-key", aes_ascii);

LUA_PUSH_IMG_BOOL(img, "installed_directly", install_directly);
LUA_PUSH_IMG_BOOL(img, "install_if_different", id.install_if_different);
--
2.50.1

Stefano Babic

unread,
Sep 8, 2025, 5:45:48 AM (3 days ago) Sep 8
to Michael Glembotzki, swup...@googlegroups.com, Michael Glembotzki
Reviewed-by: Stefano Babic <stefan...@swupdate.org>

Stefano Babic

unread,
Sep 8, 2025, 5:50:24 AM (3 days ago) Sep 8
to swup...@googlegroups.com, Michael Glembotzki
Hi Michael,

On 9/4/25 13:49, Michael Glembotzki wrote:
> Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>

This looks apparently corrent, but it breaks a Use Case. In fact, the
error should be raised if SWUpdate has no key when it starts to decrypt.

The USe Case is that no key is passed to SWUpdate via command line,
because there is an agent doing this that transfer the key via IPC (see
also swupdate_set_aes()). This is true also if sw-description is
encrypted, because the key is just required when an update is started,.

Best regards,
Stefano

Stefano Babic

unread,
Sep 8, 2025, 6:18:16 AM (3 days ago) Sep 8
to Michael Glembotzki, swup...@googlegroups.com, Michael Glembotzki
Hi Michael,

On 9/5/25 10:47, Michael Glembotzki wrote:
> Fixes: c9641aca
>

This refers to your tree and it is not in repo. It should be squashed
with 5/16.

Regards,
Stefano

Stefano Babic

unread,
Sep 8, 2025, 6:19:17 AM (3 days ago) Sep 8
to Michael Glembotzki, swup...@googlegroups.com, Michael Glembotzki
On 9/5/25 10:47, Michael Glembotzki wrote:
> Fixes: 9c9aa3ca
> Fixes: 82e825c7
>

These make no sense to me.
Regards,
Stefano

Michael Glembotzki

unread,
Sep 8, 2025, 7:15:45 AM (3 days ago) Sep 8
to swupdate
Hi Stefano,
Stefano Babic schrieb am Montag, 8. September 2025 um 12:19:17 UTC+2:
On 9/5/25 10:47, Michael Glembotzki wrote:
> Fixes: 9c9aa3ca
> Fixes: 82e825c7
>

These make no sense to me.
17/18 and 18/18 are fixup commit in my tree :/. I sent them one day after v5. The reference makes no sense.
I will squash them on v6.

Best regards,
Michael

Michael Glembotzki

unread,
Sep 8, 2025, 7:18:50 AM (3 days ago) Sep 8
to swupdate
Hi Stefano,

Stefano Babic schrieb am Montag, 8. September 2025 um 11:50:24 UTC+2:
Hi Michael,

On 9/4/25 13:49, Michael Glembotzki wrote:
> Signed-off-by: Michael Glembotzki <Michael.G...@iris-sensing.com>

This looks apparently corrent, but it breaks a Use Case. In fact, the
error should be raised if SWUpdate has no key when it starts to decrypt.

The USe Case is that no key is passed to SWUpdate via command line,
because there is an agent doing this that transfer the key via IPC (see
also swupdate_set_aes()). This is true also if sw-description is
encrypted, because the key is just required when an update is started,.

Best regards,
Stefano

Ah, okay, I see. Should we print it as a warning without exit(),
or would you rather skip the check?
 
Best regards,
Michael

Stefano Babic

unread,
Sep 8, 2025, 7:40:58 AM (3 days ago) Sep 8
to Michael Glembotzki, swupdate
Hi Michael,

On 08.09.25 13:15, Michael Glembotzki wrote:
> Hi Stefano,
> Stefano Babic schrieb am Montag, 8. September 2025 um 12:19:17 UTC+2:
>
> On 9/5/25 10:47, Michael Glembotzki wrote:
> > Fixes: 9c9aa3ca
> > Fixes: 82e825c7
> >
>
> These make no sense to me.
>
> 17/18 and 18/18 are fixup commit in my tree :/. I sent them one day
> after v5. The reference makes no sense.
> I will squash them on v6.

Ok

Best regards,
Stefano
> --
> You received this message because you are subscribed to the Google
> Groups "swupdate" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to swupdate+u...@googlegroups.com
> <mailto:swupdate+u...@googlegroups.com>.
> To view this discussion visit https://groups.google.com/d/msgid/
> swupdate/2ee502e0-a03a-49ec-832c-00131d1fd9c5n%40googlegroups.com
> <https://groups.google.com/d/msgid/swupdate/2ee502e0-
> a03a-49ec-832c-00131d1fd9c5n%40googlegroups.com?
> utm_medium=email&utm_source=footer>.

Reply all
Reply to author
Forward
0 new messages