Commit d1c3b6b8 authored by Eric Biggers's avatar Eric Biggers Committed by Mikulas Patocka
Browse files

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: default avatarEric Biggers <ebiggers@kernel.org>
Signed-off-by: default avatarMikulas Patocka <mpatocka@redhat.com>
parent 0e4c1eb5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+30 −55
Original line number Diff line number Diff line
@@ -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 = {