Blame view

crypto/gcm.c 27.4 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>
42c271c6c   Herbert Xu   [CRYPTO] scatterw...
14
  #include <crypto/scatterwalk.h>
9382d97af   Huang Ying   crypto: gcm - Use...
15
16
  #include <crypto/hash.h>
  #include "internal.h"
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
17
  #include <linux/completion.h>
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
18
19
20
21
22
  #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...
23
  struct gcm_instance_ctx {
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
24
  	struct crypto_skcipher_spawn ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
25
  	struct crypto_ahash_spawn ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
26
27
28
29
  };
  
  struct crypto_gcm_ctx {
  	struct crypto_ablkcipher *ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
30
  	struct crypto_ahash *ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
31
  };
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
32
33
34
35
  struct crypto_rfc4106_ctx {
  	struct crypto_aead *child;
  	u8 nonce[4];
  };
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
36
  struct crypto_gcm_ghash_ctx {
9382d97af   Huang Ying   crypto: gcm - Use...
37
38
  	unsigned int cryptlen;
  	struct scatterlist *src;
62c5593ae   Huang Ying   crypto: gcm - fix...
39
  	void (*complete)(struct aead_request *req, int err);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
40
41
42
43
  };
  
  struct crypto_gcm_req_priv_ctx {
  	u8 auth_tag[16];
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
44
  	u8 iauth_tag[16];
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
45
46
  	struct scatterlist src[2];
  	struct scatterlist dst[2];
9382d97af   Huang Ying   crypto: gcm - Use...
47
48
49
50
51
  	struct crypto_gcm_ghash_ctx ghash_ctx;
  	union {
  		struct ahash_request ahreq;
  		struct ablkcipher_request abreq;
  	} u;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
52
  };
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
53
54
55
56
  struct crypto_gcm_setkey_result {
  	int err;
  	struct completion completion;
  };
9382d97af   Huang Ying   crypto: gcm - Use...
57
  static void *gcm_zeroes;
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
58
59
60
61
62
63
64
  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...
65
  static void crypto_gcm_setkey_done(struct crypto_async_request *req, int err)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
66
  {
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
67
  	struct crypto_gcm_setkey_result *result = req->data;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
68

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
69
70
71
72
73
  	if (err == -EINPROGRESS)
  		return;
  
  	result->err = err;
  	complete(&result->completion);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
74
75
76
77
78
79
  }
  
  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...
80
  	struct crypto_ahash *ghash = ctx->ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
81
  	struct crypto_ablkcipher *ctr = ctx->ctr;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
82
83
84
85
86
87
88
89
90
91
  	struct {
  		be128 hash;
  		u8 iv[8];
  
  		struct crypto_gcm_setkey_result result;
  
  		struct scatterlist sg[1];
  		struct ablkcipher_request req;
  	} *data;
  	int err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
92
93
94
95
96
97
98
  
  	crypto_ablkcipher_clear_flags(ctr, CRYPTO_TFM_REQ_MASK);
  	crypto_ablkcipher_set_flags(ctr, crypto_aead_get_flags(aead) &
  				   CRYPTO_TFM_REQ_MASK);
  
  	err = crypto_ablkcipher_setkey(ctr, key, keylen);
  	if (err)
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
99
  		return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
100
101
102
  
  	crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) &
  				       CRYPTO_TFM_RES_MASK);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  	data = kzalloc(sizeof(*data) + crypto_ablkcipher_reqsize(ctr),
  		       GFP_KERNEL);
  	if (!data)
  		return -ENOMEM;
  
  	init_completion(&data->result.completion);
  	sg_init_one(data->sg, &data->hash, sizeof(data->hash));
  	ablkcipher_request_set_tfm(&data->req, ctr);
  	ablkcipher_request_set_callback(&data->req, CRYPTO_TFM_REQ_MAY_SLEEP |
  						    CRYPTO_TFM_REQ_MAY_BACKLOG,
  					crypto_gcm_setkey_done,
  					&data->result);
  	ablkcipher_request_set_crypt(&data->req, data->sg, data->sg,
  				     sizeof(data->hash), data->iv);
  
  	err = crypto_ablkcipher_encrypt(&data->req);
  	if (err == -EINPROGRESS || err == -EBUSY) {
  		err = wait_for_completion_interruptible(
  			&data->result.completion);
  		if (!err)
  			err = data->result.err;
  	}
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
125
126
  	if (err)
  		goto out;
9382d97af   Huang Ying   crypto: gcm - Use...
127
128
129
130
131
132
  	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...
133

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
134
135
  out:
  	kfree(data);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
136
137
  	return err;
  }
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  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;
  }
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
156
157
158
  static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req,
  				  struct aead_request *req,
  				  unsigned int cryptlen)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
