diff options
author | Milan Broz <mbroz@redhat.com> | 2009-12-10 18:51:56 -0500 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2009-12-10 18:51:56 -0500 |
commit | b95bf2d3d5a48b095bffe2a0cd8c40453cf59557 (patch) | |
tree | bcb6bdd0e5b67eb0aa2277aac125686bb911950a /drivers/md | |
parent | 5861f1be00b3b70f8ab5e5a81392a6cf69666cd2 (diff) |
dm crypt: separate essiv allocation from initialisation
This patch separates the construction of IV from its initialisation.
(For ESSIV it is a hash calculation based on volume key.)
Constructor code now preallocates hash tfm and salt array
and saves it in a private IV structure.
The next patch requires this to reinitialise the wiped IV
without reallocating memory when resuming a suspended device.
Cc: stable@kernel.org
Signed-off-by: Milan Broz <mbroz@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/dm-crypt.c | 69 |
1 files changed, 43 insertions, 26 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 2301d223f2ae..446153a071d6 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c | |||
@@ -71,11 +71,14 @@ struct crypt_iv_operations { | |||
71 | int (*ctr)(struct crypt_config *cc, struct dm_target *ti, | 71 | int (*ctr)(struct crypt_config *cc, struct dm_target *ti, |
72 | const char *opts); | 72 | const char *opts); |
73 | void (*dtr)(struct crypt_config *cc); | 73 | void (*dtr)(struct crypt_config *cc); |
74 | int (*init)(struct crypt_config *cc); | ||
74 | int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector); | 75 | int (*generator)(struct crypt_config *cc, u8 *iv, sector_t sector); |
75 | }; | 76 | }; |
76 | 77 | ||
77 | struct iv_essiv_private { | 78 | struct iv_essiv_private { |
78 | struct crypto_cipher *tfm; | 79 | struct crypto_cipher *tfm; |
80 | struct crypto_hash *hash_tfm; | ||
81 | u8 *salt; | ||
79 | }; | 82 | }; |
80 | 83 | ||
81 | struct iv_benbi_private { | 84 | struct iv_benbi_private { |
@@ -176,12 +179,38 @@ static int crypt_iv_plain_gen(struct crypt_config *cc, u8 *iv, sector_t sector) | |||
176 | return 0; | 179 | return 0; |
177 | } | 180 | } |
178 | 181 | ||
182 | /* Initialise ESSIV - compute salt but no local memory allocations */ | ||
183 | static int crypt_iv_essiv_init(struct crypt_config *cc) | ||
184 | { | ||
185 | struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv; | ||
186 | struct hash_desc desc; | ||
187 | struct scatterlist sg; | ||
188 | int err; | ||
189 | |||
190 | sg_init_one(&sg, cc->key, cc->key_size); | ||
191 | desc.tfm = essiv->hash_tfm; | ||
192 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
193 | |||
194 | err = crypto_hash_digest(&desc, &sg, cc->key_size, essiv->salt); | ||
195 | if (err) | ||
196 | return err; | ||
197 | |||
198 | return crypto_cipher_setkey(essiv->tfm, essiv->salt, | ||
199 | crypto_hash_digestsize(essiv->hash_tfm)); | ||
200 | } | ||
201 | |||
179 | static void crypt_iv_essiv_dtr(struct crypt_config *cc) | 202 | static void crypt_iv_essiv_dtr(struct crypt_config *cc) |
180 | { | 203 | { |
181 | struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv; | 204 | struct iv_essiv_private *essiv = &cc->iv_gen_private.essiv; |
182 | 205 | ||
183 | crypto_free_cipher(essiv->tfm); | 206 | crypto_free_cipher(essiv->tfm); |
184 | essiv->tfm = NULL; | 207 | essiv->tfm = NULL; |
208 | |||
209 | crypto_free_hash(essiv->hash_tfm); | ||
210 | essiv->hash_tfm = NULL; | ||
211 | |||
212 | kzfree(essiv->salt); | ||
213 | essiv->salt = NULL; | ||
185 | } | 214 | } |
186 | 215 | ||
187 | static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | 216 | static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, |
@@ -189,9 +218,6 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
189 | { | 218 | { |
190 | struct crypto_cipher *essiv_tfm = NULL; | 219 | struct crypto_cipher *essiv_tfm = NULL; |
191 | struct crypto_hash *hash_tfm = NULL; | 220 | struct crypto_hash *hash_tfm = NULL; |
192 | struct hash_desc desc; | ||
193 | struct scatterlist sg; | ||
194 | unsigned int saltsize; | ||
195 | u8 *salt = NULL; | 221 | u8 *salt = NULL; |
196 | int err; | 222 | int err; |
197 | 223 | ||
@@ -200,7 +226,7 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
200 | return -EINVAL; | 226 | return -EINVAL; |
201 | } | 227 | } |
202 | 228 | ||
203 | /* Hash the cipher key with the given hash algorithm */ | 229 | /* Allocate hash algorithm */ |
204 | hash_tfm = crypto_alloc_hash(opts, 0, CRYPTO_ALG_ASYNC); | 230 | hash_tfm = crypto_alloc_hash(opts, 0, CRYPTO_ALG_ASYNC); |
205 | if (IS_ERR(hash_tfm)) { | 231 | if (IS_ERR(hash_tfm)) { |
206 | ti->error = "Error initializing ESSIV hash"; | 232 | ti->error = "Error initializing ESSIV hash"; |
@@ -208,27 +234,14 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
208 | goto bad; | 234 | goto bad; |
209 | } | 235 | } |
210 | 236 | ||
211 | saltsize = crypto_hash_digestsize(hash_tfm); | 237 | salt = kzalloc(crypto_hash_digestsize(hash_tfm), GFP_KERNEL); |
212 | salt = kzalloc(saltsize, GFP_KERNEL); | ||
213 | if (!salt) { | 238 | if (!salt) { |
214 | ti->error = "Error kmallocing salt storage in ESSIV"; | 239 | ti->error = "Error kmallocing salt storage in ESSIV"; |
215 | err = -ENOMEM; | 240 | err = -ENOMEM; |
216 | goto bad; | 241 | goto bad; |
217 | } | 242 | } |
218 | 243 | ||
219 | sg_init_one(&sg, cc->key, cc->key_size); | 244 | /* Allocate essiv_tfm */ |
220 | desc.tfm = hash_tfm; | ||
221 | desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP; | ||
222 | err = crypto_hash_digest(&desc, &sg, cc->key_size, salt); | ||
223 | crypto_free_hash(hash_tfm); | ||
224 | hash_tfm = NULL; | ||
225 | |||
226 | if (err) { | ||
227 | ti->error = "Error calculating hash in ESSIV"; | ||
228 | goto bad; | ||
229 | } | ||
230 | |||
231 | /* Setup the essiv_tfm with the given salt */ | ||
232 | essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC); | 245 | essiv_tfm = crypto_alloc_cipher(cc->cipher, 0, CRYPTO_ALG_ASYNC); |
233 | if (IS_ERR(essiv_tfm)) { | 246 | if (IS_ERR(essiv_tfm)) { |
234 | ti->error = "Error allocating crypto tfm for ESSIV"; | 247 | ti->error = "Error allocating crypto tfm for ESSIV"; |
@@ -242,14 +255,11 @@ static int crypt_iv_essiv_ctr(struct crypt_config *cc, struct dm_target *ti, | |||
242 | err = -EINVAL; | 255 | err = -EINVAL; |
243 | goto bad; | 256 | goto bad; |
244 | } | 257 | } |
245 | err = crypto_cipher_setkey(essiv_tfm, salt, saltsize); | ||
246 | if (err) { | ||
247 | ti->error = "Failed to set key for ESSIV cipher"; | ||
248 | goto bad; | ||
249 | } | ||
250 | kzfree(salt); | ||
251 | 258 | ||
259 | cc->iv_gen_private.essiv.salt = salt; | ||
252 | cc->iv_gen_private.essiv.tfm = essiv_tfm; | 260 | cc->iv_gen_private.essiv.tfm = essiv_tfm; |
261 | cc->iv_gen_private.essiv.hash_tfm = hash_tfm; | ||
262 | |||
253 | return 0; | 263 | return 0; |
254 | 264 | ||
255 | bad: | 265 | bad: |
@@ -257,7 +267,7 @@ bad: | |||
257 | crypto_free_cipher(essiv_tfm); | 267 | crypto_free_cipher(essiv_tfm); |
258 | if (hash_tfm && !IS_ERR(hash_tfm)) | 268 | if (hash_tfm && !IS_ERR(hash_tfm)) |
259 | crypto_free_hash(hash_tfm); | 269 | crypto_free_hash(hash_tfm); |
260 | kzfree(salt); | 270 | kfree(salt); |
261 | return err; | 271 | return err; |
262 | } | 272 | } |
263 | 273 | ||
@@ -323,6 +333,7 @@ static struct crypt_iv_operations crypt_iv_plain_ops = { | |||
323 | static struct crypt_iv_operations crypt_iv_essiv_ops = { | 333 | static struct crypt_iv_operations crypt_iv_essiv_ops = { |
324 | .ctr = crypt_iv_essiv_ctr, | 334 | .ctr = crypt_iv_essiv_ctr, |
325 | .dtr = crypt_iv_essiv_dtr, | 335 | .dtr = crypt_iv_essiv_dtr, |
336 | .init = crypt_iv_essiv_init, | ||
326 | .generator = crypt_iv_essiv_gen | 337 | .generator = crypt_iv_essiv_gen |
327 | }; | 338 | }; |
328 | 339 | ||
@@ -1054,6 +1065,12 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) | |||
1054 | cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0) | 1065 | cc->iv_gen_ops->ctr(cc, ti, ivopts) < 0) |
1055 | goto bad_ivmode; | 1066 | goto bad_ivmode; |
1056 | 1067 | ||
1068 | if (cc->iv_gen_ops && cc->iv_gen_ops->init && | ||
1069 | cc->iv_gen_ops->init(cc) < 0) { | ||
1070 | ti->error = "Error initialising IV"; | ||
1071 | goto bad_slab_pool; | ||
1072 | } | ||
1073 | |||
1057 | cc->iv_size = crypto_ablkcipher_ivsize(tfm); | 1074 | cc->iv_size = crypto_ablkcipher_ivsize(tfm); |
1058 | if (cc->iv_size) | 1075 | if (cc->iv_size) |
1059 | /* at least a 64 bit sector number should fit in our buffer */ | 1076 | /* at least a 64 bit sector number should fit in our buffer */ |