diff --git a/Kconfig b/Kconfig
index 5a3dc9a..d3412b3 100644
--- a/Kconfig
+++ b/Kconfig
@@ -507,6 +507,18 @@ 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 && !PKCS11
+	depends on SSL_IMPL_OPENSSL
+	default n
+	help
+	  This option enables support for asymmetrical encrypted sw-description,
+	  making it possible to encrypt images device specific. The artifacts
+	  persist in being symmetrically encrypted by retrieving an AES key from
+	  the sw-description, which may be the same or distinct for each artifact.
+	  Cryptographic Message Syntax (CMS) with OpenSSL is used for encryption.
+
 config ENCRYPTED_IMAGES_HARDEN_LOGGING
 	bool "Harden logging for encrypted images"
 	default n
diff --git a/core/cpio_utils.c b/core/cpio_utils.c
index 6e2c239..0a4b39a 100644
--- a/core/cpio_utils.c
+++ b/core/cpio_utils.c
@@ -445,6 +445,10 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 	unsigned char *aes_key = NULL;
 	unsigned char *ivt = NULL;
 	unsigned char ivtbuf[AES_BLK_SIZE];
+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+	unsigned char aeskeybuf[AES_256_KEY_LEN];
+#endif
+	char keylen;
 
 	struct InputState input_state = {
 		.fdin = fdin,
@@ -514,7 +518,26 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 	}
 
 	if (encrypted) {
+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+		if (!imgaeskey || !imgivt) {
+			ERROR("Missing image aes_key or image ivt");
+			return -EINVAL;
+		}
+		keylen = strlen(imgaeskey) / 2;
+		if (!keylen || !is_hex_str(imgaeskey) || ascii_to_bin(aeskeybuf, keylen, imgaeskey)) {
+			ERROR("Invalid image aes_key");
+			return -EINVAL;
+		}
+		if (!strlen(imgivt) || !is_hex_str(imgivt) || ascii_to_bin(ivtbuf, sizeof(ivtbuf), imgivt)) {
+			ERROR("Invalid image ivt");
+			return -EINVAL;
+		}
+
+		aes_key = aeskeybuf;
+		ivt = ivtbuf;
+#else
 		aes_key = get_aes_key();
+		keylen = get_aes_keylen();
 		if (imgivt) {
 			if (!strlen(imgivt) || !is_hex_str(imgivt) || ascii_to_bin(ivtbuf, sizeof(ivtbuf), imgivt)) {
 				ERROR("Invalid image ivt");
@@ -523,7 +546,8 @@ static int __swupdate_copy(int fdin, unsigned char *inbuf, void *out, size_t nby
 			ivt = ivtbuf;
 		} else
 			ivt = get_aes_ivt();
-		decrypt_state.dcrypt = swupdate_DECRYPT_init(aes_key, get_aes_keylen(), ivt);
+#endif
+		decrypt_state.dcrypt = swupdate_DECRYPT_init(aes_key, keylen, ivt);
 		if (!decrypt_state.dcrypt) {
 			ERROR("decrypt initialization failure, aborting");
 			ret = -EFAULT;
diff --git a/core/installer.c b/core/installer.c
index db86075..ba85f98 100644
--- a/core/installer.c
+++ b/core/installer.c
@@ -498,6 +498,13 @@ void cleanup_files(struct swupdate_cfg *software) {
 		free(fn);
 	}
 #endif
+
+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+	if (asprintf(&fn, "%s%s.enc", TMPDIR, SW_DESCRIPTION_FILENAME) != ENOMEM_ASPRINTF) {
+		remove_sw_file(fn);
+		free(fn);
+	}
+#endif
 }
 
 int preupdatecmd(struct swupdate_cfg *swcfg)
diff --git a/core/stream_interface.c b/core/stream_interface.c
index bfafa30..ba88193 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 "sslapi.h"
 
 #define BUFF_SIZE	 4096
 #define PERCENT_LB_INDEX	4
@@ -144,11 +145,14 @@ static int extract_files(int fd, struct swupdate_cfg *software)
 	int fdout;
 	struct img_type *img, *part;
 	char output_file[MAX_IMAGE_FNAME];
+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+	char enc_output_file[MAX_IMAGE_FNAME];
+#endif
 	const char* TMPDIR = get_tmpdir();
 	bool installed_directly = false;
 	bool encrypted_sw_desc = false;
 
-#ifdef CONFIG_ENCRYPTED_SW_DESCRIPTION
+#if defined(CONFIG_ENCRYPTED_SW_DESCRIPTION) && !defined(CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION)
 	encrypted_sw_desc = true;
 #endif
 
@@ -168,6 +172,16 @@ static int extract_files(int fd, struct swupdate_cfg *software)
 			if (extract_file_to_tmp(fd, SW_DESCRIPTION_FILENAME, &offset, encrypted_sw_desc) < 0 )
 				return -1;
 
+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+			snprintf(output_file, sizeof(output_file), "%s%s", TMPDIR, SW_DESCRIPTION_FILENAME);
+			snprintf(enc_output_file, sizeof(enc_output_file), "%s.enc", output_file);
+			if (rename(output_file, enc_output_file))
+				return -1;
+
+			if (swupdate_decrypt_file(software->dgst, enc_output_file, output_file))
+				return -1;
+#endif
+
 			status = STREAM_WAIT_SIGNATURE;
 			break;
 
@@ -381,10 +395,13 @@ static int save_stream(int fdin, struct swupdate_cfg *software)
 	unsigned int tmpsize;
 	unsigned long offset;
 	char output_file[MAX_IMAGE_FNAME];
+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+	char enc_output_file[MAX_IMAGE_FNAME];
+#endif
 	const char* TMPDIR = get_tmpdir();
 	bool encrypted_sw_desc = false;
 
-#ifdef CONFIG_ENCRYPTED_SW_DESCRIPTION
+#if defined(CONFIG_ENCRYPTED_SW_DESCRIPTION) && !defined(CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION)
 	encrypted_sw_desc = true;
 #endif
 	if (fdin < 0)
@@ -452,6 +469,20 @@ static int save_stream(int fdin, struct swupdate_cfg *software)
 		ret = -EINVAL;
 		goto no_copy_output;
 	}
+
+#ifdef CONFIG_ASYM_ENCRYPTED_SW_DESCRIPTION
+	snprintf(output_file, sizeof(output_file), "%s%s", TMPDIR, SW_DESCRIPTION_FILENAME);
+	snprintf(enc_output_file, sizeof(enc_output_file), "%s.enc", output_file);
+	if (rename(output_file, enc_output_file)) {
+		ret = -EINVAL;
+		goto no_copy_output;
+	}
+	if (swupdate_decrypt_file(software->dgst, enc_output_file, output_file)) {
+		ret = -EINVAL;
+		goto no_copy_output;
+	}
+#endif
+
 #ifdef CONFIG_SIGNED_IMAGES
 	snprintf(output_file, sizeof(output_file), "%s.sig", SW_DESCRIPTION_FILENAME);
 	if (extract_file_to_tmp(tmpfd, output_file, &offset, false) < 0 ) {
