Commit | Line | Data |
---|---|---|
71ebc4d1 MW |
1 | /* |
2 | * ChaCha20-Poly1305 AEAD, RFC7539 | |
3 | * | |
4 | * Copyright (C) 2015 Martin Willi | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | */ | |
11 | ||
12 | #include <crypto/internal/aead.h> | |
13 | #include <crypto/internal/hash.h> | |
14 | #include <crypto/internal/skcipher.h> | |
15 | #include <crypto/scatterwalk.h> | |
1ca1b917 | 16 | #include <crypto/chacha.h> |
2546f811 | 17 | #include <crypto/poly1305.h> |
71ebc4d1 MW |
18 | #include <linux/err.h> |
19 | #include <linux/init.h> | |
20 | #include <linux/kernel.h> | |
21 | #include <linux/module.h> | |
22 | ||
23 | #include "internal.h" | |
24 | ||
71ebc4d1 MW |
25 | struct chachapoly_instance_ctx { |
26 | struct crypto_skcipher_spawn chacha; | |
27 | struct crypto_ahash_spawn poly; | |
28 | unsigned int saltlen; | |
29 | }; | |
30 | ||
31 | struct chachapoly_ctx { | |
1e1f0061 | 32 | struct crypto_skcipher *chacha; |
71ebc4d1 MW |
33 | struct crypto_ahash *poly; |
34 | /* key bytes we use for the ChaCha20 IV */ | |
35 | unsigned int saltlen; | |
36 | u8 salt[]; | |
37 | }; | |
38 | ||
39 | struct poly_req { | |
40 | /* zero byte padding for AD/ciphertext, as needed */ | |
41 | u8 pad[POLY1305_BLOCK_SIZE]; | |
42 | /* tail data with AD/ciphertext lengths */ | |
43 | struct { | |
44 | __le64 assoclen; | |
45 | __le64 cryptlen; | |
46 | } tail; | |
47 | struct scatterlist src[1]; | |
48 | struct ahash_request req; /* must be last member */ | |
49 | }; | |
50 | ||
51 | struct chacha_req { | |
1ca1b917 | 52 | u8 iv[CHACHA_IV_SIZE]; |
71ebc4d1 | 53 | struct scatterlist src[1]; |
1e1f0061 | 54 | struct skcipher_request req; /* must be last member */ |
71ebc4d1 MW |
55 | }; |
56 | ||
57 | struct chachapoly_req_ctx { | |
74790922 HX |
58 | struct scatterlist src[2]; |
59 | struct scatterlist dst[2]; | |
c2b7b20a MW |
60 | /* the key we generate for Poly1305 using Chacha20 */ |
61 | u8 key[POLY1305_KEY_SIZE]; | |
71ebc4d1 MW |
62 | /* calculated Poly1305 tag */ |
63 | u8 tag[POLY1305_DIGEST_SIZE]; | |
64 | /* length of data to en/decrypt, without ICV */ | |
65 | unsigned int cryptlen; | |
74790922 HX |
66 | /* Actual AD, excluding IV */ |
67 | unsigned int assoclen; | |
71ebc4d1 MW |
68 | union { |
69 | struct poly_req poly; | |
70 | struct chacha_req chacha; | |
71 | } u; | |
72 | }; | |
73 | ||
74 | static inline void async_done_continue(struct aead_request *req, int err, | |
75 | int (*cont)(struct aead_request *)) | |
76 | { | |
77 | if (!err) | |
78 | err = cont(req); | |
79 | ||
80 | if (err != -EINPROGRESS && err != -EBUSY) | |
81 | aead_request_complete(req, err); | |
82 | } | |
83 | ||
84 | static void chacha_iv(u8 *iv, struct aead_request *req, u32 icb) | |
85 | { | |
86 | struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | |
87 | __le32 leicb = cpu_to_le32(icb); | |
88 | ||
89 | memcpy(iv, &leicb, sizeof(leicb)); | |
90 | memcpy(iv + sizeof(leicb), ctx->salt, ctx->saltlen); | |
91 | memcpy(iv + sizeof(leicb) + ctx->saltlen, req->iv, | |
1ca1b917 | 92 | CHACHA_IV_SIZE - sizeof(leicb) - ctx->saltlen); |
71ebc4d1 MW |
93 | } |
94 | ||
95 | static int poly_verify_tag(struct aead_request *req) | |
96 | { | |
97 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
98 | u8 tag[sizeof(rctx->tag)]; | |
99 | ||
74790922 HX |
100 | scatterwalk_map_and_copy(tag, req->src, |
101 | req->assoclen + rctx->cryptlen, | |
102 | sizeof(tag), 0); | |
71ebc4d1 MW |
103 | if (crypto_memneq(tag, rctx->tag, sizeof(tag))) |
104 | return -EBADMSG; | |
105 | return 0; | |
106 | } | |
107 | ||
108 | static int poly_copy_tag(struct aead_request *req) | |
109 | { | |
110 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
111 | ||
74790922 HX |
112 | scatterwalk_map_and_copy(rctx->tag, req->dst, |
113 | req->assoclen + rctx->cryptlen, | |
71ebc4d1 MW |
114 | sizeof(rctx->tag), 1); |
115 | return 0; | |
116 | } | |
117 | ||
118 | static void chacha_decrypt_done(struct crypto_async_request *areq, int err) | |
119 | { | |
120 | async_done_continue(areq->data, err, poly_verify_tag); | |
121 | } | |
122 | ||
123 | static int chacha_decrypt(struct aead_request *req) | |
124 | { | |
125 | struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | |
126 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
127 | struct chacha_req *creq = &rctx->u.chacha; | |
74790922 | 128 | struct scatterlist *src, *dst; |
71ebc4d1 MW |
129 | int err; |
130 | ||
161151d7 JD |
131 | if (rctx->cryptlen == 0) |
132 | goto skip; | |
133 | ||
71ebc4d1 MW |
134 | chacha_iv(creq->iv, req, 1); |
135 | ||
74790922 HX |
136 | sg_init_table(rctx->src, 2); |
137 | src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen); | |
138 | dst = src; | |
139 | ||
140 | if (req->src != req->dst) { | |
141 | sg_init_table(rctx->dst, 2); | |
142 | dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen); | |
143 | } | |
144 | ||
1e1f0061 HX |
145 | skcipher_request_set_callback(&creq->req, aead_request_flags(req), |
146 | chacha_decrypt_done, req); | |
147 | skcipher_request_set_tfm(&creq->req, ctx->chacha); | |
148 | skcipher_request_set_crypt(&creq->req, src, dst, | |
149 | rctx->cryptlen, creq->iv); | |
150 | err = crypto_skcipher_decrypt(&creq->req); | |
71ebc4d1 MW |
151 | if (err) |
152 | return err; | |
153 | ||
161151d7 | 154 | skip: |
71ebc4d1 MW |
155 | return poly_verify_tag(req); |
156 | } | |
157 | ||
158 | static int poly_tail_continue(struct aead_request *req) | |
159 | { | |
160 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
161 | ||
162 | if (rctx->cryptlen == req->cryptlen) /* encrypting */ | |
163 | return poly_copy_tag(req); | |
164 | ||
165 | return chacha_decrypt(req); | |
166 | } | |
167 | ||
168 | static void poly_tail_done(struct crypto_async_request *areq, int err) | |
169 | { | |
170 | async_done_continue(areq->data, err, poly_tail_continue); | |
171 | } | |
172 | ||
173 | static int poly_tail(struct aead_request *req) | |
174 | { | |
74790922 HX |
175 | struct crypto_aead *tfm = crypto_aead_reqtfm(req); |
176 | struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm); | |
71ebc4d1 MW |
177 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); |
178 | struct poly_req *preq = &rctx->u.poly; | |
179 | __le64 len; | |
180 | int err; | |
181 | ||
182 | sg_init_table(preq->src, 1); | |
74790922 | 183 | len = cpu_to_le64(rctx->assoclen); |
71ebc4d1 MW |
184 | memcpy(&preq->tail.assoclen, &len, sizeof(len)); |
185 | len = cpu_to_le64(rctx->cryptlen); | |
186 | memcpy(&preq->tail.cryptlen, &len, sizeof(len)); | |
187 | sg_set_buf(preq->src, &preq->tail, sizeof(preq->tail)); | |
188 | ||
189 | ahash_request_set_callback(&preq->req, aead_request_flags(req), | |
190 | poly_tail_done, req); | |
191 | ahash_request_set_tfm(&preq->req, ctx->poly); | |
192 | ahash_request_set_crypt(&preq->req, preq->src, | |
193 | rctx->tag, sizeof(preq->tail)); | |
194 | ||
195 | err = crypto_ahash_finup(&preq->req); | |
196 | if (err) | |
197 | return err; | |
198 | ||
199 | return poly_tail_continue(req); | |
200 | } | |
201 | ||
202 | static void poly_cipherpad_done(struct crypto_async_request *areq, int err) | |
203 | { | |
204 | async_done_continue(areq->data, err, poly_tail); | |
205 | } | |
206 | ||
207 | static int poly_cipherpad(struct aead_request *req) | |
208 | { | |
209 | struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | |
210 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
211 | struct poly_req *preq = &rctx->u.poly; | |
212 | unsigned int padlen, bs = POLY1305_BLOCK_SIZE; | |
213 | int err; | |
214 | ||
215 | padlen = (bs - (rctx->cryptlen % bs)) % bs; | |
216 | memset(preq->pad, 0, sizeof(preq->pad)); | |
217 | sg_init_table(preq->src, 1); | |
218 | sg_set_buf(preq->src, &preq->pad, padlen); | |
219 | ||
220 | ahash_request_set_callback(&preq->req, aead_request_flags(req), | |
221 | poly_cipherpad_done, req); | |
222 | ahash_request_set_tfm(&preq->req, ctx->poly); | |
223 | ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen); | |
224 | ||
225 | err = crypto_ahash_update(&preq->req); | |
226 | if (err) | |
227 | return err; | |
228 | ||
229 | return poly_tail(req); | |
230 | } | |
231 | ||
232 | static void poly_cipher_done(struct crypto_async_request *areq, int err) | |
233 | { | |
234 | async_done_continue(areq->data, err, poly_cipherpad); | |
235 | } | |
236 | ||
237 | static int poly_cipher(struct aead_request *req) | |
238 | { | |
239 | struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | |
240 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
241 | struct poly_req *preq = &rctx->u.poly; | |
242 | struct scatterlist *crypt = req->src; | |
243 | int err; | |
244 | ||
245 | if (rctx->cryptlen == req->cryptlen) /* encrypting */ | |
246 | crypt = req->dst; | |
247 | ||
74790922 HX |
248 | sg_init_table(rctx->src, 2); |
249 | crypt = scatterwalk_ffwd(rctx->src, crypt, req->assoclen); | |
250 | ||
71ebc4d1 MW |
251 | ahash_request_set_callback(&preq->req, aead_request_flags(req), |
252 | poly_cipher_done, req); | |
253 | ahash_request_set_tfm(&preq->req, ctx->poly); | |
254 | ahash_request_set_crypt(&preq->req, crypt, NULL, rctx->cryptlen); | |
255 | ||
256 | err = crypto_ahash_update(&preq->req); | |
257 | if (err) | |
258 | return err; | |
259 | ||
260 | return poly_cipherpad(req); | |
261 | } | |
262 | ||
263 | static void poly_adpad_done(struct crypto_async_request *areq, int err) | |
264 | { | |
265 | async_done_continue(areq->data, err, poly_cipher); | |
266 | } | |
267 | ||
268 | static int poly_adpad(struct aead_request *req) | |
269 | { | |
270 | struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | |
271 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
272 | struct poly_req *preq = &rctx->u.poly; | |
273 | unsigned int padlen, bs = POLY1305_BLOCK_SIZE; | |
274 | int err; | |
275 | ||
74790922 | 276 | padlen = (bs - (rctx->assoclen % bs)) % bs; |
71ebc4d1 MW |
277 | memset(preq->pad, 0, sizeof(preq->pad)); |
278 | sg_init_table(preq->src, 1); | |
279 | sg_set_buf(preq->src, preq->pad, padlen); | |
280 | ||
281 | ahash_request_set_callback(&preq->req, aead_request_flags(req), | |
282 | poly_adpad_done, req); | |
283 | ahash_request_set_tfm(&preq->req, ctx->poly); | |
284 | ahash_request_set_crypt(&preq->req, preq->src, NULL, padlen); | |
285 | ||
286 | err = crypto_ahash_update(&preq->req); | |
287 | if (err) | |
288 | return err; | |
289 | ||
290 | return poly_cipher(req); | |
291 | } | |
292 | ||
293 | static void poly_ad_done(struct crypto_async_request *areq, int err) | |
294 | { | |
295 | async_done_continue(areq->data, err, poly_adpad); | |
296 | } | |
297 | ||
298 | static int poly_ad(struct aead_request *req) | |
299 | { | |
300 | struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | |
301 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
302 | struct poly_req *preq = &rctx->u.poly; | |
303 | int err; | |
304 | ||
305 | ahash_request_set_callback(&preq->req, aead_request_flags(req), | |
306 | poly_ad_done, req); | |
307 | ahash_request_set_tfm(&preq->req, ctx->poly); | |
74790922 | 308 | ahash_request_set_crypt(&preq->req, req->src, NULL, rctx->assoclen); |
71ebc4d1 MW |
309 | |
310 | err = crypto_ahash_update(&preq->req); | |
311 | if (err) | |
312 | return err; | |
313 | ||
314 | return poly_adpad(req); | |
315 | } | |
316 | ||
c2b7b20a | 317 | static void poly_setkey_done(struct crypto_async_request *areq, int err) |
71ebc4d1 MW |
318 | { |
319 | async_done_continue(areq->data, err, poly_ad); | |
320 | } | |
321 | ||
c2b7b20a | 322 | static int poly_setkey(struct aead_request *req) |
71ebc4d1 MW |
323 | { |
324 | struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | |
325 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
326 | struct poly_req *preq = &rctx->u.poly; | |
327 | int err; | |
328 | ||
c2b7b20a MW |
329 | sg_init_table(preq->src, 1); |
330 | sg_set_buf(preq->src, rctx->key, sizeof(rctx->key)); | |
331 | ||
71ebc4d1 | 332 | ahash_request_set_callback(&preq->req, aead_request_flags(req), |
c2b7b20a | 333 | poly_setkey_done, req); |
71ebc4d1 | 334 | ahash_request_set_tfm(&preq->req, ctx->poly); |
c2b7b20a | 335 | ahash_request_set_crypt(&preq->req, preq->src, NULL, sizeof(rctx->key)); |
71ebc4d1 | 336 | |
c2b7b20a | 337 | err = crypto_ahash_update(&preq->req); |
71ebc4d1 MW |
338 | if (err) |
339 | return err; | |
340 | ||
341 | return poly_ad(req); | |
342 | } | |
343 | ||
c2b7b20a | 344 | static void poly_init_done(struct crypto_async_request *areq, int err) |
71ebc4d1 | 345 | { |
c2b7b20a MW |
346 | async_done_continue(areq->data, err, poly_setkey); |
347 | } | |
348 | ||
349 | static int poly_init(struct aead_request *req) | |
350 | { | |
351 | struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | |
71ebc4d1 | 352 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); |
c2b7b20a | 353 | struct poly_req *preq = &rctx->u.poly; |
71ebc4d1 MW |
354 | int err; |
355 | ||
c2b7b20a MW |
356 | ahash_request_set_callback(&preq->req, aead_request_flags(req), |
357 | poly_init_done, req); | |
358 | ahash_request_set_tfm(&preq->req, ctx->poly); | |
71ebc4d1 | 359 | |
c2b7b20a | 360 | err = crypto_ahash_init(&preq->req); |
71ebc4d1 MW |
361 | if (err) |
362 | return err; | |
363 | ||
c2b7b20a | 364 | return poly_setkey(req); |
71ebc4d1 MW |
365 | } |
366 | ||
367 | static void poly_genkey_done(struct crypto_async_request *areq, int err) | |
368 | { | |
c2b7b20a | 369 | async_done_continue(areq->data, err, poly_init); |
71ebc4d1 MW |
370 | } |
371 | ||
372 | static int poly_genkey(struct aead_request *req) | |
373 | { | |
74790922 HX |
374 | struct crypto_aead *tfm = crypto_aead_reqtfm(req); |
375 | struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm); | |
71ebc4d1 MW |
376 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); |
377 | struct chacha_req *creq = &rctx->u.chacha; | |
378 | int err; | |
379 | ||
74790922 HX |
380 | rctx->assoclen = req->assoclen; |
381 | ||
382 | if (crypto_aead_ivsize(tfm) == 8) { | |
383 | if (rctx->assoclen < 8) | |
384 | return -EINVAL; | |
385 | rctx->assoclen -= 8; | |
386 | } | |
387 | ||
71ebc4d1 | 388 | sg_init_table(creq->src, 1); |
c2b7b20a MW |
389 | memset(rctx->key, 0, sizeof(rctx->key)); |
390 | sg_set_buf(creq->src, rctx->key, sizeof(rctx->key)); | |
71ebc4d1 MW |
391 | |
392 | chacha_iv(creq->iv, req, 0); | |
393 | ||
1e1f0061 HX |
394 | skcipher_request_set_callback(&creq->req, aead_request_flags(req), |
395 | poly_genkey_done, req); | |
396 | skcipher_request_set_tfm(&creq->req, ctx->chacha); | |
397 | skcipher_request_set_crypt(&creq->req, creq->src, creq->src, | |
398 | POLY1305_KEY_SIZE, creq->iv); | |
71ebc4d1 | 399 | |
1e1f0061 | 400 | err = crypto_skcipher_decrypt(&creq->req); |
71ebc4d1 MW |
401 | if (err) |
402 | return err; | |
403 | ||
c2b7b20a | 404 | return poly_init(req); |
71ebc4d1 MW |
405 | } |
406 | ||
407 | static void chacha_encrypt_done(struct crypto_async_request *areq, int err) | |
408 | { | |
409 | async_done_continue(areq->data, err, poly_genkey); | |
410 | } | |
411 | ||
412 | static int chacha_encrypt(struct aead_request *req) | |
413 | { | |
414 | struct chachapoly_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); | |
415 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
416 | struct chacha_req *creq = &rctx->u.chacha; | |
74790922 | 417 | struct scatterlist *src, *dst; |
71ebc4d1 MW |
418 | int err; |
419 | ||
161151d7 JD |
420 | if (req->cryptlen == 0) |
421 | goto skip; | |
422 | ||
71ebc4d1 MW |
423 | chacha_iv(creq->iv, req, 1); |
424 | ||
74790922 HX |
425 | sg_init_table(rctx->src, 2); |
426 | src = scatterwalk_ffwd(rctx->src, req->src, req->assoclen); | |
427 | dst = src; | |
428 | ||
429 | if (req->src != req->dst) { | |
430 | sg_init_table(rctx->dst, 2); | |
431 | dst = scatterwalk_ffwd(rctx->dst, req->dst, req->assoclen); | |
432 | } | |
433 | ||
1e1f0061 HX |
434 | skcipher_request_set_callback(&creq->req, aead_request_flags(req), |
435 | chacha_encrypt_done, req); | |
436 | skcipher_request_set_tfm(&creq->req, ctx->chacha); | |
437 | skcipher_request_set_crypt(&creq->req, src, dst, | |
438 | req->cryptlen, creq->iv); | |
439 | err = crypto_skcipher_encrypt(&creq->req); | |
71ebc4d1 MW |
440 | if (err) |
441 | return err; | |
442 | ||
161151d7 | 443 | skip: |
71ebc4d1 MW |
444 | return poly_genkey(req); |
445 | } | |
446 | ||
447 | static int chachapoly_encrypt(struct aead_request *req) | |
448 | { | |
449 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
450 | ||
451 | rctx->cryptlen = req->cryptlen; | |
452 | ||
453 | /* encrypt call chain: | |
454 | * - chacha_encrypt/done() | |
c2b7b20a | 455 | * - poly_genkey/done() |
71ebc4d1 | 456 | * - poly_init/done() |
c2b7b20a | 457 | * - poly_setkey/done() |
71ebc4d1 MW |
458 | * - poly_ad/done() |
459 | * - poly_adpad/done() | |
460 | * - poly_cipher/done() | |
461 | * - poly_cipherpad/done() | |
462 | * - poly_tail/done/continue() | |
463 | * - poly_copy_tag() | |
464 | */ | |
465 | return chacha_encrypt(req); | |
466 | } | |
467 | ||
468 | static int chachapoly_decrypt(struct aead_request *req) | |
469 | { | |
470 | struct chachapoly_req_ctx *rctx = aead_request_ctx(req); | |
471 | ||
71ebc4d1 MW |
472 | rctx->cryptlen = req->cryptlen - POLY1305_DIGEST_SIZE; |
473 | ||
474 | /* decrypt call chain: | |
c2b7b20a | 475 | * - poly_genkey/done() |
71ebc4d1 | 476 | * - poly_init/done() |
c2b7b20a | 477 | * - poly_setkey/done() |
71ebc4d1 MW |
478 | * - poly_ad/done() |
479 | * - poly_adpad/done() | |
480 | * - poly_cipher/done() | |
481 | * - poly_cipherpad/done() | |
482 | * - poly_tail/done/continue() | |
483 | * - chacha_decrypt/done() | |
484 | * - poly_verify_tag() | |
485 | */ | |
486 | return poly_genkey(req); | |
487 | } | |
488 | ||
489 | static int chachapoly_setkey(struct crypto_aead *aead, const u8 *key, | |
490 | unsigned int keylen) | |
491 | { | |
492 | struct chachapoly_ctx *ctx = crypto_aead_ctx(aead); | |
493 | int err; | |
494 | ||
1ca1b917 | 495 | if (keylen != ctx->saltlen + CHACHA_KEY_SIZE) |
71ebc4d1 MW |
496 | return -EINVAL; |
497 | ||
498 | keylen -= ctx->saltlen; | |
499 | memcpy(ctx->salt, key + keylen, ctx->saltlen); | |
500 | ||
1e1f0061 HX |
501 | crypto_skcipher_clear_flags(ctx->chacha, CRYPTO_TFM_REQ_MASK); |
502 | crypto_skcipher_set_flags(ctx->chacha, crypto_aead_get_flags(aead) & | |
503 | CRYPTO_TFM_REQ_MASK); | |
71ebc4d1 | 504 | |
1e1f0061 HX |
505 | err = crypto_skcipher_setkey(ctx->chacha, key, keylen); |
506 | crypto_aead_set_flags(aead, crypto_skcipher_get_flags(ctx->chacha) & | |
507 | CRYPTO_TFM_RES_MASK); | |
71ebc4d1 MW |
508 | return err; |
509 | } | |
510 | ||
511 | static int chachapoly_setauthsize(struct crypto_aead *tfm, | |
512 | unsigned int authsize) | |
513 | { | |
514 | if (authsize != POLY1305_DIGEST_SIZE) | |
515 | return -EINVAL; | |
516 | ||
517 | return 0; | |
518 | } | |
519 | ||
74790922 | 520 | static int chachapoly_init(struct crypto_aead *tfm) |
71ebc4d1 | 521 | { |
74790922 HX |
522 | struct aead_instance *inst = aead_alg_instance(tfm); |
523 | struct chachapoly_instance_ctx *ictx = aead_instance_ctx(inst); | |
524 | struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm); | |
1e1f0061 | 525 | struct crypto_skcipher *chacha; |
71ebc4d1 MW |
526 | struct crypto_ahash *poly; |
527 | unsigned long align; | |
528 | ||
529 | poly = crypto_spawn_ahash(&ictx->poly); | |
530 | if (IS_ERR(poly)) | |
531 | return PTR_ERR(poly); | |
532 | ||
60425a8b | 533 | chacha = crypto_spawn_skcipher(&ictx->chacha); |
71ebc4d1 MW |
534 | if (IS_ERR(chacha)) { |
535 | crypto_free_ahash(poly); | |
536 | return PTR_ERR(chacha); | |
537 | } | |
538 | ||
539 | ctx->chacha = chacha; | |
540 | ctx->poly = poly; | |
541 | ctx->saltlen = ictx->saltlen; | |
542 | ||
74790922 | 543 | align = crypto_aead_alignmask(tfm); |
71ebc4d1 | 544 | align &= ~(crypto_tfm_ctx_alignment() - 1); |
74790922 HX |
545 | crypto_aead_set_reqsize( |
546 | tfm, | |
547 | align + offsetof(struct chachapoly_req_ctx, u) + | |
548 | max(offsetof(struct chacha_req, req) + | |
1e1f0061 HX |
549 | sizeof(struct skcipher_request) + |
550 | crypto_skcipher_reqsize(chacha), | |
74790922 HX |
551 | offsetof(struct poly_req, req) + |
552 | sizeof(struct ahash_request) + | |
553 | crypto_ahash_reqsize(poly))); | |
71ebc4d1 MW |
554 | |
555 | return 0; | |
556 | } | |
557 | ||
74790922 | 558 | static void chachapoly_exit(struct crypto_aead *tfm) |
71ebc4d1 | 559 | { |
74790922 | 560 | struct chachapoly_ctx *ctx = crypto_aead_ctx(tfm); |
71ebc4d1 MW |
561 | |
562 | crypto_free_ahash(ctx->poly); | |
1e1f0061 | 563 | crypto_free_skcipher(ctx->chacha); |
71ebc4d1 MW |
564 | } |
565 | ||
74790922 HX |
566 | static void chachapoly_free(struct aead_instance *inst) |
567 | { | |
568 | struct chachapoly_instance_ctx *ctx = aead_instance_ctx(inst); | |
569 | ||
570 | crypto_drop_skcipher(&ctx->chacha); | |
571 | crypto_drop_ahash(&ctx->poly); | |
572 | kfree(inst); | |
573 | } | |
574 | ||
575 | static int chachapoly_create(struct crypto_template *tmpl, struct rtattr **tb, | |
576 | const char *name, unsigned int ivsize) | |
71ebc4d1 MW |
577 | { |
578 | struct crypto_attr_type *algt; | |
74790922 | 579 | struct aead_instance *inst; |
1e1f0061 | 580 | struct skcipher_alg *chacha; |
71ebc4d1 | 581 | struct crypto_alg *poly; |
74790922 | 582 | struct hash_alg_common *poly_hash; |
71ebc4d1 MW |
583 | struct chachapoly_instance_ctx *ctx; |
584 | const char *chacha_name, *poly_name; | |
585 | int err; | |
586 | ||
587 | if (ivsize > CHACHAPOLY_IV_SIZE) | |
74790922 | 588 | return -EINVAL; |
71ebc4d1 MW |
589 | |
590 | algt = crypto_get_attr_type(tb); | |
591 | if (IS_ERR(algt)) | |
74790922 | 592 | return PTR_ERR(algt); |
71ebc4d1 | 593 | |
5e4b8c1f | 594 | if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) |
74790922 | 595 | return -EINVAL; |
71ebc4d1 MW |
596 | |
597 | chacha_name = crypto_attr_alg_name(tb[1]); | |
598 | if (IS_ERR(chacha_name)) | |
74790922 | 599 | return PTR_ERR(chacha_name); |
71ebc4d1 MW |
600 | poly_name = crypto_attr_alg_name(tb[2]); |
601 | if (IS_ERR(poly_name)) | |
74790922 | 602 | return PTR_ERR(poly_name); |
71ebc4d1 MW |
603 | |
604 | poly = crypto_find_alg(poly_name, &crypto_ahash_type, | |
605 | CRYPTO_ALG_TYPE_HASH, | |
1e1f0061 HX |
606 | CRYPTO_ALG_TYPE_AHASH_MASK | |
607 | crypto_requires_sync(algt->type, | |
608 | algt->mask)); | |
71ebc4d1 | 609 | if (IS_ERR(poly)) |
74790922 | 610 | return PTR_ERR(poly); |
e57121d0 EB |
611 | poly_hash = __crypto_hash_alg_common(poly); |
612 | ||
613 | err = -EINVAL; | |
614 | if (poly_hash->digestsize != POLY1305_DIGEST_SIZE) | |
615 | goto out_put_poly; | |
71ebc4d1 MW |
616 | |
617 | err = -ENOMEM; | |
618 | inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL); | |
619 | if (!inst) | |
620 | goto out_put_poly; | |
621 | ||
74790922 | 622 | ctx = aead_instance_ctx(inst); |
71ebc4d1 | 623 | ctx->saltlen = CHACHAPOLY_IV_SIZE - ivsize; |
74790922 HX |
624 | err = crypto_init_ahash_spawn(&ctx->poly, poly_hash, |
625 | aead_crypto_instance(inst)); | |
71ebc4d1 MW |
626 | if (err) |
627 | goto err_free_inst; | |
628 | ||
74790922 | 629 | crypto_set_skcipher_spawn(&ctx->chacha, aead_crypto_instance(inst)); |
a35528ec EB |
630 | err = crypto_grab_skcipher(&ctx->chacha, chacha_name, 0, |
631 | crypto_requires_sync(algt->type, | |
632 | algt->mask)); | |
71ebc4d1 MW |
633 | if (err) |
634 | goto err_drop_poly; | |
635 | ||
1e1f0061 | 636 | chacha = crypto_spawn_skcipher_alg(&ctx->chacha); |
71ebc4d1 MW |
637 | |
638 | err = -EINVAL; | |
639 | /* Need 16-byte IV size, including Initial Block Counter value */ | |
1ca1b917 | 640 | if (crypto_skcipher_alg_ivsize(chacha) != CHACHA_IV_SIZE) |
71ebc4d1 MW |
641 | goto out_drop_chacha; |
642 | /* Not a stream cipher? */ | |
1e1f0061 | 643 | if (chacha->base.cra_blocksize != 1) |
71ebc4d1 MW |
644 | goto out_drop_chacha; |
645 | ||
646 | err = -ENAMETOOLONG; | |
74790922 | 647 | if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, |
5e27f38f EB |
648 | "%s(%s,%s)", name, chacha->base.cra_name, |
649 | poly->cra_name) >= CRYPTO_MAX_ALG_NAME) | |
71ebc4d1 | 650 | goto out_drop_chacha; |
74790922 | 651 | if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, |
1e1f0061 | 652 | "%s(%s,%s)", name, chacha->base.cra_driver_name, |
71ebc4d1 MW |
653 | poly->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) |
654 | goto out_drop_chacha; | |
655 | ||
1e1f0061 | 656 | inst->alg.base.cra_flags = (chacha->base.cra_flags | poly->cra_flags) & |
74790922 | 657 | CRYPTO_ALG_ASYNC; |
1e1f0061 | 658 | inst->alg.base.cra_priority = (chacha->base.cra_priority + |
74790922 HX |
659 | poly->cra_priority) / 2; |
660 | inst->alg.base.cra_blocksize = 1; | |
1e1f0061 | 661 | inst->alg.base.cra_alignmask = chacha->base.cra_alignmask | |
74790922 HX |
662 | poly->cra_alignmask; |
663 | inst->alg.base.cra_ctxsize = sizeof(struct chachapoly_ctx) + | |
664 | ctx->saltlen; | |
665 | inst->alg.ivsize = ivsize; | |
1e1f0061 | 666 | inst->alg.chunksize = crypto_skcipher_alg_chunksize(chacha); |
74790922 HX |
667 | inst->alg.maxauthsize = POLY1305_DIGEST_SIZE; |
668 | inst->alg.init = chachapoly_init; | |
669 | inst->alg.exit = chachapoly_exit; | |
670 | inst->alg.encrypt = chachapoly_encrypt; | |
671 | inst->alg.decrypt = chachapoly_decrypt; | |
672 | inst->alg.setkey = chachapoly_setkey; | |
673 | inst->alg.setauthsize = chachapoly_setauthsize; | |
674 | ||
675 | inst->free = chachapoly_free; | |
676 | ||
677 | err = aead_register_instance(tmpl, inst); | |
678 | if (err) | |
679 | goto out_drop_chacha; | |
680 | ||
681 | out_put_poly: | |
71ebc4d1 | 682 | crypto_mod_put(poly); |
74790922 | 683 | return err; |
71ebc4d1 MW |
684 | |
685 | out_drop_chacha: | |
686 | crypto_drop_skcipher(&ctx->chacha); | |
687 | err_drop_poly: | |
688 | crypto_drop_ahash(&ctx->poly); | |
689 | err_free_inst: | |
690 | kfree(inst); | |
74790922 | 691 | goto out_put_poly; |
71ebc4d1 MW |
692 | } |
693 | ||
74790922 | 694 | static int rfc7539_create(struct crypto_template *tmpl, struct rtattr **tb) |
4db4ad26 | 695 | { |
74790922 | 696 | return chachapoly_create(tmpl, tb, "rfc7539", 12); |
4db4ad26 MW |
697 | } |
698 | ||
74790922 | 699 | static int rfc7539esp_create(struct crypto_template *tmpl, struct rtattr **tb) |
71ebc4d1 | 700 | { |
74790922 | 701 | return chachapoly_create(tmpl, tb, "rfc7539esp", 8); |
71ebc4d1 MW |
702 | } |
703 | ||
1a5e02b6 XW |
704 | static struct crypto_template rfc7539_tmpls[] = { |
705 | { | |
706 | .name = "rfc7539", | |
707 | .create = rfc7539_create, | |
708 | .module = THIS_MODULE, | |
709 | }, { | |
710 | .name = "rfc7539esp", | |
711 | .create = rfc7539esp_create, | |
712 | .module = THIS_MODULE, | |
713 | }, | |
4db4ad26 MW |
714 | }; |
715 | ||
71ebc4d1 MW |
716 | static int __init chacha20poly1305_module_init(void) |
717 | { | |
1a5e02b6 XW |
718 | return crypto_register_templates(rfc7539_tmpls, |
719 | ARRAY_SIZE(rfc7539_tmpls)); | |
71ebc4d1 MW |
720 | } |
721 | ||
722 | static void __exit chacha20poly1305_module_exit(void) | |
723 | { | |
1a5e02b6 XW |
724 | crypto_unregister_templates(rfc7539_tmpls, |
725 | ARRAY_SIZE(rfc7539_tmpls)); | |
71ebc4d1 MW |
726 | } |
727 | ||
c4741b23 | 728 | subsys_initcall(chacha20poly1305_module_init); |
71ebc4d1 MW |
729 | module_exit(chacha20poly1305_module_exit); |
730 | ||
731 | MODULE_LICENSE("GPL"); | |
732 | MODULE_AUTHOR("Martin Willi <martin@strongswan.org>"); | |
733 | MODULE_DESCRIPTION("ChaCha20-Poly1305 AEAD"); | |
71ebc4d1 | 734 | MODULE_ALIAS_CRYPTO("rfc7539"); |
4db4ad26 | 735 | MODULE_ALIAS_CRYPTO("rfc7539esp"); |