Blame view

crypto/seqiv.c 5.44 KB
0a270321d   Herbert Xu   [CRYPTO] seqiv: A...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * seqiv: Sequence Number IV Generator
   *
   * This generator generates an IV based on a sequence number by xoring it
   * with a salt.  This algorithm is mainly useful for CTR and similar modes.
   *
   * 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.
   *
   */
661cfd0e5   Herbert Xu   crypto: seqiv - U...
15
  #include <crypto/internal/geniv.h>
856e3f409   Herbert Xu   crypto: seqiv - A...
16
  #include <crypto/scatterwalk.h>
3a01d0ee2   Herbert Xu   crypto: skcipher ...
17
  #include <crypto/skcipher.h>
0a270321d   Herbert Xu   [CRYPTO] seqiv: A...
18
19
20
21
  #include <linux/err.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
22
  #include <linux/slab.h>
0a270321d   Herbert Xu   [CRYPTO] seqiv: A...
23
  #include <linux/string.h>
0677157b2   Herbert Xu   crypto: seqiv - U...
24
  static void seqiv_free(struct crypto_instance *inst);
856e3f409   Herbert Xu   crypto: seqiv - A...
25
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
  static void seqiv_aead_encrypt_complete2(struct aead_request *req, int err)
  {
  	struct aead_request *subreq = aead_request_ctx(req);
  	struct crypto_aead *geniv;
  
  	if (err == -EINPROGRESS)
  		return;
  
  	if (err)
  		goto out;
  
  	geniv = crypto_aead_reqtfm(req);
  	memcpy(req->iv, subreq->iv, crypto_aead_ivsize(geniv));
  
  out:
  	kzfree(subreq->iv);
  }
  
  static void seqiv_aead_encrypt_complete(struct crypto_async_request *base,
  					int err)
  {
  	struct aead_request *req = base->data;
  
  	seqiv_aead_encrypt_complete2(req, err);
  	aead_request_complete(req, err);
  }
856e3f409   Herbert Xu   crypto: seqiv - A...
51
52
53
  static int seqiv_aead_encrypt(struct aead_request *req)
  {
  	struct crypto_aead *geniv = crypto_aead_reqtfm(req);
659e7f528   Herbert Xu   crypto: seqiv - U...
54
  	struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
856e3f409   Herbert Xu   crypto: seqiv - A...
55
56
57
58
  	struct aead_request *subreq = aead_request_ctx(req);
  	crypto_completion_t compl;
  	void *data;
  	u8 *info;
dd04446e4   Herbert Xu   crypto: seqiv - S...
59
  	unsigned int ivsize = 8;
856e3f409   Herbert Xu   crypto: seqiv - A...
60
  	int err;
dd04446e4   Herbert Xu   crypto: seqiv - S...
61
62
  	if (req->cryptlen < ivsize)
  		return -EINVAL;
659e7f528   Herbert Xu   crypto: seqiv - U...
63
  	aead_request_set_tfm(subreq, ctx->child);
856e3f409   Herbert Xu   crypto: seqiv - A...
64
65
66
67
  
  	compl = req->base.complete;
  	data = req->base.data;
  	info = req->iv;
856e3f409   Herbert Xu   crypto: seqiv - A...
68
  	if (req->src != req->dst) {
ef22871f2   Herbert Xu   crypto: seqiv - U...
69
  		SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull);
856e3f409   Herbert Xu   crypto: seqiv - A...
70

ef22871f2   Herbert Xu   crypto: seqiv - U...
71
72
73
74
75
76
77
78
  		skcipher_request_set_tfm(nreq, ctx->sknull);
  		skcipher_request_set_callback(nreq, req->base.flags,
  					      NULL, NULL);
  		skcipher_request_set_crypt(nreq, req->src, req->dst,
  					   req->assoclen + req->cryptlen,
  					   NULL);
  
  		err = crypto_skcipher_encrypt(nreq);
856e3f409   Herbert Xu   crypto: seqiv - A...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  		if (err)
  			return err;
  	}
  
  	if (unlikely(!IS_ALIGNED((unsigned long)info,
  				 crypto_aead_alignmask(geniv) + 1))) {
  		info = kmalloc(ivsize, req->base.flags &
  				       CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL:
  								  GFP_ATOMIC);
  		if (!info)
  			return -ENOMEM;
  
  		memcpy(info, req->iv, ivsize);
  		compl = seqiv_aead_encrypt_complete;
  		data = req;
  	}
  
  	aead_request_set_callback(subreq, req->base.flags, compl, data);
  	aead_request_set_crypt(subreq, req->dst, req->dst,
  			       req->cryptlen - ivsize, info);
