Blame view

crypto/gcm.c 33.5 KB
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1
2
3
4
5
6
7
8
9
  /*
   * GCM: Galois/Counter Mode.
   *
   * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 as published
   * by the Free Software Foundation.
   */
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
10
  #include <crypto/gf128mul.h>
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
11
  #include <crypto/internal/aead.h>
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
12
  #include <crypto/internal/skcipher.h>
9382d97af   Huang Ying   crypto: gcm - Use...
13
  #include <crypto/internal/hash.h>
17db85469   Herbert Xu   crypto: gcm - Use...
14
  #include <crypto/null.h>
42c271c6c   Herbert Xu   [CRYPTO] scatterw...
15
  #include <crypto/scatterwalk.h>
9382d97af   Huang Ying   crypto: gcm - Use...
16
17
  #include <crypto/hash.h>
  #include "internal.h"
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
18
  #include <linux/completion.h>
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
19
20
21
22
23
  #include <linux/err.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/slab.h>
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
24
  struct gcm_instance_ctx {
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
25
  	struct crypto_skcipher_spawn ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
26
  	struct crypto_ahash_spawn ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
27
28
29
  };
  
  struct crypto_gcm_ctx {
16f37ecdd   Herbert Xu   crypto: gcm - Use...
30
  	struct crypto_skcipher *ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
31
  	struct crypto_ahash *ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
32
  };
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
33
34
35
36
  struct crypto_rfc4106_ctx {
  	struct crypto_aead *child;
  	u8 nonce[4];
  };
7b05a373a   Herbert Xu   crypto: gcm - Use...
37
38
39
40
41
  struct crypto_rfc4106_req_ctx {
  	struct scatterlist src[3];
  	struct scatterlist dst[3];
  	struct aead_request subreq;
  };
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
42
43
  struct crypto_rfc4543_instance_ctx {
  	struct crypto_aead_spawn aead;
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
44
  };
73c89c15b   Tobias Brunner   crypto: gcm - Add...
45
46
  struct crypto_rfc4543_ctx {
  	struct crypto_aead *child;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
47
  	struct crypto_skcipher *null;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
48
49
50
51
  	u8 nonce[4];
  };
  
  struct crypto_rfc4543_req_ctx {
73c89c15b   Tobias Brunner   crypto: gcm - Add...
52
53
  	struct aead_request subreq;
  };
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
54
  struct crypto_gcm_ghash_ctx {
9382d97af   Huang Ying   crypto: gcm - Use...
55
56
  	unsigned int cryptlen;
  	struct scatterlist *src;
adcbc688f   Herbert Xu   crypto: gcm - Con...
57
  	int (*complete)(struct aead_request *req, u32 flags);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
58
59
60
  };
  
  struct crypto_gcm_req_priv_ctx {
adcbc688f   Herbert Xu   crypto: gcm - Con...
61
  	u8 iv[16];
dc0d0dc42   Franck LENORMAND   MLK-19365: crypto...
62
63
64
65
66
67
68
69
70
71
72
  
  	/*
  	 * We need to force auth_tag to be on its own cacheline.
  	 *
  	 * We put it on its cacheline with the macro ____cacheline_aligned.
  	 * The next fields must be on another cacheline so we add a dummy field
  	 * which is located on another cacheline to enforce that.
  	 */
  	u8 auth_tag[16] ____cacheline_aligned;
  
  	u8 dummy_align_auth_tag ____cacheline_aligned;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
73
  	u8 iauth_tag[16];
adcbc688f   Herbert Xu   crypto: gcm - Con...
74
75
76
  	struct scatterlist src[3];
  	struct scatterlist dst[3];
  	struct scatterlist sg;
9382d97af   Huang Ying   crypto: gcm - Use...
77
78
79
  	struct crypto_gcm_ghash_ctx ghash_ctx;
  	union {
  		struct ahash_request ahreq;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
80
  		struct skcipher_request skreq;
9382d97af   Huang Ying   crypto: gcm - Use...
81
  	} u;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
82
  };
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
83
84
85
86
  struct crypto_gcm_setkey_result {
  	int err;
  	struct completion completion;
  };
adcbc688f   Herbert Xu   crypto: gcm - Con...
87
88
89
90
91
92
  static struct {
  	u8 buf[16];
  	struct scatterlist sg;
  } *gcm_zeroes;
  
  static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc);
9382d97af   Huang Ying   crypto: gcm - Use...
93

2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
94
95
96
97
98
99
100
  static inline struct crypto_gcm_req_priv_ctx *crypto_gcm_reqctx(
  	struct aead_request *req)
  {
  	unsigned long align = crypto_aead_alignmask(crypto_aead_reqtfm(req));
  
  	return (void *)PTR_ALIGN((u8 *)aead_request_ctx(req), align + 1);
  }
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
101
  static void crypto_gcm_setkey_done(struct crypto_async_request *req, int err)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
102
  {
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
103
  	struct crypto_gcm_setkey_result *result = req->data;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
104

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
105
106
107
108
109
  	if (err == -EINPROGRESS)
  		return;
  
  	result->err = err;
  	complete(&result->completion);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
110
111
112
113
114
115
  }
  
  static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
  			     unsigned int keylen)
  {
  	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
9382d97af   Huang Ying   crypto: gcm - Use...
116
  	struct crypto_ahash *ghash = ctx->ghash;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
117
  	struct crypto_skcipher *ctr = ctx->ctr;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
118
119
  	struct {
  		be128 hash;
50d2e6dc1   Ondrej Mosnáček   crypto: gcm - Fix...
120
  		u8 iv[16];
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
121

bc08b5144   Radu Solea   MLK-14785 CAAM: F...
122
  		struct crypto_gcm_setkey_result result ____cacheline_aligned;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
123
124
  
  		struct scatterlist sg[1];
16f37ecdd   Herbert Xu   crypto: gcm - Use...
125
  		struct skcipher_request req;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
126
127
  	} *data;
  	int err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
128

16f37ecdd   Herbert Xu   crypto: gcm - Use...
129
130
131
132
133
  	crypto_skcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
  	crypto_skcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
  				       CRYPTO_TFM_REQ_MASK);
  	err = crypto_skcipher_setkey(ctr, key, keylen);
  	crypto_aead_set_flags(aead, crypto_skcipher_get_flags(ctr) &
adcbc688f   Herbert Xu   crypto: gcm - Con...
134
  				    CRYPTO_TFM_RES_MASK);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
135
  	if (err)
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
136
  		return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
137

16f37ecdd   Herbert Xu   crypto: gcm - Use...
138
  	data = kzalloc(sizeof(*data) + crypto_skcipher_reqsize(ctr),
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
139
140
141
142
143
144
  		       GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
  
  	init_completion(&data->result.completion);
  	sg_init_one(data->sg, &data->hash, sizeof(data->hash));
16f37ecdd   Herbert Xu   crypto: gcm - Use...
145
146
147
148
149
150
151
152
153
  	skcipher_request_set_tfm(&data->req, ctr);
  	skcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP |
  						  CRYPTO_TFM_REQ_MAY_BACKLOG,
  				      crypto_gcm_setkey_done,
  				      &data->result);
  	skcipher_request_set_crypt(&data->req, data->sg, data->sg,
  				   sizeof(data->hash), data->iv);
  
  	err = crypto_skcipher_encrypt(&data->req);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
154
  	if (err == -EINPROGRESS || err == -EBUSY) {
f3ad58707   Gilad Ben-Yossef   crypto: gcm - wai...
155
156
  		wait_for_completion(&data->result.completion);
  		err = data->result.err;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
157
  	}
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
158
159
  	if (err)
  		goto out;
9382d97af   Huang Ying   crypto: gcm - Use...
160
161
162
163
164
165
  	crypto_ahash_clear_flags(ghash, CRYPTO_TFM_REQ_MASK);
  	crypto_ahash_set_flags(ghash, crypto_aead_get_flags(aead) &
  			       CRYPTO_TFM_REQ_MASK);
  	err = crypto_ahash_setkey(ghash, (u8 *)&data->hash, sizeof(be128));
  	crypto_aead_set_flags(aead, crypto_ahash_get_flags(ghash) &
  			      CRYPTO_TFM_RES_MASK);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
