crypto: arm - simplify bit sliced AES
Subsystems (3)
cover crypto: arm - simplify bit sliced AES
This contains a couple of improvements/simplifications for the bit sliced AES driver implemented on ARM and arm64.
Ard Biesheuvel (3):
crypto: arm/aes-neonbs-ctr - deal with non-multiples of AES block size
crypto: arm64/aes-neonbs-ctr - fallback to plain NEON for final chunk
crypto: arm64/aes-neonbs-xts - use plain NEON for non-power-of-2 input
sizes
arch/arm/crypto/aes-neonbs-core.S | 105 ++++---- arch/arm/crypto/aes-neonbs-glue.c | 35 ++- arch/arm64/crypto/aes-glue.c | 1 + arch/arm64/crypto/aes-neonbs-core.S | 264 +++++--------------- arch/arm64/crypto/aes-neonbs-glue.c | 97 ++++--- 5 files changed, 189 insertions(+), 313 deletions(-)
Signature · 1 line
2.30.2
PATCH 1/3 crypto: arm/aes-neonbs-ctr - deal with non-multiples of AES block size
Instead of falling back to C code to deal with the final bit of input that is not a round multiple of the block size, handle this in the asm code, permitting us to use overlapping loads and stores for performance, and implement the 16-byte wide XOR using a single NEON instruction.
Since NEON loads and stores have a natural width of 16 bytes, we need to handle inputs of less than 16 bytes in a special way, but this rarely occurs in practice so it does not impact performance. All other input sizes can be consumed directly by the NEON asm code, although it should be noted that the core AES transform can still only process 128 bytes (8 AES blocks) at a time.
--- arch/arm/crypto/aes-neonbs-core.S | 105 ++++++++++++-------- arch/arm/crypto/aes-neonbs-glue.c | 35 +++---- 2 files changed, 77 insertions(+), 63 deletions(-)
arch/arm/crypto/aes-neonbs-core.S +63 -42
@@ -758,29 +758,24 @@ ENTRY(aesbs_cbc_decrypt) ENDPROC(aesbs_cbc_decrypt) .macro next_ctr, q - vmov.32 \q\()h[1], r10 + vmov \q\()h, r9, r10 adds r10, r10, #1 - vmov.32 \q\()h[0], r9 adcs r9, r9, #0 - vmov.32 \q\()l[1], r8 + vmov \q\()l, r7, r8 adcs r8, r8, #0 - vmov.32 \q\()l[0], r7 adc r7, r7, #0 vrev32.8 \q, \q .endm /* * aesbs_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], - * int rounds, int blocks, u8 ctr[], u8 final[]) + * int rounds, int bytes, u8 ctr[]) */ ENTRY(aesbs_ctr_encrypt) mov ip, sp push {r4-r10, lr} - ldm ip, {r5-r7} // load args 4-6 - teq r7, #0 - addne r5, r5, #1 // one extra block if final != 0 - + ldm ip, {r5, r6} // load args 4-5 vld1.8 {q0}, [r6] // load counter vrev32.8 q1, q0 vmov r9, r10, d3
@@ -792,20 +787,19 @@ ENTRY(aesbs_ctr_encrypt) adc r7, r7, #0 99: vmov q1, q0 + sub lr, r5, #1 vmov q2, q0 + adr ip, 0f vmov q3, q0 + and lr, lr, #112 vmov q4, q0 + cmp r5, #112 vmov q5, q0 + sub ip, ip, lr, lsl #1 vmov q6, q0 + add ip, ip, lr, lsr #2 vmov q7, q0 - - adr ip, 0f - sub lr, r5, #1 - and lr, lr, #7 - cmp r5, #8 - sub ip, ip, lr, lsl #5 - sub ip, ip, lr, lsl #2 - movlt pc, ip // computed goto if blocks < 8 + movle pc, ip // computed goto if bytes < 112 next_ctr q1 next_ctr q2
@@ -820,12 +814,14 @@ ENTRY(aesbs_ctr_encrypt) bl aesbs_encrypt8 adr ip, 1f - and lr, r5, #7 - cmp r5, #8 - movgt r4, #0 - ldrle r4, [sp, #40] // load final in the last round - sub ip, ip, lr, lsl #2 - movlt pc, ip // computed goto if blocks < 8 + sub lr, r5, #1 + cmp r5, #128 + bic lr, lr, #15 + ands r4, r5, #15 // preserves C flag + teqcs r5, r5 // set Z flag if not last iteration + sub ip, ip, lr, lsr #2 + rsb r4, r4, #16 + movcc pc, ip // computed goto if bytes < 128 vld1.8 {q8}, [r1]! vld1.8 {q9}, [r1]!
@@ -834,46 +830,70 @@ ENTRY(aesbs_ctr_encrypt) vld1.8 {q12}, [r1]! vld1.8 {q13}, [r1]! vld1.8 {q14}, [r1]! - teq r4, #0 // skip last block if 'final' -1: bne 2f +1: subne r1, r1, r4 vld1.8 {q15}, [r1]! -2: adr ip, 3f - cmp r5, #8 - sub ip, ip, lr, lsl #3 - movlt pc, ip // computed goto if blocks < 8 + add ip, ip, #2f - 1b veor q0, q0, q8 - vst1.8 {q0}, [r0]! veor q1, q1, q9 - vst1.8 {q1}, [r0]! veor q4, q4, q10 - vst1.8 {q4}, [r0]! veor q6, q6, q11 - vst1.8 {q6}, [r0]! veor q3, q3, q12 - vst1.8 {q3}, [r0]! veor q7, q7, q13 - vst1.8 {q7}, [r0]! veor q2, q2, q14 + bne 3f + veor q5, q5, q15 + + movcc pc, ip // computed goto if bytes < 128 + + vst1.8 {q0}, [r0]! + vst1.8 {q1}, [r0]! + vst1.8 {q4}, [r0]! + vst1.8 {q6}, [r0]! + vst1.8 {q3}, [r0]! + vst1.8 {q7}, [r0]! vst1.8 {q2}, [r0]! - teq r4, #0 // skip last block if 'final' - W(bne) 5f -3: veor q5, q5, q15 +2: subne r0, r0, r4 vst1.8 {q5}, [r0]! -4: next_ctr q0 + next_ctr q0 - subs r5, r5, #8 + subs r5, r5, #128 bgt 99b vst1.8 {q0}, [r6] pop {r4-r10, pc} -5: vst1.8 {q5}, [r4] - b 4b +3: adr lr, .Lpermute_table + 16 + cmp r5, #16 // Z flag remains cleared + sub lr, lr, r4 + vld1.8 {q8-q9}, [lr] + vtbl.8 d16, {q5}, d16 + vtbl.8 d17, {q5}, d17 + veor q5, q8, q15 + bcc 4f // have to reload prev if R5 < 16 + vtbx.8 d10, {q2}, d18 + vtbx.8 d11, {q2}, d19 + mov pc, ip // branch back to VST sequence + +4: sub r0, r0, r4 + vshr.s8 q9, q9, #7 // create mask for VBIF + vld1.8 {q8}, [r0] // reload + vbif q5, q8, q9 + vst1.8 {q5}, [r0] + pop {r4-r10, pc} ENDPROC(aesbs_ctr_encrypt) + .align 6 +.Lpermute_table: + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 + .byte 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .byte 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + .macro next_tweak, out, in, const, tmp vshr.s64 \tmp, \in, #63 vand \tmp, \tmp, \const
@@ -888,6 +908,7 @@ ENDPROC(aesbs_ctr_encrypt) * aesbs_xts_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, * int blocks, u8 iv[], int reorder_last_tweak) */ + .align 6 __xts_prepare8: vld1.8 {q14}, [r7] // load iv vmov.i32 d30, #0x87 // compose tweak mask vector
arch/arm/crypto/aes-neonbs-glue.c +14 -21
@@ -37,7 +37,7 @@ asmlinkage void aesbs_cbc_decrypt(u8 out[], u8 const in[], u8 const rk[], int rounds, int blocks, u8 iv[]); asmlinkage void aesbs_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[], -int rounds,int blocks,u8 ctr[],u8 final[]); +int rounds,int blocks,u8 ctr[]); asmlinkage void aesbs_xts_encrypt(u8 out[], u8 const in[], u8 const rk[],int rounds,int blocks,u8 iv[],int );
@@ -243,32 +243,25 @@ static int ctr_encrypt(struct skcipher_request *req) err =skcipher_walk_virt (&walk, req, false);while (walk.nbytes >0 ) { -unsigned int blocks = walk.nbytes /AES_BLOCK_SIZE ; -u8 *final = (walk.total %AES_BLOCK_SIZE ) ? buf :NULL ; +const u8 *src = walk.src.virt.addr; +u8 *dst = walk.dst.virt.addr; +int bytes = walk.nbytes; -if (walk.nbytes < walk.total) { - blocks =round_down (blocks, - walk.stride /AES_BLOCK_SIZE ); - final =NULL ; - } +if (unlikely (bytes <AES_BLOCK_SIZE )) + src = dst =memcpy (buf +sizeof (buf) - bytes, + src, bytes); +else if (walk.nbytes < walk.total) + bytes &= ~(8 *AES_BLOCK_SIZE -1 );kernel_neon_begin (); -aesbs_ctr_encrypt (walk.dst.virt.addr, walk.src.virt.addr, - ctx->rk, ctx->rounds, blocks, walk.iv, final); +aesbs_ctr_encrypt (dst, src, ctx->rk, ctx->rounds, bytes, walk.iv);kernel_neon_end (); -if (final) { -u8 *dst = walk.dst.virt.addr + blocks *AES_BLOCK_SIZE ; -u8 *src = walk.src.virt.addr + blocks *AES_BLOCK_SIZE ; +if (unlikely (bytes <AES_BLOCK_SIZE )) +memcpy (walk.dst.virt.addr, + buf +sizeof (buf) - bytes, bytes); -crypto_xor_cpy (dst, src, final, - walk.total %AES_BLOCK_SIZE ); - - err =skcipher_walk_done (&walk,0 ); -break ; - } - err =skcipher_walk_done (&walk, - walk.nbytes - blocks *AES_BLOCK_SIZE ); + err =skcipher_walk_done (&walk, walk.nbytes - bytes); }return err;
Signature · 1 line
2.30.2
PATCH 2/3 crypto: arm64/aes-neonbs-ctr - fallback to plain NEON for final chunk
In reply to Ard BiesheuvelInstead of processing the entire input with the 8-way bit sliced algorithm, which is sub-optimal for inputs that are not a multiple of 128 bytes in size, invoke the plain NEON version of CTR for the remainder of the input after processing the bulk using 128 byte strides.
This allows us to greatly simplify the asm code that implements CTR, and get rid of all the branches and special code paths. It also gains us a couple of percent of performance.
--- arch/arm64/crypto/aes-glue.c | 1 + arch/arm64/crypto/aes-neonbs-core.S | 132 ++++---------------- arch/arm64/crypto/aes-neonbs-glue.c | 64 +++++----- 3 files changed, 55 insertions(+), 142 deletions(-)
arch/arm64/crypto/aes-glue.c +1 -0
@@ -983,6 +983,7 @@ module_cpu_feature_match(AES, aes_init);module_init (aes_init);EXPORT_SYMBOL (neon_aes_ecb_encrypt);EXPORT_SYMBOL (neon_aes_cbc_encrypt); +EXPORT_SYMBOL (neon_aes_ctr_encrypt);EXPORT_SYMBOL (neon_aes_xts_encrypt);EXPORT_SYMBOL (neon_aes_xts_decrypt);#endif
arch/arm64/crypto/aes-neonbs-core.S +25 -107
158 lines not on this page · raw message
arch/arm64/crypto/aes-neonbs-glue.c +29 -35
141 lines not on this page · raw message
Signature · 1 line
2.30.2
PATCH 3/3 crypto: arm64/aes-neonbs-xts - use plain NEON for non-power-of-2 input sizes
In reply to Ard BiesheuvelEven though the kernel's implementations of AES-XTS were updated to implement ciphertext stealing and can operate on inputs of any size larger than or equal to the AES block size, this feature is rarely used in practice.
In fact, in the kernel, AES-XTS is only used to operate on 4096 or 512 byte blocks, which means that not only the ciphertext stealing is effectively dead code, the logic in the bit sliced NEON implementation to deal with fewer than 8 blocks at a time is also never used.
Since the bit-sliced NEON driver already depends on the plain NEON version, which is slower but can operate on smaller data quantities more straightforwardly, let's fallback to the plain NEON implementation of XTS for any residual inputs that are not multiples of 128 bytes. This allows us to remove a lot of complicated logic that rarely gets exercised in practice.
--- arch/arm64/crypto/aes-neonbs-core.S | 132 ++++++-------------- arch/arm64/crypto/aes-neonbs-glue.c | 33 ++--- 2 files changed, 57 insertions(+), 108 deletions(-)
arch/arm64/crypto/aes-neonbs-core.S +40 -92
@@ -735,119 +735,67 @@ SYM_FUNC_END(aesbs_cbc_decrypt) * int blocks, u8 iv[]) */ SYM_FUNC_START_LOCAL(__xts_crypt8) - mov x6, #1 - lsl x6, x6, x23 - subs w23, w23, #8 - csel x23, x23, xzr, pl - csel x6, x6, xzr, mi + movi v18.2s, #0x1 + movi v19.2s, #0x87 + uzp1 v18.4s, v18.4s, v19.4s + + ld1 {v0.16b-v3.16b}, [x1], #64 + ld1 {v4.16b-v7.16b}, [x1], #64 + + next_tweak v26, v25, v18, v19 + next_tweak v27, v26, v18, v19 + next_tweak v28, v27, v18, v19 + next_tweak v29, v28, v18, v19 + next_tweak v30, v29, v18, v19 + next_tweak v31, v30, v18, v19 + next_tweak v16, v31, v18, v19 + next_tweak v17, v16, v18, v19 - ld1 {v0.16b}, [x20], #16 - next_tweak v26, v25, v30, v31 eor v0.16b, v0.16b, v25.16b - tbnz x6, #1, 0f - - ld1 {v1.16b}, [x20], #16 - next_tweak v27, v26, v30, v31 eor v1.16b, v1.16b, v26.16b - tbnz x6, #2, 0f - - ld1 {v2.16b}, [x20], #16 - next_tweak v28, v27, v30, v31 eor v2.16b, v2.16b, v27.16b - tbnz x6, #3, 0f - - ld1 {v3.16b}, [x20], #16 - next_tweak v29, v28, v30, v31 eor v3.16b, v3.16b, v28.16b - tbnz x6, #4, 0f - - ld1 {v4.16b}, [x20], #16 - str q29, [sp, #.Lframe_local_offset] eor v4.16b, v4.16b, v29.16b - next_tweak v29, v29, v30, v31 - tbnz x6, #5, 0f - - ld1 {v5.16b}, [x20], #16 - str q29, [sp, #.Lframe_local_offset + 16] - eor v5.16b, v5.16b, v29.16b - next_tweak v29, v29, v30, v31 - tbnz x6, #6, 0f + eor v5.16b, v5.16b, v30.16b + eor v6.16b, v6.16b, v31.16b + eor v7.16b, v7.16b, v16.16b - ld1 {v6.16b}, [x20], #16 - str q29, [sp, #.Lframe_local_offset + 32] - eor v6.16b, v6.16b, v29.16b - next_tweak v29, v29, v30, v31 - tbnz x6, #7, 0f + stp q16, q17, [sp, #16] - ld1 {v7.16b}, [x20], #16 - str q29, [sp, #.Lframe_local_offset + 48] - eor v7.16b, v7.16b, v29.16b - next_tweak v29, v29, v30, v31 - -0: mov bskey, x21 - mov rounds, x22 + mov bskey, x2 + mov rounds, x3 br x16 SYM_FUNC_END(__xts_crypt8) .macro __xts_crypt, do8, o0, o1, o2, o3, o4, o5, o6, o7 - frame_push 6, 64 - - mov x19, x0 - mov x20, x1 - mov x21, x2 - mov x22, x3 - mov x23, x4 - mov x24, x5 + stp x29, x30, [sp, #-48]! + mov x29, sp - movi v30.2s, #0x1 - movi v25.2s, #0x87 - uzp1 v30.4s, v30.4s, v25.4s - ld1 {v25.16b}, [x24] + ld1 {v25.16b}, [x5] -99: adr x16, \do8 +0: adr x16, \do8 bl __xts_crypt8 - ldp q16, q17, [sp, #.Lframe_local_offset] - ldp q18, q19, [sp, #.Lframe_local_offset + 32] + eor v16.16b, \o0\().16b, v25.16b + eor v17.16b, \o1\().16b, v26.16b + eor v18.16b, \o2\().16b, v27.16b + eor v19.16b, \o3\().16b, v28.16b - eor \o0\().16b, \o0\().16b, v25.16b - eor \o1\().16b, \o1\().16b, v26.16b - eor \o2\().16b, \o2\().16b, v27.16b - eor \o3\().16b, \o3\().16b, v28.16b + ldp q24, q25, [sp, #16] - st1 {\o0\().16b}, [x19], #16 - mov v25.16b, v26.16b - tbnz x6, #1, 1f - st1 {\o1\().16b}, [x19], #16 - mov v25.16b, v27.16b - tbnz x6, #2, 1f - st1 {\o2\().16b}, [x19], #16 - mov v25.16b, v28.16b - tbnz x6, #3, 1f - st1 {\o3\().16b}, [x19], #16 - mov v25.16b, v29.16b - tbnz x6, #4, 1f - - eor \o4\().16b, \o4\().16b, v16.16b - eor \o5\().16b, \o5\().16b, v17.16b - eor \o6\().16b, \o6\().16b, v18.16b - eor \o7\().16b, \o7\().16b, v19.16b - - st1 {\o4\().16b}, [x19], #16 - tbnz x6, #5, 1f - st1 {\o5\().16b}, [x19], #16 - tbnz x6, #6, 1f - st1 {\o6\().16b}, [x19], #16 - tbnz x6, #7, 1f - st1 {\o7\().16b}, [x19], #16 + eor v20.16b, \o4\().16b, v29.16b + eor v21.16b, \o5\().16b, v30.16b + eor v22.16b, \o6\().16b, v31.16b + eor v23.16b, \o7\().16b, v24.16b - cbz x23, 1f - st1 {v25.16b}, [x24] + st1 {v16.16b-v19.16b}, [x0], #64 + st1 {v20.16b-v23.16b}, [x0], #64 - b 99b + subs x4, x4, #8 + b.gt 0b -1: st1 {v25.16b}, [x24] - frame_pop + st1 {v25.16b}, [x5] + ldp x29, x30, [sp], #48 ret .endm
arch/arm64/crypto/aes-neonbs-glue.c +17 -16
@@ -302,23 +302,18 @@ static int __xts_crypt(struct skcipher_request *req, bool encrypt,return err;while (walk.nbytes >=AES_BLOCK_SIZE ) { -unsigned int blocks = walk.nbytes /AES_BLOCK_SIZE ; - -if (walk.nbytes < walk.total || walk.nbytes %AES_BLOCK_SIZE ) - blocks =round_down (blocks, - walk.stride /AES_BLOCK_SIZE ); - +int blocks = (walk.nbytes /AES_BLOCK_SIZE ) & ~7 ; out = walk.dst.virt.addr; in = walk.src.virt.addr; nbytes = walk.nbytes;kernel_neon_begin (); -if (likely (blocks >6 )) {/* plain NEON is faster otherwise */ -if (first) +if (blocks >=8 ) { +if (first ==1 )neon_aes_ecb_encrypt (walk.iv, walk.iv, ctx->twkey, ctx->key.rounds,1 ); - first =0 ; + first =2 ;fn (out, in, ctx->key.rk, ctx->key.rounds, blocks, walk.iv);
@@ -327,10 +322,17 @@ static int __xts_crypt(struct skcipher_request *req, bool encrypt, in += blocks *AES_BLOCK_SIZE ; nbytes -= blocks *AES_BLOCK_SIZE ; } - -if (walk.nbytes == walk.total && nbytes >0 ) - goto xts_tail; - +if (walk.nbytes == walk.total && nbytes >0 ) { +if (encrypt) +neon_aes_xts_encrypt (out, in, ctx->cts.key_enc, + ctx->key.rounds, nbytes, + ctx->twkey, walk.iv, first); +else +neon_aes_xts_decrypt (out, in, ctx->cts.key_dec, + ctx->key.rounds, nbytes, + ctx->twkey, walk.iv, first); + nbytes = first =0 ; + }kernel_neon_end (); err =skcipher_walk_done (&walk, nbytes); }
@@ -355,13 +357,12 @@ static int __xts_crypt(struct skcipher_request *req, bool encrypt, nbytes = walk.nbytes;kernel_neon_begin (); -xts_tail:if (encrypt)neon_aes_xts_encrypt (out, in, ctx->cts.key_enc, ctx->key.rounds, - nbytes, ctx->twkey, walk.iv, first ?:2 ); + nbytes, ctx->twkey, walk.iv, first);else neon_aes_xts_decrypt (out, in, ctx->cts.key_dec, ctx->key.rounds, - nbytes, ctx->twkey, walk.iv, first ?:2 ); + nbytes, ctx->twkey, walk.iv, first);kernel_neon_end ();return skcipher_walk_done (&walk,0 );
Signature · 1 line
2.30.2
Herbert Xu
maintainerQuoted 9 lines · Ard Biesheuvel
This contains a couple of improvements/simplifications for the bit sliced AES driver implemented on ARM and arm64.
Ard Biesheuvel (3):
crypto: arm/aes-neonbs-ctr - deal with non-multiples of AES block size
crypto: arm64/aes-neonbs-ctr - fallback to plain NEON for final chunk
crypto: arm64/aes-neonbs-xts - use plain NEON for non-power-of-2 input
sizes
Quoted 6 lines
arch/arm/crypto/aes-neonbs-core.S | 105 ++++---- arch/arm/crypto/aes-neonbs-glue.c | 35 ++- arch/arm64/crypto/aes-glue.c | 1 + arch/arm64/crypto/aes-neonbs-core.S | 264 +++++--------------- arch/arm64/crypto/aes-neonbs-glue.c | 97 ++++--- 5 files changed, 189 insertions(+), 313 deletions(-)
All applied. Thanks.
Signature · 3 lines
Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt