]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
dm-crypt: Reimplement elephant diffuser using AES library
authorEric Biggers <ebiggers@kernel.org>
Sat, 21 Mar 2026 23:06:50 +0000 (16:06 -0700)
committerMikulas Patocka <mpatocka@redhat.com>
Mon, 23 Mar 2026 16:51:13 +0000 (17:51 +0100)
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>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
drivers/md/Kconfig
drivers/md/dm-crypt.c

index 53351048d3ec64c6459600d362aa71547916142b..a3fcdca7e6db3178cb4b25f3f32de15043f81198 100644 (file)
@@ -300,6 +300,7 @@ config DM_CRYPT
        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
index 54823341c9fda46b2d8e13428cbd51f3edf642d5..76b0c6bfd45cc17ad9c67d9890575fd48ef7f1a3 100644 (file)
@@ -32,6 +32,7 @@
 #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>
@@ -133,7 +134,7 @@ struct iv_tcw_private {
 
 #define ELEPHANT_MAX_KEY_SIZE 32
 struct iv_elephant_private {
-       struct crypto_skcipher *tfm;
+       struct aes_enckey *key;
 };
 
 /*
@@ -767,8 +768,8 @@ 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,
@@ -777,13 +778,9 @@ static int crypt_iv_elephant_ctr(struct crypt_config *cc, struct dm_target *ti,
        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)
@@ -935,41 +932,28 @@ static void diffuser_b_encrypt(u32 *d, size_t n)
        }
 }
 
-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));
@@ -1001,23 +985,15 @@ static int crypt_iv_elephant(struct crypt_config *cc, struct dm_crypt_request *d
        }
 
        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);
 }
@@ -1026,7 +1002,7 @@ 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;
 }
@@ -1036,16 +1012,15 @@ 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 = {