|
@@ -2,6 +2,7 @@
|
|
|
* Copyright (C) 2003 Christophe Saout <christophe@saout.de>
|
|
|
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
|
|
|
* Copyright (C) 2006-2009 Red Hat, Inc. All rights reserved.
|
|
|
+ * Copyright (C) 2013 Milan Broz <gmazyland@gmail.com>
|
|
|
*
|
|
|
* This file is released under the GPL.
|
|
|
*/
|
|
@@ -98,6 +99,13 @@ struct iv_lmk_private {
|
|
|
u8 *seed;
|
|
|
};
|
|
|
|
|
|
+#define TCW_WHITENING_SIZE 16
|
|
|
+struct iv_tcw_private {
|
|
|
+ struct crypto_shash *crc32_tfm;
|
|
|
+ u8 *iv_seed;
|
|
|
+ u8 *whitening;
|
|
|
+};
|
|
|
+
|
|
|
/*
|
|
|
* Crypt: maps a linear range of a block device
|
|
|
* and encrypts / decrypts at the same time.
|
|
@@ -139,6 +147,7 @@ struct crypt_config {
|
|
|
struct iv_essiv_private essiv;
|
|
|
struct iv_benbi_private benbi;
|
|
|
struct iv_lmk_private lmk;
|
|
|
+ struct iv_tcw_private tcw;
|
|
|
} iv_gen_private;
|
|
|
sector_t iv_offset;
|
|
|
unsigned int iv_size;
|
|
@@ -231,6 +240,16 @@ static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc)
|
|
|
* version 3: the same as version 2 with additional IV seed
|
|
|
* (it uses 65 keys, last key is used as IV seed)
|
|
|
*
|
|
|
+ * tcw: Compatible implementation of the block chaining mode used
|
|
|
+ * by the TrueCrypt device encryption system (prior to version 4.1).
|
|
|
+ * For more info see: http://www.truecrypt.org
|
|
|
+ * It operates on full 512 byte sectors and uses CBC
|
|
|
+ * with an IV derived from initial key and the sector number.
|
|
|
+ * In addition, whitening value is applied on every sector, whitening
|
|
|
+ * is calculated from initial key, sector number and mixed using CRC32.
|
|
|
+ * Note that this encryption scheme is vulnerable to watermarking attacks
|
|
|
+ * and should be used for old compatible containers access only.
|
|
|
+ *
|
|
|
* plumb: unimplemented, see:
|
|
|
* http://article.gmane.org/gmane.linux.kernel.device-mapper.dm-crypt/454
|
|
|
*/
|
|
@@ -609,6 +628,153 @@ static int crypt_iv_lmk_post(struct crypt_config *cc, u8 *iv,
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
+static void crypt_iv_tcw_dtr(struct crypt_config *cc)
|
|
|
+{
|
|
|
+ struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
|
|
|
+
|
|
|
+ kzfree(tcw->iv_seed);
|
|
|
+ tcw->iv_seed = NULL;
|
|
|
+ kzfree(tcw->whitening);
|
|
|
+ tcw->whitening = NULL;
|
|
|
+
|
|
|
+ if (tcw->crc32_tfm && !IS_ERR(tcw->crc32_tfm))
|
|
|
+ crypto_free_shash(tcw->crc32_tfm);
|
|
|
+ tcw->crc32_tfm = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+static int crypt_iv_tcw_ctr(struct crypt_config *cc, struct dm_target *ti,
|
|
|
+ const char *opts)
|
|
|
+{
|
|
|
+ struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
|
|
|
+
|
|
|
+ if (cc->key_size <= (cc->iv_size + TCW_WHITENING_SIZE)) {
|
|
|
+ ti->error = "Wrong key size for TCW";
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ tcw->crc32_tfm = crypto_alloc_shash("crc32", 0, 0);
|
|
|
+ if (IS_ERR(tcw->crc32_tfm)) {
|
|
|
+ ti->error = "Error initializing CRC32 in TCW";
|
|
|
+ return PTR_ERR(tcw->crc32_tfm);
|
|
|
+ }
|
|
|
+
|
|
|
+ tcw->iv_seed = kzalloc(cc->iv_size, GFP_KERNEL);
|
|
|
+ tcw->whitening = kzalloc(TCW_WHITENING_SIZE, GFP_KERNEL);
|
|
|
+ if (!tcw->iv_seed || !tcw->whitening) {
|
|
|
+ crypt_iv_tcw_dtr(cc);
|
|
|
+ ti->error = "Error allocating seed storage in TCW";
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int crypt_iv_tcw_init(struct crypt_config *cc)
|
|
|
+{
|
|
|
+ struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
|
|
|
+ int key_offset = cc->key_size - cc->iv_size - TCW_WHITENING_SIZE;
|
|
|
+
|
|
|
+ memcpy(tcw->iv_seed, &cc->key[key_offset], cc->iv_size);
|
|
|
+ memcpy(tcw->whitening, &cc->key[key_offset + cc->iv_size],
|
|
|
+ TCW_WHITENING_SIZE);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int crypt_iv_tcw_wipe(struct crypt_config *cc)
|
|
|
+{
|
|
|
+ struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
|
|
|
+
|
|
|
+ memset(tcw->iv_seed, 0, cc->iv_size);
|
|
|
+ memset(tcw->whitening, 0, TCW_WHITENING_SIZE);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int crypt_iv_tcw_whitening(struct crypt_config *cc,
|
|
|
+ struct dm_crypt_request *dmreq,
|
|
|
+ u8 *data)
|
|
|
+{
|
|
|
+ struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
|
|
|
+ u64 sector = cpu_to_le64((u64)dmreq->iv_sector);
|
|
|
+ u8 buf[TCW_WHITENING_SIZE];
|
|
|
+ struct {
|
|
|
+ struct shash_desc desc;
|
|
|
+ char ctx[crypto_shash_descsize(tcw->crc32_tfm)];
|
|
|
+ } sdesc;
|
|
|
+ int i, r;
|
|
|
+
|
|
|
+ /* xor whitening with sector number */
|
|
|
+ memcpy(buf, tcw->whitening, TCW_WHITENING_SIZE);
|
|
|
+ crypto_xor(buf, (u8 *)§or, 8);
|
|
|
+ crypto_xor(&buf[8], (u8 *)§or, 8);
|
|
|
+
|
|
|
+ /* calculate crc32 for every 32bit part and xor it */
|
|
|
+ sdesc.desc.tfm = tcw->crc32_tfm;
|
|
|
+ sdesc.desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
|
|
+ for (i = 0; i < 4; i++) {
|
|
|
+ r = crypto_shash_init(&sdesc.desc);
|
|
|
+ if (r)
|
|
|
+ goto out;
|
|
|
+ r = crypto_shash_update(&sdesc.desc, &buf[i * 4], 4);
|
|
|
+ if (r)
|
|
|
+ goto out;
|
|
|
+ r = crypto_shash_final(&sdesc.desc, &buf[i * 4]);
|
|
|
+ if (r)
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ crypto_xor(&buf[0], &buf[12], 4);
|
|
|
+ crypto_xor(&buf[4], &buf[8], 4);
|
|
|
+
|
|
|
+ /* apply whitening (8 bytes) to whole sector */
|
|
|
+ for (i = 0; i < ((1 << SECTOR_SHIFT) / 8); i++)
|
|
|
+ crypto_xor(data + i * 8, buf, 8);
|
|
|
+out:
|
|
|
+ memset(buf, 0, sizeof(buf));
|
|
|
+ return r;
|
|
|
+}
|
|
|
+
|
|
|
+static int crypt_iv_tcw_gen(struct crypt_config *cc, u8 *iv,
|
|
|
+ struct dm_crypt_request *dmreq)
|
|
|
+{
|
|
|
+ struct iv_tcw_private *tcw = &cc->iv_gen_private.tcw;
|
|
|
+ u64 sector = cpu_to_le64((u64)dmreq->iv_sector);
|
|
|
+ u8 *src;
|
|
|
+ int r = 0;
|
|
|
+
|
|
|
+ /* Remove whitening from ciphertext */
|
|
|
+ if (bio_data_dir(dmreq->ctx->bio_in) != WRITE) {
|
|
|
+ src = kmap_atomic(sg_page(&dmreq->sg_in));
|
|
|
+ r = crypt_iv_tcw_whitening(cc, dmreq, src + dmreq->sg_in.offset);
|
|
|
+ kunmap_atomic(src);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Calculate IV */
|
|
|
+ memcpy(iv, tcw->iv_seed, cc->iv_size);
|
|
|
+ crypto_xor(iv, (u8 *)§or, 8);
|
|
|
+ if (cc->iv_size > 8)
|
|
|
+ crypto_xor(&iv[8], (u8 *)§or, cc->iv_size - 8);
|
|
|
+
|
|
|
+ return r;
|
|
|
+}
|
|
|
+
|
|
|
+static int crypt_iv_tcw_post(struct crypt_config *cc, u8 *iv,
|
|
|
+ struct dm_crypt_request *dmreq)
|
|
|
+{
|
|
|
+ u8 *dst;
|
|
|
+ int r;
|
|
|
+
|
|
|
+ if (bio_data_dir(dmreq->ctx->bio_in) != WRITE)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* Apply whitening on ciphertext */
|
|
|
+ dst = kmap_atomic(sg_page(&dmreq->sg_out));
|
|
|
+ r = crypt_iv_tcw_whitening(cc, dmreq, dst + dmreq->sg_out.offset);
|
|
|
+ kunmap_atomic(dst);
|
|
|
+
|
|
|
+ return r;
|
|
|
+}
|
|
|
+
|
|
|
static struct crypt_iv_operations crypt_iv_plain_ops = {
|
|
|
.generator = crypt_iv_plain_gen
|
|
|
};
|
|
@@ -644,6 +810,15 @@ static struct crypt_iv_operations crypt_iv_lmk_ops = {
|
|
|
.post = crypt_iv_lmk_post
|
|
|
};
|
|
|
|
|
|
+static struct crypt_iv_operations crypt_iv_tcw_ops = {
|
|
|
+ .ctr = crypt_iv_tcw_ctr,
|
|
|
+ .dtr = crypt_iv_tcw_dtr,
|
|
|
+ .init = crypt_iv_tcw_init,
|
|
|
+ .wipe = crypt_iv_tcw_wipe,
|
|
|
+ .generator = crypt_iv_tcw_gen,
|
|
|
+ .post = crypt_iv_tcw_post
|
|
|
+};
|
|
|
+
|
|
|
static void crypt_convert_init(struct crypt_config *cc,
|
|
|
struct convert_context *ctx,
|
|
|
struct bio *bio_out, struct bio *bio_in,
|
|
@@ -1491,14 +1666,20 @@ static int crypt_ctr_cipher(struct dm_target *ti,
|
|
|
cc->iv_gen_ops = &crypt_iv_null_ops;
|
|
|
else if (strcmp(ivmode, "lmk") == 0) {
|
|
|
cc->iv_gen_ops = &crypt_iv_lmk_ops;
|
|
|
- /* Version 2 and 3 is recognised according
|
|
|
+ /*
|
|
|
+ * Version 2 and 3 is recognised according
|
|
|
* to length of provided multi-key string.
|
|
|
* If present (version 3), last key is used as IV seed.
|
|
|
+ * All keys (including IV seed) are always the same size.
|
|
|
*/
|
|
|
if (cc->key_size % cc->key_parts) {
|
|
|
cc->key_parts++;
|
|
|
cc->key_extra_size = cc->key_size / cc->key_parts;
|
|
|
}
|
|
|
+ } else if (strcmp(ivmode, "tcw") == 0) {
|
|
|
+ cc->iv_gen_ops = &crypt_iv_tcw_ops;
|
|
|
+ cc->key_parts += 2; /* IV + whitening */
|
|
|
+ cc->key_extra_size = cc->iv_size + TCW_WHITENING_SIZE;
|
|
|
} else {
|
|
|
ret = -EINVAL;
|
|
|
ti->error = "Invalid IV mode";
|
|
@@ -1824,7 +2005,7 @@ static int crypt_iterate_devices(struct dm_target *ti,
|
|
|
|
|
|
static struct target_type crypt_target = {
|
|
|
.name = "crypt",
|
|
|
- .version = {1, 12, 1},
|
|
|
+ .version = {1, 13, 0},
|
|
|
.module = THIS_MODULE,
|
|
|
.ctr = crypt_ctr,
|
|
|
.dtr = crypt_dtr,
|