diff mbox

[1/2] dm-crypt: Properly handle extra key string in initialization

Message ID 1382275000-10660-1-git-send-email-gmazyland@gmail.com (mailing list archive)
State Superseded, archived
Delegated to: Mike Snitzer
Headers show

Commit Message

Milan Broz Oct. 20, 2013, 1:16 p.m. UTC
Some encryption modes use extra keys (e.g. loopAES has IV seed)
which are not used in block cipher initialization but are part
of key string in table constructor.

Patch adds additional field which described lengh of this extra
keys and substracts it before real key encryption setting.

Because extra keys are calculated during IV mode setting,
key initialization is moved after this step.

For now, this change has no effect to supported modes
(thanks to ilog2 rounding) but is required by following patch.

Signed-off-by: Milan Broz <gmazyland@gmail.com>
---
 drivers/md/dm-crypt.c | 27 +++++++++++++++++----------
 1 file changed, 17 insertions(+), 10 deletions(-)

Comments

Mike Snitzer Oct. 28, 2013, 3:44 p.m. UTC | #1
On Sun, Oct 20 2013 at  9:16am -0400,
Milan Broz <gmazyland@gmail.com> wrote:

> Some encryption modes use extra keys (e.g. loopAES has IV seed)
> which are not used in block cipher initialization but are part
> of key string in table constructor.
> 
> Patch adds additional field which described lengh of this extra
> keys and substracts it before real key encryption setting.

typo, s/lengh/length/

But that aside, an example of the extra keys use with a theoretical
example via ctr input -- documented in patch header -- would be
helpful.  As it stands the code is doing some unituitive things (see
below).

