lkml.org 
[lkml]   [2004]   [Feb]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [PATCH/proposal] dm-crypt: add digest-based iv generation mode
On Fri, Feb 20, 2004 at 12:14:27PM -0500, Jean-Luc Cooke wrote:

> As for naming the cipher-hash as "aes-sha256", why not just go all the way
> and specify the mode of operation as well?
>
> cipher-hash-modeop example: aes-sha256-cbc

cipher-modeop[-hash] is less ambiguous, because the hash-less config is
the backward-compatible mode (and for Kamikaze ECB mode).

> As for hashing the hey etc. You should be using HMAC for that.

Ok, I've rewritten it so you can now generate an IV through HMAC with
a user-specified digest and changed the config string to
<cipher>-<mode>[-<digest>].

And I'm memcpy'ing the tfm onto the stack now to have a local copy.
So I don't need to lock and it makes HMAC precomputation possible
because I don't destroy the original tfm context.

(this is a diff against the original dm-crypt version in linux-2.6.3-mm1)


diff -Nur linux-2.6.3-mm1.orig/drivers/md/dm-crypt.c linux-2.6.3-mm1/drivers/md/dm-crypt.c
--- linux-2.6.3-mm1.orig/drivers/md/dm-crypt.c 2004-02-21 03:05:21.444341304 +0100
+++ linux-2.6.3-mm1/drivers/md/dm-crypt.c 2004-02-21 03:05:44.070901544 +0100
@@ -61,11 +61,13 @@
/*
* crypto related data
*/
- struct crypto_tfm *tfm;
+ struct crypto_tfm *cipher;
+ struct crypto_tfm *digest;
sector_t iv_offset;
int (*iv_generator)(struct crypt_config *cc, u8 *iv, sector_t sector);
int iv_size;
int key_size;
+ int digest_size;
u8 key[0];
};

@@ -102,6 +104,32 @@
return 0;
}

+static int crypt_iv_hmac(struct crypt_config *cc, u8 *iv, sector_t sector)
+{
+ struct scatterlist sg = {
+ .page = virt_to_page(iv),
+ .offset = offset_in_page(iv),
+ .length = sizeof(u64) / sizeof(u8)
+ };
+ int i;
+ int tfm_size = sizeof(*cc->digest) + cc->digest->__crt_alg->cra_ctxsize;
+ char tfm[tfm_size];
+
+ *(u64 *)iv = cpu_to_le64((u64)sector);
+
+ /* HMAC has already been initialized, finish it on private copy */
+ memcpy(tfm, cc->digest, tfm_size);
+ crypto_hmac_update(cc->digest, &sg, 1);
+ crypto_hmac_final(cc->digest, cc->key,
+ (unsigned int *)&cc->key_size, iv);
+
+ /* fill the rest of the vector if it is larger */
+ for(i = cc->digest_size; i < cc->iv_size; i += cc->digest_size)
+ memcpy(iv + i, iv, min(cc->digest_size, cc->iv_size - i));
+
+ return 0;
+}
+
static inline int
crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out,
struct scatterlist *in, unsigned int length,
@@ -116,14 +144,14 @@
return r;

if (write)
- r = crypto_cipher_encrypt_iv(cc->tfm, out, in, length, iv);
+ r = crypto_cipher_encrypt_iv(cc->cipher, out, in, length, iv);
else
- r = crypto_cipher_decrypt_iv(cc->tfm, out, in, length, iv);
+ r = crypto_cipher_decrypt_iv(cc->cipher, out, in, length, iv);
} else {
if (write)
- r = crypto_cipher_encrypt(cc->tfm, out, in, length);
+ r = crypto_cipher_encrypt(cc->cipher, out, in, length);
else
- r = crypto_cipher_decrypt(cc->tfm, out, in, length);
+ r = crypto_cipher_decrypt(cc->cipher, out, in, length);
}

return r;
@@ -401,6 +429,17 @@
}
}

