public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] dm-crypt: Use MD5 library instead of crypto_shash
@ 2025-10-11 18:10 Eric Biggers
  2025-10-13 13:57 ` Mikulas Patocka
  2025-10-14  7:56 ` Ard Biesheuvel
  0 siblings, 2 replies; 3+ messages in thread
From: Eric Biggers @ 2025-10-11 18:10 UTC (permalink / raw)
  To: dm-devel, Alasdair Kergon, Mike Snitzer, Mikulas Patocka
  Cc: linux-crypto, linux-kernel, Eric Biggers

The lmk IV mode, which dm-crypt supports for Loop-AES compatibility,
involves an MD5 computation.  Update its implementation to use the MD5
library API instead of crypto_shash.  This has many benefits, such as:

- Simpler code.  Notably, much of the error-handling code is no longer
  needed, since the library functions can't fail.

- Reduced stack usage.  crypt_iv_lmk_one() now allocates only 112 bytes
  on the stack instead of 520 bytes.

- The library functions are strongly typed, preventing bugs like
  https://lore.kernel.org/r/f1625ddc-e82e-4b77-80c2-dc8e45b54848@gmail.com

- Slightly improved performance, as the library provides direct access
  to the MD5 code without unnecessary overhead such as indirect calls.

To preserve the existing behavior of lmk support being disabled when the
kernel is booted with "fips=1", make crypt_iv_lmk_ctr() check
fips_enabled itself.  Previously it relied on crypto_alloc_shash("md5")
failing.  (I don't know for sure that lmk *actually* needs to be
disallowed in FIPS mode; this just preserves the existing behavior.)

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

diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 104aa53550905..dcd232a2ca244 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -297,10 +297,11 @@ config DM_CRYPT
 	depends on (TRUSTED_KEYS || TRUSTED_KEYS=n)
 	select CRC32
 	select CRYPTO
 	select CRYPTO_CBC
 	select CRYPTO_ESSIV
+	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 5ef43231fe77f..04a553529dc27 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -19,10 +19,11 @@
 #include <linux/blk-integrity.h>
 #include <linux/crc32.h>
 #include <linux/mempool.h>
 #include <linux/slab.h>
 #include <linux/crypto.h>
+#include <linux/fips.h>
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
 #include <linux/backing-dev.h>
 #include <linux/atomic.h>
 #include <linux/scatterlist.h>
@@ -118,11 +119,10 @@ struct iv_benbi_private {
 	int shift;
 };
 
 #define LMK_SEED_SIZE 64 /* hash + 0 */
 struct iv_lmk_private {
-	struct crypto_shash *hash_tfm;
 	u8 *seed;
 };
 
 #define TCW_WHITENING_SIZE 16
 struct iv_tcw_private {
@@ -463,14 +463,10 @@ static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv,
 
 static void crypt_iv_lmk_dtr(struct crypt_config *cc)
 {
 	struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
 
-	if (lmk->hash_tfm && !IS_ERR(lmk->hash_tfm))
-		crypto_free_shash(lmk->hash_tfm);
-	lmk->hash_tfm = NULL;
-
 	kfree_sensitive(lmk->seed);
 	lmk->seed = NULL;
 }
 
 static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
@@ -481,26 +477,24 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
 	if (cc->sector_size != (1 << SECTOR_SHIFT)) {
 		ti->error = "Unsupported sector size for LMK";
 		return -EINVAL;
 	}
 
-	lmk->hash_tfm = crypto_alloc_shash("md5", 0,
-					   CRYPTO_ALG_ALLOCATES_MEMORY);
-	if (IS_ERR(lmk->hash_tfm)) {
-		ti->error = "Error initializing LMK hash";
-		return PTR_ERR(lmk->hash_tfm);
+	if (fips_enabled) {
+		ti->error = "LMK support is disabled due to FIPS";
+		/* ... because it uses MD5. */
+		return -EINVAL;
 	}
 
 	/* No seed in LMK version 2 */
 	if (cc->key_parts == cc->tfms_count) {
 		lmk->seed = NULL;
 		return 0;
 	}
 
 	lmk->seed = kzalloc(LMK_SEED_SIZE, GFP_KERNEL);
 	if (!lmk->seed) {
-		crypt_iv_lmk_dtr(cc);
 		ti->error = "Error kmallocing seed storage in LMK";
 		return -ENOMEM;
 	}
 
 	return 0;
@@ -512,11 +506,11 @@ static int crypt_iv_lmk_init(struct crypt_config *cc)
 	int subkey_size = cc->key_size / cc->key_parts;
 
 	/* LMK seed is on the position of LMK_KEYS + 1 key */
 	if (lmk->seed)
 		memcpy(lmk->seed, cc->key + (cc->tfms_count * subkey_size),
-		       crypto_shash_digestsize(lmk->hash_tfm));
+		       MD5_DIGEST_SIZE);
 
 	return 0;
 }
 
 static int crypt_iv_lmk_wipe(struct crypt_config *cc)