159
160
161
  {
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
162
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
  	struct scatterlist *dst;
  	__be32 counter = cpu_to_be32(1);
  
  	memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag));
  	memcpy(req->iv + 12, &counter, 4);
  
  	sg_init_table(pctx->src, 2);
  	sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag));
  	scatterwalk_sg_chain(pctx->src, 2, req->src);
  
  	dst = pctx->src;
  	if (req->src != req->dst) {
  		sg_init_table(pctx->dst, 2);
  		sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag));
  		scatterwalk_sg_chain(pctx->dst, 2, req->dst);
  		dst = pctx->dst;
  	}
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
180
181
  
  	ablkcipher_request_set_tfm(ablk_req, ctx->ctr);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
182
183
184
  	ablkcipher_request_set_crypt(ablk_req, pctx->src, dst,
  				     cryptlen + sizeof(pctx->auth_tag),
  				     req->iv);
9382d97af   Huang Ying   crypto: gcm - Use...
185
186
187
188
189
190
191
192
193
194
  }
  
  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);
  static void gcm_hash_final_done(struct crypto_async_request *areq, int err);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
195

9382d97af   Huang Ying   crypto: gcm - Use...
196
197
198
199
200
201
202
  static int gcm_hash_update(struct aead_request *req,
  			   struct crypto_gcm_req_priv_ctx *pctx,
  			   crypto_completion_t complete,
  			   struct scatterlist *src,
  			   unsigned int len)
  {
  	struct ahash_request *ahreq = &pctx->u.ahreq;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
203

9382d97af   Huang Ying   crypto: gcm - Use...
204
205
206
207
208
  	ahash_request_set_callback(ahreq, aead_request_flags(req),
  				   complete, req);
  	ahash_request_set_crypt(ahreq, src, NULL, len);
  
  	return crypto_ahash_update(ahreq);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
209
  }
9382d97af   Huang Ying   crypto: gcm - Use...
210
211
212
213
  static int gcm_hash_remain(struct aead_request *req,
  			   struct crypto_gcm_req_priv_ctx *pctx,
  			   unsigned int remain,
  			   crypto_completion_t complete)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
