2 * ChaCha20 256-bit cipher algorithm, RFC7539, arm64 NEON functions
4 * Copyright (C) 2016 - 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org>
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.
11 * ChaCha20 256-bit cipher algorithm, RFC7539, SIMD glue code
13 * Copyright (C) 2015 Martin Willi
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
21 #include <crypto/algapi.h>
22 #include <crypto/chacha20.h>
23 #include <crypto/internal/skcipher.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
27 #include <asm/hwcap.h>
31 asmlinkage
void chacha20_block_xor_neon(u32
*state
, u8
*dst
, const u8
*src
);
32 asmlinkage
void chacha20_4block_xor_neon(u32
*state
, u8
*dst
, const u8
*src
);
34 static void chacha20_doneon(u32
*state
, u8
*dst
, const u8
*src
,
37 u8 buf
[CHACHA20_BLOCK_SIZE
];
39 while (bytes
>= CHACHA20_BLOCK_SIZE
* 4) {
41 chacha20_4block_xor_neon(state
, dst
, src
);
43 bytes
-= CHACHA20_BLOCK_SIZE
* 4;
44 src
+= CHACHA20_BLOCK_SIZE
* 4;
45 dst
+= CHACHA20_BLOCK_SIZE
* 4;
53 while (bytes
>= CHACHA20_BLOCK_SIZE
) {
54 chacha20_block_xor_neon(state
, dst
, src
);
55 bytes
-= CHACHA20_BLOCK_SIZE
;
56 src
+= CHACHA20_BLOCK_SIZE
;
57 dst
+= CHACHA20_BLOCK_SIZE
;
61 memcpy(buf
, src
, bytes
);
62 chacha20_block_xor_neon(state
, buf
, buf
);
63 memcpy(dst
, buf
, bytes
);
68 static int chacha20_neon(struct skcipher_request
*req
)
70 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
71 struct chacha20_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
72 struct skcipher_walk walk
;
76 if (!may_use_simd() || req
->cryptlen
<= CHACHA20_BLOCK_SIZE
)
77 return crypto_chacha20_crypt(req
);
79 err
= skcipher_walk_virt(&walk
, req
, false);
81 crypto_chacha20_init(state
, ctx
, walk
.iv
);
83 while (walk
.nbytes
> 0) {
84 unsigned int nbytes
= walk
.nbytes
;
86 if (nbytes
< walk
.total
)
87 nbytes
= round_down(nbytes
, walk
.stride
);
89 chacha20_doneon(state
, walk
.dst
.virt
.addr
, walk
.src
.virt
.addr
,
91 err
= skcipher_walk_done(&walk
, walk
.nbytes
- nbytes
);
97 static struct skcipher_alg alg
= {
98 .base
.cra_name
= "chacha20",
99 .base
.cra_driver_name
= "chacha20-neon",
100 .base
.cra_priority
= 300,
101 .base
.cra_blocksize
= 1,
102 .base
.cra_ctxsize
= sizeof(struct chacha20_ctx
),
103 .base
.cra_module
= THIS_MODULE
,
105 .min_keysize
= CHACHA20_KEY_SIZE
,
106 .max_keysize
= CHACHA20_KEY_SIZE
,
107 .ivsize
= CHACHA20_IV_SIZE
,
108 .chunksize
= CHACHA20_BLOCK_SIZE
,
109 .walksize
= 4 * CHACHA20_BLOCK_SIZE
,
110 .setkey
= crypto_chacha20_setkey
,
111 .encrypt
= chacha20_neon
,
112 .decrypt
= chacha20_neon
,
115 static int __init
chacha20_simd_mod_init(void)
117 if (!(elf_hwcap
& HWCAP_ASIMD
))
120 return crypto_register_skcipher(&alg
);
123 static void __exit
chacha20_simd_mod_fini(void)
125 crypto_unregister_skcipher(&alg
);
128 module_init(chacha20_simd_mod_init
);
129 module_exit(chacha20_simd_mod_fini
);
131 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
132 MODULE_LICENSE("GPL v2");
133 MODULE_ALIAS_CRYPTO("chacha20");