@@ -8,7 +8,7 @@ Parameters: <cipher> <key> <iv_offset> <device path> <offset>
<cipher>
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: <cipher> <key> <iv_offset> <device path> <offset>
Key used for encryption. It is encoded as a hexadecimal number.
You can only use key sizes that are valid for the selected cipher.
+<keycount>
+ 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.
+
<iv_offset>
The IV offset is a sector count that is added to the sector number
before creating the IV.
@@ -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,