166

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
167
  out:
adcbc688f   Herbert Xu   crypto: gcm - Con...
168
  	kzfree(data);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
169
170
  	return err;
  }
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
  static int crypto_gcm_setauthsize(struct crypto_aead *tfm,
  				  unsigned int authsize)
  {
  	switch (authsize) {
  	case 4:
  	case 8:
  	case 12:
  	case 13:
  	case 14:
  	case 15:
  	case 16:
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return 0;
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
189
  static void crypto_gcm_init_common(struct aead_request *req)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
190
  {
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
191
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
192
  	__be32 counter = cpu_to_be32(1);
adcbc688f   Herbert Xu   crypto: gcm - Con...
193
  	struct scatterlist *sg;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
194
195
  
  	memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag));
adcbc688f   Herbert Xu   crypto: gcm - Con...
196
197
  	memcpy(pctx->iv, req->iv, 12);
  	memcpy(pctx->iv + 12, &counter, 4);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
198

adcbc688f   Herbert Xu   crypto: gcm - Con...
199
  	sg_init_table(pctx->src, 3);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
200
  	sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag));
adcbc688f   Herbert Xu   crypto: gcm - Con...
201
202
  	sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen);
  	if (sg != pctx->src + 1)
c56f6d127   Dan Williams   crypto: replace s...
203
  		sg_chain(pctx->src, 2, sg);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
204

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
205
  	if (req->src != req->dst) {
adcbc688f   Herbert Xu   crypto: gcm - Con...
206
  		sg_init_table(pctx->dst, 3);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
207
  		sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag));
adcbc688f   Herbert Xu   crypto: gcm - Con...
208
209
  		sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen);
  		if (sg != pctx->dst + 1)
c56f6d127   Dan Williams   crypto: replace s...
210
  			sg_chain(pctx->dst, 2, sg);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
211
  	}
adcbc688f   Herbert Xu   crypto: gcm - Con...
212
213
214
215
216
217
218
219
  }
  
  static void crypto_gcm_init_crypt(struct aead_request *req,
  				  unsigned int cryptlen)
  {
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
220
  	struct skcipher_request *skreq = &pctx->u.skreq;
adcbc688f   Herbert Xu   crypto: gcm - Con...
221
222
223
  	struct scatterlist *dst;
  
  	dst = req->src == req->dst ? pctx->src : pctx->dst;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
224

16f37ecdd   Herbert Xu   crypto: gcm - Use...
225
226
  	skcipher_request_set_tfm(skreq, ctx->ctr);
  	skcipher_request_set_crypt(skreq, pctx->src, dst,
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
227
  				     cryptlen + sizeof(pctx->auth_tag),
adcbc688f   Herbert Xu   crypto: gcm - Con...
228
  				     pctx->iv);
9382d97af   Huang Ying   crypto: gcm - Use...
229
230
231
232
233
234
235
236
237
  }
  
  static inline unsigned int gcm_remain(unsigned int len)
  {
  	len &= 0xfU;
  	return len ? 16 - len : 0;
  }
  
  static void gcm_hash_len_done(struct crypto_async_request *areq, int err);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
238

9382d97af   Huang Ying   crypto: gcm - Use...
239
  static int gcm_hash_update(struct aead_request *req,
3e3dc25fe   Mark Rustad   crypto: Resolve s...
240
  			   crypto_completion_t compl,
9382d97af   Huang Ying   crypto: gcm - Use...
241
  			   struct scatterlist *src,
adcbc688f   Herbert Xu   crypto: gcm - Con...
242
  			   unsigned int len, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
243
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
244
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
245
  	struct ahash_request *ahreq = &pctx->u.ahreq;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
246

adcbc688f   Herbert Xu   crypto: gcm - Con...
247
  	ahash_request_set_callback(ahreq, flags, compl, req);
9382d97af   Huang Ying   crypto: gcm - Use...
248
249
250
  	ahash_request_set_crypt(ahreq, src, NULL, len);
  
  	return crypto_ahash_update(ahreq);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
251
  }
9382d97af   Huang Ying   crypto: gcm - Use...
252
  static int gcm_hash_remain(struct aead_request *req,
9382d97af   Huang Ying   crypto: gcm - Use...
253
  			   unsigned int remain,
adcbc688f   Herbert Xu   crypto: gcm - Con...
254
  			   crypto_completion_t compl, u32 flags)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