214
  {
9382d97af   Huang Ying   crypto: gcm - Use...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
  	struct ahash_request *ahreq = &pctx->u.ahreq;
  
  	ahash_request_set_callback(ahreq, aead_request_flags(req),
  				   complete, req);
  	sg_init_one(pctx->src, gcm_zeroes, remain);
  	ahash_request_set_crypt(ahreq, pctx->src, NULL, remain);
  
  	return crypto_ahash_update(ahreq);
  }
  
  static int gcm_hash_len(struct aead_request *req,
  			struct crypto_gcm_req_priv_ctx *pctx)
  {
  	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);
  	sg_init_one(pctx->src, pctx->iauth_tag, 16);
  	ahash_request_set_callback(ahreq, aead_request_flags(req),
  				   gcm_hash_len_done, req);
  	ahash_request_set_crypt(ahreq, pctx->src,
  				NULL, sizeof(lengths));
  
  	return crypto_ahash_update(ahreq);
  }
  
  static int gcm_hash_final(struct aead_request *req,
  			  struct crypto_gcm_req_priv_ctx *pctx)
  {
  	struct ahash_request *ahreq = &pctx->u.ahreq;
  
  	ahash_request_set_callback(ahreq, aead_request_flags(req),
  				   gcm_hash_final_done, req);
  	ahash_request_set_crypt(ahreq, NULL, pctx->iauth_tag, 0);
  
  	return crypto_ahash_final(ahreq);
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
255
  static void __gcm_hash_final_done(struct aead_request *req, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
256
  {
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
257
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
258
259
260
261
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
  
  	if (!err)
  		crypto_xor(pctx->auth_tag, pctx->iauth_tag, 16);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
262

62c5593ae   Huang Ying   crypto: gcm - fix...
263
  	gctx->complete(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
264
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
265
  static void gcm_hash_final_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
266
267
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
268
269
270
271
272
273
  
  	__gcm_hash_final_done(req, err);
  }
  
  static void __gcm_hash_len_done(struct aead_request *req, int err)
  {
9382d97af   Huang Ying   crypto: gcm - Use...
274
275
276
277
278
279
280
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  
  	if (!err) {
  		err = gcm_hash_final(req, pctx);
  		if (err == -EINPROGRESS || err == -EBUSY)
  			return;
  	}
62c5593ae   Huang Ying   crypto: gcm - fix...
281
  	__gcm_hash_final_done(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
282
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
283
  static void gcm_hash_len_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
284
285
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
286
287
288
289
290
291
  
  	__gcm_hash_len_done(req, err);
  }
  
  static void __gcm_hash_crypt_remain_done(struct aead_request *req, int err)
  {
9382d97af   Huang Ying   crypto: gcm - Use...
292
293
294
295
296
297
298
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  
  	if (!err) {
  		err = gcm_hash_len(req, pctx);
  		if (err == -EINPROGRESS || err == -EBUSY)
  			return;
  	}
62c5593ae   Huang Ying   crypto: gcm - fix...
299
  	__gcm_hash_len_done(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
300
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
301
302
  static void gcm_hash_crypt_remain_done(struct crypto_async_request *areq,
  				       int err)
9382d97af   Huang Ying   crypto: gcm - Use...
303
304
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
305
306
307
308
309
310
  
  	__gcm_hash_crypt_remain_done(req, err);
  }
  
  static void __gcm_hash_crypt_done(struct aead_request *req, int err)
  {
9382d97af   Huang Ying   crypto: gcm - Use...
311
312
313
314
315
316
317
318
319
320
321
322
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
  	unsigned int remain;
  
  	if (!err) {
  		remain = gcm_remain(gctx->cryptlen);
  		BUG_ON(!remain);
  		err = gcm_hash_remain(req, pctx, remain,
  				      gcm_hash_crypt_remain_done);
  		if (err == -EINPROGRESS || err == -EBUSY)
  			return;
  	}
62c5593ae   Huang Ying   crypto: gcm - fix...
323
  	__gcm_hash_crypt_remain_done(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
324
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
325
  static void gcm_hash_crypt_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
326
327
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
328
329
330
331
332
333
  
  	__gcm_hash_crypt_done(req, err);
  }
  
  static void __gcm_hash_assoc_remain_done(struct aead_request *req, int err)
  {
9382d97af   Huang Ying   crypto: gcm - Use...
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
  	crypto_completion_t complete;
  	unsigned int remain = 0;
  
  	if (!err && gctx->cryptlen) {
  		remain = gcm_remain(gctx->cryptlen);
  		complete = remain ? gcm_hash_crypt_done :
  			gcm_hash_crypt_remain_done;
  		err = gcm_hash_update(req, pctx, complete,
  				      gctx->src, gctx->cryptlen);
  		if (err == -EINPROGRESS || err == -EBUSY)
  			return;
  	}
  
  	if (remain)
62c5593ae   Huang Ying   crypto: gcm - fix...
350
  		__gcm_hash_crypt_done(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
351
  	else
62c5593ae   Huang Ying   crypto: gcm - fix...
352
  		__gcm_hash_crypt_remain_done(req, err);
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
359
360
361
362
363
  
  	__gcm_hash_assoc_remain_done(req, err);
  }
  
  static void __gcm_hash_assoc_done(struct aead_request *req, int err)
  {
9382d97af   Huang Ying   crypto: gcm - Use...
364
365
366
367
368
369
370
371
372
373
374
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  	unsigned int remain;
  
  	if (!err) {
  		remain = gcm_remain(req->assoclen);
  		BUG_ON(!remain);
  		err = gcm_hash_remain(req, pctx, remain,
  				      gcm_hash_assoc_remain_done);
  		if (err == -EINPROGRESS || err == -EBUSY)
  			return;
  	}
62c5593ae   Huang Ying   crypto: gcm - fix...
375
  	__gcm_hash_assoc_remain_done(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
376
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
377
  static void gcm_hash_assoc_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
378
379
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
380
381
382
383
384
385
  
  	__gcm_hash_assoc_done(req, err);
  }
  
  static void __gcm_hash_init_done(struct aead_request *req, int err)
  {
9382d97af   Huang Ying   crypto: gcm - Use...
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  	crypto_completion_t complete;
  	unsigned int remain = 0;
  
  	if (!err && req->assoclen) {
  		remain = gcm_remain(req->assoclen);
  		complete = remain ? gcm_hash_assoc_done :
  			gcm_hash_assoc_remain_done;
  		err = gcm_hash_update(req, pctx, complete,
  				      req->assoc, req->assoclen);
  		if (err == -EINPROGRESS || err == -EBUSY)
  			return;
  	}
  
  	if (remain)
62c5593ae   Huang Ying   crypto: gcm - fix...
401
  		__gcm_hash_assoc_done(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
402
  	else
62c5593ae   Huang Ying   crypto: gcm - fix...
403
404
405
406
407
408
409
410
  		__gcm_hash_assoc_remain_done(req, err);
  }
  
  static void gcm_hash_init_done(struct crypto_async_request *areq, int err)
  {
  	struct aead_request *req = areq->data;
  
  	__gcm_hash_init_done(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
  }
  
  static int gcm_hash(struct aead_request *req,
  		    struct crypto_gcm_req_priv_ctx *pctx)
  {
  	struct ahash_request *ahreq = &pctx->u.ahreq;
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
  	struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(req->base.tfm);
  	unsigned int remain;
  	crypto_completion_t complete;
  	int err;
  
  	ahash_request_set_tfm(ahreq, ctx->ghash);
  
  	ahash_request_set_callback(ahreq, aead_request_flags(req),
  				   gcm_hash_init_done, req);
  	err = crypto_ahash_init(ahreq);
  	if (err)
  		return err;
  	remain = gcm_remain(req->assoclen);
  	complete = remain ? gcm_hash_assoc_done : gcm_hash_assoc_remain_done;
  	err = gcm_hash_update(req, pctx, complete, req->assoc, req->assoclen);
  	if (err)
  		return err;
  	if (remain) {
  		err = gcm_hash_remain(req, pctx, remain,
  				      gcm_hash_assoc_remain_done);
  		if (err)
  			return err;
  	}
  	remain = gcm_remain(gctx->cryptlen);
  	complete = remain ? gcm_hash_crypt_done : gcm_hash_crypt_remain_done;
  	err = gcm_hash_update(req, pctx, complete, gctx->src, gctx->cryptlen);
  	if (err)
  		return err;
  	if (remain) {
  		err = gcm_hash_remain(req, pctx, remain,
  				      gcm_hash_crypt_remain_done);
  		if (err)
  			return err;
  	}
  	err = gcm_hash_len(req, pctx);
  	if (err)
  		return err;
  	err = gcm_hash_final(req, pctx);
  	if (err)
  		return err;
  
  	return 0;
  }
  
  static void gcm_enc_copy_hash(struct aead_request *req,
  			      struct crypto_gcm_req_priv_ctx *pctx)
  {
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	u8 *auth_tag = pctx->auth_tag;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
467

6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
468
469
  	scatterwalk_map_and_copy(auth_tag, req->dst, req->cryptlen,
  				 crypto_aead_authsize(aead), 1);
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
470
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
471
  static void gcm_enc_hash_done(struct aead_request *req, int err)
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
472
  {
9382d97af   Huang Ying   crypto: gcm - Use...
473
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
474
475
  
  	if (!err)
9382d97af   Huang Ying   crypto: gcm - Use...
476
  		gcm_enc_copy_hash(req, pctx);
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
477

28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
478
479
  	aead_request_complete(req, err);
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
480
  static void gcm_encrypt_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
481
482
483
484
485
486
487
488
  {
  	struct aead_request *req = areq->data;
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  
  	if (!err) {
  		err = gcm_hash(req, pctx);
  		if (err == -EINPROGRESS || err == -EBUSY)
  			return;
62c5593ae   Huang Ying   crypto: gcm - fix...
489
490
491
492
  		else if (!err) {
  			crypto_xor(pctx->auth_tag, pctx->iauth_tag, 16);
  			gcm_enc_copy_hash(req, pctx);
  		}
9382d97af   Huang Ying   crypto: gcm - Use...
493
  	}
62c5593ae   Huang Ying   crypto: gcm - fix...
494
  	aead_request_complete(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
495
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
496
497
  static int crypto_gcm_encrypt(struct aead_request *req)
  {
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
498
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
499
500
  	struct ablkcipher_request *abreq = &pctx->u.abreq;
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
501
502
503
504
  	int err;
  
  	crypto_gcm_init_crypt(abreq, req, req->cryptlen);
  	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
9382d97af   Huang Ying   crypto: gcm - Use...
505
506
507
508
509
  					gcm_encrypt_done, req);
  
  	gctx->src = req->dst;
  	gctx->cryptlen = req->cryptlen;
  	gctx->complete = gcm_enc_hash_done;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
510

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
511
  	err = crypto_ablkcipher_encrypt(abreq);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
512
513
  	if (err)
  		return err;
9382d97af   Huang Ying   crypto: gcm - Use...
514
515
516
517
518
519
520
521
  	err = gcm_hash(req, pctx);
  	if (err)
  		return err;
  
  	crypto_xor(pctx->auth_tag, pctx->iauth_tag, 16);
  	gcm_enc_copy_hash(req, pctx);
  
  	return 0;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
522
  }
9382d97af   Huang Ying   crypto: gcm - Use...
523
524
  static int crypto_gcm_verify(struct aead_request *req,
  			     struct crypto_gcm_req_priv_ctx *pctx)
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
525
526
  {
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
527
528
529
530
  	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...
531
  	crypto_xor(auth_tag, iauth_tag, 16);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
532
533
534
  	scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
  	return memcmp(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
  }
9382d97af   Huang Ying   crypto: gcm - Use...
535
  static void gcm_decrypt_done(struct crypto_async_request *areq, int err)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
536
  {
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
537
  	struct aead_request *req = areq->data;
9382d97af   Huang Ying   crypto: gcm - Use...
538
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
539
540
  
  	if (!err)
9382d97af   Huang Ying   crypto: gcm - Use...
541
  		err = crypto_gcm_verify(req, pctx);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
542
543
  
  	aead_request_complete(req, err);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
544
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
545
  static void gcm_dec_hash_done(struct aead_request *req, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
546
  {
9382d97af   Huang Ying   crypto: gcm - Use...
547
548
549
550
551
552
553
554
555
556
557
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  	struct ablkcipher_request *abreq = &pctx->u.abreq;
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
  
  	if (!err) {
  		ablkcipher_request_set_callback(abreq, aead_request_flags(req),
  						gcm_decrypt_done, req);
  		crypto_gcm_init_crypt(abreq, req, gctx->cryptlen);
  		err = crypto_ablkcipher_decrypt(abreq);
  		if (err == -EINPROGRESS || err == -EBUSY)
  			return;
62c5593ae   Huang Ying   crypto: gcm - fix...
558
559
  		else if (!err)
  			err = crypto_gcm_verify(req, pctx);
9382d97af   Huang Ying   crypto: gcm - Use...
560
  	}
62c5593ae   Huang Ying   crypto: gcm - fix...
561
  	aead_request_complete(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
562
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
563
564
  static int crypto_gcm_decrypt(struct aead_request *req)
  {
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
565
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
566
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
567
568
  	struct ablkcipher_request *abreq = &pctx->u.abreq;
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
569
  	unsigned int authsize = crypto_aead_authsize(aead);
9382d97af   Huang Ying   crypto: gcm - Use...
570
  	unsigned int cryptlen = req->cryptlen;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
571
  	int err;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
572
  	if (cryptlen < authsize)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
573
  		return -EINVAL;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
574
  	cryptlen -= authsize;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
575

9382d97af   Huang Ying   crypto: gcm - Use...
576
577
578
  	gctx->src = req->src;
  	gctx->cryptlen = cryptlen;
  	gctx->complete = gcm_dec_hash_done;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
579

9382d97af   Huang Ying   crypto: gcm - Use...
580
581
582
  	err = gcm_hash(req, pctx);
  	if (err)
  		return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
583

9382d97af   Huang Ying   crypto: gcm - Use...
584
585
586
  	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
  					gcm_decrypt_done, req);
  	crypto_gcm_init_crypt(abreq, req, cryptlen);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
587
588
589
  	err = crypto_ablkcipher_decrypt(abreq);
  	if (err)
  		return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
590

9382d97af   Huang Ying   crypto: gcm - Use...
591
  	return crypto_gcm_verify(req, pctx);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
592
593
594
595
596
597
598
599
  }
  
  static int crypto_gcm_init_tfm(struct crypto_tfm *tfm)
  {
  	struct crypto_instance *inst = (void *)tfm->__crt_alg;
  	struct gcm_instance_ctx *ictx = crypto_instance_ctx(inst);
  	struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm);
  	struct crypto_ablkcipher *ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
600
  	struct crypto_ahash *ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
601
602
  	unsigned long align;
  	int err;
9382d97af   Huang Ying   crypto: gcm - Use...
603
604
605
  	ghash = crypto_spawn_ahash(&ictx->ghash);
  	if (IS_ERR(ghash))
  		return PTR_ERR(ghash);
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
606
  	ctr = crypto_spawn_skcipher(&ictx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
607
608
  	err = PTR_ERR(ctr);
  	if (IS_ERR(ctr))
9382d97af   Huang Ying   crypto: gcm - Use...
609
  		goto err_free_hash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
610
611
  
  	ctx->ctr = ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
612
  	ctx->ghash = ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
613

2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
614
  	align = crypto_tfm_alg_alignmask(tfm);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
615
  	align &= ~(crypto_tfm_ctx_alignment() - 1);
7f6813786   Herbert Xu   [CRYPTO] gcm: Put...
616
  	tfm->crt_aead.reqsize = align +
9382d97af   Huang Ying   crypto: gcm - Use...
617
618
619
620
621
  		offsetof(struct crypto_gcm_req_priv_ctx, u) +
  		max(sizeof(struct ablkcipher_request) +
  		    crypto_ablkcipher_reqsize(ctr),
  		    sizeof(struct ahash_request) +
  		    crypto_ahash_reqsize(ghash));
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
622
623
  
  	return 0;
9382d97af   Huang Ying   crypto: gcm - Use...
624
625
626
627
  
  err_free_hash:
  	crypto_free_ahash(ghash);
  	return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
628
629
630
631
632
  }
  
  static void crypto_gcm_exit_tfm(struct crypto_tfm *tfm)
  {
  	struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm);
9382d97af   Huang Ying   crypto: gcm - Use...
633
  	crypto_free_ahash(ctx->ghash);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
634
635
  	crypto_free_ablkcipher(ctx->ctr);
  }
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
636
637
  static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb,
  						       const char *full_name,
9382d97af   Huang Ying   crypto: gcm - Use...
638
639
  						       const char *ctr_name,
  						       const char *ghash_name)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
640
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
641
  	struct crypto_attr_type *algt;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
642
643
  	struct crypto_instance *inst;
  	struct crypto_alg *ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
644
645
  	struct crypto_alg *ghash_alg;
  	struct ahash_alg *ghash_ahash_alg;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
646
647
  	struct gcm_instance_ctx *ctx;
  	int err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
648

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
649
650
651
  	algt = crypto_get_attr_type(tb);
  	err = PTR_ERR(algt);
  	if (IS_ERR(algt))
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
652
  		return ERR_PTR(err);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
653
654
  	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
  		return ERR_PTR(-EINVAL);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
655

9382d97af   Huang Ying   crypto: gcm - Use...
656
657
658
659
660
661
662
663
  	ghash_alg = crypto_find_alg(ghash_name, &crypto_ahash_type,
  				    CRYPTO_ALG_TYPE_HASH,
  				    CRYPTO_ALG_TYPE_AHASH_MASK);
  	err = PTR_ERR(ghash_alg);
  	if (IS_ERR(ghash_alg))
  		return ERR_PTR(err);
  
  	err = -ENOMEM;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
664
665
  	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
  	if (!inst)
9382d97af   Huang Ying   crypto: gcm - Use...
666
  		goto out_put_ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
667

1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
668
  	ctx = crypto_instance_ctx(inst);
9382d97af   Huang Ying   crypto: gcm - Use...
669
670
671
672
673
  	ghash_ahash_alg = container_of(ghash_alg, struct ahash_alg, halg.base);
  	err = crypto_init_ahash_spawn(&ctx->ghash, &ghash_ahash_alg->halg,
  				      inst);
  	if (err)
  		goto err_free_inst;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
674
675
676
677
678
  	crypto_set_skcipher_spawn(&ctx->ctr, inst);
  	err = crypto_grab_skcipher(&ctx->ctr, ctr_name, 0,
  				   crypto_requires_sync(algt->type,
  							algt->mask));
  	if (err)
9382d97af   Huang Ying   crypto: gcm - Use...
679
  		goto err_drop_ghash;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
680
681
  
  	ctr = crypto_skcipher_spawn_alg(&ctx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
682

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
683
  	/* We only support 16-byte blocks. */
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
684
  	if (ctr->cra_ablkcipher.ivsize != 16)
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
685
686
687
688
689
  		goto out_put_ctr;
  
  	/* Not a stream cipher? */
  	err = -EINVAL;
  	if (ctr->cra_blocksize != 1)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
690
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
691
  	err = -ENAMETOOLONG;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
692
  	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
9382d97af   Huang Ying   crypto: gcm - Use...
693
694
  		     "gcm_base(%s,%s)", ctr->cra_driver_name,
  		     ghash_alg->cra_driver_name) >=
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
695
  	    CRYPTO_MAX_ALG_NAME)
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
696
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
697

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
698
  	memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
699
700
  	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
  	inst->alg.cra_flags |= ctr->cra_flags & CRYPTO_ALG_ASYNC;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
701
  	inst->alg.cra_priority = ctr->cra_priority;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
702
  	inst->alg.cra_blocksize = 1;
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
703
  	inst->alg.cra_alignmask = ctr->cra_alignmask | (__alignof__(u64) - 1);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
704
  	inst->alg.cra_type = &crypto_aead_type;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
705
  	inst->alg.cra_aead.ivsize = 16;
7ba683a6d   Herbert Xu   [CRYPTO] aead: Ma...
706
  	inst->alg.cra_aead.maxauthsize = 16;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
707
708
709
710
  	inst->alg.cra_ctxsize = sizeof(struct crypto_gcm_ctx);
  	inst->alg.cra_init = crypto_gcm_init_tfm;
  	inst->alg.cra_exit = crypto_gcm_exit_tfm;
  	inst->alg.cra_aead.setkey = crypto_gcm_setkey;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
711
  	inst->alg.cra_aead.setauthsize = crypto_gcm_setauthsize;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
712
713
714
715
  	inst->alg.cra_aead.encrypt = crypto_gcm_encrypt;
  	inst->alg.cra_aead.decrypt = crypto_gcm_decrypt;
  
  out:
9382d97af   Huang Ying   crypto: gcm - Use...
716
  	crypto_mod_put(ghash_alg);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
717
  	return inst;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
718
719
720
  
  out_put_ctr:
  	crypto_drop_skcipher(&ctx->ctr);
9382d97af   Huang Ying   crypto: gcm - Use...
721
722
  err_drop_ghash:
  	crypto_drop_ahash(&ctx->ghash);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
723
724
  err_free_inst:
  	kfree(inst);
9382d97af   Huang Ying   crypto: gcm - Use...
725
  out_put_ghash:
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
726
727
728
  	inst = ERR_PTR(err);
  	goto out;
  }
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
  static struct crypto_instance *crypto_gcm_alloc(struct rtattr **tb)
  {
  	int err;
  	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]);
  	err = PTR_ERR(cipher_name);
  	if (IS_ERR(cipher_name))
  		return ERR_PTR(err);
  
  	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >=
  	    CRYPTO_MAX_ALG_NAME)
  		return ERR_PTR(-ENAMETOOLONG);
  
  	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >=
  	    CRYPTO_MAX_ALG_NAME)
  		return ERR_PTR(-ENAMETOOLONG);
9382d97af   Huang Ying   crypto: gcm - Use...
748
  	return crypto_gcm_alloc_common(tb, full_name, ctr_name, "ghash");
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
749
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
750
751
752
  static void crypto_gcm_free(struct crypto_instance *inst)
  {
  	struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst);
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
753
  	crypto_drop_skcipher(&ctx->ctr);
9382d97af   Huang Ying   crypto: gcm - Use...
754
  	crypto_drop_ahash(&ctx->ghash);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
755
756
757
758
759
760
761
762
763
  	kfree(inst);
  }
  
  static struct crypto_template crypto_gcm_tmpl = {
  	.name = "gcm",
  	.alloc = crypto_gcm_alloc,
  	.free = crypto_gcm_free,
  	.module = THIS_MODULE,
  };
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
764
765
766
767
  static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb)
  {
  	int err;
  	const char *ctr_name;
9382d97af   Huang Ying   crypto: gcm - Use...
768
  	const char *ghash_name;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
769
770
771
772
773
774
  	char full_name[CRYPTO_MAX_ALG_NAME];
  
  	ctr_name = crypto_attr_alg_name(tb[1]);
  	err = PTR_ERR(ctr_name);
  	if (IS_ERR(ctr_name))
  		return ERR_PTR(err);
9382d97af   Huang Ying   crypto: gcm - Use...
775
776
777
778
779
780
781
  	ghash_name = crypto_attr_alg_name(tb[2]);
  	err = PTR_ERR(ghash_name);
  	if (IS_ERR(ghash_name))
  		return ERR_PTR(err);
  
  	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s,%s)",
  		     ctr_name, ghash_name) >= CRYPTO_MAX_ALG_NAME)
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
782
  		return ERR_PTR(-ENAMETOOLONG);
9382d97af   Huang Ying   crypto: gcm - Use...
783
  	return crypto_gcm_alloc_common(tb, full_name, ctr_name, ghash_name);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
784
785
786
787
788
789
790
791
  }
  
  static struct crypto_template crypto_gcm_base_tmpl = {
  	.name = "gcm_base",
  	.alloc = crypto_gcm_base_alloc,
  	.free = crypto_gcm_free,
  	.module = THIS_MODULE,
  };
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
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
986
987
988
989
990
991
992
993
994
995
  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)
  {
  	struct aead_request *subreq = aead_request_ctx(req);
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead);
  	struct crypto_aead *child = ctx->child;
  	u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
  			   crypto_aead_alignmask(child) + 1);
  
  	memcpy(iv, ctx->nonce, 4);
  	memcpy(iv + 4, req->iv, 8);
  
  	aead_request_set_tfm(subreq, child);
  	aead_request_set_callback(subreq, req->base.flags, req->base.complete,
  				  req->base.data);
  	aead_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, iv);
  	aead_request_set_assoc(subreq, req->assoc, req->assoclen);
  
  	return subreq;
  }
  
  static int crypto_rfc4106_encrypt(struct aead_request *req)
  {
  	req = crypto_rfc4106_crypt(req);
  
  	return crypto_aead_encrypt(req);
  }
  
  static int crypto_rfc4106_decrypt(struct aead_request *req)
  {
  	req = crypto_rfc4106_crypt(req);
  
  	return crypto_aead_decrypt(req);
  }
  
  static int crypto_rfc4106_init_tfm(struct crypto_tfm *tfm)
  {
  	struct crypto_instance *inst = (void *)tfm->__crt_alg;
  	struct crypto_aead_spawn *spawn = crypto_instance_ctx(inst);
  	struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm);
  	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);
  	tfm->crt_aead.reqsize = sizeof(struct aead_request) +
  				ALIGN(crypto_aead_reqsize(aead),
  				      crypto_tfm_ctx_alignment()) +
  				align + 16;
  
  	return 0;
  }
  
  static void crypto_rfc4106_exit_tfm(struct crypto_tfm *tfm)
  {
  	struct crypto_rfc4106_ctx *ctx = crypto_tfm_ctx(tfm);
  
  	crypto_free_aead(ctx->child);
  }
  
  static struct crypto_instance *crypto_rfc4106_alloc(struct rtattr **tb)
  {
  	struct crypto_attr_type *algt;
  	struct crypto_instance *inst;
  	struct crypto_aead_spawn *spawn;
  	struct crypto_alg *alg;
  	const char *ccm_name;
  	int err;
  
  	algt = crypto_get_attr_type(tb);
  	err = PTR_ERR(algt);
  	if (IS_ERR(algt))
  		return ERR_PTR(err);
  
  	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
  		return ERR_PTR(-EINVAL);
  
  	ccm_name = crypto_attr_alg_name(tb[1]);
  	err = PTR_ERR(ccm_name);
  	if (IS_ERR(ccm_name))
  		return ERR_PTR(err);
  
  	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
  	if (!inst)
  		return ERR_PTR(-ENOMEM);
  
  	spawn = crypto_instance_ctx(inst);
  	crypto_set_aead_spawn(spawn, inst);
  	err = crypto_grab_aead(spawn, ccm_name, 0,
  			       crypto_requires_sync(algt->type, algt->mask));
  	if (err)
  		goto out_free_inst;
  
  	alg = crypto_aead_spawn_alg(spawn);
  
  	err = -EINVAL;
  
  	/* We only support 16-byte blocks. */
  	if (alg->cra_aead.ivsize != 16)
  		goto out_drop_alg;
  
  	/* Not a stream cipher? */
  	if (alg->cra_blocksize != 1)
  		goto out_drop_alg;
  
  	err = -ENAMETOOLONG;
  	if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
  		     "rfc4106(%s)", alg->cra_name) >= CRYPTO_MAX_ALG_NAME ||
  	    snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
  		     "rfc4106(%s)", alg->cra_driver_name) >=
  	    CRYPTO_MAX_ALG_NAME)
  		goto out_drop_alg;
  
  	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
  	inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
  	inst->alg.cra_priority = alg->cra_priority;
  	inst->alg.cra_blocksize = 1;
  	inst->alg.cra_alignmask = alg->cra_alignmask;
  	inst->alg.cra_type = &crypto_nivaead_type;
  
  	inst->alg.cra_aead.ivsize = 8;
  	inst->alg.cra_aead.maxauthsize = 16;
  
  	inst->alg.cra_ctxsize = sizeof(struct crypto_rfc4106_ctx);
  
  	inst->alg.cra_init = crypto_rfc4106_init_tfm;
  	inst->alg.cra_exit = crypto_rfc4106_exit_tfm;
  
  	inst->alg.cra_aead.setkey = crypto_rfc4106_setkey;
  	inst->alg.cra_aead.setauthsize = crypto_rfc4106_setauthsize;
  	inst->alg.cra_aead.encrypt = crypto_rfc4106_encrypt;
  	inst->alg.cra_aead.decrypt = crypto_rfc4106_decrypt;
  
  	inst->alg.cra_aead.geniv = "seqiv";
  
  out:
  	return inst;
  
  out_drop_alg:
  	crypto_drop_aead(spawn);
  out_free_inst:
  	kfree(inst);
  	inst = ERR_PTR(err);
  	goto out;
  }
  
  static void crypto_rfc4106_free(struct crypto_instance *inst)
  {
  	crypto_drop_spawn(crypto_instance_ctx(inst));
  	kfree(inst);
  }
  
  static struct crypto_template crypto_rfc4106_tmpl = {
  	.name = "rfc4106",
  	.alloc = crypto_rfc4106_alloc,
  	.free = crypto_rfc4106_free,
  	.module = THIS_MODULE,
  };
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
996
997
  static int __init crypto_gcm_module_init(void)
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
998
  	int err;