374d4ad18   Herbert Xu   crypto: aead - Re...
99
  	aead_request_set_ad(subreq, req->assoclen + ivsize);
856e3f409   Herbert Xu   crypto: seqiv - A...
100
101
102
103
104
105
106
107
108
  
  	crypto_xor(info, ctx->salt, ivsize);
  	scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1);
  
  	err = crypto_aead_encrypt(subreq);
  	if (unlikely(info != req->iv))
  		seqiv_aead_encrypt_complete2(req, err);
  	return err;
  }
856e3f409   Herbert Xu   crypto: seqiv - A...
109
110
111
  static int seqiv_aead_decrypt(struct aead_request *req)
  {
  	struct crypto_aead *geniv = crypto_aead_reqtfm(req);
659e7f528   Herbert Xu   crypto: seqiv - U...
112
  	struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv);
856e3f409   Herbert Xu   crypto: seqiv - A...
113
114
115
  	struct aead_request *subreq = aead_request_ctx(req);
  	crypto_completion_t compl;
  	void *data;
dd04446e4   Herbert Xu   crypto: seqiv - S...
116
117
118
119
  	unsigned int ivsize = 8;
  
  	if (req->cryptlen < ivsize + crypto_aead_authsize(geniv))
  		return -EINVAL;
856e3f409   Herbert Xu   crypto: seqiv - A...
120

659e7f528   Herbert Xu   crypto: seqiv - U...
121
  	aead_request_set_tfm(subreq, ctx->child);
856e3f409   Herbert Xu   crypto: seqiv - A...
122
123
124
  
  	compl = req->base.complete;
  	data = req->base.data;
856e3f409   Herbert Xu   crypto: seqiv - A...
125
126
127
  	aead_request_set_callback(subreq, req->base.flags, compl, data);
  	aead_request_set_crypt(subreq, req->src, req->dst,
  			       req->cryptlen - ivsize, req->iv);
374d4ad18   Herbert Xu   crypto: aead - Re...
128
  	aead_request_set_ad(subreq, req->assoclen + ivsize);
856e3f409   Herbert Xu   crypto: seqiv - A...
129
130
  
  	scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0);
856e3f409   Herbert Xu   crypto: seqiv - A...
131
132
133
  
  	return crypto_aead_decrypt(subreq);
  }
