Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/crypto/chacha.c
26131 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], bool arch)
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
if (arch)
67
chacha_crypt(&state, walk.dst.virt.addr,
68
walk.src.virt.addr, nbytes, ctx->nrounds);
69
else
70
chacha_crypt_generic(&state, walk.dst.virt.addr,
71
walk.src.virt.addr, nbytes,
72
ctx->nrounds);
73
err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
74
}
75
76
return err;
77
}
78
79
static int crypto_chacha_crypt_generic(struct skcipher_request *req)
80
{
81
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
82
const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
83
84
return chacha_stream_xor(req, ctx, req->iv, false);
85
}
86
87
static int crypto_chacha_crypt_arch(struct skcipher_request *req)
88
{
89
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
90
const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
91
92
return chacha_stream_xor(req, ctx, req->iv, true);
93
}
94
95
static int crypto_xchacha_crypt(struct skcipher_request *req, bool arch)
96
{
97
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
98
const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
99
struct chacha_ctx subctx;
100
struct chacha_state state;
101
u8 real_iv[16];
102
103
/* Compute the subkey given the original key and first 128 nonce bits */
104
chacha_init(&state, ctx->key, req->iv);
105
if (arch)
106
hchacha_block(&state, subctx.key, ctx->nrounds);
107
else
108
hchacha_block_generic(&state, subctx.key, ctx->nrounds);
109
subctx.nrounds = ctx->nrounds;
110
111
/* Build the real IV */
112
memcpy(&real_iv[0], req->iv + 24, 8); /* stream position */
113
memcpy(&real_iv[8], req->iv + 16, 8); /* remaining 64 nonce bits */
114
115
/* Generate the stream and XOR it with the data */
116
return chacha_stream_xor(req, &subctx, real_iv, arch);
117
}
118
119
static int crypto_xchacha_crypt_generic(struct skcipher_request *req)
120
{
121
return crypto_xchacha_crypt(req, false);
122
}
123
124
static int crypto_xchacha_crypt_arch(struct skcipher_request *req)
125
{
126
return crypto_xchacha_crypt(req, true);
127
}
128
129
static struct skcipher_alg algs[] = {
130
{
131
.base.cra_name = "chacha20",
132
.base.cra_driver_name = "chacha20-generic",
133
.base.cra_priority = 100,
134
.base.cra_blocksize = 1,
135
.base.cra_ctxsize = sizeof(struct chacha_ctx),
136
.base.cra_module = THIS_MODULE,
137
138
.min_keysize = CHACHA_KEY_SIZE,
139
.max_keysize = CHACHA_KEY_SIZE,
140
.ivsize = CHACHA_IV_SIZE,
141
.chunksize = CHACHA_BLOCK_SIZE,
142
.setkey = chacha20_setkey,
143
.encrypt = crypto_chacha_crypt_generic,
144
.decrypt = crypto_chacha_crypt_generic,
145
},
146
{
147
.base.cra_name = "xchacha20",
148
.base.cra_driver_name = "xchacha20-generic",
149
.base.cra_priority = 100,
150
.base.cra_blocksize = 1,
151
.base.cra_ctxsize = sizeof(struct chacha_ctx),
152
.base.cra_module = THIS_MODULE,
153
154
.min_keysize = CHACHA_KEY_SIZE,
155
.max_keysize = CHACHA_KEY_SIZE,
156
.ivsize = XCHACHA_IV_SIZE,
157
.chunksize = CHACHA_BLOCK_SIZE,
158
.setkey = chacha20_setkey,
159
.encrypt = crypto_xchacha_crypt_generic,
160
.decrypt = crypto_xchacha_crypt_generic,
161
},
162
{
163
.base.cra_name = "xchacha12",
164
.base.cra_driver_name = "xchacha12-generic",
165
.base.cra_priority = 100,
166
.base.cra_blocksize = 1,
167
.base.cra_ctxsize = sizeof(struct chacha_ctx),
168
.base.cra_module = THIS_MODULE,
169
170
.min_keysize = CHACHA_KEY_SIZE,
171
.max_keysize = CHACHA_KEY_SIZE,
172
.ivsize = XCHACHA_IV_SIZE,
173
.chunksize = CHACHA_BLOCK_SIZE,
174
.setkey = chacha12_setkey,
175
.encrypt = crypto_xchacha_crypt_generic,
176
.decrypt = crypto_xchacha_crypt_generic,
177
},
178
{
179
.base.cra_name = "chacha20",
180
.base.cra_driver_name = "chacha20-" __stringify(ARCH),
181
.base.cra_priority = 300,
182
.base.cra_blocksize = 1,
183
.base.cra_ctxsize = sizeof(struct chacha_ctx),
184
.base.cra_module = THIS_MODULE,
185
186
.min_keysize = CHACHA_KEY_SIZE,
187
.max_keysize = CHACHA_KEY_SIZE,
188
.ivsize = CHACHA_IV_SIZE,
189
.chunksize = CHACHA_BLOCK_SIZE,
190
.setkey = chacha20_setkey,
191
.encrypt = crypto_chacha_crypt_arch,
192
.decrypt = crypto_chacha_crypt_arch,
193
},
194
{
195
.base.cra_name = "xchacha20",
196
.base.cra_driver_name = "xchacha20-" __stringify(ARCH),
197
.base.cra_priority = 300,
198
.base.cra_blocksize = 1,
199
.base.cra_ctxsize = sizeof(struct chacha_ctx),
200
.base.cra_module = THIS_MODULE,
201
202
.min_keysize = CHACHA_KEY_SIZE,
203
.max_keysize = CHACHA_KEY_SIZE,
204
.ivsize = XCHACHA_IV_SIZE,
205
.chunksize = CHACHA_BLOCK_SIZE,
206
.setkey = chacha20_setkey,
207
.encrypt = crypto_xchacha_crypt_arch,
208
.decrypt = crypto_xchacha_crypt_arch,
209
},
210
{
211
.base.cra_name = "xchacha12",
212
.base.cra_driver_name = "xchacha12-" __stringify(ARCH),
213
.base.cra_priority = 300,
214
.base.cra_blocksize = 1,
215
.base.cra_ctxsize = sizeof(struct chacha_ctx),
216
.base.cra_module = THIS_MODULE,
217
218
.min_keysize = CHACHA_KEY_SIZE,
219
.max_keysize = CHACHA_KEY_SIZE,
220
.ivsize = XCHACHA_IV_SIZE,
221
.chunksize = CHACHA_BLOCK_SIZE,
222
.setkey = chacha12_setkey,
223
.encrypt = crypto_xchacha_crypt_arch,
224
.decrypt = crypto_xchacha_crypt_arch,
225
}
226
};
227
228
static unsigned int num_algs;
229
230
static int __init crypto_chacha_mod_init(void)
231
{
232
/* register the arch flavours only if they differ from generic */
233
num_algs = ARRAY_SIZE(algs);
234
BUILD_BUG_ON(ARRAY_SIZE(algs) % 2 != 0);
235
if (!chacha_is_arch_optimized())
236
num_algs /= 2;
237
238
return crypto_register_skciphers(algs, num_algs);
239
}
240
241
static void __exit crypto_chacha_mod_fini(void)
242
{
243
crypto_unregister_skciphers(algs, num_algs);
244
}
245
246
module_init(crypto_chacha_mod_init);
247
module_exit(crypto_chacha_mod_fini);
248
249
MODULE_LICENSE("GPL");
250
MODULE_AUTHOR("Martin Willi <[email protected]>");
251
MODULE_DESCRIPTION("Crypto API wrappers for the ChaCha20, XChaCha20, and XChaCha12 stream ciphers");
252
MODULE_ALIAS_CRYPTO("chacha20");
253
MODULE_ALIAS_CRYPTO("chacha20-generic");
254
MODULE_ALIAS_CRYPTO("chacha20-" __stringify(ARCH));
255
MODULE_ALIAS_CRYPTO("xchacha20");
256
MODULE_ALIAS_CRYPTO("xchacha20-generic");
257
MODULE_ALIAS_CRYPTO("xchacha20-" __stringify(ARCH));
258
MODULE_ALIAS_CRYPTO("xchacha12");
259
MODULE_ALIAS_CRYPTO("xchacha12-generic");
260
MODULE_ALIAS_CRYPTO("xchacha12-" __stringify(ARCH));
261
262