chacha_generic.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * ChaCha and XChaCha stream ciphers, including ChaCha20 (RFC7539)
  4. *
  5. * Copyright (C) 2015 Martin Willi
  6. * Copyright (C) 2018 Google LLC
  7. */
  8. #include <asm/unaligned.h>
  9. #include <crypto/algapi.h>
  10. #include <crypto/internal/chacha.h>
  11. #include <crypto/internal/skcipher.h>
  12. #include <linux/module.h>
  13. static int chacha_stream_xor(struct skcipher_request *req,
  14. const struct chacha_ctx *ctx, const u8 *iv)
  15. {
  16. struct skcipher_walk walk;
  17. u32 state[16];
  18. int err;
  19. err = skcipher_walk_virt(&walk, req, false);
  20. chacha_init_generic(state, ctx->key, iv);
  21. while (walk.nbytes > 0) {
  22. unsigned int nbytes = walk.nbytes;
  23. if (nbytes < walk.total)
  24. nbytes = round_down(nbytes, CHACHA_BLOCK_SIZE);
  25. chacha_crypt_generic(state, walk.dst.virt.addr,
  26. walk.src.virt.addr, nbytes, ctx->nrounds);
  27. err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
  28. }
  29. return err;
  30. }
  31. static int crypto_chacha_crypt(struct skcipher_request *req)
  32. {
  33. struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  34. struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
  35. return chacha_stream_xor(req, ctx, req->iv);
  36. }
  37. static int crypto_xchacha_crypt(struct skcipher_request *req)
  38. {
  39. struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  40. struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
  41. struct chacha_ctx subctx;
  42. u32 state[16];
  43. u8 real_iv[16];
  44. /* Compute the subkey given the original key and first 128 nonce bits */
  45. chacha_init_generic(state, ctx->key, req->iv);
  46. hchacha_block_generic(state, subctx.key, ctx->nrounds);
  47. subctx.nrounds = ctx->nrounds;
  48. /* Build the real IV */
  49. memcpy(&real_iv[0], req->iv + 24, 8); /* stream position */
  50. memcpy(&real_iv[8], req->iv + 16, 8); /* remaining 64 nonce bits */
  51. /* Generate the stream and XOR it with the data */
  52. return chacha_stream_xor(req, &subctx, real_iv);
  53. }
  54. static struct skcipher_alg algs[] = {
  55. {
  56. .base.cra_name = "chacha20",
  57. .base.cra_driver_name = "chacha20-generic",
  58. .base.cra_priority = 100,
  59. .base.cra_blocksize = 1,
  60. .base.cra_ctxsize = sizeof(struct chacha_ctx),
  61. .base.cra_module = THIS_MODULE,
  62. .min_keysize = CHACHA_KEY_SIZE,
  63. .max_keysize = CHACHA_KEY_SIZE,
  64. .ivsize = CHACHA_IV_SIZE,
  65. .chunksize = CHACHA_BLOCK_SIZE,
  66. .setkey = chacha20_setkey,
  67. .encrypt = crypto_chacha_crypt,
  68. .decrypt = crypto_chacha_crypt,
  69. }, {
  70. .base.cra_name = "xchacha20",
  71. .base.cra_driver_name = "xchacha20-generic",
  72. .base.cra_priority = 100,
  73. .base.cra_blocksize = 1,
  74. .base.cra_ctxsize = sizeof(struct chacha_ctx),
  75. .base.cra_module = THIS_MODULE,
  76. .min_keysize = CHACHA_KEY_SIZE,
  77. .max_keysize = CHACHA_KEY_SIZE,
  78. .ivsize = XCHACHA_IV_SIZE,
  79. .chunksize = CHACHA_BLOCK_SIZE,
  80. .setkey = chacha20_setkey,
  81. .encrypt = crypto_xchacha_crypt,
  82. .decrypt = crypto_xchacha_crypt,
  83. }, {
  84. .base.cra_name = "xchacha12",
  85. .base.cra_driver_name = "xchacha12-generic",
  86. .base.cra_priority = 100,
  87. .base.cra_blocksize = 1,
  88. .base.cra_ctxsize = sizeof(struct chacha_ctx),
  89. .base.cra_module = THIS_MODULE,
  90. .min_keysize = CHACHA_KEY_SIZE,
  91. .max_keysize = CHACHA_KEY_SIZE,
  92. .ivsize = XCHACHA_IV_SIZE,
  93. .chunksize = CHACHA_BLOCK_SIZE,
  94. .setkey = chacha12_setkey,
  95. .encrypt = crypto_xchacha_crypt,
  96. .decrypt = crypto_xchacha_crypt,
  97. }
  98. };
  99. static int __init chacha_generic_mod_init(void)
  100. {
  101. return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
  102. }
  103. static void __exit chacha_generic_mod_fini(void)
  104. {
  105. crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
  106. }
  107. subsys_initcall(chacha_generic_mod_init);
  108. module_exit(chacha_generic_mod_fini);
  109. MODULE_LICENSE("GPL");
  110. MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
  111. MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (generic)");
  112. MODULE_ALIAS_CRYPTO("chacha20");
  113. MODULE_ALIAS_CRYPTO("chacha20-generic");
  114. MODULE_ALIAS_CRYPTO("xchacha20");
  115. MODULE_ALIAS_CRYPTO("xchacha20-generic");
  116. MODULE_ALIAS_CRYPTO("xchacha12");
  117. MODULE_ALIAS_CRYPTO("xchacha12-generic");