255
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
256
  	return gcm_hash_update(req, compl, &gcm_zeroes->sg, remain, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
257
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
258
  static int gcm_hash_len(struct aead_request *req, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
259
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
260
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
261
262
263
264
265
266
267
  	struct ahash_request *ahreq = &pctx->u.ahreq;
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
  	u128 lengths;
  
  	lengths.a = cpu_to_be64(req->assoclen * 8);
  	lengths.b = cpu_to_be64(gctx->cryptlen * 8);
  	memcpy(pctx->iauth_tag, &lengths, 16);
adcbc688f   Herbert Xu   crypto: gcm - Con...
268
269
270
271
  	sg_init_one(&pctx->sg, pctx->iauth_tag, 16);
  	ahash_request_set_callback(ahreq, flags, gcm_hash_len_done, req);
  	ahash_request_set_crypt(ahreq, &pctx->sg,
  				pctx->iauth_tag, sizeof(lengths));
9382d97af   Huang Ying   crypto: gcm - Use...
272

adcbc688f   Herbert Xu   crypto: gcm - Con...
273
  	return crypto_ahash_finup(ahreq);
9382d97af   Huang Ying   crypto: gcm - Use...
274
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
275
  static int gcm_hash_len_continue(struct aead_request *req, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
276
  {
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
277
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
278
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
adcbc688f   Herbert Xu   crypto: gcm - Con...
279
  	return gctx->complete(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
280
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
281
  static void gcm_hash_len_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
282
283
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
284

adcbc688f   Herbert Xu   crypto: gcm - Con...
285
286
  	if (err)
  		goto out;
9382d97af   Huang Ying   crypto: gcm - Use...
287

adcbc688f   Herbert Xu   crypto: gcm - Con...
288
289
290
  	err = gcm_hash_len_continue(req, 0);
  	if (err == -EINPROGRESS)
  		return;
62c5593ae   Huang Ying   crypto: gcm - fix...
291

adcbc688f   Herbert Xu   crypto: gcm - Con...
292
293
  out:
  	aead_request_complete(req, err);
62c5593ae   Huang Ying   crypto: gcm - fix...
294
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
295
  static int gcm_hash_crypt_remain_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
296
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
297
298
  	return gcm_hash_len(req, flags) ?:
  	       gcm_hash_len_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
299
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
300
301
  static void gcm_hash_crypt_remain_done(struct crypto_async_request *areq,
  				       int err)
9382d97af   Huang Ying   crypto: gcm - Use...
302
303
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
304

adcbc688f   Herbert Xu   crypto: gcm - Con...
305
306
307
308
309
310
311
312
313
  	if (err)
  		goto out;
  
  	err = gcm_hash_crypt_remain_continue(req, 0);
  	if (err == -EINPROGRESS)
  		return;
  
  out:
  	aead_request_complete(req, err);
62c5593ae   Huang Ying   crypto: gcm - fix...
314
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
315
  static int gcm_hash_crypt_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
316
  {
9382d97af   Huang Ying   crypto: gcm - Use...
317
318
319
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
  	unsigned int remain;
adcbc688f   Herbert Xu   crypto: gcm - Con...
320
321
322
323
324
  	remain = gcm_remain(gctx->cryptlen);
  	if (remain)
  		return gcm_hash_remain(req, remain,
  				       gcm_hash_crypt_remain_done, flags) ?:
  		       gcm_hash_crypt_remain_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
325

adcbc688f   Herbert Xu   crypto: gcm - Con...
326
  	return gcm_hash_crypt_remain_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
327
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
328
  static void gcm_hash_crypt_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
329
330
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
331

adcbc688f   Herbert Xu   crypto: gcm - Con...
332
333
334
335
336
337
338
339
340
  	if (err)
  		goto out;
  
  	err = gcm_hash_crypt_continue(req, 0);
  	if (err == -EINPROGRESS)
  		return;
  
  out:
  	aead_request_complete(req, err);
62c5593ae   Huang Ying   crypto: gcm - fix...
341
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
342
  static int gcm_hash_assoc_remain_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
343
  {
9382d97af   Huang Ying   crypto: gcm - Use...
344
345
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
9382d97af   Huang Ying   crypto: gcm - Use...
346

adcbc688f   Herbert Xu   crypto: gcm - Con...
347
348
349
350
351
352
  	if (gctx->cryptlen)
  		return gcm_hash_update(req, gcm_hash_crypt_done,
  				       gctx->src, gctx->cryptlen, flags) ?:
  		       gcm_hash_crypt_continue(req, flags);
  
  	return gcm_hash_crypt_remain_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
353
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
354
355
  static void gcm_hash_assoc_remain_done(struct crypto_async_request *areq,
  				       int err)
9382d97af   Huang Ying   crypto: gcm - Use...
356
357
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
358

adcbc688f   Herbert Xu   crypto: gcm - Con...
359
360
361
362
363
364
365
366
367
  	if (err)
  		goto out;
  
  	err = gcm_hash_assoc_remain_continue(req, 0);
  	if (err == -EINPROGRESS)
  		return;
  
  out:
  	aead_request_complete(req, err);
62c5593ae   Huang Ying   crypto: gcm - fix...
368
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
369
  static int gcm_hash_assoc_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
370
  {
9382d97af   Huang Ying   crypto: gcm - Use...
371
  	unsigned int remain;
adcbc688f   Herbert Xu   crypto: gcm - Con...
372
373
374
375
376
  	remain = gcm_remain(req->assoclen);
  	if (remain)
  		return gcm_hash_remain(req, remain,
  				       gcm_hash_assoc_remain_done, flags) ?:
  		       gcm_hash_assoc_remain_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
377

adcbc688f   Herbert Xu   crypto: gcm - Con...
378
  	return gcm_hash_assoc_remain_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
379
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
380
  static void gcm_hash_assoc_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
381
382
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
383

adcbc688f   Herbert Xu   crypto: gcm - Con...
384
385
386
387
388
389
390
391
392
  	if (err)
  		goto out;
  
  	err = gcm_hash_assoc_continue(req, 0);
  	if (err == -EINPROGRESS)
  		return;
  
  out:
  	aead_request_complete(req, err);
62c5593ae   Huang Ying   crypto: gcm - fix...
393
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
394
  static int gcm_hash_init_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
395
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
396
397
398
399
  	if (req->assoclen)
  		return gcm_hash_update(req, gcm_hash_assoc_done,
  				       req->src, req->assoclen, flags) ?:
  		       gcm_hash_assoc_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
400

adcbc688f   Herbert Xu   crypto: gcm - Con...
401
  	return gcm_hash_assoc_remain_continue(req, flags);
62c5593ae   Huang Ying   crypto: gcm - fix...
402
403
404
405
406
  }
  
  static void gcm_hash_init_done(struct crypto_async_request *areq, int err)
  {
  	struct aead_request *req = areq->data;
adcbc688f   Herbert Xu   crypto: gcm - Con...
407
408
409
410
411
412
413
414
415
  	if (err)
  		goto out;
  
  	err = gcm_hash_init_continue(req, 0);
  	if (err == -EINPROGRESS)
  		return;
  
  out:
  	aead_request_complete(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
416
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
417
  static int gcm_hash(struct aead_request *req, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
418
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
419
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
420
  	struct ahash_request *ahreq = &pctx->u.ahreq;
adcbc688f   Herbert Xu   crypto: gcm - Con...
421
  	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
9382d97af   Huang Ying   crypto: gcm - Use...
422
423
  
  	ahash_request_set_tfm(ahreq, ctx->ghash);
adcbc688f   Herbert Xu   crypto: gcm - Con...
424
425
426
  	ahash_request_set_callback(ahreq, flags, gcm_hash_init_done, req);
  	return crypto_ahash_init(ahreq) ?:
  	       gcm_hash_init_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
427
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
428
  static int gcm_enc_copy_hash(struct aead_request *req, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
429
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
430
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
431
432
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	u8 *auth_tag = pctx->auth_tag;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
433

adcbc688f   Herbert Xu   crypto: gcm - Con...
434
435
436
  	crypto_xor(auth_tag, pctx->iauth_tag, 16);
  	scatterwalk_map_and_copy(auth_tag, req->dst,
  				 req->assoclen + req->cryptlen,
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
437
  				 crypto_aead_authsize(aead), 1);
adcbc688f   Herbert Xu   crypto: gcm - Con...
438
  	return 0;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
439
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
440
  static int gcm_encrypt_continue(struct aead_request *req, u32 flags)
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
441
  {
9382d97af   Huang Ying   crypto: gcm - Use...
442
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
adcbc688f   Herbert Xu   crypto: gcm - Con...
443
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
444

adcbc688f   Herbert Xu   crypto: gcm - Con...
445
446
447
  	gctx->src = sg_next(req->src == req->dst ? pctx->src : pctx->dst);
  	gctx->cryptlen = req->cryptlen;
  	gctx->complete = gcm_enc_copy_hash;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
448

adcbc688f   Herbert Xu   crypto: gcm - Con...
449
  	return gcm_hash(req, flags);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
450
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
451
  static void gcm_encrypt_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
452
453
  {
  	struct aead_request *req = areq->data;
9382d97af   Huang Ying   crypto: gcm - Use...
454

adcbc688f   Herbert Xu   crypto: gcm - Con...
455
456
457
458
459
460
  	if (err)
  		goto out;
  
  	err = gcm_encrypt_continue(req, 0);
  	if (err == -EINPROGRESS)
  		return;
9382d97af   Huang Ying   crypto: gcm - Use...
461

adcbc688f   Herbert Xu   crypto: gcm - Con...
462
  out:
62c5593ae   Huang Ying   crypto: gcm - fix...
463
  	aead_request_complete(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
464
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
465
466
  static int crypto_gcm_encrypt(struct aead_request *req)
  {
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
467
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
468
  	struct skcipher_request *skreq = &pctx->u.skreq;
adcbc688f   Herbert Xu   crypto: gcm - Con...
469
  	u32 flags = aead_request_flags(req);
9382d97af   Huang Ying   crypto: gcm - Use...
470

adcbc688f   Herbert Xu   crypto: gcm - Con...
471
472
  	crypto_gcm_init_common(req);
  	crypto_gcm_init_crypt(req, req->cryptlen);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
473
  	skcipher_request_set_callback(skreq, flags, gcm_encrypt_done, req);
9382d97af   Huang Ying   crypto: gcm - Use...
474

16f37ecdd   Herbert Xu   crypto: gcm - Use...
475
  	return crypto_skcipher_encrypt(skreq) ?:
adcbc688f   Herbert Xu   crypto: gcm - Con...
476
  	       gcm_encrypt_continue(req, flags);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
477
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
478
  static int crypto_gcm_verify(struct aead_request *req)
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
479
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
480
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
481
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
482
483
484
485
  	u8 *auth_tag = pctx->auth_tag;
  	u8 *iauth_tag = pctx->iauth_tag;
  	unsigned int authsize = crypto_aead_authsize(aead);
  	unsigned int cryptlen = req->cryptlen - authsize;
9382d97af   Huang Ying   crypto: gcm - Use...
486
  	crypto_xor(auth_tag, iauth_tag, 16);
adcbc688f   Herbert Xu   crypto: gcm - Con...
487
488
  	scatterwalk_map_and_copy(iauth_tag, req->src,
  				 req->assoclen + cryptlen, authsize, 0);
6bf37e5aa   James Yonan   crypto: crypto_me...
489
  	return crypto_memneq(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
490
  }
9382d97af   Huang Ying   crypto: gcm - Use...
491
  static void gcm_decrypt_done(struct crypto_async_request *areq, int err)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
492
  {
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
493
494
495
  	struct aead_request *req = areq->data;
  
  	if (!err)
adcbc688f   Herbert Xu   crypto: gcm - Con...
496
  		err = crypto_gcm_verify(req);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
497
498
  
  	aead_request_complete(req, err);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
499
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
500
  static int gcm_dec_hash_continue(struct aead_request *req, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
501
  {
9382d97af   Huang Ying   crypto: gcm - Use...
502
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
503
  	struct skcipher_request *skreq = &pctx->u.skreq;
9382d97af   Huang Ying   crypto: gcm - Use...
504
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
adcbc688f   Herbert Xu   crypto: gcm - Con...
505
  	crypto_gcm_init_crypt(req, gctx->cryptlen);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
506
507
  	skcipher_request_set_callback(skreq, flags, gcm_decrypt_done, req);
  	return crypto_skcipher_decrypt(skreq) ?: crypto_gcm_verify(req);
9382d97af   Huang Ying   crypto: gcm - Use...
508
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
509
510
  static int crypto_gcm_decrypt(struct aead_request *req)
  {
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
511
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
512
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
513
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
514
  	unsigned int authsize = crypto_aead_authsize(aead);
9382d97af   Huang Ying   crypto: gcm - Use...
515
  	unsigned int cryptlen = req->cryptlen;
adcbc688f   Herbert Xu   crypto: gcm - Con...
516
  	u32 flags = aead_request_flags(req);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
517

6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
518
  	cryptlen -= authsize;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
519

adcbc688f   Herbert Xu   crypto: gcm - Con...
520
  	crypto_gcm_init_common(req);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
521

adcbc688f   Herbert Xu   crypto: gcm - Con...
522
523
524
  	gctx->src = sg_next(pctx->src);
  	gctx->cryptlen = cryptlen;
  	gctx->complete = gcm_dec_hash_continue;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
525

adcbc688f   Herbert Xu   crypto: gcm - Con...
526
  	return gcm_hash(req, flags);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
527
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
528
  static int crypto_gcm_init_tfm(struct crypto_aead *tfm)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
529
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
530
531
532
  	struct aead_instance *inst = aead_alg_instance(tfm);
  	struct gcm_instance_ctx *ictx = aead_instance_ctx(inst);
  	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
533
  	struct crypto_skcipher *ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
534
  	struct crypto_ahash *ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
535
536
  	unsigned long align;
  	int err;
9382d97af   Huang Ying   crypto: gcm - Use...
537
538
539
  	ghash = crypto_spawn_ahash(&ictx->ghash);
  	if (IS_ERR(ghash))
  		return PTR_ERR(ghash);
60425a8ba   Eric Biggers   crypto: skcipher ...
540
  	ctr = crypto_spawn_skcipher(&ictx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
541
542
  	err = PTR_ERR(ctr);
  	if (IS_ERR(ctr))
9382d97af   Huang Ying   crypto: gcm - Use...
543
  		goto err_free_hash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
544
545
  
  	ctx->ctr = ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
546
  	ctx->ghash = ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
547

adcbc688f   Herbert Xu   crypto: gcm - Con...
548
  	align = crypto_aead_alignmask(tfm);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
549
  	align &= ~(crypto_tfm_ctx_alignment() - 1);
adcbc688f   Herbert Xu   crypto: gcm - Con...
550
  	crypto_aead_set_reqsize(tfm,
5d72336f1   Herbert Xu   crypto: gcm - Use...
551
  		align + offsetof(struct crypto_gcm_req_priv_ctx, u) +
16f37ecdd   Herbert Xu   crypto: gcm - Use...
552
553
  		max(sizeof(struct skcipher_request) +
  		    crypto_skcipher_reqsize(ctr),
9382d97af   Huang Ying   crypto: gcm - Use...
554
  		    sizeof(struct ahash_request) +
5d72336f1   Herbert Xu   crypto: gcm - Use...
555
  		    crypto_ahash_reqsize(ghash)));
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
556
557
  
  	return 0;
9382d97af   Huang Ying   crypto: gcm - Use...
558
559
560
561
  
  err_free_hash:
  	crypto_free_ahash(ghash);
  	return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
562
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
563
  static void crypto_gcm_exit_tfm(struct crypto_aead *tfm)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
564
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
565
  	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(tfm);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
566

9382d97af   Huang Ying   crypto: gcm - Use...
567
  	crypto_free_ahash(ctx->ghash);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
568
  	crypto_free_skcipher(ctx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
569
  }
7b05a373a   Herbert Xu   crypto: gcm - Use...
570
571
572
573
574
575
576
577
  static void crypto_gcm_free(struct aead_instance *inst)
  {
  	struct gcm_instance_ctx *ctx = aead_instance_ctx(inst);
  
  	crypto_drop_skcipher(&ctx->ctr);
  	crypto_drop_ahash(&ctx->ghash);
  	kfree(inst);
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
578
579
580
581
582
  static int crypto_gcm_create_common(struct crypto_template *tmpl,
  				    struct rtattr **tb,
  				    const char *full_name,
  				    const char *ctr_name,
  				    const char *ghash_name)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
583
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
584
  	struct crypto_attr_type *algt;
adcbc688f   Herbert Xu   crypto: gcm - Con...
585
  	struct aead_instance *inst;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
586
  	struct skcipher_alg *ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
587
  	struct crypto_alg *ghash_alg;
adcbc688f   Herbert Xu   crypto: gcm - Con...
588
  	struct hash_alg_common *ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
589
590
  	struct gcm_instance_ctx *ctx;
  	int err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
591

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
592
  	algt = crypto_get_attr_type(tb);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
593
  	if (IS_ERR(algt))
adcbc688f   Herbert Xu   crypto: gcm - Con...
594
  		return PTR_ERR(algt);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
595

5e4b8c1fc   Herbert Xu   crypto: aead - Re...
596
  	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
adcbc688f   Herbert Xu   crypto: gcm - Con...
597
  		return -EINVAL;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
598

9382d97af   Huang Ying   crypto: gcm - Use...
599
600
  	ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type,
  				    CRYPTO_ALG_TYPE_HASH,
b30bdfa86   Herbert Xu   crypto: gcm - Fil...
601
602
603
  				    CRYPTO_ALG_TYPE_AHASH_MASK |
  				    crypto_requires_sync(algt->type,
  							 algt->mask));
9382d97af   Huang Ying   crypto: gcm - Use...
604
  	if (IS_ERR(ghash_alg))
adcbc688f   Herbert Xu   crypto: gcm - Con...
605
606
607
  		return PTR_ERR(ghash_alg);
  
  	ghash = __crypto_hash_alg_common(ghash_alg);
9382d97af   Huang Ying   crypto: gcm - Use...
608
609
  
  	err = -ENOMEM;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
610
611
  	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
  	if (!inst)
9382d97af   Huang Ying   crypto: gcm - Use...
612
  		goto out_put_ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
613

adcbc688f   Herbert Xu   crypto: gcm - Con...
614
615
616
  	ctx = aead_instance_ctx(inst);
  	err = crypto_init_ahash_spawn(&ctx->ghash, ghash,
  				      aead_crypto_instance(inst));
9382d97af   Huang Ying   crypto: gcm - Use...
617
618
  	if (err)
  		goto err_free_inst;
adcbc688f   Herbert Xu   crypto: gcm - Con...
619
620
621
622
623
  	err = -EINVAL;
  	if (ghash->digestsize != 16)
  		goto err_drop_ghash;
  
  	crypto_set_skcipher_spawn(&ctx->ctr, aead_crypto_instance(inst));
a35528eca   Eric Biggers   crypto: skcipher ...
624
625
626
  	err = crypto_grab_skcipher(&ctx->ctr, ctr_name, 0,
  				   crypto_requires_sync(algt->type,
  							algt->mask));
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
627
  	if (err)
9382d97af   Huang Ying   crypto: gcm - Use...
628
  		goto err_drop_ghash;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
629

16f37ecdd   Herbert Xu   crypto: gcm - Use...
630
  	ctr = crypto_spawn_skcipher_alg(&ctx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
631

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
632
  	/* We only support 16-byte blocks. */
9b40f79c0   Wei Yongjun   crypto: gcm - Fix...
633
  	err = -EINVAL;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
634
  	if (crypto_skcipher_alg_ivsize(ctr) != 16)
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
635
636
637
  		goto out_put_ctr;
  
  	/* Not a stream cipher? */
16f37ecdd   Herbert Xu   crypto: gcm - Use...
638
  	if (ctr->base.cra_blocksize != 1)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
639
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
640
  	err = -ENAMETOOLONG;
adcbc688f   Herbert Xu   crypto: gcm - Con...
641
  	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
16f37ecdd   Herbert Xu   crypto: gcm - Use...
642
  		     "gcm_base(%s,%s)", ctr->base.cra_driver_name,
9382d97af   Huang Ying   crypto: gcm - Use...
643
  		     ghash_alg->cra_driver_name) >=
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
644
  	    CRYPTO_MAX_ALG_NAME)
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
645
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
646

adcbc688f   Herbert Xu   crypto: gcm - Con...
647
  	memcpy(inst->alg.base.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
648
649
  	inst->alg.base.cra_flags = (ghash->base.cra_flags |
  				    ctr->base.cra_flags) & CRYPTO_ALG_ASYNC;
adcbc688f   Herbert Xu   crypto: gcm - Con...
650
  	inst->alg.base.cra_priority = (ghash->base.cra_priority +
16f37ecdd   Herbert Xu   crypto: gcm - Use...
651
  				       ctr->base.cra_priority) / 2;
adcbc688f   Herbert Xu   crypto: gcm - Con...
652
653
  	inst->alg.base.cra_blocksize = 1;
  	inst->alg.base.cra_alignmask = ghash->base.cra_alignmask |
16f37ecdd   Herbert Xu   crypto: gcm - Use...
654
  				       ctr->base.cra_alignmask;
adcbc688f   Herbert Xu   crypto: gcm - Con...
655
656
  	inst->alg.base.cra_ctxsize = sizeof(struct crypto_gcm_ctx);
  	inst->alg.ivsize = 12;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
657
  	inst->alg.chunksize = crypto_skcipher_alg_chunksize(ctr);
adcbc688f   Herbert Xu   crypto: gcm - Con...
658
659
660
661
662
663
664
  	inst->alg.maxauthsize = 16;
  	inst->alg.init = crypto_gcm_init_tfm;
  	inst->alg.exit = crypto_gcm_exit_tfm;
  	inst->alg.setkey = crypto_gcm_setkey;
  	inst->alg.setauthsize = crypto_gcm_setauthsize;
  	inst->alg.encrypt = crypto_gcm_encrypt;
  	inst->alg.decrypt = crypto_gcm_decrypt;
7b05a373a   Herbert Xu   crypto: gcm - Use...
665
  	inst->free = crypto_gcm_free;
adcbc688f   Herbert Xu   crypto: gcm - Con...
666
667
668
  	err = aead_register_instance(tmpl, inst);
  	if (err)
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
669

adcbc688f   Herbert Xu   crypto: gcm - Con...
670
  out_put_ghash:
9382d97af   Huang Ying   crypto: gcm - Use...
671
  	crypto_mod_put(ghash_alg);
adcbc688f   Herbert Xu   crypto: gcm - Con...
672
  	return err;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
673
674
675
  
  out_put_ctr:
  	crypto_drop_skcipher(&ctx->ctr);
9382d97af   Huang Ying   crypto: gcm - Use...
676
677
  err_drop_ghash:
  	crypto_drop_ahash(&ctx->ghash);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
678
679
  err_free_inst:
  	kfree(inst);
adcbc688f   Herbert Xu   crypto: gcm - Con...
680
  	goto out_put_ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
681
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
682
  static int crypto_gcm_create(struct crypto_template *tmpl, struct rtattr **tb)
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
683
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
684
685
686
687
688
  	const char *cipher_name;
  	char ctr_name[CRYPTO_MAX_ALG_NAME];
  	char full_name[CRYPTO_MAX_ALG_NAME];
  
  	cipher_name = crypto_attr_alg_name(tb[1]);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
689
  	if (IS_ERR(cipher_name))
adcbc688f   Herbert Xu   crypto: gcm - Con...
690
  		return PTR_ERR(cipher_name);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
691
692
693
  
  	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >=
  	    CRYPTO_MAX_ALG_NAME)
adcbc688f   Herbert Xu   crypto: gcm - Con...
694
  		return -ENAMETOOLONG;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
695
696
697
  
  	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >=
  	    CRYPTO_MAX_ALG_NAME)
adcbc688f   Herbert Xu   crypto: gcm - Con...
698
  		return -ENAMETOOLONG;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
699

adcbc688f   Herbert Xu   crypto: gcm - Con...
700
701
  	return crypto_gcm_create_common(tmpl, tb, full_name,
  					ctr_name, "ghash");
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
702
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
703
704
  static struct crypto_template crypto_gcm_tmpl = {
  	.name = "gcm",
adcbc688f   Herbert Xu   crypto: gcm - Con...
705
  	.create = crypto_gcm_create,
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
706
707
  	.module = THIS_MODULE,
  };
adcbc688f   Herbert Xu   crypto: gcm - Con...
708
709
  static int crypto_gcm_base_create(struct crypto_template *tmpl,
  				  struct rtattr **tb)
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
710
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
711
  	const char *ctr_name;
9382d97af   Huang Ying   crypto: gcm - Use...
712
  	const char *ghash_name;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
713
714
715
  	char full_name[CRYPTO_MAX_ALG_NAME];
  
  	ctr_name = crypto_attr_alg_name(tb[1]);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
716
  	if (IS_ERR(ctr_name))
adcbc688f   Herbert Xu   crypto: gcm - Con...
717
  		return PTR_ERR(ctr_name);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
718

9382d97af   Huang Ying   crypto: gcm - Use...
719
  	ghash_name = crypto_attr_alg_name(tb[2]);
9382d97af   Huang Ying   crypto: gcm - Use...
720
  	if (IS_ERR(ghash_name))
adcbc688f   Herbert Xu   crypto: gcm - Con...
721
  		return PTR_ERR(ghash_name);
9382d97af   Huang Ying   crypto: gcm - Use...
722
723
724
  
  	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s,%s)",
  		     ctr_name, ghash_name) >= CRYPTO_MAX_ALG_NAME)
adcbc688f   Herbert Xu   crypto: gcm - Con...
725
  		return -ENAMETOOLONG;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
726

adcbc688f   Herbert Xu   crypto: gcm - Con...
727
728
  	return crypto_gcm_create_common(tmpl, tb, full_name,
  					ctr_name, ghash_name);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
729
730
731
732
  }
  
  static struct crypto_template crypto_gcm_base_tmpl = {
  	.name = "gcm_base",
adcbc688f   Herbert Xu   crypto: gcm - Con...
733
  	.create = crypto_gcm_base_create,
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
734
735
  	.module = THIS_MODULE,
  };
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
  static int crypto_rfc4106_setkey(struct crypto_aead *parent, const u8 *key,
  				 unsigned int keylen)
  {
  	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent);
  	struct crypto_aead *child = ctx->child;
  	int err;
  
  	if (keylen < 4)
  		return -EINVAL;
  
  	keylen -= 4;
  	memcpy(ctx->nonce, key + keylen, 4);
  
  	crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
  	crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
  				     CRYPTO_TFM_REQ_MASK);
  	err = crypto_aead_setkey(child, key, keylen);
  	crypto_aead_set_flags(parent, crypto_aead_get_flags(child) &
  				      CRYPTO_TFM_RES_MASK);
  
  	return err;
  }
  
  static int crypto_rfc4106_setauthsize(struct crypto_aead *parent,
  				      unsigned int authsize)
  {
  	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(parent);
  
  	switch (authsize) {
  	case 8:
  	case 12:
  	case 16:
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	return crypto_aead_setauthsize(ctx->child, authsize);
  }
  
  static struct aead_request *crypto_rfc4106_crypt(struct aead_request *req)
  {
7b05a373a   Herbert Xu   crypto: gcm - Use...
778
  	struct crypto_rfc4106_req_ctx *rctx = aead_request_ctx(req);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
779
780
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead);
7b05a373a   Herbert Xu   crypto: gcm - Use...
781
  	struct aead_request *subreq = &rctx->subreq;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
782
  	struct crypto_aead *child = ctx->child;
7b05a373a   Herbert Xu   crypto: gcm - Use...
783
  	struct scatterlist *sg;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
784
785
  	u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
  			   crypto_aead_alignmask(child) + 1);
7b05a373a   Herbert Xu   crypto: gcm - Use...
786
  	scatterwalk_map_and_copy(iv + 12, req->src, 0, req->assoclen - 8, 0);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
787
788
  	memcpy(iv, ctx->nonce, 4);
  	memcpy(iv + 4, req->iv, 8);
7b05a373a   Herbert Xu   crypto: gcm - Use...
789
790
791
792
793
794
795
796
797
798
799
800
801
  	sg_init_table(rctx->src, 3);
  	sg_set_buf(rctx->src, iv + 12, req->assoclen - 8);
  	sg = scatterwalk_ffwd(rctx->src + 1, req->src, req->assoclen);
  	if (sg != rctx->src + 1)
  		sg_chain(rctx->src, 2, sg);
  
  	if (req->src != req->dst) {
  		sg_init_table(rctx->dst, 3);
  		sg_set_buf(rctx->dst, iv + 12, req->assoclen - 8);
  		sg = scatterwalk_ffwd(rctx->dst + 1, req->dst, req->assoclen);
  		if (sg != rctx->dst + 1)
  			sg_chain(rctx->dst, 2, sg);
  	}
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
802
803
804
  	aead_request_set_tfm(subreq, child);
  	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
  				  req->base.data);
7b05a373a   Herbert Xu   crypto: gcm - Use...
805
806
807
808
  	aead_request_set_crypt(subreq, rctx->src,
  			       req->src == req->dst ? rctx->src : rctx->dst,
  			       req->cryptlen, iv);
  	aead_request_set_ad(subreq, req->assoclen - 8);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
809
810
811
812
813
814
  
  	return subreq;
  }
  
  static int crypto_rfc4106_encrypt(struct aead_request *req)
  {
7b05a373a   Herbert Xu   crypto: gcm - Use...
815
816
  	if (req->assoclen != 16 && req->assoclen != 20)
  		return -EINVAL;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
817
818
819
820
821
822
823
  	req = crypto_rfc4106_crypt(req);
  
  	return crypto_aead_encrypt(req);
  }
  
  static int crypto_rfc4106_decrypt(struct aead_request *req)
  {
7b05a373a   Herbert Xu   crypto: gcm - Use...
824
825
  	if (req->assoclen != 16 && req->assoclen != 20)
  		return -EINVAL;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
826
827
828
829
  	req = crypto_rfc4106_crypt(req);
  
  	return crypto_aead_decrypt(req);
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
830
  static int crypto_rfc4106_init_tfm(struct crypto_aead *tfm)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
831
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
832
833
834
  	struct aead_instance *inst = aead_alg_instance(tfm);
  	struct crypto_aead_spawn *spawn = aead_instance_ctx(inst);
  	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
835
836
837
838
839
840
841
842
843
844
845
  	struct crypto_aead *aead;
  	unsigned long align;
  
  	aead = crypto_spawn_aead(spawn);
  	if (IS_ERR(aead))
  		return PTR_ERR(aead);
  
  	ctx->child = aead;
  
  	align = crypto_aead_alignmask(aead);
  	align &= ~(crypto_tfm_ctx_alignment() - 1);
adcbc688f   Herbert Xu   crypto: gcm - Con...
846
847
  	crypto_aead_set_reqsize(
  		tfm,
7b05a373a   Herbert Xu   crypto: gcm - Use...
848
  		sizeof(struct crypto_rfc4106_req_ctx) +
5d72336f1   Herbert Xu   crypto: gcm - Use...
849
  		ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
7b05a373a   Herbert Xu   crypto: gcm - Use...
850
  		align + 24);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
851
852
853
  
  	return 0;
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
854
  static void crypto_rfc4106_exit_tfm(struct crypto_aead *tfm)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
855
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
856
  	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
857
858
859
  
  	crypto_free_aead(ctx->child);
  }
7b05a373a   Herbert Xu   crypto: gcm - Use...
860
861
862
863
864
  static void crypto_rfc4106_free(struct aead_instance *inst)
  {
  	crypto_drop_aead(aead_instance_ctx(inst));
  	kfree(inst);
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
865
866
  static int crypto_rfc4106_create(struct crypto_template *tmpl,
  				 struct rtattr **tb)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
867
868
  {
  	struct crypto_attr_type *algt;
adcbc688f   Herbert Xu   crypto: gcm - Con...
869
  	struct aead_instance *inst;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
870
  	struct crypto_aead_spawn *spawn;
adcbc688f   Herbert Xu   crypto: gcm - Con...
871
  	struct aead_alg *alg;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
872
873
874
875
  	const char *ccm_name;
  	int err;
  
  	algt = crypto_get_attr_type(tb);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
876
  	if (IS_ERR(algt))
adcbc688f   Herbert Xu   crypto: gcm - Con...
877
  		return PTR_ERR(algt);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
878

5e4b8c1fc   Herbert Xu   crypto: aead - Re...
879
  	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
adcbc688f   Herbert Xu   crypto: gcm - Con...
880
  		return -EINVAL;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
881
882
  
  	ccm_name = crypto_attr_alg_name(tb[1]);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
883
  	if (IS_ERR(ccm_name))
adcbc688f   Herbert Xu   crypto: gcm - Con...
884
  		return PTR_ERR(ccm_name);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
885
886
887
  
  	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
  	if (!inst)
adcbc688f   Herbert Xu   crypto: gcm - Con...
888
  		return -ENOMEM;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
889

adcbc688f   Herbert Xu   crypto: gcm - Con...
890
891
  	spawn = aead_instance_ctx(inst);
  	crypto_set_aead_spawn(spawn, aead_crypto_instance(inst));
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
892
893
894
895
  	err = crypto_grab_aead(spawn, ccm_name, 0,
  			       crypto_requires_sync(algt->type, algt->mask));
  	if (err)
  		goto out_free_inst;
adcbc688f   Herbert Xu   crypto: gcm - Con...
896
  	alg = crypto_spawn_aead_alg(spawn);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
897
898
  
  	err = -EINVAL;
adcbc688f   Herbert Xu   crypto: gcm - Con...
899
900
  	/* Underlying IV size must be 12. */
  	if (crypto_aead_alg_ivsize(alg) != 12)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
901
902
903
  		goto out_drop_alg;
  
  	/* Not a stream cipher? */
adcbc688f   Herbert Xu   crypto: gcm - Con...
904
  	if (alg->base.cra_blocksize != 1)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
905
906
907
  		goto out_drop_alg;
  
  	err = -ENAMETOOLONG;
adcbc688f   Herbert Xu   crypto: gcm - Con...
908
909
910
911
912
  	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
  		     "rfc4106(%s)", alg->base.cra_name) >=
  	    CRYPTO_MAX_ALG_NAME ||
  	    snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
  		     "rfc4106(%s)", alg->base.cra_driver_name) >=
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
913
914
  	    CRYPTO_MAX_ALG_NAME)
  		goto out_drop_alg;
7b05a373a   Herbert Xu   crypto: gcm - Use...
915
  	inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
adcbc688f   Herbert Xu   crypto: gcm - Con...
916
917
918
  	inst->alg.base.cra_priority = alg->base.cra_priority;
  	inst->alg.base.cra_blocksize = 1;
  	inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
919

adcbc688f   Herbert Xu   crypto: gcm - Con...
920
  	inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
921

adcbc688f   Herbert Xu   crypto: gcm - Con...
922
  	inst->alg.ivsize = 8;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
923
  	inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
adcbc688f   Herbert Xu   crypto: gcm - Con...
924
  	inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
925

adcbc688f   Herbert Xu   crypto: gcm - Con...
926
927
  	inst->alg.init = crypto_rfc4106_init_tfm;
  	inst->alg.exit = crypto_rfc4106_exit_tfm;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
928

adcbc688f   Herbert Xu   crypto: gcm - Con...
929
930
931
932
  	inst->alg.setkey = crypto_rfc4106_setkey;
  	inst->alg.setauthsize = crypto_rfc4106_setauthsize;
  	inst->alg.encrypt = crypto_rfc4106_encrypt;
  	inst->alg.decrypt = crypto_rfc4106_decrypt;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
933

7b05a373a   Herbert Xu   crypto: gcm - Use...
934
  	inst->free = crypto_rfc4106_free;
adcbc688f   Herbert Xu   crypto: gcm - Con...
935
936
937
  	err = aead_register_instance(tmpl, inst);
  	if (err)
  		goto out_drop_alg;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
938
939
  
  out:
adcbc688f   Herbert Xu   crypto: gcm - Con...
940
  	return err;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
941
942
943
944
945
  
  out_drop_alg:
  	crypto_drop_aead(spawn);
  out_free_inst:
  	kfree(inst);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
946
947
  	goto out;
  }
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
948
949
  static struct crypto_template crypto_rfc4106_tmpl = {
  	.name = "rfc4106",
adcbc688f   Herbert Xu   crypto: gcm - Con...
950
  	.create = crypto_rfc4106_create,
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
951
952
  	.module = THIS_MODULE,
  };
73c89c15b   Tobias Brunner   crypto: gcm - Add...
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
  static int crypto_rfc4543_setkey(struct crypto_aead *parent, const u8 *key,
  				 unsigned int keylen)
  {
  	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent);
  	struct crypto_aead *child = ctx->child;
  	int err;
  
  	if (keylen < 4)
  		return -EINVAL;
  
  	keylen -= 4;
  	memcpy(ctx->nonce, key + keylen, 4);
  
  	crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK);
  	crypto_aead_set_flags(child, crypto_aead_get_flags(parent) &
  				     CRYPTO_TFM_REQ_MASK);
  	err = crypto_aead_setkey(child, key, keylen);
  	crypto_aead_set_flags(parent, crypto_aead_get_flags(child) &
  				      CRYPTO_TFM_RES_MASK);
  
  	return err;
  }
  
  static int crypto_rfc4543_setauthsize(struct crypto_aead *parent,
  				      unsigned int authsize)
  {
  	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(parent);
  
  	if (authsize != 16)
  		return -EINVAL;
  
  	return crypto_aead_setauthsize(ctx->child, authsize);
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
986
  static int crypto_rfc4543_crypt(struct aead_request *req, bool enc)
73c89c15b   Tobias Brunner   crypto: gcm - Add...
987
988
989
  {
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead);
adcbc688f   Herbert Xu   crypto: gcm - Con...
990
  	struct crypto_rfc4543_req_ctx *rctx = aead_request_ctx(req);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
991
  	struct aead_request *subreq = &rctx->subreq;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
992
  	unsigned int authsize = crypto_aead_authsize(aead);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
993
994
  	u8 *iv = PTR_ALIGN((u8 *)(rctx + 1) + crypto_aead_reqsize(ctx->child),
  			   crypto_aead_alignmask(ctx->child) + 1);
adcbc688f   Herbert Xu   crypto: gcm - Con...
995
996
997
998
999
1000
1001
  	int err;
  
  	if (req->src != req->dst) {
  		err = crypto_rfc4543_copy_src_to_dst(req, enc);
  		if (err)
  			return err;
  	}
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1002
1003
1004
  
  	memcpy(iv, ctx->nonce, 4);
  	memcpy(iv + 4, req->iv, 8);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1005
  	aead_request_set_tfm(subreq, ctx->child);
adcbc688f   Herbert Xu   crypto: gcm - Con...
1006
1007
1008
1009
1010
1011
1012
1013
  	aead_request_set_callback(subreq, req->base.flags,
  				  req->base.complete, req->base.data);
  	aead_request_set_crypt(subreq, req->src, req->dst,
  			       enc ? 0 : authsize, iv);
  	aead_request_set_ad(subreq, req->assoclen + req->cryptlen -
  				    subreq->cryptlen);
  
  	return enc ? crypto_aead_encrypt(subreq) : crypto_aead_decrypt(subreq);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1014
  }
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1015
1016
1017
1018
1019
  static int crypto_rfc4543_copy_src_to_dst(struct aead_request *req, bool enc)
  {
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead);
  	unsigned int authsize = crypto_aead_authsize(aead);
adcbc688f   Herbert Xu   crypto: gcm - Con...
1020
1021
  	unsigned int nbytes = req->assoclen + req->cryptlen -
  			      (enc ? 0 : authsize);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
1022
1023
1024
1025
1026
  	SKCIPHER_REQUEST_ON_STACK(nreq, ctx->null);
  
  	skcipher_request_set_tfm(nreq, ctx->null);
  	skcipher_request_set_callback(nreq, req->base.flags, NULL, NULL);
  	skcipher_request_set_crypt(nreq, req->src, req->dst, nbytes, NULL);
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1027

16f37ecdd   Herbert Xu   crypto: gcm - Use...
1028
  	return crypto_skcipher_encrypt(nreq);
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1029
  }
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1030
1031
  static int crypto_rfc4543_encrypt(struct aead_request *req)
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
1032
  	return crypto_rfc4543_crypt(req, true);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1033
1034
1035
1036
  }
  
  static int crypto_rfc4543_decrypt(struct aead_request *req)
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
1037
  	return crypto_rfc4543_crypt(req, false);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1038
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
1039
  static int crypto_rfc4543_init_tfm(struct crypto_aead *tfm)
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1040
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
1041
1042
  	struct aead_instance *inst = aead_alg_instance(tfm);
  	struct crypto_rfc4543_instance_ctx *ictx = aead_instance_ctx(inst);
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1043
  	struct crypto_aead_spawn *spawn = &ictx->aead;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1044
  	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1045
  	struct crypto_aead *aead;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
1046
  	struct crypto_skcipher *null;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1047
  	unsigned long align;
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1048
  	int err = 0;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1049
1050
1051
1052
  
  	aead = crypto_spawn_aead(spawn);
  	if (IS_ERR(aead))
  		return PTR_ERR(aead);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
1053
  	null = crypto_get_default_null_skcipher2();
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1054
1055
1056
  	err = PTR_ERR(null);
  	if (IS_ERR(null))
  		goto err_free_aead;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1057
  	ctx->child = aead;
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1058
  	ctx->null = null;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1059
1060
1061
  
  	align = crypto_aead_alignmask(aead);
  	align &= ~(crypto_tfm_ctx_alignment() - 1);
adcbc688f   Herbert Xu   crypto: gcm - Con...
1062
1063
  	crypto_aead_set_reqsize(
  		tfm,
5d72336f1   Herbert Xu   crypto: gcm - Use...
1064
1065
  		sizeof(struct crypto_rfc4543_req_ctx) +
  		ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
adcbc688f   Herbert Xu   crypto: gcm - Con...
1066
  		align + 12);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1067
1068
  
  	return 0;
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1069
1070
1071
1072
  
  err_free_aead:
  	crypto_free_aead(aead);
  	return err;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1073
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
1074
  static void crypto_rfc4543_exit_tfm(struct crypto_aead *tfm)
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1075
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
1076
  	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(tfm);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1077
1078
  
  	crypto_free_aead(ctx->child);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
1079
  	crypto_put_default_null_skcipher2();
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1080
  }
7b05a373a   Herbert Xu   crypto: gcm - Use...
1081
1082
1083
1084
1085
1086
1087
1088
  static void crypto_rfc4543_free(struct aead_instance *inst)
  {
  	struct crypto_rfc4543_instance_ctx *ctx = aead_instance_ctx(inst);
  
  	crypto_drop_aead(&ctx->aead);
  
  	kfree(inst);
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
1089
1090
  static int crypto_rfc4543_create(struct crypto_template *tmpl,
  				struct rtattr **tb)
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1091
1092
  {
  	struct crypto_attr_type *algt;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1093
  	struct aead_instance *inst;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1094
  	struct crypto_aead_spawn *spawn;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1095
  	struct aead_alg *alg;
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1096
  	struct crypto_rfc4543_instance_ctx *ctx;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1097
1098
1099
1100
  	const char *ccm_name;
  	int err;
  
  	algt = crypto_get_attr_type(tb);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1101
  	if (IS_ERR(algt))
adcbc688f   Herbert Xu   crypto: gcm - Con...
1102
  		return PTR_ERR(algt);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1103

5e4b8c1fc   Herbert Xu   crypto: aead - Re...
1104
  	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
adcbc688f   Herbert Xu   crypto: gcm - Con...
1105
  		return -EINVAL;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1106
1107
  
  	ccm_name = crypto_attr_alg_name(tb[1]);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1108
  	if (IS_ERR(ccm_name))
adcbc688f   Herbert Xu   crypto: gcm - Con...
1109
  		return PTR_ERR(ccm_name);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1110

9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1111
  	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1112
  	if (!inst)
adcbc688f   Herbert Xu   crypto: gcm - Con...
1113
  		return -ENOMEM;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1114

adcbc688f   Herbert Xu   crypto: gcm - Con...
1115
  	ctx = aead_instance_ctx(inst);
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1116
  	spawn = &ctx->aead;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1117
  	crypto_set_aead_spawn(spawn, aead_crypto_instance(inst));
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1118
1119
1120
1121
  	err = crypto_grab_aead(spawn, ccm_name, 0,
  			       crypto_requires_sync(algt->type, algt->mask));
  	if (err)
  		goto out_free_inst;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1122
  	alg = crypto_spawn_aead_alg(spawn);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1123
1124
  
  	err = -EINVAL;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1125
1126
  	/* Underlying IV size must be 12. */
  	if (crypto_aead_alg_ivsize(alg) != 12)
17db85469   Herbert Xu   crypto: gcm - Use...
1127
  		goto out_drop_alg;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1128
1129
  
  	/* Not a stream cipher? */
adcbc688f   Herbert Xu   crypto: gcm - Con...
1130
  	if (alg->base.cra_blocksize != 1)
17db85469   Herbert Xu   crypto: gcm - Use...
1131
  		goto out_drop_alg;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1132
1133
  
  	err = -ENAMETOOLONG;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1134
1135
1136
1137
1138
  	if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME,
  		     "rfc4543(%s)", alg->base.cra_name) >=
  	    CRYPTO_MAX_ALG_NAME ||
  	    snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
  		     "rfc4543(%s)", alg->base.cra_driver_name) >=
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1139
  	    CRYPTO_MAX_ALG_NAME)
17db85469   Herbert Xu   crypto: gcm - Use...
1140
  		goto out_drop_alg;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1141

adcbc688f   Herbert Xu   crypto: gcm - Con...
1142
1143
1144
1145
  	inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
  	inst->alg.base.cra_priority = alg->base.cra_priority;
  	inst->alg.base.cra_blocksize = 1;
  	inst->alg.base.cra_alignmask = alg->base.cra_alignmask;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1146

adcbc688f   Herbert Xu   crypto: gcm - Con...
1147
  	inst->alg.base.cra_ctxsize = sizeof(struct crypto_rfc4543_ctx);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1148

adcbc688f   Herbert Xu   crypto: gcm - Con...
1149
  	inst->alg.ivsize = 8;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
1150
  	inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
adcbc688f   Herbert Xu   crypto: gcm - Con...
1151
  	inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1152

adcbc688f   Herbert Xu   crypto: gcm - Con...
1153
1154
  	inst->alg.init = crypto_rfc4543_init_tfm;
  	inst->alg.exit = crypto_rfc4543_exit_tfm;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1155

adcbc688f   Herbert Xu   crypto: gcm - Con...
1156
1157
1158
1159
  	inst->alg.setkey = crypto_rfc4543_setkey;
  	inst->alg.setauthsize = crypto_rfc4543_setauthsize;
  	inst->alg.encrypt = crypto_rfc4543_encrypt;
  	inst->alg.decrypt = crypto_rfc4543_decrypt;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1160

7b05a373a   Herbert Xu   crypto: gcm - Use...
1161
  	inst->free = crypto_rfc4543_free,
adcbc688f   Herbert Xu   crypto: gcm - Con...
1162
1163
1164
  	err = aead_register_instance(tmpl, inst);
  	if (err)
  		goto out_drop_alg;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1165
1166
  
  out:
adcbc688f   Herbert Xu   crypto: gcm - Con...
1167
  	return err;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1168
1169
1170
1171
1172
  
  out_drop_alg:
  	crypto_drop_aead(spawn);
  out_free_inst:
  	kfree(inst);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1173
1174
  	goto out;
  }
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1175
1176
  static struct crypto_template crypto_rfc4543_tmpl = {
  	.name = "rfc4543",
adcbc688f   Herbert Xu   crypto: gcm - Con...
1177
  	.create = crypto_rfc4543_create,
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1178
1179
  	.module = THIS_MODULE,
  };
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1180
1181
  static int __init crypto_gcm_module_init(void)
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1182
  	int err;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1183
  	gcm_zeroes = kzalloc(sizeof(*gcm_zeroes), GFP_KERNEL);
9382d97af   Huang Ying   crypto: gcm - Use...
1184
1185
  	if (!gcm_zeroes)
  		return -ENOMEM;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1186
  	sg_init_one(&gcm_zeroes->sg, gcm_zeroes->buf, sizeof(gcm_zeroes->buf));
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1187
1188
1189
1190
1191
1192
1193
  	err = crypto_register_template(&crypto_gcm_base_tmpl);
  	if (err)
  		goto out;
  
  	err = crypto_register_template(&crypto_gcm_tmpl);
  	if (err)
  		goto out_undo_base;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
1194
1195
1196
  	err = crypto_register_template(&crypto_rfc4106_tmpl);
  	if (err)
  		goto out_undo_gcm;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1197
1198
1199
  	err = crypto_register_template(&crypto_rfc4543_tmpl);
  	if (err)
  		goto out_undo_rfc4106;
9382d97af   Huang Ying   crypto: gcm - Use...
1200
  	return 0;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1201

73c89c15b   Tobias Brunner   crypto: gcm - Add...
1202
1203
  out_undo_rfc4106:
  	crypto_unregister_template(&crypto_rfc4106_tmpl);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
1204
1205
  out_undo_gcm:
  	crypto_unregister_template(&crypto_gcm_tmpl);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1206
1207
  out_undo_base:
  	crypto_unregister_template(&crypto_gcm_base_tmpl);
9382d97af   Huang Ying   crypto: gcm - Use...
1208
1209
1210
  out:
  	kfree(gcm_zeroes);
  	return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1211
1212
1213
1214
  }
  
  static void __exit crypto_gcm_module_exit(void)
  {
9382d97af   Huang Ying   crypto: gcm - Use...
1215
  	kfree(gcm_zeroes);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1216
  	crypto_unregister_template(&crypto_rfc4543_tmpl);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
1217
  	crypto_unregister_template(&crypto_rfc4106_tmpl);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1218
  	crypto_unregister_template(&crypto_gcm_tmpl);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1219
  	crypto_unregister_template(&crypto_gcm_base_tmpl);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1220
1221
1222
1223
1224
1225
1226
1227
  }
  
  module_init(crypto_gcm_module_init);
  module_exit(crypto_gcm_module_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Galois/Counter Mode");
  MODULE_AUTHOR("Mikko Herranen <mh1@iki.fi>");
5d26a105b   Kees Cook   crypto: prefix mo...
1228
1229
1230
  MODULE_ALIAS_CRYPTO("gcm_base");
  MODULE_ALIAS_CRYPTO("rfc4106");
  MODULE_ALIAS_CRYPTO("rfc4543");
4943ba16b   Kees Cook   crypto: include c...
1231
  MODULE_ALIAS_CRYPTO("gcm");