Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/crypto/eseqiv.c
10814 views
1
/*
2
* eseqiv: Encrypted Sequence Number IV Generator
3
*
4
* This generator generates an IV based on a sequence number by xoring it
5
* with a salt and then encrypting it with the same key as used to encrypt
6
* the plain text. This algorithm requires that the block size be equal
7
* to the IV size. It is mainly useful for CBC.
8
*
9
* Copyright (c) 2007 Herbert Xu <[email protected]>
10
*
11
* This program is free software; you can redistribute it and/or modify it
12
* under the terms of the GNU General Public License as published by the Free
13
* Software Foundation; either version 2 of the License, or (at your option)
14
* any later version.
15
*
16
*/
17
18
#include <crypto/internal/skcipher.h>
19
#include <crypto/rng.h>
20
#include <crypto/scatterwalk.h>
21
#include <linux/err.h>
22
#include <linux/init.h>
23
#include <linux/kernel.h>
24
#include <linux/mm.h>
25
#include <linux/module.h>
26
#include <linux/scatterlist.h>
27
#include <linux/spinlock.h>
28
#include <linux/string.h>
29
30
struct eseqiv_request_ctx {
31
struct scatterlist src[2];
32
struct scatterlist dst[2];
33
char tail[];
34
};
35
36
struct eseqiv_ctx {
37
spinlock_t lock;
38
unsigned int reqoff;
39
char salt[];
40
};
41
42
static void eseqiv_complete2(struct skcipher_givcrypt_request *req)
43
{
44
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
45
struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req);
46
47
memcpy(req->giv, PTR_ALIGN((u8 *)reqctx->tail,
48
crypto_ablkcipher_alignmask(geniv) + 1),
49
crypto_ablkcipher_ivsize(geniv));
50
}
51
52
static void eseqiv_complete(struct crypto_async_request *base, int err)
53
{
54
struct skcipher_givcrypt_request *req = base->data;
55
56
if (err)
57
goto out;
58
59
eseqiv_complete2(req);
60
61
out:
62
skcipher_givcrypt_complete(req, err);
63
}
64
65
static int eseqiv_givencrypt(struct skcipher_givcrypt_request *req)
66
{
67
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
68
struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
69
struct eseqiv_request_ctx *reqctx = skcipher_givcrypt_reqctx(req);
70
struct ablkcipher_request *subreq;
71
crypto_completion_t complete;
72
void *data;
73
struct scatterlist *osrc, *odst;
74
struct scatterlist *dst;
75
struct page *srcp;
76
struct page *dstp;
77
u8 *giv;
78
u8 *vsrc;
79
u8 *vdst;
80
__be64 seq;
81
unsigned int ivsize;
82
unsigned int len;
83
int err;
84
85
subreq = (void *)(reqctx->tail + ctx->reqoff);
86
ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
87
88
giv = req->giv;
89
complete = req->creq.base.complete;
90
data = req->creq.base.data;
91
92
osrc = req->creq.src;
93
odst = req->creq.dst;
94
srcp = sg_page(osrc);
95
dstp = sg_page(odst);
96
vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + osrc->offset;
97
vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + odst->offset;
98
99
ivsize = crypto_ablkcipher_ivsize(geniv);
100
101
if (vsrc != giv + ivsize && vdst != giv + ivsize) {
102
giv = PTR_ALIGN((u8 *)reqctx->tail,
103
crypto_ablkcipher_alignmask(geniv) + 1);
104
complete = eseqiv_complete;
105
data = req;
106
}
107
108
ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete,
109
data);
110
111
sg_init_table(reqctx->src, 2);
112
sg_set_buf(reqctx->src, giv, ivsize);
113
scatterwalk_crypto_chain(reqctx->src, osrc, vsrc == giv + ivsize, 2);
114
115
dst = reqctx->src;
116
if (osrc != odst) {
117
sg_init_table(reqctx->dst, 2);
118
sg_set_buf(reqctx->dst, giv, ivsize);
119
scatterwalk_crypto_chain(reqctx->dst, odst, vdst == giv + ivsize, 2);
120
121
dst = reqctx->dst;
122
}
123
124
ablkcipher_request_set_crypt(subreq, reqctx->src, dst,
125
req->creq.nbytes + ivsize,
126
req->creq.info);
127
128
memcpy(req->creq.info, ctx->salt, ivsize);
129
130
len = ivsize;
131
if (ivsize > sizeof(u64)) {
132
memset(req->giv, 0, ivsize - sizeof(u64));
133
len = sizeof(u64);
134
}
135
seq = cpu_to_be64(req->seq);
136
memcpy(req->giv + ivsize - len, &seq, len);
137
138
err = crypto_ablkcipher_encrypt(subreq);
139
if (err)
140
goto out;
141
142
if (giv != req->giv)
143
eseqiv_complete2(req);
144
145
out:
146
return err;
147
}
148
149
static int eseqiv_givencrypt_first(struct skcipher_givcrypt_request *req)
150
{
151
struct crypto_ablkcipher *geniv = skcipher_givcrypt_reqtfm(req);
152
struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
153
int err = 0;
154
155
spin_lock_bh(&ctx->lock);
156
if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first)
157
goto unlock;
158
159
crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
160
err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt,
161
crypto_ablkcipher_ivsize(geniv));
162
163
unlock:
164
spin_unlock_bh(&ctx->lock);
165
166
if (err)
167
return err;
168
169
return eseqiv_givencrypt(req);
170
}
171
172
static int eseqiv_init(struct crypto_tfm *tfm)
173
{
174
struct crypto_ablkcipher *geniv = __crypto_ablkcipher_cast(tfm);
175
struct eseqiv_ctx *ctx = crypto_ablkcipher_ctx(geniv);
176
unsigned long alignmask;
177
unsigned int reqsize;
178
179
spin_lock_init(&ctx->lock);
180
181
alignmask = crypto_tfm_ctx_alignment() - 1;
182
reqsize = sizeof(struct eseqiv_request_ctx);
183
184
if (alignmask & reqsize) {
185
alignmask &= reqsize;
186
alignmask--;
187
}
188
189
alignmask = ~alignmask;
190
alignmask &= crypto_ablkcipher_alignmask(geniv);
191
192
reqsize += alignmask;
193
reqsize += crypto_ablkcipher_ivsize(geniv);
194
reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment());
195
196
ctx->reqoff = reqsize - sizeof(struct eseqiv_request_ctx);
197
198
tfm->crt_ablkcipher.reqsize = reqsize +
199
sizeof(struct ablkcipher_request);
200
201
return skcipher_geniv_init(tfm);
202
}
203
204
static struct crypto_template eseqiv_tmpl;
205
206
static struct crypto_instance *eseqiv_alloc(struct rtattr **tb)
207
{
208
struct crypto_instance *inst;
209
int err;
210
211
err = crypto_get_default_rng();
212
if (err)
213
return ERR_PTR(err);
214
215
inst = skcipher_geniv_alloc(&eseqiv_tmpl, tb, 0, 0);
216
if (IS_ERR(inst))
217
goto put_rng;
218
219
err = -EINVAL;
220
if (inst->alg.cra_ablkcipher.ivsize != inst->alg.cra_blocksize)
221
goto free_inst;
222
223
inst->alg.cra_ablkcipher.givencrypt = eseqiv_givencrypt_first;
224
225
inst->alg.cra_init = eseqiv_init;
226
inst->alg.cra_exit = skcipher_geniv_exit;
227
228
inst->alg.cra_ctxsize = sizeof(struct eseqiv_ctx);
229
inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
230
231
out:
232
return inst;
233
234
free_inst:
235
skcipher_geniv_free(inst);
236
inst = ERR_PTR(err);
237
put_rng:
238
crypto_put_default_rng();
239
goto out;
240
}
241
242
static void eseqiv_free(struct crypto_instance *inst)
243
{
244
skcipher_geniv_free(inst);
245
crypto_put_default_rng();
246
}
247
248
static struct crypto_template eseqiv_tmpl = {
249
.name = "eseqiv",
250
.alloc = eseqiv_alloc,
251
.free = eseqiv_free,
252
.module = THIS_MODULE,
253
};
254
255
static int __init eseqiv_module_init(void)
256
{
257
return crypto_register_template(&eseqiv_tmpl);
258
}
259
260
static void __exit eseqiv_module_exit(void)
261
{
262
crypto_unregister_template(&eseqiv_tmpl);
263
}
264
265
module_init(eseqiv_module_init);
266
module_exit(eseqiv_module_exit);
267
268
MODULE_LICENSE("GPL");
269
MODULE_DESCRIPTION("Encrypted Sequence Number IV Generator");
270
271