+static struct cipher_mode {
+ const char *name;
+ int mode;
+} cipher_modes[] = {
+ { "ecb", CRYPTO_TFM_MODE_ECB },
+ { "cbc", CRYPTO_TFM_MODE_CBC },
+ { "cfb", CRYPTO_TFM_MODE_CFB },
+ { "ctr", CRYPTO_TFM_MODE_CTR },
+ { NULL, 0 }
+};
+
/*
* Construct an encryption mapping:
* <cipher> <key> <iv_offset> <dev_path> <start>
@@ -412,6 +451,7 @@
char *tmp;
char *cipher;
char *mode;
+ char *digest;
int crypto_flags;
int key_size;

@@ -423,10 +463,32 @@
tmp = argv[0];
cipher = strsep(&tmp, "-");
mode = strsep(&tmp, "-");
+ digest = strsep(&tmp, "-");

if (tmp)
DMWARN("dm-crypt: Unexpected additional cipher options");

+ if (mode) {
+ struct cipher_mode *cm;
+
+ for(cm = cipher_modes; cm->name; cm++)
+ if (strcmp(cm->name, mode) == 0)
+ break;
+ if (!cm->name) {
+ ti->error = "dm-crypt: Invalid cipher mode";
+ return -EINVAL;
+ }
+
+ crypto_flags = cm->mode;
+ } else {
+ crypto_flags = CRYPTO_TFM_MODE_CBC;
+ }
+
+ if (crypto_flags == CRYPTO_TFM_MODE_ECB && digest) {
+ ti->error = "dm-crypt: ECB does not support IVs";
+ return -EINVAL;
+ }
+
key_size = strlen(argv[1]) >> 1;

cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
@@ -436,40 +498,55 @@
return -ENOMEM;
}

- if (!mode || strcmp(mode, "plain") == 0)
- cc->iv_generator = crypt_iv_plain;
- else if (strcmp(mode, "ecb") == 0)
+ cc->digest_size = 0;
+ cc->digest = NULL;
+ if (crypto_flags == CRYPTO_TFM_MODE_ECB)
cc->iv_generator = NULL;
+ else if (!digest)
+ cc->iv_generator = crypt_iv_plain;
else {
- ti->error = "dm-crypt: Invalid chaining mode";
- goto bad1;
- }
+ /* the IV generator is the name of a digest used for HMAC */
+ tfm = crypto_alloc_tfm(digest, 0);
+ if (!tfm) {
+ ti->error = "dm-crypt: Error allocating digest tfm";
+ goto bad1;
+ }
+ if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST) {
+ ti->error = "dm-crypt: Expected digest algorithm";
+ goto bad1;
+ }

- if (cc->iv_generator)
- crypto_flags = CRYPTO_TFM_MODE_CBC;
- else
- crypto_flags = CRYPTO_TFM_MODE_ECB;
+ cc->digest = tfm;
+ cc->digest_size = crypto_tfm_alg_digestsize(tfm);
+ cc->iv_generator = crypt_iv_hmac;
+ }

tfm = crypto_alloc_tfm(cipher, crypto_flags);
if (!tfm) {
ti->error = "dm-crypt: Error allocating crypto tfm";
goto bad1;
}
+ if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) {
+ ti->error = "dm-crypt: Expected cipher algorithm";
+ goto bad2;
+ }

- if (tfm->crt_u.cipher.cit_decrypt_iv && tfm->crt_u.cipher.cit_encrypt_iv)
- /* at least a 32 bit sector number should fit in our buffer */
+ if (tfm->crt_cipher.cit_decrypt_iv &&
+ tfm->crt_cipher.cit_encrypt_iv) {
+ /* at least a sector number should fit in our buffer */
cc->iv_size = max(crypto_tfm_alg_ivsize(tfm),
- (unsigned int)(sizeof(u32) / sizeof(u8)));
- else {
+ (unsigned int)(sizeof(u64) / sizeof(u8)));
+ cc->iv_size = max(cc->iv_size, cc->digest_size);
+ } else {
cc->iv_size = 0;
if (cc->iv_generator) {
- DMWARN("dm-crypt: Selected cipher does not support IVs");
- cc->iv_generator = NULL;
+ ti->error = "dm-crypt: Cipher does not support IVs";
+ goto bad2;
}
}