> Because extra keys are calculated during IV mode setting,
> key initialization is moved after this step.
> 
> For now, this change has no effect to supported modes
> (thanks to ilog2 rounding) but is required by following patch.
> 
> Signed-off-by: Milan Broz <gmazyland@gmail.com>
> ---
>  drivers/md/dm-crypt.c | 27 +++++++++++++++++----------
>  1 file changed, 17 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> index 0fce0bc..878bda7 100644
> --- a/drivers/md/dm-crypt.c
> +++ b/drivers/md/dm-crypt.c
> @@ -1497,14 +1495,23 @@ static int crypt_ctr_cipher(struct dm_target *ti,
>  		 * to length of provided multi-key string.
>  		 * If present (version 3), last key is used as IV seed.
>  		 */
> -		if (cc->key_size % cc->key_parts)
> +		if (cc->key_size % cc->key_parts) {
>  			cc->key_parts++;
> +			cc->key_extra_size = cc->key_size / cc->key_parts;
> +		}

This is leveraging existing heuristics of bumping key_parts and then
using it to establish 'key_extra_size' -- but the definition of "extra
size" is eluding me.  Say key_size=101, kepyparts=10 -- remainder is 1.
So then key_extra_size = 9.

All a bit opaque to me without a ctr usage example to help document in
the patch header.

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
Milan Broz Oct. 28, 2013, 4:46 p.m. UTC | #2
On 28.10.2013 16:44, Mike Snitzer wrote:
> On Sun, Oct 20 2013 at  9:16am -0400,
> Milan Broz <gmazyland@gmail.com> wrote:

>> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
>> index 0fce0bc..878bda7 100644
>> --- a/drivers/md/dm-crypt.c
>> +++ b/drivers/md/dm-crypt.c
>> @@ -1497,14 +1495,23 @@ static int crypt_ctr_cipher(struct dm_target *ti,
>>   		 * to length of provided multi-key string.
>>   		 * If present (version 3), last key is used as IV seed.
>>   		 */
>> -		if (cc->key_size % cc->key_parts)
>> +		if (cc->key_size % cc->key_parts) {
>>   			cc->key_parts++;
>> +			cc->key_extra_size = cc->key_size / cc->key_parts;
>> +		}
>
> This is leveraging existing heuristics of bumping key_parts and then
> using it to establish 'key_extra_size' -- but the definition of "extra
> size" is eluding me.  Say key_size=101, kepyparts=10 -- remainder is 1.
> So then key_extra_size = 9.
>
> All a bit opaque to me without a ctr usage example to help document in
> the patch header.

All this is because the table format was not designed to include more
independent keys...
(And changing it now will cause more incompatibility problems it solves.)


Anyway, if this helps:

"TCW" is just a shortcut to identify this mode,
(TrueCrypt with whitening if you want)

It uses is normal CBC mode (note cbc in cipher definition)
but with additional operation (whitening) and with key seeded
Initial vector. These additional operations are implemented
in "dmcrypt tcw iv generator".

It requires 3 independent keys:

K - is the normal encryption key, size depends on algorithm
(this is what you see for "normal" dmcrypt mapping)

Kiv - is the key used to seed Initial vector generator,
size is always the same as IV size of algorithm above
(so it is variable)

Kw - is the key used to seed whitening (and additional operation)
size is always 16 bytes (fixed)

I am partially abusing IV generator in dmcrypt for other
work (whitening) (but the same way as we already have in loopAES format).

In fact, whitening is not related to IV at all but this is the simplest
way hot to implement it.

(And again, it is very similar to loopAES handling which
uses multiple keys already.)

Example:

For activation used by cryptsetup
# cryptsetup tcryptOpen ../tc-cbc/tc-cbc-serpent.img tc

we have this table (split to parts)

# dmsetup table --showkeys tc

0 16383 crypt serpent-cbc-tcw \

34f95b96abff946b64f1339ff8653cc77c38697c93b797a496f3786e86eed778 \
# ^^^ this is serpent cipher encryption key K

1850d5112bbae17d209b8310a8f3a034 \
# ^^^ this is the seed for IV, Kiv
  
f1cd297667bc0cd1438fad28d87ef6a1 \
# ^^^ this is the seed for whitening, Kw

1 7:0 1


IOW, for tcw constructor the format of key is simply

K | Kiv | Kw

and key_parts and key_extra_size is just helper how to parse
it properly.

So, key parts = 3 in this case (we have 3 keys - K, Kiv, Kw).

key_extra_size is length of key string which contains additional
keys sizeof(Kiv + Kw) which are not used for encryption algorithm
but are processed elsewhere (in iv generator ctr).


Example for existing loopAES ("lmk IV generator") key is e.g.

K1...K64 | Kiv

(first 64 keys are for 64 independent tcms, Kiv is additional
Key used to seed IV. Thus key_parts = 65, key_extra_size = sizeof(Kiv)
because all keys including Kiv are always of the same size, code
can simply do cc->key_extra_size = cc->key_size / cc->key_parts)


In short, key_parts should now contain number of independent keys
in dmcrypt key mapping table string.

key_extra_size should contain length of the key which must
be cut off when setting core cipher key because this part is
processed elsewhere.

Milan

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
diff mbox

Patch

diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 0fce0bc..878bda7 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -171,7 +171,8 @@  struct crypt_config {
 
 	unsigned long flags;
 	unsigned int key_size;
-	unsigned int key_parts;
+	unsigned int key_parts;     /* independent parts in key buffer */
+	unsigned int key_extra_size;/* additional keys length */
 	u8 key[0];
 };
 
@@ -1274,9 +1275,12 @@  static int crypt_alloc_tfms(struct crypt_config *cc, char *ciphermode)
 
 static int crypt_setkey_allcpus(struct crypt_config *cc)
 {
-	unsigned subkey_size = cc->key_size >> ilog2(cc->tfms_count);
+	unsigned subkey_size;
 	int err = 0, i, r;
 
+	/* Ignore extra keys (which are used for IV etc) */
+	subkey_size = (cc->key_size - cc->key_extra_size) >> ilog2(cc->tfms_count);
+
 	for (i = 0; i < cc->tfms_count; i++) {
 		r = crypto_ablkcipher_setkey(cc->tfms[i],
 					     cc->key + (i * subkey_size),
@@ -1409,6 +1413,7 @@  static int crypt_ctr_cipher(struct dm_target *ti,
 		return -EINVAL;
 	}
 	cc->key_parts = cc->tfms_count;
+	cc->key_extra_size = 0;
 
 	cc->cipher = kstrdup(cipher, GFP_KERNEL);
 	if (!cc->cipher)
@@ -1460,13 +1465,6 @@  static int crypt_ctr_cipher(struct dm_target *ti,
 		goto bad;
 	}
 
-	/* Initialize and set key */
-	ret = crypt_set_key(cc, key);
-	if (ret < 0) {
-		ti->error = "Error decoding and setting key";
-		goto bad;
-	}
-
 	/* Initialize IV */
 	cc->iv_size = crypto_ablkcipher_ivsize(any_tfm(cc));
 	if (cc->iv_size)
@@ -1497,14 +1495,23 @@  static int crypt_ctr_cipher(struct dm_target *ti,
 		 * to length of provided multi-key string.
 		 * If present (version 3), last key is used as IV seed.
 		 */
-		if (cc->key_size % cc->key_parts)
+		if (cc->key_size % cc->key_parts) {
 			cc->key_parts++;
+			cc->key_extra_size = cc->key_size / cc->key_parts;
+		}
 	} else {
 		ret = -EINVAL;
 		ti->error = "Invalid IV mode";
 		goto bad;
 	}
 
+	/* Initialize and set key */
+	ret = crypt_set_key(cc, key);
+	if (ret < 0) {
+		ti->error = "Error decoding and setting key";
+		goto bad;
+	}
+
 	/* Allocate IV */
 	if (cc->iv_gen_ops && cc->iv_gen_ops->ctr) {
 		ret = cc->iv_gen_ops->ctr(cc, ti, ivopts);