From patchwork Tue Dec 21 15:28:18 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Milan Broz X-Patchwork-Id: 424651 X-Patchwork-Delegate: agk@redhat.com Received: from mx3-phx2.redhat.com (mx3-phx2.redhat.com [209.132.183.24]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oBLFWJsK002639 for ; Tue, 21 Dec 2010 15:32:40 GMT Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by mx3-phx2.redhat.com (8.13.8/8.13.8) with ESMTP id oBLFUdWr015729; Tue, 21 Dec 2010 10:30:39 -0500 Received: from int-mx12.intmail.prod.int.phx2.redhat.com (int-mx12.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id oBLFTDE6005347 for ; Tue, 21 Dec 2010 10:29:13 -0500 Received: from tawny.mazyland.cz (tawny.brq.redhat.com [10.34.26.53]) by int-mx12.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id oBLFSSc2028030; Tue, 21 Dec 2010 10:29:07 -0500 From: Milan Broz To: dm-devel@redhat.com Date: Tue, 21 Dec 2010 16:28:18 +0100 Message-Id: <7a83b9feae17586e0f54b0d71afe7a49fc5b3daa.1292944625.git.mbroz@redhat.com> In-Reply-To: References: In-Reply-To: References: X-Scanned-By: MIMEDefang 2.68 on 10.5.11.25 X-loop: dm-devel@redhat.com Cc: Max Vozeler , Milan Broz Subject: [dm-devel] [PATCH 6/7] [RFC]dm crypt: add multi-key capability X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk Reply-To: device-mapper development List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 21 Dec 2010 15:32:40 +0000 (UTC) diff --git a/Documentation/device-mapper/dm-crypt.txt b/Documentation/device-mapper/dm-crypt.txt index 524de92..2bee19f 100644 --- a/Documentation/device-mapper/dm-crypt.txt +++ b/Documentation/device-mapper/dm-crypt.txt @@ -8,7 +8,7 @@ Parameters: Encryption cipher and an optional IV generation mode. - (In format cipher-chainmode-ivopts:ivmode). + (In format cipher[:keycount]-chainmode-ivopts:ivmode). Examples: des aes-cbc-essiv:sha256 @@ -20,6 +20,11 @@ Parameters: Key used for encryption. It is encoded as a hexadecimal number. You can only use key sizes that are valid for the selected cipher. + + Multi-key compatibility mode - you can define different keys and + the sectors are according its offset (sector 0 -> key0, 1 -> key1 etc). + Keycount must power of two. + The IV offset is a sector count that is added to the sector number before creating the IV. diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 451a743..3b9d3a0 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -99,10 +99,9 @@ enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID }; /* Duplicated per CPU state for cipher */ struct crypt_cpu { struct ablkcipher_request *req; - struct crypto_ablkcipher *tfm; - /* ESSIV: struct crypto_cipher *essiv_tfm */ void *iv_private; + struct crypto_ablkcipher *tfms[0]; }; /* @@ -141,6 +140,7 @@ struct crypt_config { * per_cpu_ptr() only. */ struct crypt_cpu __percpu *cpu; + unsigned int tfms_count; /* * Layout of each crypto request: @@ -159,6 +159,7 @@ struct crypt_config { unsigned long flags; unsigned int key_size; + unsigned int key_parts; u8 key[0]; }; @@ -182,7 +183,7 @@ static struct crypto_ablkcipher *any_tfm(struct crypt_config *cc) { struct crypto_ablkcipher *tfm; /* cpu doesn't matter, output is always the same */ - tfm = __this_cpu_ptr(cc->cpu)->tfm; + tfm = __this_cpu_ptr(cc->cpu)->tfms[0]; return tfm; } @@ -562,13 +563,23 @@ static int crypt_convert_block(struct crypt_config *cc, static void kcryptd_async_done(struct crypto_async_request *async_req, int error); +static struct crypto_ablkcipher *crypt_tfm(struct crypt_config *cc, + struct crypt_cpu *cs, + struct convert_context *ctx) +{ + if (cc->tfms_count == 1) + return cs->tfms[0]; + else + return cs->tfms[(ctx->sector & (cc->tfms_count - 1))]; +} + static void crypt_alloc_req(struct crypt_config *cc, struct convert_context *ctx) { struct crypt_cpu *cs = crypt_me(cc); if (!cs->req) cs->req = mempool_alloc(cc->req_pool, GFP_NOIO); - ablkcipher_request_set_tfm(cs->req, cs->tfm); + ablkcipher_request_set_tfm(cs->req, crypt_tfm(cc, cs, ctx)); ablkcipher_request_set_callback(cs->req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, kcryptd_async_done, @@ -1095,17 +1106,50 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size) } } +static void crypt_free_tfms(struct crypt_config *cc, int cpu) +{ + struct crypt_cpu *cs = per_cpu_ptr(cc->cpu, cpu); + int i; + + for (i = 0; i < cc->tfms_count; i++) + if (cs->tfms[i] && !IS_ERR(cs->tfms[i])) { + crypto_free_ablkcipher(cs->tfms[i]); + cs->tfms[i] = NULL; + } +} + +static int crypt_alloc_tfms(struct crypt_config *cc, int cpu, char *ciphermode) +{ + struct crypt_cpu *cs = per_cpu_ptr(cc->cpu, cpu); + int i, err; + + for (i = 0; i < cc->tfms_count; i++) { + cs->tfms[i] = crypto_alloc_ablkcipher(ciphermode, 0, 0); + if (IS_ERR(cs->tfms[i])) { + err = PTR_ERR(cs->tfms[i]); + crypt_free_tfms(cc, cpu); + return err; + } + } + + return 0; +} + static int crypt_setkey_allcpus(struct crypt_config *cc) { struct crypt_cpu *cs; - int cpu, n, err; + int cpu, i, n, err; + unsigned subkey_size = cc->key_size / cc->tfms_count; err = 0; for_each_possible_cpu(cpu) { cs = per_cpu_ptr(cc->cpu, cpu); - n = crypto_ablkcipher_setkey(cs->tfm, cc->key, cc->key_size); - if (n) - err = n; + for (i = 0; i < cc->tfms_count; i++) { + n = crypto_ablkcipher_setkey(cs->tfms[i], + cc->key + (i * subkey_size), subkey_size); + if (n) + err = n; + } } return err; } @@ -1154,8 +1198,7 @@ static void crypt_dtr(struct dm_target *ti) cs = per_cpu_ptr(cc->cpu, cpu); if (cs->req) mempool_free(cs->req, cc->req_pool); - if (cs->tfm) - crypto_free_ablkcipher(cs->tfm); + crypt_free_tfms(cc, cpu); } if (cc->bs) @@ -1188,8 +1231,7 @@ static int crypt_ctr_cipher(struct dm_target *ti, char *cipher_in, char *key) { struct crypt_config *cc = ti->private; - struct crypto_ablkcipher *tfm; - char *tmp, *cipher, *chainmode, *ivmode, *ivopts; + char *tmp, *cipher, *chainmode, *ivmode, *ivopts, *keycount; char *cipher_api = NULL; int cpu, ret = -EINVAL; @@ -1201,11 +1243,23 @@ static int crypt_ctr_cipher(struct dm_target *ti, /* * Legacy dm-crypt cipher specification - * cipher-mode-iv:ivopts + * cipher[:keycount]-mode-iv:ivopts */ tmp = cipher_in; cipher = strsep(&tmp, "-"); + keycount = cipher; + cipher = strsep(&keycount, ":"); + + if (!keycount) + cc->tfms_count = 1; + else if (sscanf(keycount, "%u", &cc->tfms_count) != 1 || + !is_power_of_2(cc->tfms_count)) { + ti->error = "Bad cipher key count specification"; + return -EINVAL; + } + cc->key_parts = cc->tfms_count; + cc->cipher = kstrdup(cipher, GFP_KERNEL); if (!cc->cipher) goto bad_mem; @@ -1223,7 +1277,9 @@ static int crypt_ctr_cipher(struct dm_target *ti, if (tmp) DMWARN("Ignoring unexpected additional cipher options"); - cc->cpu = alloc_percpu(struct crypt_cpu); + cc->cpu = __alloc_percpu(sizeof(*(cc->cpu)) + + cc->tfms_count * sizeof(*(cc->cpu->tfms)), + __alignof__(struct crypt_cpu)); if (!cc->cpu) { ti->error = "Cannot allocate per cpu state"; goto bad_mem; @@ -1255,14 +1311,12 @@ static int crypt_ctr_cipher(struct dm_target *ti, /* Allocate cipher */ for_each_possible_cpu (cpu) { - tfm = crypto_alloc_ablkcipher(cipher_api, 0, 0); - if (IS_ERR(tfm)) { - ret = PTR_ERR(tfm); + ret = crypt_alloc_tfms(cc, cpu, cipher_api); + if (ret < 0) { ti->error = "Error allocating crypto tfm"; goto bad; } - per_cpu_ptr(cc->cpu, cpu)->tfm = tfm; - } + } /* Initialize and set key */ ret = crypt_set_key(cc, key); @@ -1472,7 +1526,11 @@ static int crypt_status(struct dm_target *ti, status_type_t type, break; case STATUSTYPE_TABLE: - DMEMIT("%s-%s ", cc->cipher, cc->cipher_mode); + if (cc->tfms_count == 1) + DMEMIT("%s-%s ", cc->cipher, cc->cipher_mode); + else + DMEMIT("%s:%d-%s ", cc->cipher, cc->tfms_count, + cc->cipher_mode); if (cc->key_size > 0) { if ((maxlen - sz) < ((cc->key_size << 1) + 1)) @@ -1584,7 +1642,7 @@ static int crypt_iterate_devices(struct dm_target *ti, static struct target_type crypt_target = { .name = "crypt", - .version = {1, 7, 0}, + .version = {1, 8, 0}, .module = THIS_MODULE, .ctr = crypt_ctr, .dtr = crypt_dtr,