public inbox for linux-crypto@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] dm-crypt: Reimplement elephant diffuser using AES library
@ 2026-03-21 23:06 Eric Biggers
  2026-03-21 23:06 ` [PATCH 1/2] " Eric Biggers
  2026-03-21 23:06 ` [PATCH 2/2] dm-crypt: Make crypt_iv_operations::wipe return void Eric Biggers
  0 siblings, 2 replies; 3+ messages in thread
From: Eric Biggers @ 2026-03-21 23:06 UTC (permalink / raw)
  To: dm-devel; +Cc: linux-crypto, linux-kernel, Eric Biggers

This series simplifies and optimizes dm-crypt's implementation of
Bitlocker's "elephant diffuser" to use the AES library instead of an
"ecb(aes)" crypto_skcipher.

This series is targeting linux-dm/for-next

Eric Biggers (2):
  dm-crypt: Reimplement elephant diffuser using AES library
  dm-crypt: Make crypt_iv_operations::wipe return void

 drivers/md/Kconfig    |   1 +
 drivers/md/dm-crypt.c | 103 ++++++++++++++----------------------------
 2 files changed, 36 insertions(+), 68 deletions(-)


base-commit: 23e6e57a93bcabe86d5f0eab1df0c44706ab18f3
-- 
2.53.0


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [PATCH 1/2] dm-crypt: Reimplement elephant diffuser using AES library
  2026-03-21 23:06 [PATCH 0/2] dm-crypt: Reimplement elephant diffuser using AES library Eric Biggers
@ 2026-03-21 23:06 ` Eric Biggers
  2026-03-21 23:06 ` [PATCH 2/2] dm-crypt: Make crypt_iv_operations::wipe return void Eric Biggers
  1 sibling, 0 replies; 3+ messages in thread
From: Eric Biggers @ 2026-03-21 23:06 UTC (permalink / raw)
  To: dm-devel; +Cc: linux-crypto, linux-kernel, Eric Biggers

Simplify and optimize dm-crypt's implementation of Bitlocker's "elephant
diffuser" to use the AES library instead of an "ecb(aes)"
crypto_skcipher.

Note: struct aes_enckey is fixed-size, so it could be embedded directly
in struct iv_elephant_private.  But I kept it as a separate allocation
so that the size of struct crypt_config doesn't increase.  The elephant
diffuser is rarely used in dm-crypt.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 drivers/md/Kconfig    |  1 +
 drivers/md/dm-crypt.c | 85 +++++++++++++++----------------------------
 2 files changed, 31 insertions(+), 55 deletions(-)

diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 53351048d3ec..a3fcdca7e6db 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -298,10 +298,11 @@ config DM_CRYPT
 	depends on (TRUSTED_KEYS || TRUSTED_KEYS=n)
 	select CRC32
 	select CRYPTO
 	select CRYPTO_CBC
 	select CRYPTO_ESSIV
+	select CRYPTO_LIB_AES
 	select CRYPTO_LIB_MD5 # needed by lmk IV mode
 	help
 	  This device-mapper target allows you to create a device that
 	  transparently encrypts the data on it. You'll need to activate
 	  the ciphers you're going to use in the cryptoapi configuration.
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 54823341c9fd..76b0c6bfd45c 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -30,10 +30,11 @@
 #include <linux/scatterlist.h>
 #include <linux/rbtree.h>
 #include <linux/ctype.h>
 #include <asm/page.h>
 #include <linux/unaligned.h>
+#include <crypto/aes.h>
 #include <crypto/hash.h>
 #include <crypto/md5.h>
 #include <crypto/skcipher.h>
 #include <crypto/aead.h>
 #include <crypto/authenc.h>
