2 * arch/ubicom32/crypto/aes_ubicom32.c
3 * Ubicom32 implementation of the AES Cipher Algorithm.
5 * (C) Copyright 2009, Ubicom, Inc.
7 * This file is part of the Ubicom32 Linux Kernel Port.
9 * The Ubicom32 Linux Kernel Port is free software: you can redistribute
10 * it and/or modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation, either version 2 of the
12 * License, or (at your option) any later version.
14 * The Ubicom32 Linux Kernel Port is distributed in the hope that it
15 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
16 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with the Ubicom32 Linux Kernel Port. If not,
21 * see <http://www.gnu.org/licenses/>.
23 * Ubicom32 implementation derived from (with many thanks):
28 #include <crypto/aes.h>
29 #include <crypto/algapi.h>
30 #include <linux/err.h>
31 #include <linux/module.h>
32 #include <linux/init.h>
33 #include <linux/spinlock.h>
34 #include "crypto_ubicom32.h"
35 #include <asm/linkage.h>
37 struct ubicom32_aes_ctx {
38 u8 key[AES_MAX_KEY_SIZE];
43 static inline void aes_hw_set_key(const u8 *key, u8 key_len)
46 * switch case has more overhead than 4 move.4 instructions, so just copy 256 bits
51 static inline void aes_hw_set_iv(const u8 *iv)
56 static inline void aes_hw_cipher(u8 *out, const u8 *in)
61 " ; start AES by writing 0x40(SECURITY_BASE) \n\t"
62 " move.4 0x40(%0), #0x01 \n\t"
65 " ; wait for the module to calculate the output \n\t"
66 " btst 0x04(%0), #0 \n\t"
73 SEC_GET_OUTPUT_4W(out);
76 static int __ocm_text aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
79 struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm);
81 uctx->key_len = key_len;
82 memcpy(uctx->key, in_key, key_len);
85 * leave out HASH_ALG (none = 0), CBC (no = 0), DIR (unknown) yet
87 switch (uctx->key_len) {
89 uctx->ctrl = SEC_KEY_128_BITS | SEC_ALG_AES;
92 uctx->ctrl = SEC_KEY_192_BITS | SEC_ALG_AES;
95 uctx->ctrl = SEC_KEY_256_BITS | SEC_ALG_AES;
102 static inline void aes_cipher(struct crypto_tfm *tfm, u8 *out, const u8 *in, u32 extra_flags)
104 const struct ubicom32_aes_ctx *uctx = crypto_tfm_ctx(tfm);
108 hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
110 aes_hw_set_key(uctx->key, uctx->key_len);
111 aes_hw_cipher(out, in);
116 static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
118 aes_cipher(tfm, out, in, SEC_DIR_ENCRYPT);
121 static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
123 aes_cipher(tfm, out, in, SEC_DIR_DECRYPT);
126 static struct crypto_alg aes_alg = {
128 .cra_driver_name = "aes-ubicom32",
129 .cra_priority = CRYPTO_UBICOM32_PRIORITY,
130 .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
131 .cra_blocksize = AES_BLOCK_SIZE,
132 .cra_ctxsize = sizeof(struct ubicom32_aes_ctx),
133 .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1,
134 .cra_module = THIS_MODULE,
135 .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
138 .cia_min_keysize = AES_MIN_KEY_SIZE,
139 .cia_max_keysize = AES_MAX_KEY_SIZE,
140 .cia_setkey = aes_set_key,
141 .cia_encrypt = aes_encrypt,
142 .cia_decrypt = aes_decrypt,
147 static void __ocm_text ecb_aes_crypt_loop(u8 *out, u8 *in, unsigned int n)
150 aes_hw_cipher(out, in);
151 out += AES_BLOCK_SIZE;
152 in += AES_BLOCK_SIZE;
157 static int __ocm_text ecb_aes_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
158 struct scatterlist *src, unsigned int nbytes, u32 extra_flags)
160 const struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm);
163 struct blkcipher_walk walk;
164 blkcipher_walk_init(&walk, dst, src, nbytes);
165 ret = blkcipher_walk_virt(desc, &walk);
173 hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
174 aes_hw_set_key(uctx->key, uctx->key_len);
176 while (likely((nbytes = walk.nbytes))) {
177 /* only use complete blocks */
178 unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
179 u8 *out = walk.dst.virt.addr;
180 u8 *in = walk.src.virt.addr;
182 /* finish n/16 blocks */
183 ecb_aes_crypt_loop(out, in, n);
185 nbytes &= AES_BLOCK_SIZE - 1;
186 ret = blkcipher_walk_done(desc, &walk, nbytes);
193 static int ecb_aes_encrypt(struct blkcipher_desc *desc,
194 struct scatterlist *dst, struct scatterlist *src,
197 return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT);
200 static int ecb_aes_decrypt(struct blkcipher_desc *desc,
201 struct scatterlist *dst, struct scatterlist *src,
204 return ecb_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT);
207 static struct crypto_alg ecb_aes_alg = {
208 .cra_name = "ecb(aes)",
209 .cra_driver_name = "ecb-aes-ubicom32",
210 .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
211 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
212 .cra_blocksize = AES_BLOCK_SIZE,
213 .cra_ctxsize = sizeof(struct ubicom32_aes_ctx),
214 .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1,
215 .cra_type = &crypto_blkcipher_type,
216 .cra_module = THIS_MODULE,
217 .cra_list = LIST_HEAD_INIT(ecb_aes_alg.cra_list),
220 .min_keysize = AES_MIN_KEY_SIZE,
221 .max_keysize = AES_MAX_KEY_SIZE,
222 .setkey = aes_set_key,
223 .encrypt = ecb_aes_encrypt,
224 .decrypt = ecb_aes_decrypt,
229 #if CRYPTO_UBICOM32_LOOP_ASM
230 void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
233 "; set init. iv 4w \n\t"
234 " move.4 0x50(%0), 0x0(%3) \n\t"
235 " move.4 0x54(%0), 0x4(%3) \n\t"
236 " move.4 0x58(%0), 0x8(%3) \n\t"
237 " move.4 0x5c(%0), 0xc(%3) \n\t"
239 "; we know n > 0, so we can always \n\t"
240 "; load the first block \n\t"
241 "; set input 4w \n\t"
242 " move.4 0x30(%0), 0x0(%2) \n\t"
243 " move.4 0x34(%0), 0x4(%2) \n\t"
244 " move.4 0x38(%0), 0x8(%2) \n\t"
245 " move.4 0x3c(%0), 0xc(%2) \n\t"
248 " move.4 0x40(%0), %2 \n\t"
250 "; update n & flush \n\t"
251 " add.4 %4, #-16, %4 \n\t"
254 "; while (n): work on 2nd block \n\t"
255 " 1: lsl.4 d15, %4, #0x0 \n\t"
258 "; set input 4w (2nd) \n\t"
259 " move.4 0x30(%0), 0x10(%2) \n\t"
260 " move.4 0x34(%0), 0x14(%2) \n\t"
261 " move.4 0x38(%0), 0x18(%2) \n\t"
262 " move.4 0x3c(%0), 0x1c(%2) \n\t"
264 "; update n/in asap while waiting \n\t"
265 " add.4 %4, #-16, %4 \n\t"
266 " move.4 d15, 16(%2)++ \n\t"
268 "; wait for the previous output \n\t"
269 " btst 0x04(%0), #0 \n\t"
272 "; read previous output \n\t"
273 " move.4 0x0(%1), 0x50(%0) \n\t"
274 " move.4 0x4(%1), 0x54(%0) \n\t"
275 " move.4 0x8(%1), 0x58(%0) \n\t"
276 " move.4 0xc(%1), 0x5c(%0) \n\t"
278 "; kick off hw for 2nd input \n\t"
279 " move.4 0x40(%0), %2 \n\t"
281 "; update out asap \n\t"
282 " move.4 d15, 16(%1)++ \n\t"
284 "; go back to loop \n\t"
287 "; wait for last output \n\t"
288 " 5: btst 0x04(%0), #0 \n\t"
291 "; read last output \n\t"
292 " move.4 0x0(%1), 0x50(%0) \n\t"
293 " move.4 0x4(%1), 0x54(%0) \n\t"
294 " move.4 0x8(%1), 0x58(%0) \n\t"
295 " move.4 0xc(%1), 0x5c(%0) \n\t"
298 " move.4 0x0(%3), 0x50(%0) \n\t"
299 " move.4 0x4(%3), 0x54(%0) \n\t"
300 " move.4 0x8(%3), 0x58(%0) \n\t"
301 " move.4 0xc(%3), 0x5c(%0) \n\t"
304 : "a" (SEC_BASE), "a" (out), "a" (in), "a" (iv), "d" (n)
311 static void __ocm_text cbc_aes_encrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
315 aes_hw_cipher(out, in);
316 out += AES_BLOCK_SIZE;
317 in += AES_BLOCK_SIZE;
320 SEC_COPY_4W(iv, out - AES_BLOCK_SIZE);
325 static void __ocm_text cbc_aes_decrypt_loop(u8 *out, u8 *in, u8 *iv, unsigned int n)
330 aes_hw_cipher(out, in);
331 out += AES_BLOCK_SIZE;
332 in += AES_BLOCK_SIZE;
337 static int __ocm_text cbc_aes_crypt(struct blkcipher_desc *desc,
338 struct scatterlist *dst, struct scatterlist *src,
339 unsigned int nbytes, u32 extra_flags)
341 struct ubicom32_aes_ctx *uctx = crypto_blkcipher_ctx(desc->tfm);
344 struct blkcipher_walk walk;
345 blkcipher_walk_init(&walk, dst, src, nbytes);
346 ret = blkcipher_walk_virt(desc, &walk);
354 hw_crypto_set_ctrl(uctx->ctrl | extra_flags);
355 aes_hw_set_key(uctx->key, uctx->key_len);
357 while (likely((nbytes = walk.nbytes))) {
358 /* only use complete blocks */
359 unsigned int n = nbytes & ~(AES_BLOCK_SIZE - 1);
361 u8 *out = walk.dst.virt.addr;
362 u8 *in = walk.src.virt.addr;
364 if (extra_flags & SEC_DIR_ENCRYPT) {
365 cbc_aes_encrypt_loop(out, in, walk.iv, n);
367 cbc_aes_decrypt_loop(out, in, walk.iv, n);
371 nbytes &= AES_BLOCK_SIZE - 1;
372 ret = blkcipher_walk_done(desc, &walk, nbytes);
379 static int __ocm_text cbc_aes_encrypt(struct blkcipher_desc *desc,
380 struct scatterlist *dst, struct scatterlist *src,
383 return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_ENCRYPT | SEC_CBC_SET);
386 static int __ocm_text cbc_aes_decrypt(struct blkcipher_desc *desc,
387 struct scatterlist *dst, struct scatterlist *src,
390 return cbc_aes_crypt(desc, dst, src, nbytes, SEC_DIR_DECRYPT | SEC_CBC_SET);
393 static struct crypto_alg cbc_aes_alg = {
394 .cra_name = "cbc(aes)",
395 .cra_driver_name = "cbc-aes-ubicom32",
396 .cra_priority = CRYPTO_UBICOM32_COMPOSITE_PRIORITY,
397 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
398 .cra_blocksize = AES_BLOCK_SIZE,
399 .cra_ctxsize = sizeof(struct ubicom32_aes_ctx),
400 .cra_alignmask = CRYPTO_UBICOM32_ALIGNMENT - 1,
401 .cra_type = &crypto_blkcipher_type,
402 .cra_module = THIS_MODULE,
403 .cra_list = LIST_HEAD_INIT(cbc_aes_alg.cra_list),
406 .min_keysize = AES_MIN_KEY_SIZE,
407 .max_keysize = AES_MAX_KEY_SIZE,
408 .ivsize = AES_BLOCK_SIZE,
409 .setkey = aes_set_key,
410 .encrypt = cbc_aes_encrypt,
411 .decrypt = cbc_aes_decrypt,
416 static int __init aes_init(void)
422 ret = crypto_register_alg(&aes_alg);
426 ret = crypto_register_alg(&ecb_aes_alg);
430 ret = crypto_register_alg(&cbc_aes_alg);
438 crypto_unregister_alg(&ecb_aes_alg);
440 crypto_unregister_alg(&aes_alg);
445 static void __exit aes_fini(void)
447 crypto_unregister_alg(&cbc_aes_alg);
448 crypto_unregister_alg(&ecb_aes_alg);
449 crypto_unregister_alg(&aes_alg);
452 module_init(aes_init);
453 module_exit(aes_fini);
457 MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
458 MODULE_LICENSE("GPL");