@@ -527,99 +521,71 @@ static int crypt_iv_lmk_wipe(struct crypt_config *cc)
 		memset(lmk->seed, 0, LMK_SEED_SIZE);
 
 	return 0;
 }
 
-static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
-			    struct dm_crypt_request *dmreq,
-			    u8 *data)
+static void crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
+			     struct dm_crypt_request *dmreq, u8 *data)
 {
 	struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
-	SHASH_DESC_ON_STACK(desc, lmk->hash_tfm);
-	union {
-		struct md5_state md5state;
-		u8 state[CRYPTO_MD5_STATESIZE];
-	} u;
+	struct md5_ctx ctx;
 	__le32 buf[4];
-	int i, r;
 
-	desc->tfm = lmk->hash_tfm;
-
-	r = crypto_shash_init(desc);
-	if (r)
-		return r;
+	md5_init(&ctx);
 
-	if (lmk->seed) {
-		r = crypto_shash_update(desc, lmk->seed, LMK_SEED_SIZE);
-		if (r)
-			return r;
-	}
+	if (lmk->seed)
+		md5_update(&ctx, lmk->seed, LMK_SEED_SIZE);
 
 	/* Sector is always 512B, block size 16, add data of blocks 1-31 */
-	r = crypto_shash_update(desc, data + 16, 16 * 31);
-	if (r)
-		return r;
+	md5_update(&ctx, data + 16, 16 * 31);
 
 	/* Sector is cropped to 56 bits here */
 	buf[0] = cpu_to_le32(dmreq->iv_sector & 0xFFFFFFFF);
 	buf[1] = cpu_to_le32((((u64)dmreq->iv_sector >> 32) & 0x00FFFFFF) | 0x80000000);
 	buf[2] = cpu_to_le32(4024);
 	buf[3] = 0;
-	r = crypto_shash_update(desc, (u8 *)buf, sizeof(buf));
-	if (r)
-		return r;
+	md5_update(&ctx, (u8 *)buf, sizeof(buf));
 
 	/* No MD5 padding here */
-	r = crypto_shash_export(desc, &u.md5state);
-	if (r)
-		return r;
-
-	for (i = 0; i < MD5_HASH_WORDS; i++)
-		__cpu_to_le32s(&u.md5state.hash[i]);
-	memcpy(iv, &u.md5state.hash, cc->iv_size);
-
-	return 0;
+	cpu_to_le32_array(ctx.state.h, ARRAY_SIZE(ctx.state.h));
+	memcpy(iv, ctx.state.h, cc->iv_size);
 }
 
 static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv,
 			    struct dm_crypt_request *dmreq)
 {
 	struct scatterlist *sg;
 	u8 *src;
-	int r = 0;
 
 	if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
 		sg = crypt_get_sg_data(cc, dmreq->sg_in);
 		src = kmap_local_page(sg_page(sg));
-		r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
+		crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
 		kunmap_local(src);
 	} else
 		memset(iv, 0, cc->iv_size);
