Blame view

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