diff options
author | David S. Miller <davem@davemloft.net> | 2012-08-28 15:05:54 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-08-28 23:51:24 -0400 |
commit | 81658ad0d92306ceb271994b90cd49ffde10eeda (patch) | |
tree | 8765d2fffb62a3e22752644ff329b9aec166a3eb /arch/sparc/crypto/camellia_glue.c | |
parent | 3705665069944e003b7316ba31b44558864a00de (diff) |
sparc64: Add CAMELLIA driver making use of the new camellia opcodes.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/crypto/camellia_glue.c')
-rw-r--r-- | arch/sparc/crypto/camellia_glue.c | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/arch/sparc/crypto/camellia_glue.c b/arch/sparc/crypto/camellia_glue.c new file mode 100644 index 000000000000..c258cc550a6b --- /dev/null +++ b/arch/sparc/crypto/camellia_glue.c | |||
@@ -0,0 +1,318 @@ | |||
1 | /* Glue code for CAMELLIA encryption optimized for sparc64 crypto opcodes. | ||
2 | * | ||
3 | * Copyright (C) 2012 David S. Miller <davem@davemloft.net> | ||
4 | */ | ||
5 | |||
6 | #include <linux/crypto.h> | ||
7 | #include <linux/init.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <linux/mm.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <crypto/algapi.h> | ||
12 | |||
13 | #include <asm/fpumacro.h> | ||
14 | #include <asm/pstate.h> | ||
15 | #include <asm/elf.h> | ||
16 | |||
17 | #define CAMELLIA_MIN_KEY_SIZE 16 | ||
18 | #define CAMELLIA_MAX_KEY_SIZE 32 | ||
19 | #define CAMELLIA_BLOCK_SIZE 16 | ||
20 | #define CAMELLIA_TABLE_BYTE_LEN 272 | ||
21 | |||
22 | struct camellia_sparc64_ctx { | ||
23 | u64 encrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)]; | ||
24 | u64 decrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)]; | ||
25 | int key_len; | ||
26 | }; | ||
27 | |||
28 | extern void camellia_sparc64_key_expand(const u32 *in_key, u64 *encrypt_key, | ||
29 | unsigned int key_len, u64 *decrypt_key); | ||
30 | |||
31 | static int camellia_set_key(struct crypto_tfm *tfm, const u8 *_in_key, | ||
32 | unsigned int key_len) | ||
33 | { | ||
34 | struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); | ||
35 | const u32 *in_key = (const u32 *) _in_key; | ||
36 | u32 *flags = &tfm->crt_flags; | ||
37 | |||
38 | if (key_len != 16 && key_len != 24 && key_len != 32) { | ||
39 | *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; | ||
40 | return -EINVAL; | ||
41 | } | ||
42 | |||
43 | ctx->key_len = key_len; | ||
44 | |||
45 | camellia_sparc64_key_expand(in_key, &ctx->encrypt_key[0], | ||
46 | key_len, &ctx->decrypt_key[0]); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | extern void camellia_sparc64_crypt(const u64 *key, const u32 *input, | ||
51 | u32 *output, unsigned int key_len); | ||
52 | |||
53 | static void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) | ||
54 | { | ||
55 | struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); | ||
56 | |||
57 | camellia_sparc64_crypt(&ctx->encrypt_key[0], | ||
58 | (const u32 *) src, | ||
59 | (u32 *) dst, ctx->key_len); | ||
60 | } | ||
61 | |||
62 | static void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) | ||
63 | { | ||
64 | struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); | ||
65 | |||
66 | camellia_sparc64_crypt(&ctx->decrypt_key[0], | ||
67 | (const u32 *) src, | ||
68 | (u32 *) dst, ctx->key_len); | ||
69 | } | ||
70 | |||
71 | extern void camellia_sparc64_load_keys(const u64 *key, unsigned int key_len); | ||
72 | |||
73 | typedef void ecb_crypt_op(const u64 *input, u64 *output, unsigned int len, | ||
74 | const u64 *key); | ||
75 | |||
76 | extern ecb_crypt_op camellia_sparc64_ecb_crypt_3_grand_rounds; | ||
77 | extern ecb_crypt_op camellia_sparc64_ecb_crypt_4_grand_rounds; | ||
78 | |||
79 | #define CAMELLIA_BLOCK_MASK (~(CAMELLIA_BLOCK_SIZE - 1)) | ||
80 | |||
81 | static int __ecb_crypt(struct blkcipher_desc *desc, | ||
82 | struct scatterlist *dst, struct scatterlist *src, | ||
83 | unsigned int nbytes, bool encrypt) | ||
84 | { | ||
85 | struct camellia_sparc64_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); | ||
86 | struct blkcipher_walk walk; | ||
87 | ecb_crypt_op *op; | ||
88 | const u64 *key; | ||
89 | int err; | ||
90 | |||
91 | op = camellia_sparc64_ecb_crypt_3_grand_rounds; | ||
92 | if (ctx->key_len != 16) | ||
93 | op = camellia_sparc64_ecb_crypt_4_grand_rounds; | ||
94 | |||
95 | blkcipher_walk_init(&walk, dst, src, nbytes); | ||
96 | err = blkcipher_walk_virt(desc, &walk); | ||
97 | |||
98 | if (encrypt) | ||
99 | key = &ctx->encrypt_key[0]; | ||
100 | else | ||
101 | key = &ctx->decrypt_key[0]; | ||
102 | camellia_sparc64_load_keys(key, ctx->key_len); | ||
103 | while ((nbytes = walk.nbytes)) { | ||
104 | unsigned int block_len = nbytes & CAMELLIA_BLOCK_MASK; | ||
105 | |||
106 | if (likely(block_len)) { | ||
107 | const u64 *src64; | ||
108 | u64 *dst64; | ||
109 | |||
110 | src64 = (const u64 *)walk.src.virt.addr; | ||
111 | dst64 = (u64 *) walk.dst.virt.addr; | ||
112 | op(src64, dst64, block_len, key); | ||
113 | } | ||
114 | nbytes &= CAMELLIA_BLOCK_SIZE - 1; | ||
115 | err = blkcipher_walk_done(desc, &walk, nbytes); | ||
116 | } | ||
117 | fprs_write(0); | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | static int ecb_encrypt(struct blkcipher_desc *desc, | ||
122 | struct scatterlist *dst, struct scatterlist *src, | ||
123 | unsigned int nbytes) | ||
124 | { | ||
125 | return __ecb_crypt(desc, dst, src, nbytes, true); | ||
126 | } | ||
127 | |||
128 | static int ecb_decrypt(struct blkcipher_desc *desc, | ||
129 | struct scatterlist *dst, struct scatterlist *src, | ||
130 | unsigned int nbytes) | ||
131 | { | ||
132 | return __ecb_crypt(desc, dst, src, nbytes, false); | ||
133 | } | ||
134 | |||
135 | typedef void cbc_crypt_op(const u64 *input, u64 *output, unsigned int len, | ||
136 | const u64 *key, u64 *iv); | ||
137 | |||
138 | extern cbc_crypt_op camellia_sparc64_cbc_encrypt_3_grand_rounds; | ||
139 | extern cbc_crypt_op camellia_sparc64_cbc_encrypt_4_grand_rounds; | ||
140 | extern cbc_crypt_op camellia_sparc64_cbc_decrypt_3_grand_rounds; | ||
141 | extern cbc_crypt_op camellia_sparc64_cbc_decrypt_4_grand_rounds; | ||
142 | |||
143 | static int cbc_encrypt(struct blkcipher_desc *desc, | ||
144 | struct scatterlist *dst, struct scatterlist *src, | ||
145 | unsigned int nbytes) | ||
146 | { | ||
147 | struct camellia_sparc64_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); | ||
148 | struct blkcipher_walk walk; | ||
149 | cbc_crypt_op *op; | ||
150 | const u64 *key; | ||
151 | int err; | ||
152 | |||
153 | op = camellia_sparc64_cbc_encrypt_3_grand_rounds; | ||
154 | if (ctx->key_len != 16) | ||
155 | op = camellia_sparc64_cbc_encrypt_4_grand_rounds; | ||
156 | |||
157 | blkcipher_walk_init(&walk, dst, src, nbytes); | ||
158 | err = blkcipher_walk_virt(desc, &walk); | ||
159 | |||
160 | key = &ctx->encrypt_key[0]; | ||
161 | camellia_sparc64_load_keys(key, ctx->key_len); | ||
162 | while ((nbytes = walk.nbytes)) { | ||
163 | unsigned int block_len = nbytes & CAMELLIA_BLOCK_MASK; | ||
164 | |||
165 | if (likely(block_len)) { | ||
166 | const u64 *src64; | ||
167 | u64 *dst64; | ||
168 | |||
169 | src64 = (const u64 *)walk.src.virt.addr; | ||
170 | dst64 = (u64 *) walk.dst.virt.addr; | ||
171 | op(src64, dst64, block_len, key, | ||
172 | (u64 *) walk.iv); | ||
173 | } | ||
174 | nbytes &= CAMELLIA_BLOCK_SIZE - 1; | ||
175 | err = blkcipher_walk_done(desc, &walk, nbytes); | ||
176 | } | ||
177 | fprs_write(0); | ||
178 | return err; | ||
179 | } | ||
180 | |||
181 | static int cbc_decrypt(struct blkcipher_desc *desc, | ||
182 | struct scatterlist *dst, struct scatterlist *src, | ||
183 | unsigned int nbytes) | ||
184 | { | ||
185 | struct camellia_sparc64_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); | ||
186 | struct blkcipher_walk walk; | ||
187 | cbc_crypt_op *op; | ||
188 | const u64 *key; | ||
189 | int err; | ||
190 | |||
191 | op = camellia_sparc64_cbc_decrypt_3_grand_rounds; | ||
192 | if (ctx->key_len != 16) | ||
193 | op = camellia_sparc64_cbc_decrypt_4_grand_rounds; | ||
194 | |||
195 | blkcipher_walk_init(&walk, dst, src, nbytes); | ||
196 | err = blkcipher_walk_virt(desc, &walk); | ||
197 | |||
198 | key = &ctx->decrypt_key[0]; | ||
199 | camellia_sparc64_load_keys(key, ctx->key_len); | ||
200 | while ((nbytes = walk.nbytes)) { | ||
201 | unsigned int block_len = nbytes & CAMELLIA_BLOCK_MASK; | ||
202 | |||
203 | if (likely(block_len)) { | ||
204 | const u64 *src64; | ||
205 | u64 *dst64; | ||
206 | |||
207 | src64 = (const u64 *)walk.src.virt.addr; | ||
208 | dst64 = (u64 *) walk.dst.virt.addr; | ||
209 | op(src64, dst64, block_len, key, | ||
210 | (u64 *) walk.iv); | ||
211 | } | ||
212 | nbytes &= CAMELLIA_BLOCK_SIZE - 1; | ||
213 | err = blkcipher_walk_done(desc, &walk, nbytes); | ||
214 | } | ||
215 | fprs_write(0); | ||
216 | return err; | ||
217 | } | ||
218 | |||
219 | static struct crypto_alg algs[] = { { | ||
220 | .cra_name = "camellia", | ||
221 | .cra_driver_name = "camellia-sparc64", | ||
222 | .cra_priority = 150, | ||
223 | .cra_flags = CRYPTO_ALG_TYPE_CIPHER, | ||
224 | .cra_blocksize = CAMELLIA_BLOCK_SIZE, | ||
225 | .cra_ctxsize = sizeof(struct camellia_sparc64_ctx), | ||
226 | .cra_alignmask = 3, | ||
227 | .cra_module = THIS_MODULE, | ||
228 | .cra_u = { | ||
229 | .cipher = { | ||
230 | .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, | ||
231 | .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE, | ||
232 | .cia_setkey = camellia_set_key, | ||
233 | .cia_encrypt = camellia_encrypt, | ||
234 | .cia_decrypt = camellia_decrypt | ||
235 | } | ||
236 | } | ||
237 | }, { | ||
238 | .cra_name = "ecb(camellia)", | ||
239 | .cra_driver_name = "ecb-camellia-sparc64", | ||
240 | .cra_priority = 150, | ||
241 | .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, | ||
242 | .cra_blocksize = CAMELLIA_BLOCK_SIZE, | ||
243 | .cra_ctxsize = sizeof(struct camellia_sparc64_ctx), | ||
244 | .cra_alignmask = 7, | ||
245 | .cra_type = &crypto_blkcipher_type, | ||
246 | .cra_module = THIS_MODULE, | ||
247 | .cra_u = { | ||
248 | .blkcipher = { | ||
249 | .min_keysize = CAMELLIA_MIN_KEY_SIZE, | ||
250 | .max_keysize = CAMELLIA_MAX_KEY_SIZE, | ||
251 | .setkey = camellia_set_key, | ||
252 | .encrypt = ecb_encrypt, | ||
253 | .decrypt = ecb_decrypt, | ||
254 | }, | ||
255 | }, | ||
256 | }, { | ||
257 | .cra_name = "cbc(camellia)", | ||
258 | .cra_driver_name = "cbc-camellia-sparc64", | ||
259 | .cra_priority = 150, | ||
260 | .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, | ||
261 | .cra_blocksize = CAMELLIA_BLOCK_SIZE, | ||
262 | .cra_ctxsize = sizeof(struct camellia_sparc64_ctx), | ||
263 | .cra_alignmask = 7, | ||
264 | .cra_type = &crypto_blkcipher_type, | ||
265 | .cra_module = THIS_MODULE, | ||
266 | .cra_u = { | ||
267 | .blkcipher = { | ||
268 | .min_keysize = CAMELLIA_MIN_KEY_SIZE, | ||
269 | .max_keysize = CAMELLIA_MAX_KEY_SIZE, | ||
270 | .setkey = camellia_set_key, | ||
271 | .encrypt = cbc_encrypt, | ||
272 | .decrypt = cbc_decrypt, | ||
273 | }, | ||
274 | }, | ||
275 | } | ||
276 | }; | ||
277 | |||
278 | static bool __init sparc64_has_camellia_opcode(void) | ||
279 | { | ||
280 | unsigned long cfr; | ||
281 | |||
282 | if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) | ||
283 | return false; | ||
284 | |||
285 | __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); | ||
286 | if (!(cfr & CFR_CAMELLIA)) | ||
287 | return false; | ||
288 | |||
289 | return true; | ||
290 | } | ||
291 | |||
292 | static int __init camellia_sparc64_mod_init(void) | ||
293 | { | ||
294 | int i; | ||
295 | |||
296 | for (i = 0; i < ARRAY_SIZE(algs); i++) | ||
297 | INIT_LIST_HEAD(&algs[i].cra_list); | ||
298 | |||
299 | if (sparc64_has_camellia_opcode()) { | ||
300 | pr_info("Using sparc64 camellia opcodes optimized CAMELLIA implementation\n"); | ||
301 | return crypto_register_algs(algs, ARRAY_SIZE(algs)); | ||
302 | } | ||
303 | pr_info("sparc64 camellia opcodes not available.\n"); | ||
304 | return -ENODEV; | ||
305 | } | ||
306 | |||
307 | static void __exit camellia_sparc64_mod_fini(void) | ||
308 | { | ||
309 | crypto_unregister_algs(algs, ARRAY_SIZE(algs)); | ||
310 | } | ||
311 | |||
312 | module_init(camellia_sparc64_mod_init); | ||
313 | module_exit(camellia_sparc64_mod_fini); | ||
314 | |||
315 | MODULE_LICENSE("GPL"); | ||
316 | MODULE_DESCRIPTION("Camellia Cipher Algorithm, sparc64 camellia opcode accelerated"); | ||
317 | |||
318 | MODULE_ALIAS("aes"); | ||