0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <crypto/algapi.h>
0011 #include <crypto/internal/chacha.h>
0012 #include <crypto/internal/simd.h>
0013 #include <crypto/internal/skcipher.h>
0014 #include <linux/jump_label.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017
0018 #include <asm/cputype.h>
0019 #include <asm/hwcap.h>
0020 #include <asm/neon.h>
0021 #include <asm/simd.h>
0022
0023 asmlinkage void chacha_block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
0024 int nrounds);
0025 asmlinkage void chacha_4block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
0026 int nrounds, unsigned int nbytes);
0027 asmlinkage void hchacha_block_arm(const u32 *state, u32 *out, int nrounds);
0028 asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds);
0029
0030 asmlinkage void chacha_doarm(u8 *dst, const u8 *src, unsigned int bytes,
0031 const u32 *state, int nrounds);
0032
0033 static __ro_after_init DEFINE_STATIC_KEY_FALSE(use_neon);
0034
0035 static inline bool neon_usable(void)
0036 {
0037 return static_branch_likely(&use_neon) && crypto_simd_usable();
0038 }
0039
0040 static void chacha_doneon(u32 *state, u8 *dst, const u8 *src,
0041 unsigned int bytes, int nrounds)
0042 {
0043 u8 buf[CHACHA_BLOCK_SIZE];
0044
0045 while (bytes > CHACHA_BLOCK_SIZE) {
0046 unsigned int l = min(bytes, CHACHA_BLOCK_SIZE * 4U);
0047
0048 chacha_4block_xor_neon(state, dst, src, nrounds, l);
0049 bytes -= l;
0050 src += l;
0051 dst += l;
0052 state[12] += DIV_ROUND_UP(l, CHACHA_BLOCK_SIZE);
0053 }
0054 if (bytes) {
0055 const u8 *s = src;
0056 u8 *d = dst;
0057
0058 if (bytes != CHACHA_BLOCK_SIZE)
0059 s = d = memcpy(buf, src, bytes);
0060 chacha_block_xor_neon(state, d, s, nrounds);
0061 if (d != dst)
0062 memcpy(dst, buf, bytes);
0063 state[12]++;
0064 }
0065 }
0066
0067 void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
0068 {
0069 if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon_usable()) {
0070 hchacha_block_arm(state, stream, nrounds);
0071 } else {
0072 kernel_neon_begin();
0073 hchacha_block_neon(state, stream, nrounds);
0074 kernel_neon_end();
0075 }
0076 }
0077 EXPORT_SYMBOL(hchacha_block_arch);
0078
0079 void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
0080 {
0081 chacha_init_generic(state, key, iv);
0082 }
0083 EXPORT_SYMBOL(chacha_init_arch);
0084
0085 void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
0086 int nrounds)
0087 {
0088 if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon_usable() ||
0089 bytes <= CHACHA_BLOCK_SIZE) {
0090 chacha_doarm(dst, src, bytes, state, nrounds);
0091 state[12] += DIV_ROUND_UP(bytes, CHACHA_BLOCK_SIZE);
0092 return;
0093 }
0094
0095 do {
0096 unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
0097
0098 kernel_neon_begin();
0099 chacha_doneon(state, dst, src, todo, nrounds);
0100 kernel_neon_end();
0101
0102 bytes -= todo;
0103 src += todo;
0104 dst += todo;
0105 } while (bytes);
0106 }
0107 EXPORT_SYMBOL(chacha_crypt_arch);
0108
0109 static int chacha_stream_xor(struct skcipher_request *req,
0110 const struct chacha_ctx *ctx, const u8 *iv,
0111 bool neon)
0112 {
0113 struct skcipher_walk walk;
0114 u32 state[16];
0115 int err;
0116
0117 err = skcipher_walk_virt(&walk, req, false);
0118
0119 chacha_init_generic(state, ctx->key, iv);
0120
0121 while (walk.nbytes > 0) {
0122 unsigned int nbytes = walk.nbytes;
0123
0124 if (nbytes < walk.total)
0125 nbytes = round_down(nbytes, walk.stride);
0126
0127 if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon) {
0128 chacha_doarm(walk.dst.virt.addr, walk.src.virt.addr,
0129 nbytes, state, ctx->nrounds);
0130 state[12] += DIV_ROUND_UP(nbytes, CHACHA_BLOCK_SIZE);
0131 } else {
0132 kernel_neon_begin();
0133 chacha_doneon(state, walk.dst.virt.addr,
0134 walk.src.virt.addr, nbytes, ctx->nrounds);
0135 kernel_neon_end();
0136 }
0137 err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
0138 }
0139
0140 return err;
0141 }
0142
0143 static int do_chacha(struct skcipher_request *req, bool neon)
0144 {
0145 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
0146 struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
0147
0148 return chacha_stream_xor(req, ctx, req->iv, neon);
0149 }
0150
0151 static int chacha_arm(struct skcipher_request *req)
0152 {
0153 return do_chacha(req, false);
0154 }
0155
0156 static int chacha_neon(struct skcipher_request *req)
0157 {
0158 return do_chacha(req, neon_usable());
0159 }
0160
0161 static int do_xchacha(struct skcipher_request *req, bool neon)
0162 {
0163 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
0164 struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
0165 struct chacha_ctx subctx;
0166 u32 state[16];
0167 u8 real_iv[16];
0168
0169 chacha_init_generic(state, ctx->key, req->iv);
0170
0171 if (!IS_ENABLED(CONFIG_KERNEL_MODE_NEON) || !neon) {
0172 hchacha_block_arm(state, subctx.key, ctx->nrounds);
0173 } else {
0174 kernel_neon_begin();
0175 hchacha_block_neon(state, subctx.key, ctx->nrounds);
0176 kernel_neon_end();
0177 }
0178 subctx.nrounds = ctx->nrounds;
0179
0180 memcpy(&real_iv[0], req->iv + 24, 8);
0181 memcpy(&real_iv[8], req->iv + 16, 8);
0182 return chacha_stream_xor(req, &subctx, real_iv, neon);
0183 }
0184
0185 static int xchacha_arm(struct skcipher_request *req)
0186 {
0187 return do_xchacha(req, false);
0188 }
0189
0190 static int xchacha_neon(struct skcipher_request *req)
0191 {
0192 return do_xchacha(req, neon_usable());
0193 }
0194
0195 static struct skcipher_alg arm_algs[] = {
0196 {
0197 .base.cra_name = "chacha20",
0198 .base.cra_driver_name = "chacha20-arm",
0199 .base.cra_priority = 200,
0200 .base.cra_blocksize = 1,
0201 .base.cra_ctxsize = sizeof(struct chacha_ctx),
0202 .base.cra_module = THIS_MODULE,
0203
0204 .min_keysize = CHACHA_KEY_SIZE,
0205 .max_keysize = CHACHA_KEY_SIZE,
0206 .ivsize = CHACHA_IV_SIZE,
0207 .chunksize = CHACHA_BLOCK_SIZE,
0208 .setkey = chacha20_setkey,
0209 .encrypt = chacha_arm,
0210 .decrypt = chacha_arm,
0211 }, {
0212 .base.cra_name = "xchacha20",
0213 .base.cra_driver_name = "xchacha20-arm",
0214 .base.cra_priority = 200,
0215 .base.cra_blocksize = 1,
0216 .base.cra_ctxsize = sizeof(struct chacha_ctx),
0217 .base.cra_module = THIS_MODULE,
0218
0219 .min_keysize = CHACHA_KEY_SIZE,
0220 .max_keysize = CHACHA_KEY_SIZE,
0221 .ivsize = XCHACHA_IV_SIZE,
0222 .chunksize = CHACHA_BLOCK_SIZE,
0223 .setkey = chacha20_setkey,
0224 .encrypt = xchacha_arm,
0225 .decrypt = xchacha_arm,
0226 }, {
0227 .base.cra_name = "xchacha12",
0228 .base.cra_driver_name = "xchacha12-arm",
0229 .base.cra_priority = 200,
0230 .base.cra_blocksize = 1,
0231 .base.cra_ctxsize = sizeof(struct chacha_ctx),
0232 .base.cra_module = THIS_MODULE,
0233
0234 .min_keysize = CHACHA_KEY_SIZE,
0235 .max_keysize = CHACHA_KEY_SIZE,
0236 .ivsize = XCHACHA_IV_SIZE,
0237 .chunksize = CHACHA_BLOCK_SIZE,
0238 .setkey = chacha12_setkey,
0239 .encrypt = xchacha_arm,
0240 .decrypt = xchacha_arm,
0241 },
0242 };
0243
0244 static struct skcipher_alg neon_algs[] = {
0245 {
0246 .base.cra_name = "chacha20",
0247 .base.cra_driver_name = "chacha20-neon",
0248 .base.cra_priority = 300,
0249 .base.cra_blocksize = 1,
0250 .base.cra_ctxsize = sizeof(struct chacha_ctx),
0251 .base.cra_module = THIS_MODULE,
0252
0253 .min_keysize = CHACHA_KEY_SIZE,
0254 .max_keysize = CHACHA_KEY_SIZE,
0255 .ivsize = CHACHA_IV_SIZE,
0256 .chunksize = CHACHA_BLOCK_SIZE,
0257 .walksize = 4 * CHACHA_BLOCK_SIZE,
0258 .setkey = chacha20_setkey,
0259 .encrypt = chacha_neon,
0260 .decrypt = chacha_neon,
0261 }, {
0262 .base.cra_name = "xchacha20",
0263 .base.cra_driver_name = "xchacha20-neon",
0264 .base.cra_priority = 300,
0265 .base.cra_blocksize = 1,
0266 .base.cra_ctxsize = sizeof(struct chacha_ctx),
0267 .base.cra_module = THIS_MODULE,
0268
0269 .min_keysize = CHACHA_KEY_SIZE,
0270 .max_keysize = CHACHA_KEY_SIZE,
0271 .ivsize = XCHACHA_IV_SIZE,
0272 .chunksize = CHACHA_BLOCK_SIZE,
0273 .walksize = 4 * CHACHA_BLOCK_SIZE,
0274 .setkey = chacha20_setkey,
0275 .encrypt = xchacha_neon,
0276 .decrypt = xchacha_neon,
0277 }, {
0278 .base.cra_name = "xchacha12",
0279 .base.cra_driver_name = "xchacha12-neon",
0280 .base.cra_priority = 300,
0281 .base.cra_blocksize = 1,
0282 .base.cra_ctxsize = sizeof(struct chacha_ctx),
0283 .base.cra_module = THIS_MODULE,
0284
0285 .min_keysize = CHACHA_KEY_SIZE,
0286 .max_keysize = CHACHA_KEY_SIZE,
0287 .ivsize = XCHACHA_IV_SIZE,
0288 .chunksize = CHACHA_BLOCK_SIZE,
0289 .walksize = 4 * CHACHA_BLOCK_SIZE,
0290 .setkey = chacha12_setkey,
0291 .encrypt = xchacha_neon,
0292 .decrypt = xchacha_neon,
0293 }
0294 };
0295
0296 static int __init chacha_simd_mod_init(void)
0297 {
0298 int err = 0;
0299
0300 if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER)) {
0301 err = crypto_register_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
0302 if (err)
0303 return err;
0304 }
0305
0306 if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON)) {
0307 int i;
0308
0309 switch (read_cpuid_part()) {
0310 case ARM_CPU_PART_CORTEX_A7:
0311 case ARM_CPU_PART_CORTEX_A5:
0312
0313
0314
0315
0316
0317 for (i = 0; i < ARRAY_SIZE(neon_algs); i++)
0318 neon_algs[i].base.cra_priority = 0;
0319 break;
0320 default:
0321 static_branch_enable(&use_neon);
0322 }
0323
0324 if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER)) {
0325 err = crypto_register_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
0326 if (err)
0327 crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
0328 }
0329 }
0330 return err;
0331 }
0332
0333 static void __exit chacha_simd_mod_fini(void)
0334 {
0335 if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER)) {
0336 crypto_unregister_skciphers(arm_algs, ARRAY_SIZE(arm_algs));
0337 if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && (elf_hwcap & HWCAP_NEON))
0338 crypto_unregister_skciphers(neon_algs, ARRAY_SIZE(neon_algs));
0339 }
0340 }
0341
0342 module_init(chacha_simd_mod_init);
0343 module_exit(chacha_simd_mod_fini);
0344
0345 MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (scalar and NEON accelerated)");
0346 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
0347 MODULE_LICENSE("GPL v2");
0348 MODULE_ALIAS_CRYPTO("chacha20");
0349 MODULE_ALIAS_CRYPTO("chacha20-arm");
0350 MODULE_ALIAS_CRYPTO("xchacha20");
0351 MODULE_ALIAS_CRYPTO("xchacha20-arm");
0352 MODULE_ALIAS_CRYPTO("xchacha12");
0353 MODULE_ALIAS_CRYPTO("xchacha12-arm");
0354 #ifdef CONFIG_KERNEL_MODE_NEON
0355 MODULE_ALIAS_CRYPTO("chacha20-neon");
0356 MODULE_ALIAS_CRYPTO("xchacha20-neon");
0357 MODULE_ALIAS_CRYPTO("xchacha12-neon");
0358 #endif