cc->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab,
- mempool_free_slab, _crypt_io_pool);
+ mempool_free_slab, _crypt_io_pool);
if (!cc->io_pool) {
ti->error = "dm-crypt: Cannot allocate crypt io mempool";
goto bad2;
@@ -482,7 +559,7 @@
goto bad3;
}

- cc->tfm = tfm;
+ cc->cipher = tfm;
cc->key_size = key_size;
if ((key_size == 0 && strcmp(argv[1], "-") != 0)
|| crypt_decode_key(cc->key, argv[1], key_size) < 0) {
@@ -490,11 +567,16 @@
goto bad4;
}

- if (tfm->crt_u.cipher.cit_setkey(tfm, cc->key, key_size) < 0) {
+ if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) {
ti->error = "dm-crypt: Error setting key";
goto bad4;
}

+ /* precompute part of the HMAC here, it only depends on the key */
+ if (cc->digest)
+ crypto_hmac_init(cc->digest, cc->key,
+ (unsigned int *)&key_size);
+
if (sscanf(argv[2], SECTOR_FORMAT, &cc->iv_offset) != 1) {
ti->error = "dm-crypt: Invalid iv_offset sector";
goto bad4;
@@ -521,6 +603,8 @@
bad2:
crypto_free_tfm(tfm);
bad1:
+ if (cc->digest)
+ crypto_free_tfm(cc->digest);
kfree(cc);
return -EINVAL;
}
@@ -532,7 +616,10 @@
mempool_destroy(cc->page_pool);
mempool_destroy(cc->io_pool);

- crypto_free_tfm(cc->tfm);
+ crypto_free_tfm(cc->cipher);
+ if (cc->digest)
+ crypto_free_tfm(cc->digest);
+
dm_put_device(ti, cc->dev);
kfree(cc);
}
@@ -669,9 +756,10 @@
char *result, unsigned int maxlen)
{
struct crypt_config *cc = (struct crypt_config *) ti->private;
+ struct cipher_mode *cm;
char buffer[32];
const char *cipher;
- const char *mode = NULL;
+ const char *digest;
int offset;

switch (type) {
@@ -680,20 +768,20 @@
break;

case STATUSTYPE_TABLE:
- cipher = crypto_tfm_alg_name(cc->tfm);
+ cipher = crypto_tfm_alg_name(cc->cipher);

- switch(cc->tfm->crt_u.cipher.cit_mode) {
- case CRYPTO_TFM_MODE_CBC:
- mode = "plain";
- break;
- case CRYPTO_TFM_MODE_ECB:
- mode = "ecb";
- break;
- default:
- BUG();
- }
+ for(cm = cipher_modes; cm->name; cm++)
+ if (cm->mode == cc->cipher->crt_cipher.cit_mode)
+ break;
+ BUG_ON(!cm->name);
+
+ if (cc->digest)
+ digest = crypto_tfm_alg_name(cc->digest);
+ else
+ digest = "";

- snprintf(result, maxlen, "%s-%s ", cipher, mode);
+ snprintf(result, maxlen, "%s-%s%s%s ", cipher, cm->name,
+ digest[0] ? "-" : "", digest);
offset = strlen(result);

if (cc->key_size > 0) {
diff -Nur linux-2.6.3-mm1.orig/drivers/md/Kconfig linux-2.6.3-mm1/drivers/md/Kconfig
--- linux-2.6.3-mm1.orig/drivers/md/Kconfig 2004-02-21 03:04:59.338701872 +0100
+++ linux-2.6.3-mm1/drivers/md/Kconfig 2004-02-21 03:05:44.071901392 +0100
@@ -174,6 +174,7 @@
tristate "Crypt target support"
depends on BLK_DEV_DM && EXPERIMENTAL
select CRYPTO
+ select CRYPTO_HMAC
---help---
This device-mapper target allows you to create a device that
transparently encrypts the data on it. You'll need to activate
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2005-03-22 14:01    [W:0.269 / U:0.100 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site