diff options
author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2019-09-03 12:43:37 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2019-09-09 03:35:39 -0400 |
commit | 143d2647c892cb454489dca62a9fc65941c5c557 (patch) | |
tree | b2bca03e5bdc1ec972373e91e6f12ddce8733699 /arch/arm | |
parent | 2ed8b79098cf76287c519d781a14c7983ab7e4f7 (diff) |
crypto: arm/aes-ce - implement ciphertext stealing for CBC
Instead of relying on the CTS template to wrap the accelerated CBC
skcipher, implement the ciphertext stealing part directly.
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/crypto/aes-ce-core.S | 85 | ||||
-rw-r--r-- | arch/arm/crypto/aes-ce-glue.c | 188 |
2 files changed, 256 insertions, 17 deletions
diff --git a/arch/arm/crypto/aes-ce-core.S b/arch/arm/crypto/aes-ce-core.S index 763e51604ab6..b978cdf133af 100644 --- a/arch/arm/crypto/aes-ce-core.S +++ b/arch/arm/crypto/aes-ce-core.S | |||
@@ -284,6 +284,91 @@ ENTRY(ce_aes_cbc_decrypt) | |||
284 | pop {r4-r6, pc} | 284 | pop {r4-r6, pc} |
285 | ENDPROC(ce_aes_cbc_decrypt) | 285 | ENDPROC(ce_aes_cbc_decrypt) |
286 | 286 | ||
287 | |||
288 | /* | ||
289 | * ce_aes_cbc_cts_encrypt(u8 out[], u8 const in[], u32 const rk[], | ||
290 | * int rounds, int bytes, u8 const iv[]) | ||
291 | * ce_aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[], | ||
292 | * int rounds, int bytes, u8 const iv[]) | ||
293 | */ | ||
294 | |||
295 | ENTRY(ce_aes_cbc_cts_encrypt) | ||
296 | push {r4-r6, lr} | ||
297 | ldrd r4, r5, [sp, #16] | ||
298 | |||
299 | movw ip, :lower16:.Lcts_permute_table | ||
300 | movt ip, :upper16:.Lcts_permute_table | ||
301 | sub r4, r4, #16 | ||
302 | add lr, ip, #32 | ||
303 | add ip, ip, r4 | ||
304 | sub lr, lr, r4 | ||
305 | vld1.8 {q5}, [ip] | ||
306 | vld1.8 {q6}, [lr] | ||
307 | |||
308 | add ip, r1, r4 | ||
309 | vld1.8 {q0}, [r1] @ overlapping loads | ||
310 | vld1.8 {q3}, [ip] | ||
311 | |||
312 | vld1.8 {q1}, [r5] @ get iv | ||
313 | prepare_key r2, r3 | ||
314 | |||
315 | veor q0, q0, q1 @ xor with iv | ||
316 | bl aes_encrypt | ||
317 | |||
318 | vtbl.8 d4, {d0-d1}, d10 | ||
319 | vtbl.8 d5, {d0-d1}, d11 | ||
320 | vtbl.8 d2, {d6-d7}, d12 | ||
321 | vtbl.8 d3, {d6-d7}, d13 | ||
322 | |||
323 | veor q0, q0, q1 | ||
324 | bl aes_encrypt | ||
325 | |||
326 | add r4, r0, r4 | ||
327 | vst1.8 {q2}, [r4] @ overlapping stores | ||
328 | vst1.8 {q0}, [r0] | ||
329 | |||
330 | pop {r4-r6, pc} | ||
331 | ENDPROC(ce_aes_cbc_cts_encrypt) | ||
332 | |||
333 | ENTRY(ce_aes_cbc_cts_decrypt) | ||
334 | push {r4-r6, lr} | ||
335 | ldrd r4, r5, [sp, #16] | ||
336 | |||
337 | movw ip, :lower16:.Lcts_permute_table | ||
338 | movt ip, :upper16:.Lcts_permute_table | ||
339 | sub r4, r4, #16 | ||
340 | add lr, ip, #32 | ||
341 | add ip, ip, r4 | ||
342 | sub lr, lr, r4 | ||
343 | vld1.8 {q5}, [ip] | ||
344 | vld1.8 {q6}, [lr] | ||
345 | |||
346 | add ip, r1, r4 | ||
347 | vld1.8 {q0}, [r1] @ overlapping loads | ||
348 | vld1.8 {q1}, [ip] | ||
349 | |||
350 | vld1.8 {q3}, [r5] @ get iv | ||
351 | prepare_key r2, r3 | ||
352 | |||
353 | bl aes_decrypt | ||
354 | |||
355 | vtbl.8 d4, {d0-d1}, d10 | ||
356 | vtbl.8 d5, {d0-d1}, d11 | ||
357 | vtbx.8 d0, {d2-d3}, d12 | ||
358 | vtbx.8 d1, {d2-d3}, d13 | ||
359 | |||
360 | veor q1, q1, q2 | ||
361 | bl aes_decrypt | ||
362 | veor q0, q0, q3 @ xor with iv | ||
363 | |||
364 | add r4, r0, r4 | ||
365 | vst1.8 {q1}, [r4] @ overlapping stores | ||
366 | vst1.8 {q0}, [r0] | ||
367 | |||
368 | pop {r4-r6, pc} | ||
369 | ENDPROC(ce_aes_cbc_cts_decrypt) | ||
370 | |||
371 | |||
287 | /* | 372 | /* |
288 | * aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, | 373 | * aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], int rounds, |
289 | * int blocks, u8 ctr[]) | 374 | * int blocks, u8 ctr[]) |
diff --git a/arch/arm/crypto/aes-ce-glue.c b/arch/arm/crypto/aes-ce-glue.c index c215792a2494..cdb1a07e7ad0 100644 --- a/arch/arm/crypto/aes-ce-glue.c +++ b/arch/arm/crypto/aes-ce-glue.c | |||
@@ -35,6 +35,10 @@ asmlinkage void ce_aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[], | |||
35 | int rounds, int blocks, u8 iv[]); | 35 | int rounds, int blocks, u8 iv[]); |
36 | asmlinkage void ce_aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[], | 36 | asmlinkage void ce_aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[], |
37 | int rounds, int blocks, u8 iv[]); | 37 | int rounds, int blocks, u8 iv[]); |
38 | asmlinkage void ce_aes_cbc_cts_encrypt(u8 out[], u8 const in[], u32 const rk[], | ||
39 | int rounds, int bytes, u8 const iv[]); | ||
40 | asmlinkage void ce_aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[], | ||
41 | int rounds, int bytes, u8 const iv[]); | ||
38 | 42 | ||
39 | asmlinkage void ce_aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], | 43 | asmlinkage void ce_aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], |
40 | int rounds, int blocks, u8 ctr[]); | 44 | int rounds, int blocks, u8 ctr[]); |
@@ -210,48 +214,182 @@ static int ecb_decrypt(struct skcipher_request *req) | |||
210 | return err; | 214 | return err; |
211 | } | 215 | } |
212 | 216 | ||
213 | static int cbc_encrypt(struct skcipher_request *req) | 217 | static int cbc_encrypt_walk(struct skcipher_request *req, |
218 | struct skcipher_walk *walk) | ||
214 | { | 219 | { |
215 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); | 220 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); |
216 | struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); | 221 | struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); |
217 | struct skcipher_walk walk; | ||
218 | unsigned int blocks; | 222 | unsigned int blocks; |
219 | int err; | 223 | int err = 0; |
220 | 224 | ||
221 | err = skcipher_walk_virt(&walk, req, false); | 225 | while ((blocks = (walk->nbytes / AES_BLOCK_SIZE))) { |
222 | |||
223 | while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { | ||
224 | kernel_neon_begin(); | 226 | kernel_neon_begin(); |
225 | ce_aes_cbc_encrypt(walk.dst.virt.addr, walk.src.virt.addr, | 227 | ce_aes_cbc_encrypt(walk->dst.virt.addr, walk->src.virt.addr, |
226 | ctx->key_enc, num_rounds(ctx), blocks, | 228 | ctx->key_enc, num_rounds(ctx), blocks, |
227 | walk.iv); | 229 | walk->iv); |
228 | kernel_neon_end(); | 230 | kernel_neon_end(); |
229 | err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); | 231 | err = skcipher_walk_done(walk, walk->nbytes % AES_BLOCK_SIZE); |
230 | } | 232 | } |
231 | return err; | 233 | return err; |
232 | } | 234 | } |
233 | 235 | ||
234 | static int cbc_decrypt(struct skcipher_request *req) | 236 | static int cbc_encrypt(struct skcipher_request *req) |
235 | { | 237 | { |
236 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); | ||
237 | struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); | ||
238 | struct skcipher_walk walk; | 238 | struct skcipher_walk walk; |
239 | unsigned int blocks; | ||
240 | int err; | 239 | int err; |
241 | 240 | ||
242 | err = skcipher_walk_virt(&walk, req, false); | 241 | err = skcipher_walk_virt(&walk, req, false); |
242 | if (err) | ||
243 | return err; | ||
244 | return cbc_encrypt_walk(req, &walk); | ||
245 | } | ||
243 | 246 | ||
244 | while ((blocks = (walk.nbytes / AES_BLOCK_SIZE))) { | 247 | static int cbc_decrypt_walk(struct skcipher_request *req, |
248 | struct skcipher_walk *walk) | ||
249 | { | ||
250 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); | ||
251 | struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); | ||
252 | unsigned int blocks; | ||
253 | int err = 0; | ||
254 | |||
255 | while ((blocks = (walk->nbytes / AES_BLOCK_SIZE))) { | ||
245 | kernel_neon_begin(); | 256 | kernel_neon_begin(); |
246 | ce_aes_cbc_decrypt(walk.dst.virt.addr, walk.src.virt.addr, | 257 | ce_aes_cbc_decrypt(walk->dst.virt.addr, walk->src.virt.addr, |
247 | ctx->key_dec, num_rounds(ctx), blocks, | 258 | ctx->key_dec, num_rounds(ctx), blocks, |
248 | walk.iv); | 259 | walk->iv); |
249 | kernel_neon_end(); | 260 | kernel_neon_end(); |
250 | err = skcipher_walk_done(&walk, walk.nbytes % AES_BLOCK_SIZE); | 261 | err = skcipher_walk_done(walk, walk->nbytes % AES_BLOCK_SIZE); |
251 | } | 262 | } |
252 | return err; | 263 | return err; |
253 | } | 264 | } |
254 | 265 | ||
266 | static int cbc_decrypt(struct skcipher_request *req) | ||
267 | { | ||
268 | struct skcipher_walk walk; | ||
269 | int err; | ||
270 | |||
271 | err = skcipher_walk_virt(&walk, req, false); | ||
272 | if (err) | ||
273 | return err; | ||
274 | return cbc_decrypt_walk(req, &walk); | ||
275 | } | ||
276 | |||
277 | static int cts_cbc_encrypt(struct skcipher_request *req) | ||
278 | { | ||
279 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); | ||
280 | struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); | ||
281 | int cbc_blocks = DIV_ROUND_UP(req->cryptlen, AES_BLOCK_SIZE) - 2; | ||
282 | struct scatterlist *src = req->src, *dst = req->dst; | ||
283 | struct scatterlist sg_src[2], sg_dst[2]; | ||
284 | struct skcipher_request subreq; | ||
285 | struct skcipher_walk walk; | ||
286 | int err; | ||
287 | |||
288 | skcipher_request_set_tfm(&subreq, tfm); | ||
289 | skcipher_request_set_callback(&subreq, skcipher_request_flags(req), | ||
290 | NULL, NULL); | ||
291 | |||
292 | if (req->cryptlen <= AES_BLOCK_SIZE) { | ||
293 | if (req->cryptlen < AES_BLOCK_SIZE) | ||
294 | return -EINVAL; | ||
295 | cbc_blocks = 1; | ||
296 | } | ||
297 | |||
298 | if (cbc_blocks > 0) { | ||
299 | skcipher_request_set_crypt(&subreq, req->src, req->dst, | ||
300 | cbc_blocks * AES_BLOCK_SIZE, | ||
301 | req->iv); | ||
302 | |||
303 | err = skcipher_walk_virt(&walk, &subreq, false) ?: | ||
304 | cbc_encrypt_walk(&subreq, &walk); | ||
305 | if (err) | ||
306 | return err; | ||
307 | |||
308 | if (req->cryptlen == AES_BLOCK_SIZE) | ||
309 | return 0; | ||
310 | |||
311 | dst = src = scatterwalk_ffwd(sg_src, req->src, subreq.cryptlen); | ||
312 | if (req->dst != req->src) | ||
313 | dst = scatterwalk_ffwd(sg_dst, req->dst, | ||
314 | subreq.cryptlen); | ||
315 | } | ||
316 | |||
317 | /* handle ciphertext stealing */ | ||
318 | skcipher_request_set_crypt(&subreq, src, dst, | ||
319 | req->cryptlen - cbc_blocks * AES_BLOCK_SIZE, | ||
320 | req->iv); | ||
321 | |||
322 | err = skcipher_walk_virt(&walk, &subreq, false); | ||
323 | if (err) | ||
324 | return err; | ||
325 | |||
326 | kernel_neon_begin(); | ||
327 | ce_aes_cbc_cts_encrypt(walk.dst.virt.addr, walk.src.virt.addr, | ||
328 | ctx->key_enc, num_rounds(ctx), walk.nbytes, | ||
329 | walk.iv); | ||
330 | kernel_neon_end(); | ||
331 | |||
332 | return skcipher_walk_done(&walk, 0); | ||
333 | } | ||
334 | |||
335 | static int cts_cbc_decrypt(struct skcipher_request *req) | ||
336 | { | ||
337 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); | ||
338 | struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm); | ||
339 | int cbc_blocks = DIV_ROUND_UP(req->cryptlen, AES_BLOCK_SIZE) - 2; | ||
340 | struct scatterlist *src = req->src, *dst = req->dst; | ||
341 | struct scatterlist sg_src[2], sg_dst[2]; | ||
342 | struct skcipher_request subreq; | ||
343 | struct skcipher_walk walk; | ||
344 | int err; | ||
345 | |||
346 | skcipher_request_set_tfm(&subreq, tfm); | ||
347 | skcipher_request_set_callback(&subreq, skcipher_request_flags(req), | ||
348 | NULL, NULL); | ||
349 | |||
350 | if (req->cryptlen <= AES_BLOCK_SIZE) { | ||
351 | if (req->cryptlen < AES_BLOCK_SIZE) | ||
352 | return -EINVAL; | ||
353 | cbc_blocks = 1; | ||
354 | } | ||
355 | |||
356 | if (cbc_blocks > 0) { | ||
357 | skcipher_request_set_crypt(&subreq, req->src, req->dst, | ||
358 | cbc_blocks * AES_BLOCK_SIZE, | ||
359 | req->iv); | ||
360 | |||
361 | err = skcipher_walk_virt(&walk, &subreq, false) ?: | ||
362 | cbc_decrypt_walk(&subreq, &walk); | ||
363 | if (err) | ||
364 | return err; | ||
365 | |||
366 | if (req->cryptlen == AES_BLOCK_SIZE) | ||
367 | return 0; | ||
368 | |||
369 | dst = src = scatterwalk_ffwd(sg_src, req->src, subreq.cryptlen); | ||
370 | if (req->dst != req->src) | ||
371 | dst = scatterwalk_ffwd(sg_dst, req->dst, | ||
372 | subreq.cryptlen); | ||
373 | } | ||
374 | |||
375 | /* handle ciphertext stealing */ | ||
376 | skcipher_request_set_crypt(&subreq, src, dst, | ||
377 | req->cryptlen - cbc_blocks * AES_BLOCK_SIZE, | ||
378 | req->iv); | ||
379 | |||
380 | err = skcipher_walk_virt(&walk, &subreq, false); | ||
381 | if (err) | ||
382 | return err; | ||
383 | |||
384 | kernel_neon_begin(); | ||
385 | ce_aes_cbc_cts_decrypt(walk.dst.virt.addr, walk.src.virt.addr, | ||
386 | ctx->key_dec, num_rounds(ctx), walk.nbytes, | ||
387 | walk.iv); | ||
388 | kernel_neon_end(); | ||
389 | |||
390 | return skcipher_walk_done(&walk, 0); | ||
391 | } | ||
392 | |||
255 | static int ctr_encrypt(struct skcipher_request *req) | 393 | static int ctr_encrypt(struct skcipher_request *req) |
256 | { | 394 | { |
257 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); | 395 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); |
@@ -487,6 +625,22 @@ static struct skcipher_alg aes_algs[] = { { | |||
487 | .encrypt = cbc_encrypt, | 625 | .encrypt = cbc_encrypt, |
488 | .decrypt = cbc_decrypt, | 626 | .decrypt = cbc_decrypt, |
489 | }, { | 627 | }, { |
628 | .base.cra_name = "__cts(cbc(aes))", | ||
629 | .base.cra_driver_name = "__cts-cbc-aes-ce", | ||
630 | .base.cra_priority = 300, | ||
631 | .base.cra_flags = CRYPTO_ALG_INTERNAL, | ||
632 | .base.cra_blocksize = AES_BLOCK_SIZE, | ||
633 | .base.cra_ctxsize = sizeof(struct crypto_aes_ctx), | ||
634 | .base.cra_module = THIS_MODULE, | ||
635 | |||
636 | .min_keysize = AES_MIN_KEY_SIZE, | ||
637 | .max_keysize = AES_MAX_KEY_SIZE, | ||
638 | .ivsize = AES_BLOCK_SIZE, | ||
639 | .walksize = 2 * AES_BLOCK_SIZE, | ||
640 | .setkey = ce_aes_setkey, | ||
641 | .encrypt = cts_cbc_encrypt, | ||
642 | .decrypt = cts_cbc_decrypt, | ||
643 | }, { | ||
490 | .base.cra_name = "__ctr(aes)", | 644 | .base.cra_name = "__ctr(aes)", |
491 | .base.cra_driver_name = "__ctr-aes-ce", | 645 | .base.cra_driver_name = "__ctr-aes-ce", |
492 | .base.cra_priority = 300, | 646 | .base.cra_priority = 300, |