1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * ChaCha and XChaCha stream ciphers, including ChaCha20 (RFC7539)
5 * Copyright (C) 2015 Martin Willi
6 * Copyright (C) 2018 Google LLC
9 #include <asm/unaligned.h>
10 #include <crypto/algapi.h>
11 #include <crypto/internal/chacha.h>
12 #include <crypto/internal/skcipher.h>
13 #include <linux/module.h>
15 static int chacha_stream_xor(struct skcipher_request
*req
,
16 const struct chacha_ctx
*ctx
, const u8
*iv
)
18 struct skcipher_walk walk
;
22 err
= skcipher_walk_virt(&walk
, req
, false);
24 chacha_init_generic(state
, ctx
->key
, iv
);
26 while (walk
.nbytes
> 0) {
27 unsigned int nbytes
= walk
.nbytes
;
29 if (nbytes
< walk
.total
)
30 nbytes
= round_down(nbytes
, CHACHA_BLOCK_SIZE
);
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
);
40 static int crypto_chacha_crypt(struct skcipher_request
*req
)
42 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
43 struct chacha_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
45 return chacha_stream_xor(req
, ctx
, req
->iv
);
48 static int crypto_xchacha_crypt(struct skcipher_request
*req
)
50 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
51 struct chacha_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
52 struct chacha_ctx subctx
;
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
;
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 */
65 /* Generate the stream and XOR it with the data */
66 return chacha_stream_xor(req
, &subctx
, real_iv
);
69 static struct skcipher_alg algs
[] = {
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
,
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
,
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
,
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
,
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
,
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
,
118 static int __init
chacha_generic_mod_init(void)
120 return crypto_register_skciphers(algs
, ARRAY_SIZE(algs
));
123 static void __exit
chacha_generic_mod_fini(void)
125 crypto_unregister_skciphers(algs
, ARRAY_SIZE(algs
));
128 subsys_initcall(chacha_generic_mod_init
);
129 module_exit(chacha_generic_mod_fini
);
131 MODULE_LICENSE("GPL");
132 MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
133 MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (generic)");
134 MODULE_ALIAS_CRYPTO("chacha20");
135 MODULE_ALIAS_CRYPTO("chacha20-generic");
136 MODULE_ALIAS_CRYPTO("xchacha20");
137 MODULE_ALIAS_CRYPTO("xchacha20-generic");
138 MODULE_ALIAS_CRYPTO("xchacha12");
139 MODULE_ALIAS_CRYPTO("xchacha12-generic");