mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-26 01:22:40 -04:00
dm-crypt: Use MD5 library instead of crypto_shash
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> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Acked-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
committed by
Mikulas Patocka
parent
3a86608788
commit
ba59e59b8b
@@ -299,6 +299,7 @@ config DM_CRYPT
|
||||
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
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#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>
|
||||
@@ -120,7 +121,6 @@ struct iv_benbi_private {
|
||||
|
||||
#define LMK_SEED_SIZE 64 /* hash + 0 */
|
||||
struct iv_lmk_private {
|
||||
struct crypto_shash *hash_tfm;
|
||||
u8 *seed;
|
||||
};
|
||||
|
||||
@@ -465,10 +465,6 @@ 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;
|
||||
}
|
||||
@@ -483,11 +479,10 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
|
||||
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 */
|
||||
@@ -498,7 +493,6 @@ static int crypt_iv_lmk_ctr(struct crypt_config *cc, struct dm_target *ti,
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -514,7 +508,7 @@ static int crypt_iv_lmk_init(struct crypt_config *cc)
|
||||
/* 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;
|
||||
}
|
||||
@@ -529,55 +523,31 @@ static int crypt_iv_lmk_wipe(struct crypt_config *cc)
|
||||
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;
|
||||
md5_init(&ctx);
|
||||
|
||||
r = crypto_shash_init(desc);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
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,
|
||||
@@ -585,17 +555,15 @@ static int crypt_iv_lmk_gen(struct crypt_config *cc, u8 *iv,
|
||||
{
|
||||
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,
|
||||
@@ -603,21 +571,19 @@ static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
|
||||
{
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user