Linux Audio

Check our new training course

Loading...
v5.4
  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
  9#include <asm/unaligned.h>
 10#include <crypto/algapi.h>
 11#include <crypto/chacha.h>
 12#include <crypto/internal/skcipher.h>
 13#include <linux/module.h>
 14
 15static void chacha_docrypt(u32 *state, u8 *dst, const u8 *src,
 16			   unsigned int bytes, int nrounds)
 17{
 18	/* aligned to potentially speed up crypto_xor() */
 19	u8 stream[CHACHA_BLOCK_SIZE] __aligned(sizeof(long));
 20
 21	while (bytes >= CHACHA_BLOCK_SIZE) {
 22		chacha_block(state, stream, nrounds);
 23		crypto_xor_cpy(dst, src, stream, CHACHA_BLOCK_SIZE);
 24		bytes -= CHACHA_BLOCK_SIZE;
 25		dst += CHACHA_BLOCK_SIZE;
 26		src += CHACHA_BLOCK_SIZE;
 27	}
 28	if (bytes) {
 29		chacha_block(state, stream, nrounds);
 30		crypto_xor_cpy(dst, src, stream, bytes);
 31	}
 32}
 33
 34static int chacha_stream_xor(struct skcipher_request *req,
 35			     const struct chacha_ctx *ctx, const u8 *iv)
 36{
 37	struct skcipher_walk walk;
 38	u32 state[16];
 39	int err;
 40
 41	err = skcipher_walk_virt(&walk, req, false);
 42
 43	crypto_chacha_init(state, ctx, iv);
 44
 45	while (walk.nbytes > 0) {
 46		unsigned int nbytes = walk.nbytes;
 47
 48		if (nbytes < walk.total)
 49			nbytes = round_down(nbytes, CHACHA_BLOCK_SIZE);
 50
 51		chacha_docrypt(state, walk.dst.virt.addr, walk.src.virt.addr,
 52			       nbytes, ctx->nrounds);
 53		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
 54	}
 55
 56	return err;
 57}
 58
 59void crypto_chacha_init(u32 *state, const struct chacha_ctx *ctx, const u8 *iv)
 60{
 61	state[0]  = 0x61707865; /* "expa" */
 62	state[1]  = 0x3320646e; /* "nd 3" */
 63	state[2]  = 0x79622d32; /* "2-by" */
 64	state[3]  = 0x6b206574; /* "te k" */
 65	state[4]  = ctx->key[0];
 66	state[5]  = ctx->key[1];
 67	state[6]  = ctx->key[2];
 68	state[7]  = ctx->key[3];
 69	state[8]  = ctx->key[4];
 70	state[9]  = ctx->key[5];
 71	state[10] = ctx->key[6];
 72	state[11] = ctx->key[7];
 73	state[12] = get_unaligned_le32(iv +  0);
 74	state[13] = get_unaligned_le32(iv +  4);
 75	state[14] = get_unaligned_le32(iv +  8);
 76	state[15] = get_unaligned_le32(iv + 12);
 77}
 78EXPORT_SYMBOL_GPL(crypto_chacha_init);
 79
 80static int chacha_setkey(struct crypto_skcipher *tfm, const u8 *key,
 81			 unsigned int keysize, int nrounds)
 82{
 83	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
 84	int i;
 85
 86	if (keysize != CHACHA_KEY_SIZE)
 87		return -EINVAL;
 88
 89	for (i = 0; i < ARRAY_SIZE(ctx->key); i++)
 90		ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32));
 91
 92	ctx->nrounds = nrounds;
 93	return 0;
 94}
 95
 96int crypto_chacha20_setkey(struct crypto_skcipher *tfm, const u8 *key,
 97			   unsigned int keysize)
 98{
 99	return chacha_setkey(tfm, key, keysize, 20);
100}
101EXPORT_SYMBOL_GPL(crypto_chacha20_setkey);
102
103int crypto_chacha12_setkey(struct crypto_skcipher *tfm, const u8 *key,
104			   unsigned int keysize)
105{
106	return chacha_setkey(tfm, key, keysize, 12);
107}
108EXPORT_SYMBOL_GPL(crypto_chacha12_setkey);
109
110int crypto_chacha_crypt(struct skcipher_request *req)
111{
112	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
113	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
114
115	return chacha_stream_xor(req, ctx, req->iv);
116}
117EXPORT_SYMBOL_GPL(crypto_chacha_crypt);
118
119int crypto_xchacha_crypt(struct skcipher_request *req)
120{
121	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
122	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
123	struct chacha_ctx subctx;
124	u32 state[16];
125	u8 real_iv[16];
126
127	/* Compute the subkey given the original key and first 128 nonce bits */
128	crypto_chacha_init(state, ctx, req->iv);
129	hchacha_block(state, subctx.key, ctx->nrounds);
130	subctx.nrounds = ctx->nrounds;
131
132	/* Build the real IV */
133	memcpy(&real_iv[0], req->iv + 24, 8); /* stream position */
134	memcpy(&real_iv[8], req->iv + 16, 8); /* remaining 64 nonce bits */
135
136	/* Generate the stream and XOR it with the data */
137	return chacha_stream_xor(req, &subctx, real_iv);
138}
139EXPORT_SYMBOL_GPL(crypto_xchacha_crypt);
140
141static struct skcipher_alg algs[] = {
142	{
143		.base.cra_name		= "chacha20",
144		.base.cra_driver_name	= "chacha20-generic",
145		.base.cra_priority	= 100,
146		.base.cra_blocksize	= 1,
147		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
148		.base.cra_module	= THIS_MODULE,
149
150		.min_keysize		= CHACHA_KEY_SIZE,
151		.max_keysize		= CHACHA_KEY_SIZE,
152		.ivsize			= CHACHA_IV_SIZE,
153		.chunksize		= CHACHA_BLOCK_SIZE,
154		.setkey			= crypto_chacha20_setkey,
155		.encrypt		= crypto_chacha_crypt,
156		.decrypt		= crypto_chacha_crypt,
157	}, {
158		.base.cra_name		= "xchacha20",
159		.base.cra_driver_name	= "xchacha20-generic",
160		.base.cra_priority	= 100,
161		.base.cra_blocksize	= 1,
162		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
163		.base.cra_module	= THIS_MODULE,
164
165		.min_keysize		= CHACHA_KEY_SIZE,
166		.max_keysize		= CHACHA_KEY_SIZE,
167		.ivsize			= XCHACHA_IV_SIZE,
168		.chunksize		= CHACHA_BLOCK_SIZE,
169		.setkey			= crypto_chacha20_setkey,
170		.encrypt		= crypto_xchacha_crypt,
171		.decrypt		= crypto_xchacha_crypt,
172	}, {
173		.base.cra_name		= "xchacha12",
174		.base.cra_driver_name	= "xchacha12-generic",
175		.base.cra_priority	= 100,
176		.base.cra_blocksize	= 1,
177		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
178		.base.cra_module	= THIS_MODULE,
179
180		.min_keysize		= CHACHA_KEY_SIZE,
181		.max_keysize		= CHACHA_KEY_SIZE,
182		.ivsize			= XCHACHA_IV_SIZE,
183		.chunksize		= CHACHA_BLOCK_SIZE,
184		.setkey			= crypto_chacha12_setkey,
185		.encrypt		= crypto_xchacha_crypt,
186		.decrypt		= crypto_xchacha_crypt,
187	}
188};
189
190static int __init chacha_generic_mod_init(void)
191{
192	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
193}
194
195static void __exit chacha_generic_mod_fini(void)
196{
197	crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
198}
199
200subsys_initcall(chacha_generic_mod_init);
201module_exit(chacha_generic_mod_fini);
202
203MODULE_LICENSE("GPL");
204MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
205MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (generic)");
206MODULE_ALIAS_CRYPTO("chacha20");
207MODULE_ALIAS_CRYPTO("chacha20-generic");
208MODULE_ALIAS_CRYPTO("xchacha20");
209MODULE_ALIAS_CRYPTO("xchacha20-generic");
210MODULE_ALIAS_CRYPTO("xchacha12");
211MODULE_ALIAS_CRYPTO("xchacha12-generic");
v5.9
  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
  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>
 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");