@@ -131,11 +132,11 @@ struct iv_tcw_private {
 	u8 *whitening;
 };
 
 #define ELEPHANT_MAX_KEY_SIZE 32
 struct iv_elephant_private {
-	struct crypto_skcipher *tfm;
+	struct aes_enckey *key;
 };
 
 /*
  * Crypt: maps a linear range of a block device
  * and encrypts / decrypts at the same time.
@@ -765,27 +766,23 @@ static int crypt_iv_eboiv_gen(struct crypt_config *cc, u8 *iv,
 
 static void crypt_iv_elephant_dtr(struct crypt_config *cc)
 {
 	struct iv_elephant_private *elephant = &cc->iv_gen_private.elephant;
 
-	crypto_free_skcipher(elephant->tfm);
-	elephant->tfm = NULL;
+	kfree_sensitive(elephant->key);
+	elephant->key = NULL;
 }
 
 static int crypt_iv_elephant_ctr(struct crypt_config *cc, struct dm_target *ti,
 			    const char *opts)
 {
 	struct iv_elephant_private *elephant = &cc->iv_gen_private.elephant;
 	int r;
 
-	elephant->tfm = crypto_alloc_skcipher("ecb(aes)", 0,
-					      CRYPTO_ALG_ALLOCATES_MEMORY);
-	if (IS_ERR(elephant->tfm)) {
-		r = PTR_ERR(elephant->tfm);
-		elephant->tfm = NULL;
-		return r;
-	}
+	elephant->key = kmalloc_obj(*elephant->key);
+	if (!elephant->key)
+		return -ENOMEM;
 
 	r = crypt_iv_eboiv_ctr(cc, ti, NULL);
 	if (r)
 		crypt_iv_elephant_dtr(cc);
 	return r;
@@ -933,45 +930,32 @@ static void diffuser_b_encrypt(u32 *d, size_t n)
 			i1--; i2--; i3--;
 		}
 	}
 }
 
-static int crypt_iv_elephant(struct crypt_config *cc, struct dm_crypt_request *dmreq)
+static void crypt_iv_elephant(struct crypt_config *cc,
+			      struct dm_crypt_request *dmreq)
 {
 	struct iv_elephant_private *elephant = &cc->iv_gen_private.elephant;
-	u8 *es, *ks, *data, *data2, *data_offset;
-	struct skcipher_request *req;
-	struct scatterlist *sg, *sg2, src, dst;
-	DECLARE_CRYPTO_WAIT(wait);
-	int i, r;
-
-	req = skcipher_request_alloc(elephant->tfm, GFP_NOIO);
-	es = kzalloc(16, GFP_NOIO); /* Key for AES */
-	ks = kzalloc(32, GFP_NOIO); /* Elephant sector key */
-
-	if (!req || !es || !ks) {
-		r = -ENOMEM;
-		goto out;
-	}
+	u8 *data, *data2, *data_offset;
+	struct scatterlist *sg, *sg2;
+	union {
+		__le64 w[2];
+		u8 b[16];
+	} es;
+	u8 ks[32] __aligned(__alignof(long)); /* Elephant sector key */
+	int i;
 
-	*(__le64 *)es = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
+	es.w[0] = cpu_to_le64(dmreq->iv_sector * cc->sector_size);
+	es.w[1] = 0;
 
 	/* E(Ks, e(s)) */
-	sg_init_one(&src, es, 16);
-	sg_init_one(&dst, ks, 16);
-	skcipher_request_set_crypt(req, &src, &dst, 16, NULL);
-	skcipher_request_set_callback(req, 0, crypto_req_done, &wait);
-	r = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
-	if (r)
-		goto out;
+	aes_encrypt(elephant->key, &ks[0], es.b);
 
 	/* E(Ks, e'(s)) */
-	es[15] = 0x80;
-	sg_init_one(&dst, &ks[16], 16);
-	r = crypto_wait_req(crypto_skcipher_encrypt(req), &wait);
-	if (r)
-		goto out;
+	es.b[15] = 0x80;
+	aes_encrypt(elephant->key, &ks[16], es.b);
 
 	sg = crypt_get_sg_data(cc, dmreq->sg_out);
 	data = kmap_local_page(sg_page(sg));
 	data_offset = data + sg->offset;
 
@@ -999,55 +983,46 @@ static int crypt_iv_elephant(struct crypt_config *cc, struct dm_crypt_request *d
 		diffuser_b_encrypt((u32 *)data_offset, cc->sector_size / sizeof(u32));
 		diffuser_cpu_to_disk((__le32 *)data_offset, cc->sector_size / sizeof(u32));
 	}
 
 	kunmap_local(data);
-out:
-	kfree_sensitive(ks);
-	kfree_sensitive(es);
-	skcipher_request_free(req);
-	return r;
+	memzero_explicit(ks, sizeof(ks));
+	memzero_explicit(&es, sizeof(es));
 }
 
 static int crypt_iv_elephant_gen(struct crypt_config *cc, u8 *iv,
 			    struct dm_crypt_request *dmreq)
 {
-	int r;
-
-	if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
-		r = crypt_iv_elephant(cc, dmreq);
-		if (r)
-			return r;
-	}
+	if (bio_data_dir(dmreq->ctx->bio_in) == WRITE)
+		crypt_iv_elephant(cc, dmreq);
 
 	return crypt_iv_eboiv_gen(cc, iv, dmreq);
 }
 
 static int crypt_iv_elephant_post(struct crypt_config *cc, u8 *iv,
 				  struct dm_crypt_request *dmreq)
 {
 	if (bio_data_dir(dmreq->ctx->bio_in) != WRITE)
-		return crypt_iv_elephant(cc, dmreq);
+		crypt_iv_elephant(cc, dmreq);
 
 	return 0;
 }
 
 static int crypt_iv_elephant_init(struct crypt_config *cc)
 {
 	struct iv_elephant_private *elephant = &cc->iv_gen_private.elephant;
 	int key_offset = cc->key_size - cc->key_extra_size;
 
-	return crypto_skcipher_setkey(elephant->tfm, &cc->key[key_offset], cc->key_extra_size);
+	return aes_prepareenckey(elephant->key, &cc->key[key_offset], cc->key_extra_size);
 }
 
 static int crypt_iv_elephant_wipe(struct crypt_config *cc)
 {
 	struct iv_elephant_private *elephant = &cc->iv_gen_private.elephant;
-	u8 key[ELEPHANT_MAX_KEY_SIZE];
 
-	memset(key, 0, cc->key_extra_size);
-	return crypto_skcipher_setkey(elephant->tfm, key, cc->key_extra_size);
+	memzero_explicit(elephant->key, sizeof(*elephant->key));
+	return 0;
 }
 
 static const struct crypt_iv_operations crypt_iv_plain_ops = {
 	.generator = crypt_iv_plain_gen
 };
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH 2/2] dm-crypt: Make crypt_iv_operations::wipe return void
  2026-03-21 23:06 [PATCH 0/2] dm-crypt: Reimplement elephant diffuser using AES library Eric Biggers
  2026-03-21 23:06 ` [PATCH 1/2] " Eric Biggers
@ 2026-03-21 23:06 ` Eric Biggers
  1 sibling, 0 replies; 3+ messages in thread
