Branch data Line data Source code
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 <herbert@gondor.apana.org.au>
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 : 0 : 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 : 0 : memcpy(req->giv, PTR_ALIGN((u8 *)reqctx->tail,
48 : : crypto_ablkcipher_alignmask(geniv) + 1),
49 : : crypto_ablkcipher_ivsize(geniv));
50 : 0 : }
51 : :
52 : 0 : static void eseqiv_complete(struct crypto_async_request *base, int err)
53 : : {
54 : 0 : struct skcipher_givcrypt_request *req = base->data;
55 : :
56 [ # # ]: 0 : if (err)
57 : : goto out;
58 : :
59 : 0 : eseqiv_complete2(req);
60 : :
61 : : out:
62 : : skcipher_givcrypt_complete(req, err);
63 : 0 : }
64 : :
65 : 0 : 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 : 0 : 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 : 0 : subreq = (void *)(reqctx->tail + ctx->reqoff);
86 : : ablkcipher_request_set_tfm(subreq, skcipher_geniv_cipher(geniv));
87 : :
88 : 0 : giv = req->giv;
89 : 0 : complete = req->creq.base.complete;
90 : 0 : data = req->creq.base.data;
91 : :
92 : 0 : osrc = req->creq.src;
93 : 0 : odst = req->creq.dst;
94 : : srcp = sg_page(osrc);
95 : : dstp = sg_page(odst);
96 [ # # ]: 0 : vsrc = PageHighMem(srcp) ? NULL : page_address(srcp) + osrc->offset;
97 [ # # ]: 0 : vdst = PageHighMem(dstp) ? NULL : page_address(dstp) + odst->offset;
98 : :
99 : : ivsize = crypto_ablkcipher_ivsize(geniv);
100 : :
101 [ # # ][ # # ]: 0 : if (vsrc != giv + ivsize && vdst != giv + ivsize) {
102 : 0 : giv = PTR_ALIGN((u8 *)reqctx->tail,
103 : : crypto_ablkcipher_alignmask(geniv) + 1);
104 : : complete = eseqiv_complete;
105 : : data = req;
106 : : }
107 : :
108 : 0 : ablkcipher_request_set_callback(subreq, req->creq.base.flags, complete,
109 : : data);
110 : :
111 : 0 : sg_init_table(reqctx->src, 2);
112 : : sg_set_buf(reqctx->src, giv, ivsize);
113 : 0 : scatterwalk_crypto_chain(reqctx->src, osrc, vsrc == giv + ivsize, 2);
114 : :
115 : : dst = reqctx->src;
116 [ # # ]: 0 : if (osrc != odst) {
117 : 0 : 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 : 0 : ablkcipher_request_set_crypt(subreq, reqctx->src, dst,
125 : 0 : req->creq.nbytes + ivsize,
126 : : req->creq.info);
127 : :
128 : 0 : memcpy(req->creq.info, ctx->salt, ivsize);
129 : :
130 : : len = ivsize;
131 [ # # ]: 0 : if (ivsize > sizeof(u64)) {
132 [ # # ]: 0 : memset(req->giv, 0, ivsize - sizeof(u64));
133 : : len = sizeof(u64);
134 : : }
135 [ # # ]: 0 : seq = cpu_to_be64(req->seq);
136 : 0 : memcpy(req->giv + ivsize - len, &seq, len);
137 : :
138 : : err = crypto_ablkcipher_encrypt(subreq);
139 [ # # ]: 0 : if (err)
140 : : goto out;
141 : :
142 [ # # ]: 0 : if (giv != req->giv)
143 : 0 : eseqiv_complete2(req);
144 : :
145 : : out:
146 : 0 : return err;
147 : : }
148 : :
149 : 0 : 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 [ # # ]: 0 : if (crypto_ablkcipher_crt(geniv)->givencrypt != eseqiv_givencrypt_first)
157 : : goto unlock;
158 : :
159 : 0 : crypto_ablkcipher_crt(geniv)->givencrypt = eseqiv_givencrypt;
160 : 0 : 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 [ # # ]: 0 : if (err)
167 : : return err;
168 : :
169 : 0 : return eseqiv_givencrypt(req);
170 : : }
171 : :
172 : 0 : 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 : 0 : 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 : 0 : alignmask &= crypto_ablkcipher_alignmask(geniv);
191 : :
192 : 0 : reqsize += alignmask;
193 : 0 : reqsize += crypto_ablkcipher_ivsize(geniv);
194 : 0 : reqsize = ALIGN(reqsize, crypto_tfm_ctx_alignment());
195 : :
196 : 0 : ctx->reqoff = reqsize - sizeof(struct eseqiv_request_ctx);
197 : :
198 : 0 : tfm->crt_ablkcipher.reqsize = reqsize +
199 : : sizeof(struct ablkcipher_request);
200 : :
201 : 0 : return skcipher_geniv_init(tfm);
202 : : }
203 : :
204 : : static struct crypto_template eseqiv_tmpl;
205 : :
206 : 0 : static struct crypto_instance *eseqiv_alloc(struct rtattr **tb)
207 : : {
208 : : struct crypto_instance *inst;
209 : : int err;
210 : :
211 : 0 : err = crypto_get_default_rng();
212 [ # # ]: 0 : if (err)
213 : 0 : return ERR_PTR(err);
214 : :
215 : 0 : inst = skcipher_geniv_alloc(&eseqiv_tmpl, tb, 0, 0);
216 [ # # ]: 0 : if (IS_ERR(inst))
217 : : goto put_rng;
218 : :
219 : : err = -EINVAL;
220 [ # # ]: 0 : if (inst->alg.cra_ablkcipher.ivsize != inst->alg.cra_blocksize)
221 : : goto free_inst;
222 : :
223 : 0 : inst->alg.cra_ablkcipher.givencrypt = eseqiv_givencrypt_first;
224 : :
225 : 0 : inst->alg.cra_init = eseqiv_init;
226 : 0 : inst->alg.cra_exit = skcipher_geniv_exit;
227 : :
228 : 0 : inst->alg.cra_ctxsize = sizeof(struct eseqiv_ctx);
229 : 0 : inst->alg.cra_ctxsize += inst->alg.cra_ablkcipher.ivsize;
230 : :
231 : : out:
232 : 0 : return inst;
233 : :
234 : : free_inst:
235 : 0 : skcipher_geniv_free(inst);
236 : : inst = ERR_PTR(err);
237 : : put_rng:
238 : 0 : crypto_put_default_rng();
239 : 0 : goto out;
240 : : }
241 : :
242 : 0 : static void eseqiv_free(struct crypto_instance *inst)
243 : : {
244 : 0 : skcipher_geniv_free(inst);
245 : 0 : crypto_put_default_rng();
246 : 0 : }
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 : 0 : static int __init eseqiv_module_init(void)
256 : : {
257 : 0 : return crypto_register_template(&eseqiv_tmpl);
258 : : }
259 : :
260 : 0 : static void __exit eseqiv_module_exit(void)
261 : : {
262 : 0 : crypto_unregister_template(&eseqiv_tmpl);
263 : 0 : }
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");
|