aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2019-09-03 12:43:37 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2019-09-09 03:35:39 -0400
commit143d2647c892cb454489dca62a9fc65941c5c557 (patch)
treeb2bca03e5bdc1ec972373e91e6f12ddce8733699 /arch/arm
parent2ed8b79098cf76287c519d781a14c7983ab7e4f7 (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.S85
-rw-r--r--arch/arm/crypto/aes-ce-glue.c188
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}
285ENDPROC(ce_aes_cbc_decrypt) 285ENDPROC(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
295ENTRY(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}
331ENDPROC(ce_aes_cbc_cts_encrypt)
332
333ENTRY(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}
369ENDPROC(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[]);
36asmlinkage void ce_aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[], 36asmlinkage 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[]);
38asmlinkage void ce_aes_cbc_cts_encrypt(u8 out[], u8 const in[], u32 const rk[],
39 int rounds, int bytes, u8 const iv[]);
40asmlinkage void ce_aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[],
41 int rounds, int bytes, u8 const iv[]);
38 42
39asmlinkage void ce_aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[], 43asmlinkage 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
213static int cbc_encrypt(struct skcipher_request *req) 217static 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
234static int cbc_decrypt(struct skcipher_request *req) 236static 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))) { 247static 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
266static 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
277static 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
335static 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
255static int ctr_encrypt(struct skcipher_request *req) 393static 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,