mirror of
https://github.com/torvalds/linux.git
synced 2026-05-12 16:18:45 +02:00
dm-crypt: Reimplement elephant diffuser using AES library
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>
This commit is contained in:
parent
0e4c1eb599
commit
d1c3b6b8e7
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
*(__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 = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user