0677157b2   Herbert Xu   crypto: seqiv - U...
134
  static int seqiv_aead_create(struct crypto_template *tmpl, struct rtattr **tb)
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
135
  {
856e3f409   Herbert Xu   crypto: seqiv - A...
136
137
138
  	struct aead_instance *inst;
  	struct crypto_aead_spawn *spawn;
  	struct aead_alg *alg;
0677157b2   Herbert Xu   crypto: seqiv - U...
139
  	int err;
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
140

0677157b2   Herbert Xu   crypto: seqiv - U...
141
  	inst = aead_geniv_alloc(tmpl, tb, 0, 0);
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
142
143
  
  	if (IS_ERR(inst))
0677157b2   Herbert Xu   crypto: seqiv - U...
144
145
146
  		return PTR_ERR(inst);
  
  	inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
147

661cfd0e5   Herbert Xu   crypto: seqiv - U...
148
149
  	spawn = aead_instance_ctx(inst);
  	alg = crypto_spawn_aead_alg(spawn);
0677157b2   Herbert Xu   crypto: seqiv - U...
150
  	err = -EINVAL;
dd04446e4   Herbert Xu   crypto: seqiv - S...
151
  	if (inst->alg.ivsize != sizeof(u64))
0677157b2   Herbert Xu   crypto: seqiv - U...
152
  		goto free_inst;
c0ecf8916   Herbert Xu   crypto: seqiv - E...
153

b7dcfab4a   Herbert Xu   crypto: seqiv - M...
154
  	inst->alg.encrypt = seqiv_aead_encrypt;
856e3f409   Herbert Xu   crypto: seqiv - A...
155
  	inst->alg.decrypt = seqiv_aead_decrypt;
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
156

659e7f528   Herbert Xu   crypto: seqiv - U...
157
158
  	inst->alg.init = aead_init_geniv;
  	inst->alg.exit = aead_exit_geniv;
856e3f409   Herbert Xu   crypto: seqiv - A...
159

659e7f528   Herbert Xu   crypto: seqiv - U...
160
  	inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx);
5964f26c9   Herbert Xu   crypto: seqiv - R...
161
  	inst->alg.base.cra_ctxsize += inst->alg.ivsize;
856e3f409   Herbert Xu   crypto: seqiv - A...
162

0677157b2   Herbert Xu   crypto: seqiv - U...
163
164
165
  	err = aead_register_instance(tmpl, inst);
  	if (err)
  		goto free_inst;
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
166
  out:
0677157b2   Herbert Xu   crypto: seqiv - U...
167
168
169
170
171
  	return err;
  
  free_inst:
  	aead_geniv_free(inst);
  	goto out;
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
172
  }
0677157b2   Herbert Xu   crypto: seqiv - U...
173
  static int seqiv_create(struct crypto_template *tmpl, struct rtattr **tb)
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
174
175
  {
  	struct crypto_attr_type *algt;
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
176
177
  
  	algt = crypto_get_attr_type(tb);
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
178
  	if (IS_ERR(algt))
0677157b2   Herbert Xu   crypto: seqiv - U...
179
  		return PTR_ERR(algt);
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
180
181
  
  	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & CRYPTO_ALG_TYPE_MASK)
3a01d0ee2   Herbert Xu   crypto: skcipher ...
182
  		return -EINVAL;
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
183

3a01d0ee2   Herbert Xu   crypto: skcipher ...
184
  	return seqiv_aead_create(tmpl, tb);
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
185
186
187
188
  }
  
  static void seqiv_free(struct crypto_instance *inst)
  {
3a01d0ee2   Herbert Xu   crypto: skcipher ...
189
  	aead_geniv_free(aead_instance(inst));
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
190
  }
0a270321d   Herbert Xu   [CRYPTO] seqiv: A...
191
192
  static struct crypto_template seqiv_tmpl = {
  	.name = "seqiv",
0677157b2   Herbert Xu   crypto: seqiv - U...
193
  	.create = seqiv_create,
14df4d804   Herbert Xu   [CRYPTO] seqiv: A...
194
  	.free = seqiv_free,
0a270321d   Herbert Xu   [CRYPTO] seqiv: A...
195
196
197
198
199
  	.module = THIS_MODULE,
  };
  
  static int __init seqiv_module_init(void)
  {
8a2cd1c4a   Herbert Xu   crypto: seqiv - R...
200
  	return crypto_register_template(&seqiv_tmpl);
0a270321d   Herbert Xu   [CRYPTO] seqiv: A...
201
202
203
204
205
206
207
208
209
210
211
212
  }
  
  static void __exit seqiv_module_exit(void)
  {
  	crypto_unregister_template(&seqiv_tmpl);
  }
  
  module_init(seqiv_module_init);
  module_exit(seqiv_module_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Sequence Number IV Generator");
4943ba16b   Kees Cook   crypto: include c...
213
  MODULE_ALIAS_CRYPTO("seqiv");