diff options
author | Ard Biesheuvel <ard.biesheuvel@linaro.org> | 2015-03-10 04:47:45 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2015-03-12 06:13:35 -0400 |
commit | 864cbeed4ab22de8c4d9a49101e9fd63c6f7fda2 (patch) | |
tree | ed5d371a21bfe5dc27fcab6e562a19be6af12880 /arch/arm | |
parent | 652ccae5cc4e1305fb0a4619947f9ee89d8c7f5a (diff) |
crypto: arm - add support for SHA1 using ARMv8 Crypto Instructions
This implements the SHA1 secure hash algorithm using the AArch32
versions of the ARMv8 Crypto Extensions for SHA1.
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/Kconfig | 10 | ||||
-rw-r--r-- | arch/arm/crypto/Makefile | 2 | ||||
-rw-r--r-- | arch/arm/crypto/sha1-ce-core.S | 134 | ||||
-rw-r--r-- | arch/arm/crypto/sha1-ce-glue.c | 150 |
4 files changed, 296 insertions, 0 deletions
diff --git a/arch/arm/crypto/Kconfig b/arch/arm/crypto/Kconfig index 66fe82857e99..d7bc10beb8ac 100644 --- a/arch/arm/crypto/Kconfig +++ b/arch/arm/crypto/Kconfig | |||
@@ -27,6 +27,16 @@ config CRYPTO_SHA1_ARM_NEON | |||
27 | using optimized ARM NEON assembly, when NEON instructions are | 27 | using optimized ARM NEON assembly, when NEON instructions are |
28 | available. | 28 | available. |
29 | 29 | ||
30 | config CRYPTO_SHA1_ARM_CE | ||
31 | tristate "SHA1 digest algorithm (ARM v8 Crypto Extensions)" | ||
32 | depends on KERNEL_MODE_NEON | ||
33 | select CRYPTO_SHA1_ARM | ||
34 | select CRYPTO_SHA1 | ||
35 | select CRYPTO_HASH | ||
36 | help | ||
37 | SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented | ||
38 | using special ARMv8 Crypto Extensions. | ||
39 | |||
30 | config CRYPTO_SHA512_ARM_NEON | 40 | config CRYPTO_SHA512_ARM_NEON |
31 | tristate "SHA384 and SHA512 digest algorithm (ARM NEON)" | 41 | tristate "SHA384 and SHA512 digest algorithm (ARM NEON)" |
32 | depends on KERNEL_MODE_NEON | 42 | depends on KERNEL_MODE_NEON |
diff --git a/arch/arm/crypto/Makefile b/arch/arm/crypto/Makefile index b48fa341648d..d92d05ba646e 100644 --- a/arch/arm/crypto/Makefile +++ b/arch/arm/crypto/Makefile | |||
@@ -7,12 +7,14 @@ obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o | |||
7 | obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o | 7 | obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o |
8 | obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o | 8 | obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o |
9 | obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o | 9 | obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o |
10 | obj-$(CONFIG_CRYPTO_SHA1_ARM_CE) += sha1-arm-ce.o | ||
10 | 11 | ||
11 | aes-arm-y := aes-armv4.o aes_glue.o | 12 | aes-arm-y := aes-armv4.o aes_glue.o |
12 | aes-arm-bs-y := aesbs-core.o aesbs-glue.o | 13 | aes-arm-bs-y := aesbs-core.o aesbs-glue.o |
13 | sha1-arm-y := sha1-armv4-large.o sha1_glue.o | 14 | sha1-arm-y := sha1-armv4-large.o sha1_glue.o |
14 | sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o | 15 | sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o |
15 | sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o | 16 | sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o |
17 | sha1-arm-ce-y := sha1-ce-core.o sha1-ce-glue.o | ||
16 | 18 | ||
17 | quiet_cmd_perl = PERL $@ | 19 | quiet_cmd_perl = PERL $@ |
18 | cmd_perl = $(PERL) $(<) > $(@) | 20 | cmd_perl = $(PERL) $(<) > $(@) |
diff --git a/arch/arm/crypto/sha1-ce-core.S b/arch/arm/crypto/sha1-ce-core.S new file mode 100644 index 000000000000..4aad520935d8 --- /dev/null +++ b/arch/arm/crypto/sha1-ce-core.S | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * sha1-ce-core.S - SHA-1 secure hash using ARMv8 Crypto Extensions | ||
3 | * | ||
4 | * Copyright (C) 2015 Linaro Ltd. | ||
5 | * Author: Ard Biesheuvel <ard.biesheuvel@linaro.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/linkage.h> | ||
13 | #include <asm/assembler.h> | ||
14 | |||
15 | .text | ||
16 | .fpu crypto-neon-fp-armv8 | ||
17 | |||
18 | k0 .req q0 | ||
19 | k1 .req q1 | ||
20 | k2 .req q2 | ||
21 | k3 .req q3 | ||
22 | |||
23 | ta0 .req q4 | ||
24 | ta1 .req q5 | ||
25 | tb0 .req q5 | ||
26 | tb1 .req q4 | ||
27 | |||
28 | dga .req q6 | ||
29 | dgb .req q7 | ||
30 | dgbs .req s28 | ||
31 | |||
32 | dg0 .req q12 | ||
33 | dg1a0 .req q13 | ||
34 | dg1a1 .req q14 | ||
35 | dg1b0 .req q14 | ||
36 | dg1b1 .req q13 | ||
37 | |||
38 | .macro add_only, op, ev, rc, s0, dg1 | ||
39 | .ifnb \s0 | ||
40 | vadd.u32 tb\ev, q\s0, \rc | ||
41 | .endif | ||
42 | sha1h.32 dg1b\ev, dg0 | ||
43 | .ifb \dg1 | ||
44 | sha1\op\().32 dg0, dg1a\ev, ta\ev | ||
45 | .else | ||
46 | sha1\op\().32 dg0, \dg1, ta\ev | ||
47 | .endif | ||
48 | .endm | ||
49 | |||
50 | .macro add_update, op, ev, rc, s0, s1, s2, s3, dg1 | ||
51 | sha1su0.32 q\s0, q\s1, q\s2 | ||
52 | add_only \op, \ev, \rc, \s1, \dg1 | ||
53 | sha1su1.32 q\s0, q\s3 | ||
54 | .endm | ||
55 | |||
56 | .align 6 | ||
57 | .Lsha1_rcon: | ||
58 | .word 0x5a827999, 0x5a827999, 0x5a827999, 0x5a827999 | ||
59 | .word 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1, 0x6ed9eba1 | ||
60 | .word 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc, 0x8f1bbcdc | ||
61 | .word 0xca62c1d6, 0xca62c1d6, 0xca62c1d6, 0xca62c1d6 | ||
62 | |||
63 | /* | ||
64 | * void sha1_ce_transform(int blocks, u8 const *src, u32 *state, | ||
65 | * u8 *head); | ||
66 | */ | ||
67 | ENTRY(sha1_ce_transform) | ||
68 | /* load round constants */ | ||
69 | adr ip, .Lsha1_rcon | ||
70 | vld1.32 {k0-k1}, [ip, :128]! | ||
71 | vld1.32 {k2-k3}, [ip, :128] | ||
72 | |||
73 | /* load state */ | ||
74 | vld1.32 {dga}, [r2] | ||
75 | vldr dgbs, [r2, #16] | ||
76 | |||
77 | /* load partial input (if supplied) */ | ||
78 | teq r3, #0 | ||
79 | beq 0f | ||
80 | vld1.32 {q8-q9}, [r3]! | ||
81 | vld1.32 {q10-q11}, [r3] | ||
82 | teq r0, #0 | ||
83 | b 1f | ||
84 | |||
85 | /* load input */ | ||
86 | 0: vld1.32 {q8-q9}, [r1]! | ||
87 | vld1.32 {q10-q11}, [r1]! | ||
88 | subs r0, r0, #1 | ||
89 | |||
90 | 1: | ||
91 | #ifndef CONFIG_CPU_BIG_ENDIAN | ||
92 | vrev32.8 q8, q8 | ||
93 | vrev32.8 q9, q9 | ||
94 | vrev32.8 q10, q10 | ||
95 | vrev32.8 q11, q11 | ||
96 | #endif | ||
97 | |||
98 | vadd.u32 ta0, q8, k0 | ||
99 | vmov dg0, dga | ||
100 | |||
101 | add_update c, 0, k0, 8, 9, 10, 11, dgb | ||
102 | add_update c, 1, k0, 9, 10, 11, 8 | ||
103 | add_update c, 0, k0, 10, 11, 8, 9 | ||
104 | add_update c, 1, k0, 11, 8, 9, 10 | ||
105 | add_update c, 0, k1, 8, 9, 10, 11 | ||
106 | |||
107 | add_update p, 1, k1, 9, 10, 11, 8 | ||
108 | add_update p, 0, k1, 10, 11, 8, 9 | ||
109 | add_update p, 1, k1, 11, 8, 9, 10 | ||
110 | add_update p, 0, k1, 8, 9, 10, 11 | ||
111 | add_update p, 1, k2, 9, 10, 11, 8 | ||
112 | |||
113 | add_update m, 0, k2, 10, 11, 8, 9 | ||
114 | add_update m, 1, k2, 11, 8, 9, 10 | ||
115 | add_update m, 0, k2, 8, 9, 10, 11 | ||
116 | add_update m, 1, k2, 9, 10, 11, 8 | ||
117 | add_update m, 0, k3, 10, 11, 8, 9 | ||
118 | |||
119 | add_update p, 1, k3, 11, 8, 9, 10 | ||
120 | add_only p, 0, k3, 9 | ||
121 | add_only p, 1, k3, 10 | ||
122 | add_only p, 0, k3, 11 | ||
123 | add_only p, 1 | ||
124 | |||
125 | /* update state */ | ||
126 | vadd.u32 dga, dga, dg0 | ||
127 | vadd.u32 dgb, dgb, dg1a0 | ||
128 | bne 0b | ||
129 | |||
130 | /* store new state */ | ||
131 | vst1.32 {dga}, [r2] | ||
132 | vstr dgbs, [r2, #16] | ||
133 | bx lr | ||
134 | ENDPROC(sha1_ce_transform) | ||
diff --git a/arch/arm/crypto/sha1-ce-glue.c b/arch/arm/crypto/sha1-ce-glue.c new file mode 100644 index 000000000000..a9dd90df9fd7 --- /dev/null +++ b/arch/arm/crypto/sha1-ce-glue.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * sha1-ce-glue.c - SHA-1 secure hash using ARMv8 Crypto Extensions | ||
3 | * | ||
4 | * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org> | ||
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 version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <crypto/internal/hash.h> | ||
12 | #include <crypto/sha.h> | ||
13 | #include <linux/crypto.h> | ||
14 | #include <linux/module.h> | ||
15 | |||
16 | #include <asm/crypto/sha1.h> | ||
17 | #include <asm/hwcap.h> | ||
18 | #include <asm/neon.h> | ||
19 | #include <asm/simd.h> | ||
20 | #include <asm/unaligned.h> | ||
21 | |||
22 | MODULE_DESCRIPTION("SHA1 secure hash using ARMv8 Crypto Extensions"); | ||
23 | MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); | ||
24 | MODULE_LICENSE("GPL v2"); | ||
25 | |||
26 | asmlinkage void sha1_ce_transform(int blocks, u8 const *src, u32 *state, | ||
27 | u8 *head); | ||
28 | |||
29 | static int sha1_init(struct shash_desc *desc) | ||
30 | { | ||
31 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
32 | |||
33 | *sctx = (struct sha1_state){ | ||
34 | .state = { SHA1_H0, SHA1_H1, SHA1_H2, SHA1_H3, SHA1_H4 }, | ||
35 | }; | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static int sha1_update(struct shash_desc *desc, const u8 *data, | ||
40 | unsigned int len) | ||
41 | { | ||
42 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
43 | unsigned int partial; | ||
44 | |||
45 | if (!may_use_simd()) | ||
46 | return sha1_update_arm(desc, data, len); | ||
47 | |||
48 | partial = sctx->count % SHA1_BLOCK_SIZE; | ||
49 | sctx->count += len; | ||
50 | |||
51 | if ((partial + len) >= SHA1_BLOCK_SIZE) { | ||
52 | int blocks; | ||
53 | |||
54 | if (partial) { | ||
55 | int p = SHA1_BLOCK_SIZE - partial; | ||
56 | |||
57 | memcpy(sctx->buffer + partial, data, p); | ||
58 | data += p; | ||
59 | len -= p; | ||
60 | } | ||
61 | |||
62 | blocks = len / SHA1_BLOCK_SIZE; | ||
63 | len %= SHA1_BLOCK_SIZE; | ||
64 | |||
65 | kernel_neon_begin(); | ||
66 | sha1_ce_transform(blocks, data, sctx->state, | ||
67 | partial ? sctx->buffer : NULL); | ||
68 | kernel_neon_end(); | ||
69 | |||
70 | data += blocks * SHA1_BLOCK_SIZE; | ||
71 | partial = 0; | ||
72 | } | ||
73 | if (len) | ||
74 | memcpy(sctx->buffer + partial, data, len); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int sha1_final(struct shash_desc *desc, u8 *out) | ||
79 | { | ||
80 | static const u8 padding[SHA1_BLOCK_SIZE] = { 0x80, }; | ||
81 | |||
82 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
83 | __be64 bits = cpu_to_be64(sctx->count << 3); | ||
84 | __be32 *dst = (__be32 *)out; | ||
85 | int i; | ||
86 | |||
87 | u32 padlen = SHA1_BLOCK_SIZE | ||
88 | - ((sctx->count + sizeof(bits)) % SHA1_BLOCK_SIZE); | ||
89 | |||
90 | sha1_update(desc, padding, padlen); | ||
91 | sha1_update(desc, (const u8 *)&bits, sizeof(bits)); | ||
92 | |||
93 | for (i = 0; i < SHA1_DIGEST_SIZE / sizeof(__be32); i++) | ||
94 | put_unaligned_be32(sctx->state[i], dst++); | ||
95 | |||
96 | *sctx = (struct sha1_state){}; | ||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | static int sha1_export(struct shash_desc *desc, void *out) | ||
101 | { | ||
102 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
103 | struct sha1_state *dst = out; | ||
104 | |||
105 | *dst = *sctx; | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int sha1_import(struct shash_desc *desc, const void *in) | ||
110 | { | ||
111 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
112 | struct sha1_state const *src = in; | ||
113 | |||
114 | *sctx = *src; | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static struct shash_alg alg = { | ||
119 | .init = sha1_init, | ||
120 | .update = sha1_update, | ||
121 | .final = sha1_final, | ||
122 | .export = sha1_export, | ||
123 | .import = sha1_import, | ||
124 | .descsize = sizeof(struct sha1_state), | ||
125 | .digestsize = SHA1_DIGEST_SIZE, | ||
126 | .statesize = sizeof(struct sha1_state), | ||
127 | .base = { | ||
128 | .cra_name = "sha1", | ||
129 | .cra_driver_name = "sha1-ce", | ||
130 | .cra_priority = 200, | ||
131 | .cra_flags = CRYPTO_ALG_TYPE_SHASH, | ||
132 | .cra_blocksize = SHA1_BLOCK_SIZE, | ||
133 | .cra_module = THIS_MODULE, | ||
134 | } | ||
135 | }; | ||
136 | |||
137 | static int __init sha1_ce_mod_init(void) | ||
138 | { | ||
139 | if (!(elf_hwcap2 & HWCAP2_SHA1)) | ||
140 | return -ENODEV; | ||
141 | return crypto_register_shash(&alg); | ||
142 | } | ||
143 | |||
144 | static void __exit sha1_ce_mod_fini(void) | ||
145 | { | ||
146 | crypto_unregister_shash(&alg); | ||
147 | } | ||
148 | |||
149 | module_init(sha1_ce_mod_init); | ||
150 | module_exit(sha1_ce_mod_fini); | ||