diff options
author | Aaro Koskinen <aaro.koskinen@iki.fi> | 2015-03-08 16:07:44 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2015-03-10 05:48:58 -0400 |
commit | 82be2dcfa6a1eebe0fc608296547ec80b55d512d (patch) | |
tree | 0a2afe819bbb8b645eb342e9eb18e8d37640ba3e /arch/mips/cavium-octeon/crypto | |
parent | da3cd5d7a7031a4a9e0b3f84732620c9db8bc65a (diff) |
crypto: octeon - add SHA1 module
Add OCTEON SHA1 module.
Signed-off-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'arch/mips/cavium-octeon/crypto')
-rw-r--r-- | arch/mips/cavium-octeon/crypto/Makefile | 3 | ||||
-rw-r--r-- | arch/mips/cavium-octeon/crypto/octeon-sha1.c | 241 |
2 files changed, 243 insertions, 1 deletions
diff --git a/arch/mips/cavium-octeon/crypto/Makefile b/arch/mips/cavium-octeon/crypto/Makefile index a74f76d85a2f..3f671d60a3d9 100644 --- a/arch/mips/cavium-octeon/crypto/Makefile +++ b/arch/mips/cavium-octeon/crypto/Makefile | |||
@@ -4,4 +4,5 @@ | |||
4 | 4 | ||
5 | obj-y += octeon-crypto.o | 5 | obj-y += octeon-crypto.o |
6 | 6 | ||
7 | obj-$(CONFIG_CRYPTO_MD5_OCTEON) += octeon-md5.o | 7 | obj-$(CONFIG_CRYPTO_MD5_OCTEON) += octeon-md5.o |
8 | obj-$(CONFIG_CRYPTO_SHA1_OCTEON) += octeon-sha1.o | ||
diff --git a/arch/mips/cavium-octeon/crypto/octeon-sha1.c b/arch/mips/cavium-octeon/crypto/octeon-sha1.c new file mode 100644 index 000000000000..2b74b5b67cae --- /dev/null +++ b/arch/mips/cavium-octeon/crypto/octeon-sha1.c | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * Cryptographic API. | ||
3 | * | ||
4 | * SHA1 Secure Hash Algorithm. | ||
5 | * | ||
6 | * Adapted for OCTEON by Aaro Koskinen <aaro.koskinen@iki.fi>. | ||
7 | * | ||
8 | * Based on crypto/sha1_generic.c, which is: | ||
9 | * | ||
10 | * Copyright (c) Alan Smithee. | ||
11 | * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> | ||
12 | * Copyright (c) Jean-Francois Dive <jef@linuxbe.org> | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify it | ||
15 | * under the terms of the GNU General Public License as published by the Free | ||
16 | * Software Foundation; either version 2 of the License, or (at your option) | ||
17 | * any later version. | ||
18 | */ | ||
19 | |||
20 | #include <linux/mm.h> | ||
21 | #include <crypto/sha.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <asm/byteorder.h> | ||
26 | #include <asm/octeon/octeon.h> | ||
27 | #include <crypto/internal/hash.h> | ||
28 | |||
29 | #include "octeon-crypto.h" | ||
30 | |||
31 | /* | ||
32 | * We pass everything as 64-bit. OCTEON can handle misaligned data. | ||
33 | */ | ||
34 | |||
35 | static void octeon_sha1_store_hash(struct sha1_state *sctx) | ||
36 | { | ||
37 | u64 *hash = (u64 *)sctx->state; | ||
38 | union { | ||
39 | u32 word[2]; | ||
40 | u64 dword; | ||
41 | } hash_tail = { { sctx->state[4], } }; | ||
42 | |||
43 | write_octeon_64bit_hash_dword(hash[0], 0); | ||
44 | write_octeon_64bit_hash_dword(hash[1], 1); | ||
45 | write_octeon_64bit_hash_dword(hash_tail.dword, 2); | ||
46 | memzero_explicit(&hash_tail.word[0], sizeof(hash_tail.word[0])); | ||
47 | } | ||
48 | |||
49 | static void octeon_sha1_read_hash(struct sha1_state *sctx) | ||
50 | { | ||
51 | u64 *hash = (u64 *)sctx->state; | ||
52 | union { | ||
53 | u32 word[2]; | ||
54 | u64 dword; | ||
55 | } hash_tail; | ||
56 | |||
57 | hash[0] = read_octeon_64bit_hash_dword(0); | ||
58 | hash[1] = read_octeon_64bit_hash_dword(1); | ||
59 | hash_tail.dword = read_octeon_64bit_hash_dword(2); | ||
60 | sctx->state[4] = hash_tail.word[0]; | ||
61 | memzero_explicit(&hash_tail.dword, sizeof(hash_tail.dword)); | ||
62 | } | ||
63 | |||
64 | static void octeon_sha1_transform(const void *_block) | ||
65 | { | ||
66 | const u64 *block = _block; | ||
67 | |||
68 | write_octeon_64bit_block_dword(block[0], 0); | ||
69 | write_octeon_64bit_block_dword(block[1], 1); | ||
70 | write_octeon_64bit_block_dword(block[2], 2); | ||
71 | write_octeon_64bit_block_dword(block[3], 3); | ||
72 | write_octeon_64bit_block_dword(block[4], 4); | ||
73 | write_octeon_64bit_block_dword(block[5], 5); | ||
74 | write_octeon_64bit_block_dword(block[6], 6); | ||
75 | octeon_sha1_start(block[7]); | ||
76 | } | ||
77 | |||
78 | static int octeon_sha1_init(struct shash_desc *desc) | ||
79 | { | ||
80 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
81 | |||
82 | sctx->state[0] = SHA1_H0; | ||
83 | sctx->state[1] = SHA1_H1; | ||
84 | sctx->state[2] = SHA1_H2; | ||
85 | sctx->state[3] = SHA1_H3; | ||
86 | sctx->state[4] = SHA1_H4; | ||
87 | sctx->count = 0; | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static void __octeon_sha1_update(struct sha1_state *sctx, const u8 *data, | ||
93 | unsigned int len) | ||
94 | { | ||
95 | unsigned int partial; | ||
96 | unsigned int done; | ||
97 | const u8 *src; | ||
98 | |||
99 | partial = sctx->count % SHA1_BLOCK_SIZE; | ||
100 | sctx->count += len; | ||
101 | done = 0; | ||
102 | src = data; | ||
103 | |||
104 | if ((partial + len) >= SHA1_BLOCK_SIZE) { | ||
105 | if (partial) { | ||
106 | done = -partial; | ||
107 | memcpy(sctx->buffer + partial, data, | ||
108 | done + SHA1_BLOCK_SIZE); | ||
109 | src = sctx->buffer; | ||
110 | } | ||
111 | |||
112 | do { | ||
113 | octeon_sha1_transform(src); | ||
114 | done += SHA1_BLOCK_SIZE; | ||
115 | src = data + done; | ||
116 | } while (done + SHA1_BLOCK_SIZE <= len); | ||
117 | |||
118 | partial = 0; | ||
119 | } | ||
120 | memcpy(sctx->buffer + partial, src, len - done); | ||
121 | } | ||
122 | |||
123 | static int octeon_sha1_update(struct shash_desc *desc, const u8 *data, | ||
124 | unsigned int len) | ||
125 | { | ||
126 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
127 | struct octeon_cop2_state state; | ||
128 | unsigned long flags; | ||
129 | |||
130 | /* | ||
131 | * Small updates never reach the crypto engine, so the generic sha1 is | ||
132 | * faster because of the heavyweight octeon_crypto_enable() / | ||
133 | * octeon_crypto_disable(). | ||
134 | */ | ||
135 | if ((sctx->count % SHA1_BLOCK_SIZE) + len < SHA1_BLOCK_SIZE) | ||
136 | return crypto_sha1_update(desc, data, len); | ||
137 | |||
138 | flags = octeon_crypto_enable(&state); | ||
139 | octeon_sha1_store_hash(sctx); | ||
140 | |||
141 | __octeon_sha1_update(sctx, data, len); | ||
142 | |||
143 | octeon_sha1_read_hash(sctx); | ||
144 | octeon_crypto_disable(&state, flags); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int octeon_sha1_final(struct shash_desc *desc, u8 *out) | ||
150 | { | ||
151 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
152 | static const u8 padding[64] = { 0x80, }; | ||
153 | struct octeon_cop2_state state; | ||
154 | __be32 *dst = (__be32 *)out; | ||
155 | unsigned int pad_len; | ||
156 | unsigned long flags; | ||
157 | unsigned int index; | ||
158 | __be64 bits; | ||
159 | int i; | ||
160 | |||
161 | /* Save number of bits. */ | ||
162 | bits = cpu_to_be64(sctx->count << 3); | ||
163 | |||
164 | /* Pad out to 56 mod 64. */ | ||
165 | index = sctx->count & 0x3f; | ||
166 | pad_len = (index < 56) ? (56 - index) : ((64+56) - index); | ||
167 | |||
168 | flags = octeon_crypto_enable(&state); | ||
169 | octeon_sha1_store_hash(sctx); | ||
170 | |||
171 | __octeon_sha1_update(sctx, padding, pad_len); | ||
172 | |||
173 | /* Append length (before padding). */ | ||
174 | __octeon_sha1_update(sctx, (const u8 *)&bits, sizeof(bits)); | ||
175 | |||
176 | octeon_sha1_read_hash(sctx); | ||
177 | octeon_crypto_disable(&state, flags); | ||
178 | |||
179 | /* Store state in digest */ | ||
180 | for (i = 0; i < 5; i++) | ||
181 | dst[i] = cpu_to_be32(sctx->state[i]); | ||
182 | |||
183 | /* Zeroize sensitive information. */ | ||
184 | memset(sctx, 0, sizeof(*sctx)); | ||
185 | |||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static int octeon_sha1_export(struct shash_desc *desc, void *out) | ||
190 | { | ||
191 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
192 | |||
193 | memcpy(out, sctx, sizeof(*sctx)); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static int octeon_sha1_import(struct shash_desc *desc, const void *in) | ||
198 | { | ||
199 | struct sha1_state *sctx = shash_desc_ctx(desc); | ||
200 | |||
201 | memcpy(sctx, in, sizeof(*sctx)); | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static struct shash_alg octeon_sha1_alg = { | ||
206 | .digestsize = SHA1_DIGEST_SIZE, | ||
207 | .init = octeon_sha1_init, | ||
208 | .update = octeon_sha1_update, | ||
209 | .final = octeon_sha1_final, | ||
210 | .export = octeon_sha1_export, | ||
211 | .import = octeon_sha1_import, | ||
212 | .descsize = sizeof(struct sha1_state), | ||
213 | .statesize = sizeof(struct sha1_state), | ||
214 | .base = { | ||
215 | .cra_name = "sha1", | ||
216 | .cra_driver_name= "octeon-sha1", | ||
217 | .cra_priority = OCTEON_CR_OPCODE_PRIORITY, | ||
218 | .cra_flags = CRYPTO_ALG_TYPE_SHASH, | ||
219 | .cra_blocksize = SHA1_BLOCK_SIZE, | ||
220 | .cra_module = THIS_MODULE, | ||
221 | } | ||
222 | }; | ||
223 | |||
224 | static int __init octeon_sha1_mod_init(void) | ||
225 | { | ||
226 | if (!octeon_has_crypto()) | ||
227 | return -ENOTSUPP; | ||
228 | return crypto_register_shash(&octeon_sha1_alg); | ||
229 | } | ||
230 | |||
231 | static void __exit octeon_sha1_mod_fini(void) | ||
232 | { | ||
233 | crypto_unregister_shash(&octeon_sha1_alg); | ||
234 | } | ||
235 | |||
236 | module_init(octeon_sha1_mod_init); | ||
237 | module_exit(octeon_sha1_mod_fini); | ||
238 | |||
239 | MODULE_LICENSE("GPL"); | ||
240 | MODULE_DESCRIPTION("SHA1 Secure Hash Algorithm (OCTEON)"); | ||
241 | MODULE_AUTHOR("Aaro Koskinen <aaro.koskinen@iki.fi>"); | ||