From: Eric Biggers @ 2026-03-21 23:06 UTC (permalink / raw)
  To: dm-devel; +Cc: linux-crypto, linux-kernel, Eric Biggers

Since all implementations of crypt_iv_operations::wipe now return 0,
change the return type to void.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 drivers/md/dm-crypt.c | 20 ++++++--------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 76b0c6bfd45c..885208a82c55 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -108,11 +108,11 @@ struct crypt_config;
 struct crypt_iv_operations {
 	int (*ctr)(struct crypt_config *cc, struct dm_target *ti,
 		   const char *opts);
 	void (*dtr)(struct crypt_config *cc);
 	int (*init)(struct crypt_config *cc);
-	int (*wipe)(struct crypt_config *cc);
+	void (*wipe)(struct crypt_config *cc);
 	int (*generator)(struct crypt_config *cc, u8 *iv,
 			 struct dm_crypt_request *dmreq);
 	int (*post)(struct crypt_config *cc, u8 *iv,
 		    struct dm_crypt_request *dmreq);
 };
@@ -506,18 +506,16 @@ static int crypt_iv_lmk_init(struct crypt_config *cc)
 		       MD5_DIGEST_SIZE);
 
 	return 0;
 }
 
-static int crypt_iv_lmk_wipe(struct crypt_config *cc)
+static void crypt_iv_lmk_wipe(struct crypt_config *cc)
 {
 	struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
 
 	if (lmk->seed)
 		memset(lmk->seed, 0, LMK_SEED_SIZE);
-
-	return 0;
 }
 
 static void crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
 			     struct dm_crypt_request *dmreq, u8 *data)
 {
@@ -627,18 +625,16 @@ static int crypt_iv_tcw_init(struct crypt_config *cc)
 	       TCW_WHITENING_SIZE);
 
 	return 0;
 }
 
-static int crypt_iv_tcw_wipe(struct crypt_config *cc)
+static void crypt_iv_tcw_wipe(struct crypt_config *cc)
 {
 	struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
 
 	memset(tcw->iv_seed, 0, cc->iv_size);
 	memset(tcw->whitening, 0, TCW_WHITENING_SIZE);
-
-	return 0;
 }
 
 static void crypt_iv_tcw_whitening(struct crypt_config *cc,
 				   struct dm_crypt_request *dmreq, u8 *data)
 {
@@ -1013,16 +1009,15 @@ static int crypt_iv_elephant_init(struct crypt_config *cc)
 	int key_offset = cc->key_size - cc->key_extra_size;
 
 	return aes_prepareenckey(elephant->key, &cc->key[key_offset], cc->key_extra_size);
 }
 
-static int crypt_iv_elephant_wipe(struct crypt_config *cc)
+static void crypt_iv_elephant_wipe(struct crypt_config *cc)
 {
 	struct iv_elephant_private *elephant = &cc->iv_gen_private.elephant;
 
 	memzero_explicit(elephant->key, sizeof(*elephant->key));
-	return 0;
 }
 
 static const struct crypt_iv_operations crypt_iv_plain_ops = {
 	.generator = crypt_iv_plain_gen
 };
@@ -2646,15 +2641,12 @@ static int crypt_wipe_key(struct crypt_config *cc)
 
 	clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
 	get_random_bytes(&cc->key, cc->key_size);
 
 	/* Wipe IV private keys */
-	if (cc->iv_gen_ops && cc->iv_gen_ops->wipe) {
-		r = cc->iv_gen_ops->wipe(cc);
-		if (r)
-			return r;
-	}
+	if (cc->iv_gen_ops && cc->iv_gen_ops->wipe)
+		cc->iv_gen_ops->wipe(cc);
 
 	kfree_sensitive(cc->key_string);
 	cc->key_string = NULL;
 	r = crypt_setkey(cc);
 	memset(&cc->key, 0, cc->key_size * sizeof(u8));
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-03-21 23:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-21 23:06 [PATCH 0/2] dm-crypt: Reimplement elephant diffuser using AES library Eric Biggers
2026-03-21 23:06 ` [PATCH 1/2] " Eric Biggers
2026-03-21 23:06 ` [PATCH 2/2] dm-crypt: Make crypt_iv_operations::wipe return void Eric Biggers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox