diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/aead.c | 216 |
1 files changed, 211 insertions, 5 deletions
diff --git a/crypto/aead.c b/crypto/aead.c index 15335ed9010a..9f7aca891926 100644 --- a/crypto/aead.c +++ b/crypto/aead.c | |||
@@ -12,14 +12,16 @@ | |||
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <crypto/algapi.h> | 15 | #include <crypto/internal/aead.h> |
16 | #include <linux/errno.h> | 16 | #include <linux/err.h> |
17 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
22 | 22 | ||
23 | #include "internal.h" | ||
24 | |||
23 | static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, | 25 | static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, |
24 | unsigned int keylen) | 26 | unsigned int keylen) |
25 | { | 27 | { |
@@ -55,18 +57,20 @@ static int setkey(struct crypto_aead *tfm, const u8 *key, unsigned int keylen) | |||
55 | 57 | ||
56 | int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) | 58 | int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) |
57 | { | 59 | { |
60 | struct aead_tfm *crt = crypto_aead_crt(tfm); | ||
58 | int err; | 61 | int err; |
59 | 62 | ||
60 | if (authsize > crypto_aead_alg(tfm)->maxauthsize) | 63 | if (authsize > crypto_aead_alg(tfm)->maxauthsize) |
61 | return -EINVAL; | 64 | return -EINVAL; |
62 | 65 | ||
63 | if (crypto_aead_alg(tfm)->setauthsize) { | 66 | if (crypto_aead_alg(tfm)->setauthsize) { |
64 | err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize); | 67 | err = crypto_aead_alg(tfm)->setauthsize(crt->base, authsize); |
65 | if (err) | 68 | if (err) |
66 | return err; | 69 | return err; |
67 | } | 70 | } |
68 | 71 | ||
69 | crypto_aead_crt(tfm)->authsize = authsize; | 72 | crypto_aead_crt(crt->base)->authsize = authsize; |
73 | crt->authsize = authsize; | ||
70 | return 0; | 74 | return 0; |
71 | } | 75 | } |
72 | EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); | 76 | EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); |
@@ -90,11 +94,13 @@ static int crypto_init_aead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) | |||
90 | if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) | 94 | if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) |
91 | return -EINVAL; | 95 | return -EINVAL; |
92 | 96 | ||
93 | crt->setkey = setkey; | 97 | crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ? |
98 | alg->setkey : setkey; | ||
94 | crt->encrypt = alg->encrypt; | 99 | crt->encrypt = alg->encrypt; |
95 | crt->decrypt = alg->decrypt; | 100 | crt->decrypt = alg->decrypt; |
96 | crt->givencrypt = alg->givencrypt ?: no_givcrypt; | 101 | crt->givencrypt = alg->givencrypt ?: no_givcrypt; |
97 | crt->givdecrypt = alg->givdecrypt ?: no_givcrypt; | 102 | crt->givdecrypt = alg->givdecrypt ?: no_givcrypt; |
103 | crt->base = __crypto_aead_cast(tfm); | ||
98 | crt->ivsize = alg->ivsize; | 104 | crt->ivsize = alg->ivsize; |
99 | crt->authsize = alg->maxauthsize; | 105 | crt->authsize = alg->maxauthsize; |
100 | 106 | ||
@@ -111,6 +117,7 @@ static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) | |||
111 | seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); | 117 | seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); |
112 | seq_printf(m, "ivsize : %u\n", aead->ivsize); | 118 | seq_printf(m, "ivsize : %u\n", aead->ivsize); |
113 | seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); | 119 | seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); |
120 | seq_printf(m, "geniv : %s\n", aead->geniv ?: "<built-in>"); | ||
114 | } | 121 | } |
115 | 122 | ||
116 | const struct crypto_type crypto_aead_type = { | 123 | const struct crypto_type crypto_aead_type = { |
@@ -122,5 +129,204 @@ const struct crypto_type crypto_aead_type = { | |||
122 | }; | 129 | }; |
123 | EXPORT_SYMBOL_GPL(crypto_aead_type); | 130 | EXPORT_SYMBOL_GPL(crypto_aead_type); |
124 | 131 | ||
132 | static int aead_null_givencrypt(struct aead_givcrypt_request *req) | ||
133 | { | ||
134 | return crypto_aead_encrypt(&req->areq); | ||
135 | } | ||
136 | |||
137 | static int aead_null_givdecrypt(struct aead_givcrypt_request *req) | ||
138 | { | ||
139 | return crypto_aead_decrypt(&req->areq); | ||
140 | } | ||
141 | |||
142 | static int crypto_init_nivaead_ops(struct crypto_tfm *tfm, u32 type, u32 mask) | ||
143 | { | ||
144 | struct aead_alg *alg = &tfm->__crt_alg->cra_aead; | ||
145 | struct aead_tfm *crt = &tfm->crt_aead; | ||
146 | |||
147 | if (max(alg->maxauthsize, alg->ivsize) > PAGE_SIZE / 8) | ||
148 | return -EINVAL; | ||
149 | |||
150 | crt->setkey = setkey; | ||
151 | crt->encrypt = alg->encrypt; | ||
152 | crt->decrypt = alg->decrypt; | ||
153 | if (!alg->ivsize) { | ||
154 | crt->givencrypt = aead_null_givencrypt; | ||
155 | crt->givdecrypt = aead_null_givdecrypt; | ||
156 | } | ||
157 | crt->base = __crypto_aead_cast(tfm); | ||
158 | crt->ivsize = alg->ivsize; | ||
159 | crt->authsize = alg->maxauthsize; | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg) | ||
165 | __attribute__ ((unused)); | ||
166 | static void crypto_nivaead_show(struct seq_file *m, struct crypto_alg *alg) | ||
167 | { | ||
168 | struct aead_alg *aead = &alg->cra_aead; | ||
169 | |||
170 | seq_printf(m, "type : nivaead\n"); | ||
171 | seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); | ||
172 | seq_printf(m, "ivsize : %u\n", aead->ivsize); | ||
173 | seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); | ||
174 | seq_printf(m, "geniv : %s\n", aead->geniv); | ||
175 | } | ||
176 | |||
177 | const struct crypto_type crypto_nivaead_type = { | ||
178 | .ctxsize = crypto_aead_ctxsize, | ||
179 | .init = crypto_init_nivaead_ops, | ||
180 | #ifdef CONFIG_PROC_FS | ||
181 | .show = crypto_nivaead_show, | ||
182 | #endif | ||
183 | }; | ||
184 | EXPORT_SYMBOL_GPL(crypto_nivaead_type); | ||
185 | |||
186 | static int crypto_grab_nivaead(struct crypto_aead_spawn *spawn, | ||
187 | const char *name, u32 type, u32 mask) | ||
188 | { | ||
189 | struct crypto_alg *alg; | ||
190 | int err; | ||
191 | |||
192 | type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); | ||
193 | type |= CRYPTO_ALG_TYPE_AEAD; | ||
194 | mask |= CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV; | ||
195 | |||
196 | alg = crypto_alg_mod_lookup(name, type, mask); | ||
197 | if (IS_ERR(alg)) | ||
198 | return PTR_ERR(alg); | ||
199 | |||
200 | err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask); | ||
201 | crypto_mod_put(alg); | ||
202 | return err; | ||
203 | } | ||
204 | |||
205 | struct crypto_instance *aead_geniv_alloc(struct crypto_template *tmpl, | ||
206 | struct rtattr **tb, u32 type, | ||
207 | u32 mask) | ||
208 | { | ||
209 | const char *name; | ||
210 | struct crypto_aead_spawn *spawn; | ||
211 | struct crypto_attr_type *algt; | ||
212 | struct crypto_instance *inst; | ||
213 | struct crypto_alg *alg; | ||
214 | int err; | ||
215 | |||
216 | algt = crypto_get_attr_type(tb); | ||
217 | err = PTR_ERR(algt); | ||
218 | if (IS_ERR(algt)) | ||
219 | return ERR_PTR(err); | ||
220 | |||
221 | if ((algt->type ^ (CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV)) & | ||
222 | algt->mask) | ||
223 | return ERR_PTR(-EINVAL); | ||
224 | |||
225 | name = crypto_attr_alg_name(tb[1]); | ||
226 | err = PTR_ERR(name); | ||
227 | if (IS_ERR(name)) | ||
228 | return ERR_PTR(err); | ||
229 | |||
230 | inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); | ||
231 | if (!inst) | ||
232 | return ERR_PTR(-ENOMEM); | ||
233 | |||
234 | spawn = crypto_instance_ctx(inst); | ||
235 | |||
236 | /* Ignore async algorithms if necessary. */ | ||
237 | mask |= crypto_requires_sync(algt->type, algt->mask); | ||
238 | |||
239 | crypto_set_aead_spawn(spawn, inst); | ||
240 | err = crypto_grab_nivaead(spawn, name, type, mask); | ||
241 | if (err) | ||
242 | goto err_free_inst; | ||
243 | |||
244 | alg = crypto_aead_spawn_alg(spawn); | ||
245 | |||
246 | err = -EINVAL; | ||
247 | if (!alg->cra_aead.ivsize) | ||
248 | goto err_drop_alg; | ||
249 | |||
250 | /* | ||
251 | * This is only true if we're constructing an algorithm with its | ||
252 | * default IV generator. For the default generator we elide the | ||
253 | * template name and double-check the IV generator. | ||
254 | */ | ||
255 | if (algt->mask & CRYPTO_ALG_GENIV) { | ||
256 | if (strcmp(tmpl->name, alg->cra_aead.geniv)) | ||
257 | goto err_drop_alg; | ||
258 | |||
259 | memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); | ||
260 | memcpy(inst->alg.cra_driver_name, alg->cra_driver_name, | ||
261 | CRYPTO_MAX_ALG_NAME); | ||
262 | } else { | ||
263 | err = -ENAMETOOLONG; | ||
264 | if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, | ||
265 | "%s(%s)", tmpl->name, alg->cra_name) >= | ||
266 | CRYPTO_MAX_ALG_NAME) | ||
267 | goto err_drop_alg; | ||
268 | if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, | ||
269 | "%s(%s)", tmpl->name, alg->cra_driver_name) >= | ||
270 | CRYPTO_MAX_ALG_NAME) | ||
271 | goto err_drop_alg; | ||
272 | } | ||
273 | |||
274 | inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_GENIV; | ||
275 | inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC; | ||
276 | inst->alg.cra_priority = alg->cra_priority; | ||
277 | inst->alg.cra_blocksize = alg->cra_blocksize; | ||
278 | inst->alg.cra_alignmask = alg->cra_alignmask; | ||
279 | inst->alg.cra_type = &crypto_aead_type; | ||
280 | |||
281 | inst->alg.cra_aead.ivsize = alg->cra_aead.ivsize; | ||
282 | inst->alg.cra_aead.maxauthsize = alg->cra_aead.maxauthsize; | ||
283 | inst->alg.cra_aead.geniv = alg->cra_aead.geniv; | ||
284 | |||
285 | inst->alg.cra_aead.setkey = alg->cra_aead.setkey; | ||
286 | inst->alg.cra_aead.setauthsize = alg->cra_aead.setauthsize; | ||
287 | inst->alg.cra_aead.encrypt = alg->cra_aead.encrypt; | ||
288 | inst->alg.cra_aead.decrypt = alg->cra_aead.decrypt; | ||
289 | |||
290 | out: | ||
291 | return inst; | ||
292 | |||
293 | err_drop_alg: | ||
294 | crypto_drop_aead(spawn); | ||
295 | err_free_inst: | ||
296 | kfree(inst); | ||
297 | inst = ERR_PTR(err); | ||
298 | goto out; | ||
299 | } | ||
300 | EXPORT_SYMBOL_GPL(aead_geniv_alloc); | ||
301 | |||
302 | void aead_geniv_free(struct crypto_instance *inst) | ||
303 | { | ||
304 | crypto_drop_aead(crypto_instance_ctx(inst)); | ||
305 | kfree(inst); | ||
306 | } | ||
307 | EXPORT_SYMBOL_GPL(aead_geniv_free); | ||
308 | |||
309 | int aead_geniv_init(struct crypto_tfm *tfm) | ||
310 | { | ||
311 | struct crypto_instance *inst = (void *)tfm->__crt_alg; | ||
312 | struct crypto_aead *aead; | ||
313 | |||
314 | aead = crypto_spawn_aead(crypto_instance_ctx(inst)); | ||
315 | if (IS_ERR(aead)) | ||
316 | return PTR_ERR(aead); | ||
317 | |||
318 | tfm->crt_aead.base = aead; | ||
319 | tfm->crt_aead.reqsize += crypto_aead_reqsize(aead); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | EXPORT_SYMBOL_GPL(aead_geniv_init); | ||
324 | |||
325 | void aead_geniv_exit(struct crypto_tfm *tfm) | ||
326 | { | ||
327 | crypto_free_aead(tfm->crt_aead.base); | ||
328 | } | ||
329 | EXPORT_SYMBOL_GPL(aead_geniv_exit); | ||
330 | |||
125 | MODULE_LICENSE("GPL"); | 331 | MODULE_LICENSE("GPL"); |
126 | MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); | 332 | MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); |