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