File Index
Files and directories
Sign in
FILE

chacha.c

File preview with syntax highlighting.

linux-6.19.14/crypto/chacha.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Crypto API wrappers for the ChaCha20, XChaCha20, and XChaCha12 stream ciphers
  4 *
  5 * Copyright (C) 2015 Martin Willi
  6 * Copyright (C) 2018 Google LLC
  7 */
  8
  9#include <linux/unaligned.h>
 10#include <crypto/algapi.h>
 11#include <crypto/chacha.h>
 12#include <crypto/internal/skcipher.h>
 13#include <linux/module.h>
 14
 15struct chacha_ctx {
 16	u32 key[8];
 17	int nrounds;
 18};
 19
 20static int chacha_setkey(struct crypto_skcipher *tfm,
 21			 const u8 *key, unsigned int keysize, int nrounds)
 22{
 23	struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
 24	int i;
 25
 26	if (keysize != CHACHA_KEY_SIZE)
 27		return -EINVAL;
 28
 29	for (i = 0; i < ARRAY_SIZE(ctx->key); i++)
 30		ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32));
 31
 32	ctx->nrounds = nrounds;
 33	return 0;
 34}
 35
 36static int chacha20_setkey(struct crypto_skcipher *tfm,
 37			   const u8 *key, unsigned int keysize)
 38{
 39	return chacha_setkey(tfm, key, keysize, 20);
 40}
 41
 42static int chacha12_setkey(struct crypto_skcipher *tfm,
 43			   const u8 *key, unsigned int keysize)
 44{
 45	return chacha_setkey(tfm, key, keysize, 12);
 46}
 47
 48static int chacha_stream_xor(struct skcipher_request *req,
 49			     const struct chacha_ctx *ctx,
 50			     const u8 iv[CHACHA_IV_SIZE])
 51{
 52	struct skcipher_walk walk;
 53	struct chacha_state state;
 54	int err;
 55
 56	err = skcipher_walk_virt(&walk, req, false);
 57
 58	chacha_init(&state, ctx->key, iv);
 59
 60	while (walk.nbytes > 0) {
 61		unsigned int nbytes = walk.nbytes;
 62
 63		if (nbytes < walk.total)
 64			nbytes = round_down(nbytes, CHACHA_BLOCK_SIZE);
 65
 66		chacha_crypt(&state, walk.dst.virt.addr, walk.src.virt.addr,
 67			     nbytes, ctx->nrounds);
 68		err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
 69	}
 70
 71	return err;
 72}
 73
 74static int crypto_chacha_crypt(struct skcipher_request *req)
 75{
 76	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 77	const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
 78
 79	return chacha_stream_xor(req, ctx, req->iv);
 80}
 81
 82static int crypto_xchacha_crypt(struct skcipher_request *req)
 83{
 84	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 85	const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
 86	struct chacha_ctx subctx;
 87	struct chacha_state state;
 88	u8 real_iv[16];
 89
 90	/* Compute the subkey given the original key and first 128 nonce bits */
 91	chacha_init(&state, ctx->key, req->iv);
 92	hchacha_block(&state, subctx.key, ctx->nrounds);
 93	subctx.nrounds = ctx->nrounds;
 94
 95	/* Build the real IV */
 96	memcpy(&real_iv[0], req->iv + 24, 8); /* stream position */
 97	memcpy(&real_iv[8], req->iv + 16, 8); /* remaining 64 nonce bits */
 98
 99	/* Generate the stream and XOR it with the data */
100	return chacha_stream_xor(req, &subctx, real_iv);
101}
102
103static struct skcipher_alg algs[] = {
104	{
105		.base.cra_name		= "chacha20",
106		.base.cra_driver_name	= "chacha20-lib",
107		.base.cra_priority	= 300,
108		.base.cra_blocksize	= 1,
109		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
110		.base.cra_module	= THIS_MODULE,
111
112		.min_keysize		= CHACHA_KEY_SIZE,
113		.max_keysize		= CHACHA_KEY_SIZE,
114		.ivsize			= CHACHA_IV_SIZE,
115		.chunksize		= CHACHA_BLOCK_SIZE,
116		.setkey			= chacha20_setkey,
117		.encrypt		= crypto_chacha_crypt,
118		.decrypt		= crypto_chacha_crypt,
119	},
120	{
121		.base.cra_name		= "xchacha20",
122		.base.cra_driver_name	= "xchacha20-lib",
123		.base.cra_priority	= 300,
124		.base.cra_blocksize	= 1,
125		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
126		.base.cra_module	= THIS_MODULE,
127
128		.min_keysize		= CHACHA_KEY_SIZE,
129		.max_keysize		= CHACHA_KEY_SIZE,
130		.ivsize			= XCHACHA_IV_SIZE,
131		.chunksize		= CHACHA_BLOCK_SIZE,
132		.setkey			= chacha20_setkey,
133		.encrypt		= crypto_xchacha_crypt,
134		.decrypt		= crypto_xchacha_crypt,
135	},
136	{
137		.base.cra_name		= "xchacha12",
138		.base.cra_driver_name	= "xchacha12-lib",
139		.base.cra_priority	= 300,
140		.base.cra_blocksize	= 1,
141		.base.cra_ctxsize	= sizeof(struct chacha_ctx),
142		.base.cra_module	= THIS_MODULE,
143
144		.min_keysize		= CHACHA_KEY_SIZE,
145		.max_keysize		= CHACHA_KEY_SIZE,
146		.ivsize			= XCHACHA_IV_SIZE,
147		.chunksize		= CHACHA_BLOCK_SIZE,
148		.setkey			= chacha12_setkey,
149		.encrypt		= crypto_xchacha_crypt,
150		.decrypt		= crypto_xchacha_crypt,
151	}
152};
153
154static int __init crypto_chacha_mod_init(void)
155{
156	return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
157}
158
159static void __exit crypto_chacha_mod_fini(void)
160{
161	crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
162}
163
164module_init(crypto_chacha_mod_init);
165module_exit(crypto_chacha_mod_fini);
166
167MODULE_LICENSE("GPL");
168MODULE_AUTHOR("Martin Willi <martin@strongswan.org>");
169MODULE_DESCRIPTION("Crypto API wrappers for the ChaCha20, XChaCha20, and XChaCha12 stream ciphers");
170MODULE_ALIAS_CRYPTO("chacha20");
171MODULE_ALIAS_CRYPTO("chacha20-lib");
172MODULE_ALIAS_CRYPTO("xchacha20");
173MODULE_ALIAS_CRYPTO("xchacha20-lib");
174MODULE_ALIAS_CRYPTO("xchacha12");
175MODULE_ALIAS_CRYPTO("xchacha12-lib");
~/ Read-only file preview.