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