diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2006-08-22 06:29:17 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2006-09-20 21:46:13 -0400 |
commit | d1806f6a97a536b043fe50e6d8a25b061755cf50 (patch) | |
tree | 0df6a3772783600f58fa0c5e709c650d1f832610 /drivers/md | |
parent | 69affe7fc52c14e4b81408a2076e9e58ba4af60a (diff) |
[BLOCK] dm-crypt: Use block ciphers where applicable
This patch converts dm-crypt to use the new block cipher type where
applicable. It also changes simple cipher operations to use the new
encrypt_one/decrypt_one interface.
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-crypt.c | 108 |
1 files changed, 47 insertions, 61 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 6022ed12a795..91d4081cb00e 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -5,6 +5,7 @@ | |||
5 | * This file is released under the GPL. | 5 | * This file is released under the GPL. |
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/err.h> | ||
8 | #include <linux/module.h> | 9 | #include <linux/module.h> |
9 | #include <linux/init.h> | 10 | #include <linux/init.h> |
10 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
@@ -78,11 +79,13 @@ struct crypt_config { | |||
78 | */ | 79 | */ |
79 | struct crypt_iv_operations *iv_gen_ops; | 80 | struct crypt_iv_operations *iv_gen_ops; |
80 | char *iv_mode; | 81 | char *iv_mode; |
81 | void *iv_gen_private; | 82 | struct crypto_cipher *iv_gen_private; |
82 | sector_t iv_offset; | 83 | sector_t iv_offset; |
83 | unsigned int iv_size; | 84 | unsigned int iv_size; |
84 | 85 | ||
85 | struct crypto_tfm *tfm; | 86 | char cipher[CRYPTO_MAX_ALG_NAME]; |
87 | char chainmode[CRYPTO_MAX_ALG_NAME]; | ||
88 | struct crypto_blkcipher *tfm; | ||
86 | unsigned int key_size; | 89 | unsigned int key_size; |
87 | u8 key[0]; | 90 | u8 key[0]; |
88 | }; | 91 | }; |
@@ -118,11 +121,12 @@ static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, sector_t sector) | |||
118 | static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | 121 | static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, |
119 | const char *opts) | 122 | const char *opts) |
120 | { | 123 | { |
121 | struct crypto_tfm *essiv_tfm; | 124 | struct crypto_cipher *essiv_tfm; |
122 | struct crypto_tfm *hash_tfm; | 125 | struct crypto_tfm *hash_tfm; |
123 | struct scatterlist sg; | 126 | struct scatterlist sg; |
124 | unsigned int saltsize; | 127 | unsigned int saltsize; |
125 | u8 *salt; | 128 | u8 *salt; |
129 | int err; | ||
126 | 130 | ||
127 | if (opts == NULL) { | 131 | if (opts == NULL) { |
128 | ti->error = "Digest algorithm missing for ESSIV mode"; | 132 | ti->error = "Digest algorithm missing for ESSIV mode"; |
@@ -155,51 +159,44 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
155 | crypto_free_tfm(hash_tfm); | 159 | crypto_free_tfm(hash_tfm); |
156 | 160 | ||
157 | /* Setup the essiv_tfm with the given salt */ | 161 | /* Setup the essiv_tfm with the given salt */ |
158 | essiv_tfm = crypto_alloc_tfm(crypto_tfm_alg_name(cc->tfm), | 162 | essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC); |
159 | CRYPTO_TFM_MODE_ECB | | 163 | if (IS_ERR(essiv_tfm)) { |
160 | CRYPTO_TFM_REQ_MAY_SLEEP); | ||
161 | if (essiv_tfm == NULL) { | ||
162 | ti->error = "Error allocating crypto tfm for ESSIV"; | 164 | ti->error = "Error allocating crypto tfm for ESSIV"; |
163 | kfree(salt); | 165 | kfree(salt); |
164 | return -EINVAL; | 166 | return PTR_ERR(essiv_tfm); |
165 | } | 167 | } |
166 | if (crypto_tfm_alg_blocksize(essiv_tfm) | 168 | if (crypto_cipher_blocksize(essiv_tfm) != |
167 | != crypto_tfm_alg_ivsize(cc->tfm)) { | 169 | crypto_blkcipher_ivsize(cc->tfm)) { |
168 | ti->error = "Block size of ESSIV cipher does " | 170 | ti->error = "Block size of ESSIV cipher does " |
169 | "not match IV size of block cipher"; | 171 | "not match IV size of block cipher"; |
170 | crypto_free_tfm(essiv_tfm); | 172 | crypto_free_cipher(essiv_tfm); |
171 | kfree(salt); | 173 | kfree(salt); |
172 | return -EINVAL; | 174 | return -EINVAL; |
173 | } | 175 | } |
174 | if (crypto_cipher_setkey(essiv_tfm, salt, saltsize) < 0) { | 176 | err = crypto_cipher_setkey(essiv_tfm, salt, saltsize); |
177 | if (err) { | ||
175 | ti->error = "Failed to set key for ESSIV cipher"; | 178 | ti->error = "Failed to set key for ESSIV cipher"; |
176 | crypto_free_tfm(essiv_tfm); | 179 | crypto_free_cipher(essiv_tfm); |
177 | kfree(salt); | 180 | kfree(salt); |
178 | return -EINVAL; | 181 | return err; |
179 | } | 182 | } |
180 | kfree(salt); | 183 | kfree(salt); |
181 | 184 | ||
182 | cc->iv_gen_private = (void *)essiv_tfm; | 185 | cc->iv_gen_private = essiv_tfm; |
183 | return 0; | 186 | return 0; |
184 | } | 187 | } |
185 | 188 | ||
186 | static void crypt_iv_essiv_dtr(struct crypt_config *cc) | 189 | static void crypt_iv_essiv_dtr(struct crypt_config *cc) |
187 | { | 190 | { |
188 | crypto_free_tfm((struct crypto_tfm *)cc->iv_gen_private); | 191 | crypto_free_cipher(cc->iv_gen_private); |
189 | cc->iv_gen_private = NULL; | 192 | cc->iv_gen_private = NULL; |
190 | } | 193 | } |
191 | 194 | ||
192 | static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector) | 195 | static int crypt_iv_essiv_gen(struct crypt_config *cc, u8 *iv, sector_t sector) |
193 | { | 196 | { |
194 | struct scatterlist sg; | ||
195 | |||
196 | memset(iv, 0, cc->iv_size); | 197 | memset(iv, 0, cc->iv_size); |
197 | *(u64 *)iv = cpu_to_le64(sector); | 198 | *(u64 *)iv = cpu_to_le64(sector); |
198 | 199 | crypto_cipher_encrypt_one(cc->iv_gen_private, iv, iv); | |
199 | sg_set_buf(&sg, iv, cc->iv_size); | ||
200 | crypto_cipher_encrypt((struct crypto_tfm *)cc->iv_gen_private, | ||
201 | &sg, &sg, cc->iv_size); | ||
202 | |||
203 | return 0; | 200 | return 0; |
204 | } | 201 | } |
205 | 202 | ||
@@ -220,6 +217,11 @@ crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out, | |||
220 | int write, sector_t sector) | 217 | int write, sector_t sector) |
221 | { | 218 | { |
222 | u8 iv[cc->iv_size]; | 219 | u8 iv[cc->iv_size]; |
220 | struct blkcipher_desc desc = { | ||
221 | .tfm = cc->tfm, | ||
222 | .info = iv, | ||
223 | .flags = CRYPTO_TFM_REQ_MAY_SLEEP, | ||
224 | }; | ||
223 | int r; | 225 | int r; |
224 | 226 | ||
225 | if (cc->iv_gen_ops) { | 227 | if (cc->iv_gen_ops) { |
@@ -228,14 +230,14 @@ crypt_convert_scatterlist(struct crypt_config *cc, struct scatterlist *out, | |||
228 | return r; | 230 | return r; |
229 | 231 | ||
230 | if (write) | 232 | if (write) |
231 | r = crypto_cipher_encrypt_iv(cc->tfm, out, in, length, iv); | 233 | r = crypto_blkcipher_encrypt_iv(&desc, out, in, length); |
232 | else | 234 | else |
233 | r = crypto_cipher_decrypt_iv(cc->tfm, out, in, length, iv); | 235 | r = crypto_blkcipher_decrypt_iv(&desc, out, in, length); |
234 | } else { | 236 | } else { |
235 | if (write) | 237 | if (write) |
236 | r = crypto_cipher_encrypt(cc->tfm, out, in, length); | 238 | r = crypto_blkcipher_encrypt(&desc, out, in, length); |
237 | else | 239 | else |
238 | r = crypto_cipher_decrypt(cc->tfm, out, in, length); | 240 | r = crypto_blkcipher_decrypt(&desc, out, in, length); |
239 | } | 241 | } |
240 | 242 | ||
241 | return r; | 243 | return r; |
@@ -510,13 +512,12 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size) | |||
510 | static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | 512 | static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) |
511 | { | 513 | { |
512 | struct crypt_config *cc; | 514 | struct crypt_config *cc; |
513 | struct crypto_tfm *tfm; | 515 | struct crypto_blkcipher *tfm; |
514 | char *tmp; | 516 | char *tmp; |
515 | char *cipher; | 517 | char *cipher; |
516 | char *chainmode; | 518 | char *chainmode; |
517 | char *ivmode; | 519 | char *ivmode; |
518 | char *ivopts; | 520 | char *ivopts; |
519 | unsigned int crypto_flags; | ||
520 | unsigned int key_size; | 521 | unsigned int key_size; |
521 | unsigned long long tmpll; | 522 | unsigned long long tmpll; |
522 | 523 | ||
@@ -556,31 +557,25 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
556 | ivmode = "plain"; | 557 | ivmode = "plain"; |
557 | } | 558 | } |
558 | 559 | ||
559 | /* Choose crypto_flags according to chainmode */ | 560 | if (strcmp(chainmode, "ecb") && !ivmode) { |
560 | if (strcmp(chainmode, "cbc") == 0) | 561 | ti->error = "This chaining mode requires an IV mechanism"; |
561 | crypto_flags = CRYPTO_TFM_MODE_CBC; | ||
562 | else if (strcmp(chainmode, "ecb") == 0) | ||
563 | crypto_flags = CRYPTO_TFM_MODE_ECB; | ||
564 | else { | ||
565 | ti->error = "Unknown chaining mode"; | ||
566 | goto bad1; | 562 | goto bad1; |
567 | } | 563 | } |
568 | 564 | ||
569 | if (crypto_flags != CRYPTO_TFM_MODE_ECB && !ivmode) { | 565 | if (snprintf(cc->cipher, CRYPTO_MAX_ALG_NAME, "%s(%s)", chainmode, |
570 | ti->error = "This chaining mode requires an IV mechanism"; | 566 | cipher) >= CRYPTO_MAX_ALG_NAME) { |
567 | ti->error = "Chain mode + cipher name is too long"; | ||
571 | goto bad1; | 568 | goto bad1; |
572 | } | 569 | } |
573 | 570 | ||
574 | tfm = crypto_alloc_tfm(cipher, crypto_flags | CRYPTO_TFM_REQ_MAY_SLEEP); | 571 | tfm = crypto_alloc_blkcipher(cc->cipher, 0, CRYPTO_ALG_ASYNC); |
575 | if (!tfm) { | 572 | if (IS_ERR(tfm)) { |
576 | ti->error = "Error allocating crypto tfm"; | 573 | ti->error = "Error allocating crypto tfm"; |
577 | goto bad1; | 574 | goto bad1; |
578 | } | 575 | } |
579 | if (crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER) { | ||
580 | ti->error = "Expected cipher algorithm"; | ||
581 | goto bad2; | ||
582 | } | ||
583 | 576 | ||
577 | strcpy(cc->cipher, cipher); | ||
578 | strcpy(cc->chainmode, chainmode); | ||
584 | cc->tfm = tfm; | 579 | cc->tfm = tfm; |
585 | 580 | ||
586 | /* | 581 | /* |
@@ -603,12 +598,12 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
603 | cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0) | 598 | cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0) |
604 | goto bad2; | 599 | goto bad2; |
605 | 600 | ||
606 | if (tfm->crt_cipher.cit_decrypt_iv && tfm->crt_cipher.cit_encrypt_iv) | 601 | cc->iv_size = crypto_blkcipher_ivsize(tfm); |
602 | if (cc->iv_size) | ||
607 | /* at least a 64 bit sector number should fit in our buffer */ | 603 | /* at least a 64 bit sector number should fit in our buffer */ |
608 | cc->iv_size = max(crypto_tfm_alg_ivsize(tfm), | 604 | cc->iv_size = max(cc->iv_size, |
609 | (unsigned int)(sizeof(u64) / sizeof(u8))); | 605 | (unsigned int)(sizeof(u64) / sizeof(u8))); |
610 | else { | 606 | else { |
611 | cc->iv_size = 0; | ||
612 | if (cc->iv_gen_ops) { | 607 | if (cc->iv_gen_ops) { |
613 | DMWARN("Selected cipher does not support IVs"); | 608 | DMWARN("Selected cipher does not support IVs"); |
614 | if (cc->iv_gen_ops->dtr) | 609 | if (cc->iv_gen_ops->dtr) |
@@ -629,7 +624,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
629 | goto bad4; | 624 | goto bad4; |
630 | } | 625 | } |
631 | 626 | ||
632 | if (tfm->crt_cipher.cit_setkey(tfm, cc->key, key_size) < 0) { | 627 | if (crypto_blkcipher_setkey(tfm, cc->key, key_size) < 0) { |
633 | ti->error = "Error setting key"; | 628 | ti->error = "Error setting key"; |
634 | goto bad5; | 629 | goto bad5; |
635 | } | 630 | } |
@@ -675,7 +670,7 @@ bad3: | |||
675 | if (cc->iv_gen_ops && cc->iv_gen_ops->dtr) | 670 | if (cc->iv_gen_ops && cc->iv_gen_ops->dtr) |
676 | cc->iv_gen_ops->dtr(cc); | 671 | cc->iv_gen_ops->dtr(cc); |
677 | bad2: | 672 | bad2: |
678 | crypto_free_tfm(tfm); | 673 | crypto_free_blkcipher(tfm); |
679 | bad1: | 674 | bad1: |
680 | /* Must zero key material before freeing */ | 675 | /* Must zero key material before freeing */ |
681 | memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8)); | 676 | memset(cc, 0, sizeof(*cc) + cc->key_size * sizeof(u8)); |
@@ -693,7 +688,7 @@ static void crypt_dtr(struct dm_target *ti) | |||
693 | kfree(cc->iv_mode); | 688 | kfree(cc->iv_mode); |
694 | if (cc->iv_gen_ops && cc->iv_gen_ops->dtr) | 689 | if (cc->iv_gen_ops && cc->iv_gen_ops->dtr) |
695 | cc->iv_gen_ops->dtr(cc); | 690 | cc->iv_gen_ops->dtr(cc); |
696 | crypto_free_tfm(cc->tfm); | 691 | crypto_free_blkcipher(cc->tfm); |
697 | dm_put_device(ti, cc->dev); | 692 | dm_put_device(ti, cc->dev); |
698 | 693 | ||
699 | /* Must zero key material before freeing */ | 694 | /* Must zero key material before freeing */ |
@@ -858,18 +853,9 @@ static int crypt_status(struct dm_target *ti, status_type_t type, | |||
858 | break; | 853 | break; |
859 | 854 | ||
860 | case STATUSTYPE_TABLE: | 855 | case STATUSTYPE_TABLE: |
861 | cipher = crypto_tfm_alg_name(cc->tfm); | 856 | cipher = crypto_blkcipher_name(cc->tfm); |
862 | 857 | ||
863 | switch(cc->tfm->crt_cipher.cit_mode) { | 858 | chainmode = cc->chainmode; |
864 | case CRYPTO_TFM_MODE_CBC: | ||
865 | chainmode = "cbc"; | ||
866 | break; | ||
867 | case CRYPTO_TFM_MODE_ECB: | ||
868 | chainmode = "ecb"; | ||
869 | break; | ||
870 | default: | ||
871 | BUG(); | ||
872 | } | ||
873 | 859 | ||
874 | if (cc->iv_mode) | 860 | if (cc->iv_mode) |
875 | DMEMIT("%s-%s-%s ", cipher, chainmode, cc->iv_mode); | 861 | DMEMIT("%s-%s-%s ", cipher, chainmode, cc->iv_mode); |