9382d97af   Huang Ying   crypto: gcm - Use...
999
1000
1001
  	gcm_zeroes = kzalloc(16, GFP_KERNEL);
  	if (!gcm_zeroes)
  		return -ENOMEM;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1002
1003
1004
1005
1006
1007
1008
  	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...
1009
1010
1011
  	err = crypto_register_template(&crypto_rfc4106_tmpl);
  	if (err)
  		goto out_undo_gcm;
9382d97af   Huang Ying   crypto: gcm - Use...
1012
  	return 0;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1013

dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
1014
1015
  out_undo_gcm:
  	crypto_unregister_template(&crypto_gcm_tmpl);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1016
1017
  out_undo_base:
  	crypto_unregister_template(&crypto_gcm_base_tmpl);
9382d97af   Huang Ying   crypto: gcm - Use...
1018
1019
1020
  out:
  	kfree(gcm_zeroes);
  	return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1021
1022
1023
1024
  }
  
  static void __exit crypto_gcm_module_exit(void)
  {
9382d97af   Huang Ying   crypto: gcm - Use...
1025
  	kfree(gcm_zeroes);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
1026
  	crypto_unregister_template(&crypto_rfc4106_tmpl);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1027
  	crypto_unregister_template(&crypto_gcm_tmpl);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1028
  	crypto_unregister_template(&crypto_gcm_base_tmpl);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1029
1030
1031
1032
1033
1034
1035
1036
  }
  
  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>");
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1037
  MODULE_ALIAS("gcm_base");
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
1038
  MODULE_ALIAS("rfc4106");