-
-	return r;
+	return 0;
 }
 
 static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
 			     struct dm_crypt_request *dmreq)
 {
 	struct scatterlist *sg;
 	u8 *dst;
-	int r;
 
 	if (bio_data_dir(dmreq->ctx->bio_in) == WRITE)
 		return 0;
 
 	sg = crypt_get_sg_data(cc, dmreq->sg_out);
 	dst = kmap_local_page(sg_page(sg));
-	r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
+	crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
 
 	/* Tweak the first block of plaintext sector */
-	if (!r)
-		crypto_xor(dst + sg->offset, iv, cc->iv_size);
+	crypto_xor(dst + sg->offset, iv, cc->iv_size);
 
 	kunmap_local(dst);
-	return r;
+	return 0;
 }
 
 static void crypt_iv_tcw_dtr(struct crypt_config *cc)
 {
 	struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;

base-commit: 8bd9238e511d02831022ff0270865c54ccc482d6
-- 
2.51.0


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

* Re: [PATCH] dm-crypt: Use MD5 library instead of crypto_shash
  2025-10-11 18:10 [PATCH] dm-crypt: Use MD5 library instead of crypto_shash Eric Biggers
@ 2025-10-13 13:57 ` Mikulas Patocka
  2025-10-14  7:56 ` Ard Biesheuvel
  1 sibling, 0 replies; 3+ messages in thread
From: Mikulas Patocka @ 2025-10-13 13:57 UTC (permalink / raw)
  To: Eric Biggers
  Cc: dm-devel, Alasdair Kergon, Mike Snitzer, linux-crypto,
	linux-kernel

OK.

I accepted the patch.

Mikulas



On Sat, 11 Oct 2025, Eric Biggers wrote:

> The lmk IV mode, which dm-crypt supports for Loop-AES compatibility,
> involves an MD5 computation.  Update its implementation to use the MD5
> library API instead of crypto_shash.  This has many benefits, such as:
> 
> - Simpler code.  Notably, much of the error-handling code is no longer
>   needed, since the library functions can't fail.
> 
> - Reduced stack usage.  crypt_iv_lmk_one() now allocates only 112 bytes
>   on the stack instead of 520 bytes.
> 
> - The library functions are strongly typed, preventing bugs like
>   https://lore.kernel.org/r/f1625ddc-e82e-4b77-80c2-dc8e45b54848@gmail.com
> 
> - Slightly improved performance, as the library provides direct access
>   to the MD5 code without unnecessary overhead such as indirect calls.
> 
> To preserve the existing behavior of lmk support being disabled when the
> kernel is booted with "fips=1", make crypt_iv_lmk_ctr() check
> fips_enabled itself.  Previously it relied on crypto_alloc_shash("md5")
> failing.  (I don't know for sure that lmk *actually* needs to be
> disallowed in FIPS mode; this just preserves the existing behavior.)
> 
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> ---
>  drivers/md/Kconfig    |  1 +
>  drivers/md/dm-crypt.c | 76 ++++++++++++-------------------------------
>  2 files changed, 22 insertions(+), 55 deletions(-)
> 
> diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
> index 104aa53550905..dcd232a2ca244 100644
> --- a/drivers/md/Kconfig
> +++ b/drivers/md/Kconfig
> @@ -297,10 +297,11 @@ config DM_CRYPT
>  	depends on (TRUSTED_KEYS || TRUSTED_KEYS=n)
>  	select CRC32
>  	select CRYPTO
>  	select CRYPTO_CBC
>  	select CRYPTO_ESSIV
> +	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 5ef43231fe77f..04a553529dc27 100644
> --- a/drivers/md/dm-crypt.c
> +++ b/drivers/md/dm-crypt.c
> @@ -19,10 +19,11 @@
>  #include <linux/blk-integrity.h>
>  #include <linux/crc32.h>
>  #include <linux/mempool.h>
>  #include <linux/slab.h>
>  #include <linux/crypto.h>
> +#include <linux/fips.h>
>  #include <linux/workqueue.h>
>  #include <linux/kthread.h>
>  #include <linux/backing-dev.h>
>  #include <linux/atomic.h>
>  #include <linux/scatterlist.h>
> @@ -118,11 +119,10 @@ struct iv_benbi_private {
>  	int shift;
>  };
>  
>  #define LMK_SEED_SIZE 64 /* hash + 0 */
>  struct iv_lmk_private {
> -	struct crypto_shash *hash_tfm;
>  	u8 *seed;
>  };
>  
>  #define TCW_WHITENING_SIZE 16
>  struct iv_tcw_private {
> @@ -463,14 +463,10 @@ static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv,
>  
>  static void crypt_iv_lmk_dtr(struct crypt_config *cc)
>  {
>  	struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
>  
> -	if (lmk->hash_tfm && !IS_ERR(lmk->hash_tfm))
> -		crypto_free_shash(lmk->hash_tfm);
> -	lmk->hash_tfm = NULL;
> -
>  	kfree_sensitive(lmk->seed);
>  	lmk->seed = NULL;
>  }
>  
>  static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
> @@ -481,26 +477,24 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
>  	if (cc->sector_size != (1 << SECTOR_SHIFT)) {
>  		ti->error = "Unsupported sector size for LMK";
>  		return -EINVAL;
>  	}
>  
> -	lmk->hash_tfm = crypto_alloc_shash("md5", 0,
> -					   CRYPTO_ALG_ALLOCATES_MEMORY);
> -	if (IS_ERR(lmk->hash_tfm)) {
> -		ti->error = "Error initializing LMK hash";
> -		return PTR_ERR(lmk->hash_tfm);
> +	if (fips_enabled) {
> +		ti->error = "LMK support is disabled due to FIPS";
> +		/* ... because it uses MD5. */
> +		return -EINVAL;
>  	}
>  
>  	/* No seed in LMK version 2 */
>  	if (cc->key_parts == cc->tfms_count) {
>  		lmk->seed = NULL;
>  		return 0;
>  	}
>  
>  	lmk->seed = kzalloc(LMK_SEED_SIZE, GFP_KERNEL);
>  	if (!lmk->seed) {
> -		crypt_iv_lmk_dtr(cc);
>  		ti->error = "Error kmallocing seed storage in LMK";
>  		return -ENOMEM;
>  	}
>  
>  	return 0;
> @@ -512,11 +506,11 @@ static int crypt_iv_lmk_init(struct crypt_config *cc)
>  	int subkey_size = cc->key_size / cc->key_parts;
>  
>  	/* LMK seed is on the position of LMK_KEYS + 1 key */
>  	if (lmk->seed)
>  		memcpy(lmk->seed, cc->key + (cc->tfms_count * subkey_size),
> -		       crypto_shash_digestsize(lmk->hash_tfm));
> +		       MD5_DIGEST_SIZE);
>  
>  	return 0;
>  }
>  
>  static int crypt_iv_lmk_wipe(struct crypt_config *cc)
> @@ -527,99 +521,71 @@ static int crypt_iv_lmk_wipe(struct crypt_config *cc)
>  		memset(lmk->seed, 0, LMK_SEED_SIZE);
>  
>  	return 0;
>  }
>  
> -static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
> -			    struct dm_crypt_request *dmreq,
> -			    u8 *data)
> +static void crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
> +			     struct dm_crypt_request *dmreq, u8 *data)
>  {
>  	struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
> -	SHASH_DESC_ON_STACK(desc, lmk->hash_tfm);
> -	union {
> -		struct md5_state md5state;
> -		u8 state[CRYPTO_MD5_STATESIZE];
> -	} u;
> +	struct md5_ctx ctx;
>  	__le32 buf[4];
> -	int i, r;
>  
> -	desc->tfm = lmk->hash_tfm;
> -
> -	r = crypto_shash_init(desc);
> -	if (r)
> -		return r;
> +	md5_init(&ctx);
>  
> -	if (lmk->seed) {
> -		r = crypto_shash_update(desc, lmk->seed, LMK_SEED_SIZE);
> -		if (r)
> -			return r;
> -	}
> +	if (lmk->seed)
> +		md5_update(&ctx, lmk->seed, LMK_SEED_SIZE);
>  
>  	/* Sector is always 512B, block size 16, add data of blocks 1-31 */
> -	r = crypto_shash_update(desc, data + 16, 16 * 31);
> -	if (r)
> -		return r;
> +	md5_update(&ctx, data + 16, 16 * 31);
>  
>  	/* Sector is cropped to 56 bits here */
>  	buf[0] = cpu_to_le32(dmreq->iv_sector & 0xFFFFFFFF);
>  	buf[1] = cpu_to_le32((((u64)dmreq->iv_sector >> 32) & 0x00FFFFFF) | 0x80000000);
>  	buf[2] = cpu_to_le32(4024);
>  	buf[3] = 0;
> -	r = crypto_shash_update(desc, (u8 *)buf, sizeof(buf));
> -	if (r)
> -		return r;
> +	md5_update(&ctx, (u8 *)buf, sizeof(buf));
>  
>  	/* No MD5 padding here */
> -	r = crypto_shash_export(desc, &u.md5state);
> -	if (r)
> -		return r;
> -
> -	for (i = 0; i < MD5_HASH_WORDS; i++)
> -		__cpu_to_le32s(&u.md5state.hash[i]);
> -	memcpy(iv, &u.md5state.hash, cc->iv_size);
> -
> -	return 0;
> +	cpu_to_le32_array(ctx.state.h, ARRAY_SIZE(ctx.state.h));
> +	memcpy(iv, ctx.state.h, cc->iv_size);
>  }
>  
>  static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv,
>  			    struct dm_crypt_request *dmreq)
>  {
>  	struct scatterlist *sg;
>  	u8 *src;
> -	int r = 0;
>  
>  	if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
>  		sg = crypt_get_sg_data(cc, dmreq->sg_in);
>  		src = kmap_local_page(sg_page(sg));
> -		r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
> +		crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
>  		kunmap_local(src);
>  	} else
>  		memset(iv, 0, cc->iv_size);
> -
> -	return r;
> +	return 0;
>  }
>  
>  static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
>  			     struct dm_crypt_request *dmreq)
>  {
>  	struct scatterlist *sg;
>  	u8 *dst;
> -	int r;
>  
>  	if (bio_data_dir(dmreq->ctx->bio_in) == WRITE)
>  		return 0;
>  
>  	sg = crypt_get_sg_data(cc, dmreq->sg_out);
>  	dst = kmap_local_page(sg_page(sg));
> -	r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
> +	crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
>  
>  	/* Tweak the first block of plaintext sector */
> -	if (!r)
> -		crypto_xor(dst + sg->offset, iv, cc->iv_size);
> +	crypto_xor(dst + sg->offset, iv, cc->iv_size);
>  
>  	kunmap_local(dst);
> -	return r;
> +	return 0;
>  }
>  
>  static void crypt_iv_tcw_dtr(struct crypt_config *cc)
>  {
>  	struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
> 
> base-commit: 8bd9238e511d02831022ff0270865c54ccc482d6
> -- 
> 2.51.0
> 


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

* Re: [PATCH] dm-crypt: Use MD5 library instead of crypto_shash
  2025-10-11 18:10 [PATCH] dm-crypt: Use MD5 library instead of crypto_shash Eric Biggers
  2025-10-13 13:57 ` Mikulas Patocka
@ 2025-10-14  7:56 ` Ard Biesheuvel
  1 sibling, 0 replies; 3+ messages in thread
From: Ard Biesheuvel @ 2025-10-14  7:56 UTC (permalink / raw)
  To: Eric Biggers
  Cc: dm-devel, Alasdair Kergon, Mike Snitzer, Mikulas Patocka,
	linux-crypto, linux-kernel

On Sat, 11 Oct 2025 at 20:12, Eric Biggers <ebiggers@kernel.org> wrote:
>
> The lmk IV mode, which dm-crypt supports for Loop-AES compatibility,
> involves an MD5 computation.  Update its implementation to use the MD5
> library API instead of crypto_shash.  This has many benefits, such as:
>
> - Simpler code.  Notably, much of the error-handling code is no longer
>   needed, since the library functions can't fail.
>
> - Reduced stack usage.  crypt_iv_lmk_one() now allocates only 112 bytes
>   on the stack instead of 520 bytes.
>
> - The library functions are strongly typed, preventing bugs like
>   https://lore.kernel.org/r/f1625ddc-e82e-4b77-80c2-dc8e45b54848@gmail.com
>
> - Slightly improved performance, as the library provides direct access
>   to the MD5 code without unnecessary overhead such as indirect calls.
>
> To preserve the existing behavior of lmk support being disabled when the
> kernel is booted with "fips=1", make crypt_iv_lmk_ctr() check
> fips_enabled itself.  Previously it relied on crypto_alloc_shash("md5")
> failing.  (I don't know for sure that lmk *actually* needs to be
> disallowed in FIPS mode; this just preserves the existing behavior.)
>
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>

Acked-by: Ard Biesheuvel <ardb@kernel.org>

> ---
>  drivers/md/Kconfig    |  1 +
>  drivers/md/dm-crypt.c | 76 ++++++++++++-------------------------------
>  2 files changed, 22 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
> index 104aa53550905..dcd232a2ca244 100644
> --- a/drivers/md/Kconfig
> +++ b/drivers/md/Kconfig
> @@ -297,10 +297,11 @@ config DM_CRYPT
>         depends on (TRUSTED_KEYS || TRUSTED_KEYS=n)
>         select CRC32
>         select CRYPTO
>         select CRYPTO_CBC
>         select CRYPTO_ESSIV
> +       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 5ef43231fe77f..04a553529dc27 100644
> --- a/drivers/md/dm-crypt.c
> +++ b/drivers/md/dm-crypt.c
> @@ -19,10 +19,11 @@
>  #include <linux/blk-integrity.h>
>  #include <linux/crc32.h>
>  #include <linux/mempool.h>
>  #include <linux/slab.h>
>  #include <linux/crypto.h>
> +#include <linux/fips.h>
>  #include <linux/workqueue.h>
>  #include <linux/kthread.h>
>  #include <linux/backing-dev.h>
>  #include <linux/atomic.h>
>  #include <linux/scatterlist.h>
> @@ -118,11 +119,10 @@ struct iv_benbi_private {
>         int shift;
>  };
>
>  #define LMK_SEED_SIZE 64 /* hash + 0 */
>  struct iv_lmk_private {
> -       struct crypto_shash *hash_tfm;
>         u8 *seed;
>  };
>
>  #define TCW_WHITENING_SIZE 16
>  struct iv_tcw_private {
> @@ -463,14 +463,10 @@ static int crypt_iv_null_gen(struct crypt_config *cc, u8 *iv,
>
>  static void crypt_iv_lmk_dtr(struct crypt_config *cc)
>  {
>         struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
>
> -       if (lmk->hash_tfm && !IS_ERR(lmk->hash_tfm))
> -               crypto_free_shash(lmk->hash_tfm);
> -       lmk->hash_tfm = NULL;
> -
>         kfree_sensitive(lmk->seed);
>         lmk->seed = NULL;
>  }
>
>  static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
> @@ -481,26 +477,24 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
>         if (cc->sector_size != (1 << SECTOR_SHIFT)) {
>                 ti->error = "Unsupported sector size for LMK";
>                 return -EINVAL;
>         }
>
> -       lmk->hash_tfm = crypto_alloc_shash("md5", 0,
> -                                          CRYPTO_ALG_ALLOCATES_MEMORY);
> -       if (IS_ERR(lmk->hash_tfm)) {
> -               ti->error = "Error initializing LMK hash";
> -               return PTR_ERR(lmk->hash_tfm);
> +       if (fips_enabled) {
> +               ti->error = "LMK support is disabled due to FIPS";
> +               /* ... because it uses MD5. */
> +               return -EINVAL;
>         }
>
>         /* No seed in LMK version 2 */
>         if (cc->key_parts == cc->tfms_count) {
>                 lmk->seed = NULL;
>                 return 0;
>         }
>
>         lmk->seed = kzalloc(LMK_SEED_SIZE, GFP_KERNEL);
>         if (!lmk->seed) {
> -               crypt_iv_lmk_dtr(cc);
>                 ti->error = "Error kmallocing seed storage in LMK";
>                 return -ENOMEM;
>         }
>
>         return 0;
> @@ -512,11 +506,11 @@ static int crypt_iv_lmk_init(struct crypt_config *cc)
>         int subkey_size = cc->key_size / cc->key_parts;
>
>         /* LMK seed is on the position of LMK_KEYS + 1 key */
>         if (lmk->seed)
>                 memcpy(lmk->seed, cc->key + (cc->tfms_count * subkey_size),
> -                      crypto_shash_digestsize(lmk->hash_tfm));
> +                      MD5_DIGEST_SIZE);
>
>         return 0;
>  }
>
>  static int crypt_iv_lmk_wipe(struct crypt_config *cc)
> @@ -527,99 +521,71 @@ static int crypt_iv_lmk_wipe(struct crypt_config *cc)
>                 memset(lmk->seed, 0, LMK_SEED_SIZE);
>
>         return 0;
>  }
>
> -static int crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
> -                           struct dm_crypt_request *dmreq,
> -                           u8 *data)
> +static void crypt_iv_lmk_one(struct crypt_config *cc, u8 *iv,
> +                            struct dm_crypt_request *dmreq, u8 *data)
>  {
>         struct iv_lmk_private *lmk = &cc->iv_gen_private.lmk;
> -       SHASH_DESC_ON_STACK(desc, lmk->hash_tfm);
> -       union {
> -               struct md5_state md5state;
> -               u8 state[CRYPTO_MD5_STATESIZE];
> -       } u;
> +       struct md5_ctx ctx;
>         __le32 buf[4];
> -       int i, r;
>
> -       desc->tfm = lmk->hash_tfm;
> -
> -       r = crypto_shash_init(desc);
> -       if (r)
> -               return r;
> +       md5_init(&ctx);
>
> -       if (lmk->seed) {
> -               r = crypto_shash_update(desc, lmk->seed, LMK_SEED_SIZE);
> -               if (r)
> -                       return r;
> -       }
> +       if (lmk->seed)
> +               md5_update(&ctx, lmk->seed, LMK_SEED_SIZE);
>
>         /* Sector is always 512B, block size 16, add data of blocks 1-31 */
> -       r = crypto_shash_update(desc, data + 16, 16 * 31);
> -       if (r)
> -               return r;
> +       md5_update(&ctx, data + 16, 16 * 31);
>
>         /* Sector is cropped to 56 bits here */
>         buf[0] = cpu_to_le32(dmreq->iv_sector & 0xFFFFFFFF);
>         buf[1] = cpu_to_le32((((u64)dmreq->iv_sector >> 32) & 0x00FFFFFF) | 0x80000000);
>         buf[2] = cpu_to_le32(4024);
>         buf[3] = 0;
> -       r = crypto_shash_update(desc, (u8 *)buf, sizeof(buf));
> -       if (r)
> -               return r;
> +       md5_update(&ctx, (u8 *)buf, sizeof(buf));
>
>         /* No MD5 padding here */
> -       r = crypto_shash_export(desc, &u.md5state);
> -       if (r)
> -               return r;
> -
> -       for (i = 0; i < MD5_HASH_WORDS; i++)
> -               __cpu_to_le32s(&u.md5state.hash[i]);
> -       memcpy(iv, &u.md5state.hash, cc->iv_size);
> -
> -       return 0;
> +       cpu_to_le32_array(ctx.state.h, ARRAY_SIZE(ctx.state.h));
> +       memcpy(iv, ctx.state.h, cc->iv_size);
>  }
>
>  static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv,
>                             struct dm_crypt_request *dmreq)
>  {
>         struct scatterlist *sg;
>         u8 *src;
> -       int r = 0;
>
>         if (bio_data_dir(dmreq->ctx->bio_in) == WRITE) {
>                 sg = crypt_get_sg_data(cc, dmreq->sg_in);
>                 src = kmap_local_page(sg_page(sg));
> -               r = crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
> +               crypt_iv_lmk_one(cc, iv, dmreq, src + sg->offset);
>                 kunmap_local(src);
>         } else
>                 memset(iv, 0, cc->iv_size);
> -
> -       return r;
> +       return 0;
>  }
>
>  static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
>                              struct dm_crypt_request *dmreq)
>  {
>         struct scatterlist *sg;
>         u8 *dst;
> -       int r;
>
>         if (bio_data_dir(dmreq->ctx->bio_in) == WRITE)
>                 return 0;
>
>         sg = crypt_get_sg_data(cc, dmreq->sg_out);
>         dst = kmap_local_page(sg_page(sg));
> -       r = crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
> +       crypt_iv_lmk_one(cc, iv, dmreq, dst + sg->offset);
>
>         /* Tweak the first block of plaintext sector */
> -       if (!r)
> -               crypto_xor(dst + sg->offset, iv, cc->iv_size);
> +       crypto_xor(dst + sg->offset, iv, cc->iv_size);
>
>         kunmap_local(dst);
> -       return r;
> +       return 0;
>  }
>
>  static void crypt_iv_tcw_dtr(struct crypt_config *cc)
>  {
>         struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
>
> base-commit: 8bd9238e511d02831022ff0270865c54ccc482d6
> --
> 2.51.0
>
>

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

end of thread, other threads:[~2025-10-14  7:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-11 18:10 [PATCH] dm-crypt: Use MD5 library instead of crypto_shash Eric Biggers
2025-10-13 13:57 ` Mikulas Patocka
2025-10-14  7:56 ` Ard Biesheuvel

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