Commit 5ebaee6d authored by Milan Broz's avatar Milan Broz Committed by Alasdair G Kergon

dm crypt: simplify crypt_ctr

Allocate cipher strings indpendently of struct crypt_config and move
cipher parsing and allocation into a separate function to prepare for
supporting the cryptoapi format e.g. "xts(aes)".

No functional change in this patch.
Signed-off-by: default avatarMilan Broz <mbroz@redhat.com>
Signed-off-by: default avatarAlasdair G Kergon <agk@redhat.com>
parent 28513fcc
...@@ -107,11 +107,10 @@ struct crypt_config { ...@@ -107,11 +107,10 @@ struct crypt_config {
struct workqueue_struct *io_queue; struct workqueue_struct *io_queue;
struct workqueue_struct *crypt_queue; struct workqueue_struct *crypt_queue;
/* char *cipher;
* crypto related data char *cipher_mode;
*/
struct crypt_iv_operations *iv_gen_ops; struct crypt_iv_operations *iv_gen_ops;
char *iv_mode;
union { union {
struct iv_essiv_private essiv; struct iv_essiv_private essiv;
struct iv_benbi_private benbi; struct iv_benbi_private benbi;
...@@ -135,8 +134,6 @@ struct crypt_config { ...@@ -135,8 +134,6 @@ struct crypt_config {
unsigned int dmreq_start; unsigned int dmreq_start;
struct ablkcipher_request *req; struct ablkcipher_request *req;
char cipher[CRYPTO_MAX_ALG_NAME];
char chainmode[CRYPTO_MAX_ALG_NAME];
struct crypto_ablkcipher *tfm; struct crypto_ablkcipher *tfm;
unsigned long flags; unsigned long flags;
unsigned int key_size; unsigned int key_size;
...@@ -1032,90 +1029,102 @@ static void crypt_dtr(struct dm_target *ti) ...@@ -1032,90 +1029,102 @@ static void crypt_dtr(struct dm_target *ti)
if (cc->dev) if (cc->dev)
dm_put_device(ti, cc->dev); dm_put_device(ti, cc->dev);
kfree(cc->iv_mode); kzfree(cc->cipher);
kzfree(cc->cipher_mode);
/* Must zero key material before freeing */ /* Must zero key material before freeing */
kzfree(cc); kzfree(cc);
} }
/* static int crypt_ctr_cipher(struct dm_target *ti,
* Construct an encryption mapping: char *cipher_in, char *key)
* <cipher> <key> <iv_offset> <dev_path> <start>
*/
static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{ {
struct crypt_config *cc; struct crypt_config *cc = ti->private;
char *tmp; char *tmp, *cipher, *chainmode, *ivmode, *ivopts;
char *cipher; char *cipher_api = NULL;
char *chainmode;
char *ivmode;
char *ivopts;
unsigned int key_size;
unsigned long long tmpll;
int ret = -EINVAL; int ret = -EINVAL;
if (argc != 5) { /* Convert to crypto api definition? */
ti->error = "Not enough arguments"; if (strchr(cipher_in, '(')) {
ti->error = "Bad cipher specification";
return -EINVAL; return -EINVAL;
} }
tmp = argv[0]; /*
* Legacy dm-crypt cipher specification
* cipher-mode-iv:ivopts
*/
tmp = cipher_in;
cipher = strsep(&tmp, "-"); cipher = strsep(&tmp, "-");
cc->cipher = kstrdup(cipher, GFP_KERNEL);
if (!cc->cipher)
goto bad_mem;
if (tmp) {
cc->cipher_mode = kstrdup(tmp, GFP_KERNEL);
if (!cc->cipher_mode)
goto bad_mem;
}
chainmode = strsep(&tmp, "-"); chainmode = strsep(&tmp, "-");
ivopts = strsep(&tmp, "-"); ivopts = strsep(&tmp, "-");
ivmode = strsep(&ivopts, ":"); ivmode = strsep(&ivopts, ":");
if (tmp) if (tmp)
DMWARN("Unexpected additional cipher options"); DMWARN("Ignoring unexpected additional cipher options");
key_size = strlen(argv[1]) >> 1;
cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
if (!cc) {
ti->error = "Cannot allocate transparent encryption context";
return -ENOMEM;
}
ti->private = cc; /* Compatibility mode for old dm-crypt mappings */
if (!chainmode || (!strcmp(chainmode, "plain") && !ivmode)) {
/* Compatibility mode for old dm-crypt cipher strings */ kfree(cc->cipher_mode);
if (!chainmode || (strcmp(chainmode, "plain") == 0 && !ivmode)) { cc->cipher_mode = kstrdup("cbc-plain", GFP_KERNEL);
chainmode = "cbc"; chainmode = "cbc";
ivmode = "plain"; ivmode = "plain";
} }
if (strcmp(chainmode, "ecb") && !ivmode) { if (strcmp(chainmode, "ecb") && !ivmode) {
ti->error = "This chaining mode requires an IV mechanism"; ti->error = "IV mechanism required";
goto bad; return -EINVAL;
} }
ret = -ENOMEM; cipher_api = kmalloc(CRYPTO_MAX_ALG_NAME, GFP_KERNEL);
if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)", if (!cipher_api)
chainmode, cipher) >= CRYPTO_MAX_ALG_NAME) { goto bad_mem;
ti->error = "Chain mode + cipher name is too long";
goto bad; ret = snprintf(cipher_api, CRYPTO_MAX_ALG_NAME,
"%s(%s)", chainmode, cipher);
if (ret < 0) {
kfree(cipher_api);
goto bad_mem;
} }
cc->tfm = crypto_alloc_ablkcipher(cc->cipher, 0, 0); /* Allocate cipher */
cc->tfm = crypto_alloc_ablkcipher(cipher_api, 0, 0);
if (IS_ERR(cc->tfm)) { if (IS_ERR(cc->tfm)) {
ret = PTR_ERR(cc->tfm);
ti->error = "Error allocating crypto tfm"; ti->error = "Error allocating crypto tfm";
goto bad; goto bad;
} }
strcpy(cc->cipher, cipher); /* Initialize and set key */
strcpy(cc->chainmode, chainmode); ret = crypt_set_key(cc, key);
ret = crypt_set_key(cc, argv[1]);
if (ret < 0) { if (ret < 0) {
ti->error = "Error decoding and setting key"; ti->error = "Error decoding and setting key";
goto bad; goto bad;
} }
/* /* Initialize IV */
* Choose ivmode. Valid modes: "plain", "essiv:<esshash>", "benbi". cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm);
* See comments at iv code if (cc->iv_size)
*/ /* at least a 64 bit sector number should fit in our buffer */
ret = -EINVAL; cc->iv_size = max(cc->iv_size,
(unsigned int)(sizeof(u64) / sizeof(u8)));
else if (ivmode) {
DMWARN("Selected cipher does not support IVs");
ivmode = NULL;
}
/* Choose ivmode, see comments at iv code. */
if (ivmode == NULL) if (ivmode == NULL)
cc->iv_gen_ops = NULL; cc->iv_gen_ops = NULL;
else if (strcmp(ivmode, "plain") == 0) else if (strcmp(ivmode, "plain") == 0)
...@@ -1129,6 +1138,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1129,6 +1138,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
else if (strcmp(ivmode, "null") == 0) else if (strcmp(ivmode, "null") == 0)
cc->iv_gen_ops = &crypt_iv_null_ops; cc->iv_gen_ops = &crypt_iv_null_ops;
else { else {
ret = -EINVAL;
ti->error = "Invalid IV mode"; ti->error = "Invalid IV mode";
goto bad; goto bad;
} }
...@@ -1151,20 +1161,45 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1151,20 +1161,45 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
} }
} }
cc->iv_size = crypto_ablkcipher_ivsize(cc->tfm); ret = 0;
if (cc->iv_size) bad:
/* at least a 64 bit sector number should fit in our buffer */ kfree(cipher_api);
cc->iv_size = max(cc->iv_size, return ret;
(unsigned int)(sizeof(u64) / sizeof(u8)));
else { bad_mem:
if (cc->iv_gen_ops) { ti->error = "Cannot allocate cipher strings";
DMWARN("Selected cipher does not support IVs"); return -ENOMEM;
if (cc->iv_gen_ops->dtr) }
cc->iv_gen_ops->dtr(cc);
cc->iv_gen_ops = NULL; /*
* Construct an encryption mapping:
* <cipher> <key> <iv_offset> <dev_path> <start>
*/
static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct crypt_config *cc;
unsigned int key_size;
unsigned long long tmpll;
int ret;
if (argc != 5) {
ti->error = "Not enough arguments";
return -EINVAL;
} }
key_size = strlen(argv[1]) >> 1;
cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
if (!cc) {
ti->error = "Cannot allocate encryption context";
return -ENOMEM;
} }
ti->private = cc;
ret = crypt_ctr_cipher(ti, argv[0], argv[1]);
if (ret < 0)
goto bad;
ret = -ENOMEM; ret = -ENOMEM;
cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool); cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
if (!cc->io_pool) { if (!cc->io_pool) {
...@@ -1217,17 +1252,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) ...@@ -1217,17 +1252,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
cc->start = tmpll; cc->start = tmpll;
ret = -ENOMEM; ret = -ENOMEM;
if (ivmode && cc->iv_gen_ops) {
if (ivopts)
*(ivopts - 1) = ':';
cc->iv_mode = kstrdup(ivmode, GFP_KERNEL);
if (!cc->iv_mode) {
ti->error = "Error kmallocing iv_mode string";
goto bad;
}
} else
cc->iv_mode = NULL;
cc->io_queue = create_singlethread_workqueue("kcryptd_io"); cc->io_queue = create_singlethread_workqueue("kcryptd_io");
if (!cc->io_queue) { if (!cc->io_queue) {
ti->error = "Couldn't create kcryptd io queue"; ti->error = "Couldn't create kcryptd io queue";
...@@ -1273,7 +1297,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio, ...@@ -1273,7 +1297,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio,
static int crypt_status(struct dm_target *ti, status_type_t type, static int crypt_status(struct dm_target *ti, status_type_t type,
char *result, unsigned int maxlen) char *result, unsigned int maxlen)
{ {
struct crypt_config *cc = (struct crypt_config *) ti->private; struct crypt_config *cc = ti->private;
unsigned int sz = 0; unsigned int sz = 0;
switch (type) { switch (type) {
...@@ -1282,11 +1306,10 @@ static int crypt_status(struct dm_target *ti, status_type_t type, ...@@ -1282,11 +1306,10 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
break; break;
case STATUSTYPE_TABLE: case STATUSTYPE_TABLE:
if (cc->iv_mode) if (cc->cipher_mode)
DMEMIT("%s-%s-%s ", cc->cipher, cc->chainmode, DMEMIT("%s-%s ", cc->cipher, cc->cipher_mode);
cc->iv_mode);
else else
DMEMIT("%s-%s ", cc->cipher, cc->chainmode); DMEMIT("%s ", cc->cipher);
if (cc->key_size > 0) { if (cc->key_size > 0) {
if ((maxlen - sz) < ((cc->key_size << 1) + 1)) if ((maxlen - sz) < ((cc->key_size << 1) + 1))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment