1// SPDX-License-Identifier: GPL-2.0-only
2/* Glue code for CAMELLIA encryption optimized for sparc64 crypto opcodes.
3 *
4 * Copyright (C) 2012 David S. Miller <davem@davemloft.net>
5 */
6
7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8
9#include <linux/crypto.h>
10#include <linux/init.h>
11#include <linux/module.h>
12#include <linux/mm.h>
13#include <linux/types.h>
14#include <crypto/algapi.h>
15#include <crypto/internal/skcipher.h>
16
17#include <asm/fpumacro.h>
18#include <asm/opcodes.h>
19#include <asm/pstate.h>
20#include <asm/elf.h>
21
22#define CAMELLIA_MIN_KEY_SIZE 16
23#define CAMELLIA_MAX_KEY_SIZE 32
24#define CAMELLIA_BLOCK_SIZE 16
25#define CAMELLIA_TABLE_BYTE_LEN 272
26
27struct camellia_sparc64_ctx {
28 u64 encrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)];
29 u64 decrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)];
30 int key_len;
31};
32
33extern void camellia_sparc64_key_expand(const u32 *in_key, u64 *encrypt_key,
34 unsigned int key_len, u64 *decrypt_key);
35
36static int camellia_set_key(struct crypto_tfm *tfm, const u8 *_in_key,
37 unsigned int key_len)
38{
39 struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
40 const u32 *in_key = (const u32 *) _in_key;
41
42 if (key_len != 16 && key_len != 24 && key_len != 32)
43 return -EINVAL;
44
45 ctx->key_len = key_len;
46
47 camellia_sparc64_key_expand(in_key, encrypt_key: &ctx->encrypt_key[0],
48 key_len, decrypt_key: &ctx->decrypt_key[0]);
49 return 0;
50}
51
52static int camellia_set_key_skcipher(struct crypto_skcipher *tfm,
53 const u8 *in_key, unsigned int key_len)
54{
55 return camellia_set_key(tfm: crypto_skcipher_tfm(tfm), in_key: in_key, key_len);
56}
57
58extern void camellia_sparc64_crypt(const u64 *key, const u32 *input,
59 u32 *output, unsigned int key_len);
60
61static void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
62{
63 struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
64
65 camellia_sparc64_crypt(key: &ctx->encrypt_key[0],
66 input: (const u32 *) src,
67 output: (u32 *) dst, key_len: ctx->key_len);
68}
69
70static void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
71{
72 struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
73
74 camellia_sparc64_crypt(key: &ctx->decrypt_key[0],
75 input: (const u32 *) src,
76 output: (u32 *) dst, key_len: ctx->key_len);
77}
78
79extern void camellia_sparc64_load_keys(const u64 *key, unsigned int key_len);
80
81typedef void ecb_crypt_op(const u64 *input, u64 *output, unsigned int len,
82 const u64 *key);
83
84extern ecb_crypt_op camellia_sparc64_ecb_crypt_3_grand_rounds;
85extern ecb_crypt_op camellia_sparc64_ecb_crypt_4_grand_rounds;
86
87static int __ecb_crypt(struct skcipher_request *req, bool encrypt)
88{
89 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
90 const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
91 struct skcipher_walk walk;
92 ecb_crypt_op *op;
93 const u64 *key;
94 unsigned int nbytes;
95 int err;
96
97 op = camellia_sparc64_ecb_crypt_3_grand_rounds;
98 if (ctx->key_len != 16)
99 op = camellia_sparc64_ecb_crypt_4_grand_rounds;
100
101 err = skcipher_walk_virt(walk: &walk, req, atomic: true);
102 if (err)
103 return err;
104
105 if (encrypt)
106 key = &ctx->encrypt_key[0];
107 else
108 key = &ctx->decrypt_key[0];
109 camellia_sparc64_load_keys(key, key_len: ctx->key_len);
110 while ((nbytes = walk.nbytes) != 0) {
111 op(walk.src.virt.addr, walk.dst.virt.addr,
112 round_down(nbytes, CAMELLIA_BLOCK_SIZE), key);
113 err = skcipher_walk_done(walk: &walk, res: nbytes % CAMELLIA_BLOCK_SIZE);
114 }
115 fprs_write(0);
116 return err;
117}
118
119static int ecb_encrypt(struct skcipher_request *req)
120{
121 return __ecb_crypt(req, encrypt: true);
122}
123
124static int ecb_decrypt(struct skcipher_request *req)
125{
126 return __ecb_crypt(req, encrypt: false);
127}
128
129typedef void cbc_crypt_op(const u64 *input, u64 *output, unsigned int len,
130 const u64 *key, u64 *iv);
131
132extern cbc_crypt_op camellia_sparc64_cbc_encrypt_3_grand_rounds;
133extern cbc_crypt_op camellia_sparc64_cbc_encrypt_4_grand_rounds;
134extern cbc_crypt_op camellia_sparc64_cbc_decrypt_3_grand_rounds;
135extern cbc_crypt_op camellia_sparc64_cbc_decrypt_4_grand_rounds;
136
137static int cbc_encrypt(struct skcipher_request *req)
138{
139 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
140 const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
141 struct skcipher_walk walk;
142 cbc_crypt_op *op;
143 const u64 *key;
144 unsigned int nbytes;
145 int err;
146
147 op = camellia_sparc64_cbc_encrypt_3_grand_rounds;
148 if (ctx->key_len != 16)
149 op = camellia_sparc64_cbc_encrypt_4_grand_rounds;
150
151 err = skcipher_walk_virt(walk: &walk, req, atomic: true);
152 if (err)
153 return err;
154
155 key = &ctx->encrypt_key[0];
156 camellia_sparc64_load_keys(key, key_len: ctx->key_len);
157 while ((nbytes = walk.nbytes) != 0) {
158 op(walk.src.virt.addr, walk.dst.virt.addr,
159 round_down(nbytes, CAMELLIA_BLOCK_SIZE), key, walk.iv);
160 err = skcipher_walk_done(walk: &walk, res: nbytes % CAMELLIA_BLOCK_SIZE);
161 }
162 fprs_write(0);
163 return err;
164}
165
166static int cbc_decrypt(struct skcipher_request *req)
167{
168 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
169 const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
170 struct skcipher_walk walk;
171 cbc_crypt_op *op;
172 const u64 *key;
173 unsigned int nbytes;
174 int err;
175
176 op = camellia_sparc64_cbc_decrypt_3_grand_rounds;
177 if (ctx->key_len != 16)
178 op = camellia_sparc64_cbc_decrypt_4_grand_rounds;
179
180 err = skcipher_walk_virt(walk: &walk, req, atomic: true);
181 if (err)
182 return err;
183
184 key = &ctx->decrypt_key[0];
185 camellia_sparc64_load_keys(key, key_len: ctx->key_len);
186 while ((nbytes = walk.nbytes) != 0) {
187 op(walk.src.virt.addr, walk.dst.virt.addr,
188 round_down(nbytes, CAMELLIA_BLOCK_SIZE), key, walk.iv);
189 err = skcipher_walk_done(walk: &walk, res: nbytes % CAMELLIA_BLOCK_SIZE);
190 }
191 fprs_write(0);
192 return err;
193}
194
195static struct crypto_alg cipher_alg = {
196 .cra_name = "camellia",
197 .cra_driver_name = "camellia-sparc64",
198 .cra_priority = SPARC_CR_OPCODE_PRIORITY,
199 .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
200 .cra_blocksize = CAMELLIA_BLOCK_SIZE,
201 .cra_ctxsize = sizeof(struct camellia_sparc64_ctx),
202 .cra_alignmask = 3,
203 .cra_module = THIS_MODULE,
204 .cra_u = {
205 .cipher = {
206 .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE,
207 .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE,
208 .cia_setkey = camellia_set_key,
209 .cia_encrypt = camellia_encrypt,
210 .cia_decrypt = camellia_decrypt
211 }
212 }
213};
214
215static struct skcipher_alg skcipher_algs[] = {
216 {
217 .base.cra_name = "ecb(camellia)",
218 .base.cra_driver_name = "ecb-camellia-sparc64",
219 .base.cra_priority = SPARC_CR_OPCODE_PRIORITY,
220 .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
221 .base.cra_ctxsize = sizeof(struct camellia_sparc64_ctx),
222 .base.cra_alignmask = 7,
223 .base.cra_module = THIS_MODULE,
224 .min_keysize = CAMELLIA_MIN_KEY_SIZE,
225 .max_keysize = CAMELLIA_MAX_KEY_SIZE,
226 .setkey = camellia_set_key_skcipher,
227 .encrypt = ecb_encrypt,
228 .decrypt = ecb_decrypt,
229 }, {
230 .base.cra_name = "cbc(camellia)",
231 .base.cra_driver_name = "cbc-camellia-sparc64",
232 .base.cra_priority = SPARC_CR_OPCODE_PRIORITY,
233 .base.cra_blocksize = CAMELLIA_BLOCK_SIZE,
234 .base.cra_ctxsize = sizeof(struct camellia_sparc64_ctx),
235 .base.cra_alignmask = 7,
236 .base.cra_module = THIS_MODULE,
237 .min_keysize = CAMELLIA_MIN_KEY_SIZE,
238 .max_keysize = CAMELLIA_MAX_KEY_SIZE,
239 .ivsize = CAMELLIA_BLOCK_SIZE,
240 .setkey = camellia_set_key_skcipher,
241 .encrypt = cbc_encrypt,
242 .decrypt = cbc_decrypt,
243 }
244};
245
246static bool __init sparc64_has_camellia_opcode(void)
247{
248 unsigned long cfr;
249
250 if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
251 return false;
252
253 __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
254 if (!(cfr & CFR_CAMELLIA))
255 return false;
256
257 return true;
258}
259
260static int __init camellia_sparc64_mod_init(void)
261{
262 int err;
263
264 if (!sparc64_has_camellia_opcode()) {
265 pr_info("sparc64 camellia opcodes not available.\n");
266 return -ENODEV;
267 }
268 pr_info("Using sparc64 camellia opcodes optimized CAMELLIA implementation\n");
269 err = crypto_register_alg(alg: &cipher_alg);
270 if (err)
271 return err;
272 err = crypto_register_skciphers(skcipher_algs,
273 ARRAY_SIZE(skcipher_algs));
274 if (err)
275 crypto_unregister_alg(alg: &cipher_alg);
276 return err;
277}
278
279static void __exit camellia_sparc64_mod_fini(void)
280{
281 crypto_unregister_alg(alg: &cipher_alg);
282 crypto_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
283}
284
285module_init(camellia_sparc64_mod_init);
286module_exit(camellia_sparc64_mod_fini);
287
288MODULE_LICENSE("GPL");
289MODULE_DESCRIPTION("Camellia Cipher Algorithm, sparc64 camellia opcode accelerated");
290
291MODULE_ALIAS_CRYPTO("camellia");
292
293#include "crop_devid.c"
294

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of linux/arch/sparc/crypto/camellia_glue.c