Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/crypto/chacha.c
29266 views
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
15
struct chacha_ctx {
16
u32 key[8];
17
int nrounds;
18
};
19
20
static 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
36
static 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
42
static 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
48
static 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
74
static 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
82
static 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
103
static 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
154
static int __init crypto_chacha_mod_init(void)
155
{
156
return crypto_register_skciphers(algs, ARRAY_SIZE(algs));
157
}
158
159
static void __exit crypto_chacha_mod_fini(void)
160
{
161
crypto_unregister_skciphers(algs, ARRAY_SIZE(algs));
162
}
163
164
module_init(crypto_chacha_mod_init);
165
module_exit(crypto_chacha_mod_fini);
166
167
MODULE_LICENSE("GPL");
168
MODULE_AUTHOR("Martin Willi <[email protected]>");
169
MODULE_DESCRIPTION("Crypto API wrappers for the ChaCha20, XChaCha20, and XChaCha12 stream ciphers");
170
MODULE_ALIAS_CRYPTO("chacha20");
171
MODULE_ALIAS_CRYPTO("chacha20-lib");
172
MODULE_ALIAS_CRYPTO("xchacha20");
173
MODULE_ALIAS_CRYPTO("xchacha20-lib");
174
MODULE_ALIAS_CRYPTO("xchacha12");
175
MODULE_ALIAS_CRYPTO("xchacha12-lib");
176
177