chacha-neon-glue.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. /*
  2. * ARM NEON and scalar accelerated ChaCha and XChaCha stream ciphers,
  3. * including ChaCha20 (RFC7539)
  4. *
  5. * Copyright (C) 2016 - 2017 Linaro, Ltd. <[email protected]>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * Based on:
  12. * ChaCha20 256-bit cipher algorithm, RFC7539, SIMD glue code
  13. *
  14. * Copyright (C) 2015 Martin Willi
  15. *
  16. * This program is free software; you can redistribute it and/or modify
  17. * it under the terms of the GNU General Public License as published by
  18. * the Free Software Foundation; either version 2 of the License, or
  19. * (at your option) any later version.
  20. */
  21. #include <crypto/algapi.h>
  22. #include <crypto/internal/chacha.h>
  23. #include <crypto/internal/simd.h>
  24. #include <crypto/internal/skcipher.h>
  25. #include <linux/jump_label.h>
  26. #include <linux/kernel.h>
  27. #include <linux/module.h>
  28. #include <asm/hwcap.h>
  29. #include <asm/neon.h>
  30. #include <asm/simd.h>
  31. asmlinkage void chacha_block_xor_neon(u32 *state, u8 *dst, const u8 *src,
  32. int nrounds);
  33. asmlinkage void chacha_4block_xor_neon(u32 *state, u8 *dst, const u8 *src,
  34. int nrounds, int bytes);
  35. asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds);
  36. static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
  37. static void chacha_doneon(u32 *state, u8 *dst, const u8 *src,
  38. int bytes, int nrounds)
  39. {
  40. while (bytes > 0) {
  41. int l = min(bytes, CHACHA_BLOCK_SIZE * 5);
  42. if (l <= CHACHA_BLOCK_SIZE) {
  43. u8 buf[CHACHA_BLOCK_SIZE];
  44. memcpy(buf, src, l);
  45. chacha_block_xor_neon(state, buf, buf, nrounds);
  46. memcpy(dst, buf, l);
  47. state[12] += 1;
  48. break;
  49. }
  50. chacha_4block_xor_neon(state, dst, src, nrounds, l);
  51. bytes -= l;
  52. src += l;
  53. dst += l;
  54. state[12] += DIV_ROUND_UP(l, CHACHA_BLOCK_SIZE);
  55. }
  56. }
  57. void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
  58. {
  59. if (!static_branch_likely(&have_neon) || !crypto_simd_usable()) {
  60. hchacha_block_generic(state, stream, nrounds);
  61. } else {
  62. kernel_neon_begin();
  63. hchacha_block_neon(state, stream, nrounds);
  64. kernel_neon_end();
  65. }
  66. }
  67. EXPORT_SYMBOL(hchacha_block_arch);
  68. void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
  69. {
  70. chacha_init_generic(state, key, iv);
  71. }
  72. EXPORT_SYMBOL(chacha_init_arch);
  73. void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, unsigned int bytes,
  74. int nrounds)
  75. {
  76. if (!static_branch_likely(&have_neon) || bytes <= CHACHA_BLOCK_SIZE ||
  77. !crypto_simd_usable())
  78. return chacha_crypt_generic(state, dst, src, bytes, nrounds);
  79. do {
  80. unsigned int todo = min_t(unsigned int, bytes, SZ_4K);
  81. kernel_neon_begin();
  82. chacha_doneon(state, dst, src, todo, nrounds);
  83. kernel_neon_end();
  84. bytes -= todo;
  85. src += todo;
  86. dst += todo;
  87. } while (bytes);
  88. }
  89. EXPORT_SYMBOL(chacha_crypt_arch);
  90. static int chacha_neon_stream_xor(struct skcipher_request *req,
  91. const struct chacha_ctx *ctx, const u8 *iv)
  92. {
  93. struct skcipher_walk walk;
  94. u32 state[16];
  95. int err;
  96. err = skcipher_walk_virt(&walk, req, false);
  97. chacha_init_generic(state, ctx->key, iv);
  98. while (walk.nbytes > 0) {
  99. unsigned int nbytes = walk.nbytes;
  100. if (nbytes < walk.total)
  101. nbytes = rounddown(nbytes, walk.stride);
  102. if (!static_branch_likely(&have_neon) ||
  103. !crypto_simd_usable()) {
  104. chacha_crypt_generic(state, walk.dst.virt.addr,
  105. walk.src.virt.addr, nbytes,
  106. ctx->nrounds);
  107. } else {
  108. kernel_neon_begin();
  109. chacha_doneon(state, walk.dst.virt.addr,
  110. walk.src.virt.addr, nbytes, ctx->nrounds);
  111. kernel_neon_end();
  112. }
  113. err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
  114. }
  115. return err;
  116. }
  117. static int chacha_neon(struct skcipher_request *req)
  118. {
  119. struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  120. struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
  121. return chacha_neon_stream_xor(req, ctx, req->iv);
  122. }
  123. static int xchacha_neon(struct skcipher_request *req)
  124. {
  125. struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  126. struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
  127. struct chacha_ctx subctx;
  128. u32 state[16];
  129. u8 real_iv[16];
  130. chacha_init_generic(state, ctx->key, req->iv);
  131. hchacha_block_arch(state, subctx.key, ctx->nrounds);
  132. subctx.nrounds = ctx->nrounds;
  133. memcpy(&real_iv[0], req->iv + 24, 8);
  134. memcpy(&real_iv[8], req->iv + 16, 8);
  135. return chacha_neon_stream_xor(req, &subctx, real_iv);
  136. }
  137. static struct skcipher_alg algs[] = {
  138. {
  139. .base.cra_name = "chacha20",
  140. .base.cra_driver_name = "chacha20-neon",
  141. .base.cra_priority = 300,
  142. .base.cra_blocksize = 1,
  143. .base.cra_ctxsize = sizeof(struct chacha_ctx),
  144. .base.cra_module = THIS_MODULE,
  145. .min_keysize = CHACHA_KEY_SIZE,
  146. .max_keysize = CHACHA_KEY_SIZE,
  147. .ivsize = CHACHA_IV_SIZE,
  148. .chunksize = CHACHA_BLOCK_SIZE,
  149. .walksize = 5 * CHACHA_BLOCK_SIZE,
  150. .setkey = chacha20_setkey,
  151. .encrypt = chacha_neon,
  152. .decrypt = chacha_neon,
  153. }, {
  154. .base.cra_name = "xchacha20",
  155. .base.cra_driver_name = "xchacha20-neon",
  156. .base.cra_priority = 300,
  157. .base.cra_blocksize = 1,
  158. .base.cra_ctxsize = sizeof(struct chacha_ctx),
  159. .base.cra_module = THIS_MODULE,
  160. .min_keysize = CHACHA_KEY_SIZE,
  161. .max_keysize = CHACHA_KEY_SIZE,
  162. .ivsize = XCHACHA_IV_SIZE,
  163. .chunksize = CHACHA_BLOCK_SIZE,
  164. .walksize = 5 * CHACHA_BLOCK_SIZE,
  165. .setkey = chacha20_setkey,
  166. .encrypt = xchacha_neon,
  167. .decrypt = xchacha_neon,
  168. }, {
  169. .base.cra_name = "xchacha12",
  170. .base.cra_driver_name = "xchacha12-neon",
  171. .base.cra_priority = 300,
  172. .base.cra_blocksize = 1,
  173. .base.cra_ctxsize = sizeof(struct chacha_ctx),
  174. .base.cra_module = THIS_MODULE,
  175. .min_keysize = CHACHA_KEY_SIZE,
  176. .max_keysize = CHACHA_KEY_SIZE,
  177. .ivsize = XCHACHA_IV_SIZE,
  178. .chunksize = CHACHA_BLOCK_SIZE,
  179. .walksize = 5 * CHACHA_BLOCK_SIZE,
  180. .setkey = chacha12_setkey,
  181. .encrypt = xchacha_neon,
  182. .decrypt = xchacha_neon,
  183. }
  184. };
  185. static int __init chacha_simd_mod_init(void)
  186. {
  187. if (!cpu_have_named_feature(ASIMD))
  188. return 0;
  189. static_branch_enable(&have_neon);
  190. return IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) ?
  191. crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0;
  192. }
  193. static void __exit chacha_simd_mod_fini(void)
  194. {
  195. if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) && cpu_have_named_feature(ASIMD))
  196. crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
  197. }
  198. module_init(chacha_simd_mod_init);
  199. module_exit(chacha_simd_mod_fini);
  200. MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (NEON accelerated)");
  201. MODULE_AUTHOR("Ard Biesheuvel <[email protected]>");
  202. MODULE_LICENSE("GPL v2");
  203. MODULE_ALIAS_CRYPTO("chacha20");
  204. MODULE_ALIAS_CRYPTO("chacha20-neon");
  205. MODULE_ALIAS_CRYPTO("xchacha20");
  206. MODULE_ALIAS_CRYPTO("xchacha20-neon");
  207. MODULE_ALIAS_CRYPTO("xchacha12");
  208. MODULE_ALIAS_CRYPTO("xchacha12-neon");