Blame view

crypto/gcm.c 33.2 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];
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
62
  	u8 auth_tag[16];
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
63
  	u8 iauth_tag[16];
adcbc688f   Herbert Xu   crypto: gcm - Con...
64
65
66
  	struct scatterlist src[3];
  	struct scatterlist dst[3];
  	struct scatterlist sg;
9382d97af   Huang Ying   crypto: gcm - Use...
67
68
69
  	struct crypto_gcm_ghash_ctx ghash_ctx;
  	union {
  		struct ahash_request ahreq;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
70
  		struct skcipher_request skreq;
9382d97af   Huang Ying   crypto: gcm - Use...
71
  	} u;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
72
  };
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
73
74
75
76
  struct crypto_gcm_setkey_result {
  	int err;
  	struct completion completion;
  };
adcbc688f   Herbert Xu   crypto: gcm - Con...
77
78
79
80
81
82
  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...
83

2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
84
85
86
87
88
89
90
  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...
91
  static void crypto_gcm_setkey_done(struct crypto_async_request *req, int err)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
92
  {
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
93
  	struct crypto_gcm_setkey_result *result = req->data;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
94

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
95
96
97
98
99
  	if (err == -EINPROGRESS)
  		return;
  
  	result->err = err;
  	complete(&result->completion);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
100
101
102
103
104
105
  }
  
  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...
106
  	struct crypto_ahash *ghash = ctx->ghash;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
107
  	struct crypto_skcipher *ctr = ctx->ctr;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
108
109
  	struct {
  		be128 hash;
50d2e6dc1   Ondrej Mosnáček   crypto: gcm - Fix...
110
  		u8 iv[16];
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
111

eb7b813dd   Radu Solea   MLK-14785 CAAM: F...
112
  		struct crypto_gcm_setkey_result result ____cacheline_aligned;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
113
114
  
  		struct scatterlist sg[1];
16f37ecdd   Herbert Xu   crypto: gcm - Use...
115
  		struct skcipher_request req;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
116
117
  	} *data;
  	int err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
118

16f37ecdd   Herbert Xu   crypto: gcm - Use...
119
120
121
122
123
  	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...
124
  				    CRYPTO_TFM_RES_MASK);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
125
  	if (err)
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
126
  		return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
127

16f37ecdd   Herbert Xu   crypto: gcm - Use...
128
  	data = kzalloc(sizeof(*data) + crypto_skcipher_reqsize(ctr),
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
129
130
131
132
133
134
  		       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...
135
136
137
138
139
140
141
142
143
  	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...
144
145
146
147
148
149
  	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...
150
151
  	if (err)
  		goto out;
9382d97af   Huang Ying   crypto: gcm - Use...
152
153
154
155
156
157
  	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...
158

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
159
  out:
adcbc688f   Herbert Xu   crypto: gcm - Con...
160
  	kzfree(data);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
161
162
  	return err;
  }
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
  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...
181
  static void crypto_gcm_init_common(struct aead_request *req)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
182
  {
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
183
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
184
  	__be32 counter = cpu_to_be32(1);
adcbc688f   Herbert Xu   crypto: gcm - Con...
185
  	struct scatterlist *sg;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
186
187
  
  	memset(pctx->auth_tag, 0, sizeof(pctx->auth_tag));
adcbc688f   Herbert Xu   crypto: gcm - Con...
188
189
  	memcpy(pctx->iv, req->iv, 12);
  	memcpy(pctx->iv + 12, &counter, 4);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
190

adcbc688f   Herbert Xu   crypto: gcm - Con...
191
  	sg_init_table(pctx->src, 3);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
192
  	sg_set_buf(pctx->src, pctx->auth_tag, sizeof(pctx->auth_tag));
adcbc688f   Herbert Xu   crypto: gcm - Con...
193
194
  	sg = scatterwalk_ffwd(pctx->src + 1, req->src, req->assoclen);
  	if (sg != pctx->src + 1)
c56f6d127   Dan Williams   crypto: replace s...
195
  		sg_chain(pctx->src, 2, sg);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
196

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
197
  	if (req->src != req->dst) {
adcbc688f   Herbert Xu   crypto: gcm - Con...
198
  		sg_init_table(pctx->dst, 3);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
199
  		sg_set_buf(pctx->dst, pctx->auth_tag, sizeof(pctx->auth_tag));
adcbc688f   Herbert Xu   crypto: gcm - Con...
200
201
  		sg = scatterwalk_ffwd(pctx->dst + 1, req->dst, req->assoclen);
  		if (sg != pctx->dst + 1)
c56f6d127   Dan Williams   crypto: replace s...
202
  			sg_chain(pctx->dst, 2, sg);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
203
  	}
adcbc688f   Herbert Xu   crypto: gcm - Con...
204
205
206
207
208
209
210
211
  }
  
  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...
212
  	struct skcipher_request *skreq = &pctx->u.skreq;
adcbc688f   Herbert Xu   crypto: gcm - Con...
213
214
215
  	struct scatterlist *dst;
  
  	dst = req->src == req->dst ? pctx->src : pctx->dst;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
216

16f37ecdd   Herbert Xu   crypto: gcm - Use...
217
218
  	skcipher_request_set_tfm(skreq, ctx->ctr);
  	skcipher_request_set_crypt(skreq, pctx->src, dst,
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
219
  				     cryptlen + sizeof(pctx->auth_tag),
adcbc688f   Herbert Xu   crypto: gcm - Con...
220
  				     pctx->iv);
9382d97af   Huang Ying   crypto: gcm - Use...
221
222
223
224
225
226
227
228
229
  }
  
  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...
230

9382d97af   Huang Ying   crypto: gcm - Use...
231
  static int gcm_hash_update(struct aead_request *req,
3e3dc25fe   Mark Rustad   crypto: Resolve s...
232
  			   crypto_completion_t compl,
9382d97af   Huang Ying   crypto: gcm - Use...
233
  			   struct scatterlist *src,
adcbc688f   Herbert Xu   crypto: gcm - Con...
234
  			   unsigned int len, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
235
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
236
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
237
  	struct ahash_request *ahreq = &pctx->u.ahreq;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
238

adcbc688f   Herbert Xu   crypto: gcm - Con...
239
  	ahash_request_set_callback(ahreq, flags, compl, req);
9382d97af   Huang Ying   crypto: gcm - Use...
240
241
242
  	ahash_request_set_crypt(ahreq, src, NULL, len);
  
  	return crypto_ahash_update(ahreq);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
243
  }
9382d97af   Huang Ying   crypto: gcm - Use...
244
  static int gcm_hash_remain(struct aead_request *req,
9382d97af   Huang Ying   crypto: gcm - Use...
245
  			   unsigned int remain,
adcbc688f   Herbert Xu   crypto: gcm - Con...
246
  			   crypto_completion_t compl, u32 flags)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
247
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
248
  	return gcm_hash_update(req, compl, &gcm_zeroes->sg, remain, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
249
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
250
  static int gcm_hash_len(struct aead_request *req, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
251
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
252
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
253
254
255
256
257
258
259
  	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...
260
261
262
263
  	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...
264

adcbc688f   Herbert Xu   crypto: gcm - Con...
265
  	return crypto_ahash_finup(ahreq);
9382d97af   Huang Ying   crypto: gcm - Use...
266
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
267
  static int gcm_hash_len_continue(struct aead_request *req, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
268
  {
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
269
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
270
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
adcbc688f   Herbert Xu   crypto: gcm - Con...
271
  	return gctx->complete(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
272
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
273
  static void gcm_hash_len_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
274
275
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
276

adcbc688f   Herbert Xu   crypto: gcm - Con...
277
278
  	if (err)
  		goto out;
9382d97af   Huang Ying   crypto: gcm - Use...
279

adcbc688f   Herbert Xu   crypto: gcm - Con...
280
281
282
  	err = gcm_hash_len_continue(req, 0);
  	if (err == -EINPROGRESS)
  		return;
62c5593ae   Huang Ying   crypto: gcm - fix...
283

adcbc688f   Herbert Xu   crypto: gcm - Con...
284
285
  out:
  	aead_request_complete(req, err);
62c5593ae   Huang Ying   crypto: gcm - fix...
286
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
287
  static int gcm_hash_crypt_remain_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
288
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
289
290
  	return gcm_hash_len(req, flags) ?:
  	       gcm_hash_len_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
291
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
292
293
  static void gcm_hash_crypt_remain_done(struct crypto_async_request *areq,
  				       int err)
9382d97af   Huang Ying   crypto: gcm - Use...
294
295
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
296

adcbc688f   Herbert Xu   crypto: gcm - Con...
297
298
299
300
301
302
303
304
305
  	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...
306
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
307
  static int gcm_hash_crypt_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
308
  {
9382d97af   Huang Ying   crypto: gcm - Use...
309
310
311
  	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...
312
313
314
315
316
  	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...
317

adcbc688f   Herbert Xu   crypto: gcm - Con...
318
  	return gcm_hash_crypt_remain_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
319
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
320
  static void gcm_hash_crypt_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
321
322
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
323

adcbc688f   Herbert Xu   crypto: gcm - Con...
324
325
326
327
328
329
330
331
332
  	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...
333
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
334
  static int gcm_hash_assoc_remain_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
335
  {
9382d97af   Huang Ying   crypto: gcm - Use...
336
337
  	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...
338

adcbc688f   Herbert Xu   crypto: gcm - Con...
339
340
341
342
343
344
  	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...
345
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
346
347
  static void gcm_hash_assoc_remain_done(struct crypto_async_request *areq,
  				       int err)
9382d97af   Huang Ying   crypto: gcm - Use...
348
349
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
350

adcbc688f   Herbert Xu   crypto: gcm - Con...
351
352
353
354
355
356
357
358
359
  	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...
360
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
361
  static int gcm_hash_assoc_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
362
  {
9382d97af   Huang Ying   crypto: gcm - Use...
363
  	unsigned int remain;
adcbc688f   Herbert Xu   crypto: gcm - Con...
364
365
366
367
368
  	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...
369

adcbc688f   Herbert Xu   crypto: gcm - Con...
370
  	return gcm_hash_assoc_remain_continue(req, flags);
9382d97af   Huang Ying   crypto: gcm - Use...
371
  }
62c5593ae   Huang Ying   crypto: gcm - fix...
372
  static void gcm_hash_assoc_done(struct crypto_async_request *areq, int err)
9382d97af   Huang Ying   crypto: gcm - Use...
373
374
  {
  	struct aead_request *req = areq->data;
62c5593ae   Huang Ying   crypto: gcm - fix...
375

adcbc688f   Herbert Xu   crypto: gcm - Con...
376
377
378
379
380
381
382
383
384
  	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...
385
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
386
  static int gcm_hash_init_continue(struct aead_request *req, u32 flags)
62c5593ae   Huang Ying   crypto: gcm - fix...
387
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
388
389
390
391
  	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...
392

adcbc688f   Herbert Xu   crypto: gcm - Con...
393
  	return gcm_hash_assoc_remain_continue(req, flags);
62c5593ae   Huang Ying   crypto: gcm - fix...
394
395
396
397
398
  }
  
  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...
399
400
401
402
403
404
405
406
407
  	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...
408
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
409
  static int gcm_hash(struct aead_request *req, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
410
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
411
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
412
  	struct ahash_request *ahreq = &pctx->u.ahreq;
adcbc688f   Herbert Xu   crypto: gcm - Con...
413
  	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(crypto_aead_reqtfm(req));
9382d97af   Huang Ying   crypto: gcm - Use...
414
415
  
  	ahash_request_set_tfm(ahreq, ctx->ghash);
adcbc688f   Herbert Xu   crypto: gcm - Con...
416
417
418
  	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...
419
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
420
  static int gcm_enc_copy_hash(struct aead_request *req, u32 flags)
9382d97af   Huang Ying   crypto: gcm - Use...
421
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
422
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
9382d97af   Huang Ying   crypto: gcm - Use...
423
424
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	u8 *auth_tag = pctx->auth_tag;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
425

adcbc688f   Herbert Xu   crypto: gcm - Con...
426
427
428
  	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...
429
  				 crypto_aead_authsize(aead), 1);
adcbc688f   Herbert Xu   crypto: gcm - Con...
430
  	return 0;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
431
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
432
  static int gcm_encrypt_continue(struct aead_request *req, u32 flags)
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
433
  {
9382d97af   Huang Ying   crypto: gcm - Use...
434
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
adcbc688f   Herbert Xu   crypto: gcm - Con...
435
  	struct crypto_gcm_ghash_ctx *gctx = &pctx->ghash_ctx;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
436

adcbc688f   Herbert Xu   crypto: gcm - Con...
437
438
439
  	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...
440

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

adcbc688f   Herbert Xu   crypto: gcm - Con...
447
448
449
450
451
452
  	if (err)
  		goto out;
  
  	err = gcm_encrypt_continue(req, 0);
  	if (err == -EINPROGRESS)
  		return;
9382d97af   Huang Ying   crypto: gcm - Use...
453

adcbc688f   Herbert Xu   crypto: gcm - Con...
454
  out:
62c5593ae   Huang Ying   crypto: gcm - fix...
455
  	aead_request_complete(req, err);
9382d97af   Huang Ying   crypto: gcm - Use...
456
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
457
458
  static int crypto_gcm_encrypt(struct aead_request *req)
  {
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
459
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
460
  	struct skcipher_request *skreq = &pctx->u.skreq;
adcbc688f   Herbert Xu   crypto: gcm - Con...
461
  	u32 flags = aead_request_flags(req);
9382d97af   Huang Ying   crypto: gcm - Use...
462

adcbc688f   Herbert Xu   crypto: gcm - Con...
463
464
  	crypto_gcm_init_common(req);
  	crypto_gcm_init_crypt(req, req->cryptlen);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
465
  	skcipher_request_set_callback(skreq, flags, gcm_encrypt_done, req);
9382d97af   Huang Ying   crypto: gcm - Use...
466

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

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

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

adcbc688f   Herbert Xu   crypto: gcm - Con...
514
515
516
  	gctx->src = sg_next(pctx->src);
  	gctx->cryptlen = cryptlen;
  	gctx->complete = gcm_dec_hash_continue;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
517

adcbc688f   Herbert Xu   crypto: gcm - Con...
518
  	return gcm_hash(req, flags);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
519
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
520
  static int crypto_gcm_init_tfm(struct crypto_aead *tfm)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
521
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
522
523
524
  	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...
525
  	struct crypto_skcipher *ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
526
  	struct crypto_ahash *ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
527
528
  	unsigned long align;
  	int err;
9382d97af   Huang Ying   crypto: gcm - Use...
529
530
531
  	ghash = crypto_spawn_ahash(&ictx->ghash);
  	if (IS_ERR(ghash))
  		return PTR_ERR(ghash);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
532
  	ctr = crypto_spawn_skcipher2(&ictx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
533
534
  	err = PTR_ERR(ctr);
  	if (IS_ERR(ctr))
9382d97af   Huang Ying   crypto: gcm - Use...
535
  		goto err_free_hash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
536
537
  
  	ctx->ctr = ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
538
  	ctx->ghash = ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
539

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

9382d97af   Huang Ying   crypto: gcm - Use...
559
  	crypto_free_ahash(ctx->ghash);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
560
  	crypto_free_skcipher(ctx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
561
  }
7b05a373a   Herbert Xu   crypto: gcm - Use...
562
563
564
565
566
567
568
569
  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...
570
571
572
573
574
  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...
575
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
576
  	struct crypto_attr_type *algt;
adcbc688f   Herbert Xu   crypto: gcm - Con...
577
  	struct aead_instance *inst;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
578
  	struct skcipher_alg *ctr;
9382d97af   Huang Ying   crypto: gcm - Use...
579
  	struct crypto_alg *ghash_alg;
adcbc688f   Herbert Xu   crypto: gcm - Con...
580
  	struct hash_alg_common *ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
581
582
  	struct gcm_instance_ctx *ctx;
  	int err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
583

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
584
  	algt = crypto_get_attr_type(tb);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
585
  	if (IS_ERR(algt))
adcbc688f   Herbert Xu   crypto: gcm - Con...
586
  		return PTR_ERR(algt);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
587

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

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

adcbc688f   Herbert Xu   crypto: gcm - Con...
606
607
608
  	ctx = aead_instance_ctx(inst);
  	err = crypto_init_ahash_spawn(&ctx->ghash, ghash,
  				      aead_crypto_instance(inst));
9382d97af   Huang Ying   crypto: gcm - Use...
609
610
  	if (err)
  		goto err_free_inst;
adcbc688f   Herbert Xu   crypto: gcm - Con...
611
612
613
614
615
  	err = -EINVAL;
  	if (ghash->digestsize != 16)
  		goto err_drop_ghash;
  
  	crypto_set_skcipher_spawn(&ctx->ctr, aead_crypto_instance(inst));
16f37ecdd   Herbert Xu   crypto: gcm - Use...
616
617
618
  	err = crypto_grab_skcipher2(&ctx->ctr, ctr_name, 0,
  				    crypto_requires_sync(algt->type,
  							 algt->mask));
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
619
  	if (err)
9382d97af   Huang Ying   crypto: gcm - Use...
620
  		goto err_drop_ghash;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
621

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

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
624
  	/* We only support 16-byte blocks. */
16f37ecdd   Herbert Xu   crypto: gcm - Use...
625
  	if (crypto_skcipher_alg_ivsize(ctr) != 16)
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
626
627
628
629
  		goto out_put_ctr;
  
  	/* Not a stream cipher? */
  	err = -EINVAL;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
630
  	if (ctr->base.cra_blocksize != 1)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
631
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
632
  	err = -ENAMETOOLONG;
adcbc688f   Herbert Xu   crypto: gcm - Con...
633
  	if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME,
16f37ecdd   Herbert Xu   crypto: gcm - Use...
634
  		     "gcm_base(%s,%s)", ctr->base.cra_driver_name,
9382d97af   Huang Ying   crypto: gcm - Use...
635
  		     ghash_alg->cra_driver_name) >=
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
636
  	    CRYPTO_MAX_ALG_NAME)
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
637
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
638

adcbc688f   Herbert Xu   crypto: gcm - Con...
639
  	memcpy(inst->alg.base.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
640
641
  	inst->alg.base.cra_flags = (ghash->base.cra_flags |
  				    ctr->base.cra_flags) & CRYPTO_ALG_ASYNC;
adcbc688f   Herbert Xu   crypto: gcm - Con...
642
  	inst->alg.base.cra_priority = (ghash->base.cra_priority +
16f37ecdd   Herbert Xu   crypto: gcm - Use...
643
  				       ctr->base.cra_priority) / 2;
adcbc688f   Herbert Xu   crypto: gcm - Con...
644
645
  	inst->alg.base.cra_blocksize = 1;
  	inst->alg.base.cra_alignmask = ghash->base.cra_alignmask |
16f37ecdd   Herbert Xu   crypto: gcm - Use...
646
  				       ctr->base.cra_alignmask;
adcbc688f   Herbert Xu   crypto: gcm - Con...
647
648
  	inst->alg.base.cra_ctxsize = sizeof(struct crypto_gcm_ctx);
  	inst->alg.ivsize = 12;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
649
  	inst->alg.chunksize = crypto_skcipher_alg_chunksize(ctr);
adcbc688f   Herbert Xu   crypto: gcm - Con...
650
651
652
653
654
655
656
  	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...
657
  	inst->free = crypto_gcm_free;
adcbc688f   Herbert Xu   crypto: gcm - Con...
658
659
660
  	err = aead_register_instance(tmpl, inst);
  	if (err)
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
661

adcbc688f   Herbert Xu   crypto: gcm - Con...
662
  out_put_ghash:
9382d97af   Huang Ying   crypto: gcm - Use...
663
  	crypto_mod_put(ghash_alg);
adcbc688f   Herbert Xu   crypto: gcm - Con...
664
  	return err;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
665
666
667
  
  out_put_ctr:
  	crypto_drop_skcipher(&ctx->ctr);
9382d97af   Huang Ying   crypto: gcm - Use...
668
669
  err_drop_ghash:
  	crypto_drop_ahash(&ctx->ghash);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
670
671
  err_free_inst:
  	kfree(inst);
adcbc688f   Herbert Xu   crypto: gcm - Con...
672
  	goto out_put_ghash;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
673
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
674
  static int crypto_gcm_create(struct crypto_template *tmpl, struct rtattr **tb)
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
675
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
676
677
678
679
680
  	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...
681
  	if (IS_ERR(cipher_name))
adcbc688f   Herbert Xu   crypto: gcm - Con...
682
  		return PTR_ERR(cipher_name);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
683
684
685
  
  	if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", cipher_name) >=
  	    CRYPTO_MAX_ALG_NAME)
adcbc688f   Herbert Xu   crypto: gcm - Con...
686
  		return -ENAMETOOLONG;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
687
688
689
  
  	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm(%s)", cipher_name) >=
  	    CRYPTO_MAX_ALG_NAME)
adcbc688f   Herbert Xu   crypto: gcm - Con...
690
  		return -ENAMETOOLONG;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
691

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

9382d97af   Huang Ying   crypto: gcm - Use...
711
  	ghash_name = crypto_attr_alg_name(tb[2]);
9382d97af   Huang Ying   crypto: gcm - Use...
712
  	if (IS_ERR(ghash_name))
adcbc688f   Herbert Xu   crypto: gcm - Con...
713
  		return PTR_ERR(ghash_name);
9382d97af   Huang Ying   crypto: gcm - Use...
714
715
716
  
  	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...
717
  		return -ENAMETOOLONG;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
718

adcbc688f   Herbert Xu   crypto: gcm - Con...
719
720
  	return crypto_gcm_create_common(tmpl, tb, full_name,
  					ctr_name, ghash_name);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
721
722
723
724
  }
  
  static struct crypto_template crypto_gcm_base_tmpl = {
  	.name = "gcm_base",
adcbc688f   Herbert Xu   crypto: gcm - Con...
725
  	.create = crypto_gcm_base_create,
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
726
727
  	.module = THIS_MODULE,
  };
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
728
729
730
731
732
733
734
735
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
  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...
770
  	struct crypto_rfc4106_req_ctx *rctx = aead_request_ctx(req);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
771
772
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(aead);
7b05a373a   Herbert Xu   crypto: gcm - Use...
773
  	struct aead_request *subreq = &rctx->subreq;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
774
  	struct crypto_aead *child = ctx->child;
7b05a373a   Herbert Xu   crypto: gcm - Use...
775
  	struct scatterlist *sg;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
776
777
  	u8 *iv = PTR_ALIGN((u8 *)(subreq + 1) + crypto_aead_reqsize(child),
  			   crypto_aead_alignmask(child) + 1);
7b05a373a   Herbert Xu   crypto: gcm - Use...
778
  	scatterwalk_map_and_copy(iv + 12, req->src, 0, req->assoclen - 8, 0);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
779
780
  	memcpy(iv, ctx->nonce, 4);
  	memcpy(iv + 4, req->iv, 8);
7b05a373a   Herbert Xu   crypto: gcm - Use...
781
782
783
784
785
786
787
788
789
790
791
792
793
  	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...
794
795
796
  	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...
797
798
799
800
  	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...
801
802
803
804
805
806
  
  	return subreq;
  }
  
  static int crypto_rfc4106_encrypt(struct aead_request *req)
  {
7b05a373a   Herbert Xu   crypto: gcm - Use...
807
808
  	if (req->assoclen != 16 && req->assoclen != 20)
  		return -EINVAL;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
809
810
811
812
813
814
815
  	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...
816
817
  	if (req->assoclen != 16 && req->assoclen != 20)
  		return -EINVAL;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
818
819
820
821
  	req = crypto_rfc4106_crypt(req);
  
  	return crypto_aead_decrypt(req);
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
822
  static int crypto_rfc4106_init_tfm(struct crypto_aead *tfm)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
823
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
824
825
826
  	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...
827
828
829
830
831
832
833
834
835
836
837
  	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...
838
839
  	crypto_aead_set_reqsize(
  		tfm,
7b05a373a   Herbert Xu   crypto: gcm - Use...
840
  		sizeof(struct crypto_rfc4106_req_ctx) +
5d72336f1   Herbert Xu   crypto: gcm - Use...
841
  		ALIGN(crypto_aead_reqsize(aead), crypto_tfm_ctx_alignment()) +
7b05a373a   Herbert Xu   crypto: gcm - Use...
842
  		align + 24);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
843
844
845
  
  	return 0;
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
846
  static void crypto_rfc4106_exit_tfm(struct crypto_aead *tfm)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
847
  {
adcbc688f   Herbert Xu   crypto: gcm - Con...
848
  	struct crypto_rfc4106_ctx *ctx = crypto_aead_ctx(tfm);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
849
850
851
  
  	crypto_free_aead(ctx->child);
  }
7b05a373a   Herbert Xu   crypto: gcm - Use...
852
853
854
855
856
  static void crypto_rfc4106_free(struct aead_instance *inst)
  {
  	crypto_drop_aead(aead_instance_ctx(inst));
  	kfree(inst);
  }
adcbc688f   Herbert Xu   crypto: gcm - Con...
857
858
  static int crypto_rfc4106_create(struct crypto_template *tmpl,
  				 struct rtattr **tb)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
859
860
  {
  	struct crypto_attr_type *algt;
adcbc688f   Herbert Xu   crypto: gcm - Con...
861
  	struct aead_instance *inst;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
862
  	struct crypto_aead_spawn *spawn;
adcbc688f   Herbert Xu   crypto: gcm - Con...
863
  	struct aead_alg *alg;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
864
865
866
867
  	const char *ccm_name;
  	int err;
  
  	algt = crypto_get_attr_type(tb);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
868
  	if (IS_ERR(algt))
adcbc688f   Herbert Xu   crypto: gcm - Con...
869
  		return PTR_ERR(algt);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
870

5e4b8c1fc   Herbert Xu   crypto: aead - Re...
871
  	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
adcbc688f   Herbert Xu   crypto: gcm - Con...
872
  		return -EINVAL;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
873
874
  
  	ccm_name = crypto_attr_alg_name(tb[1]);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
875
  	if (IS_ERR(ccm_name))
adcbc688f   Herbert Xu   crypto: gcm - Con...
876
  		return PTR_ERR(ccm_name);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
877
878
879
  
  	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
  	if (!inst)
adcbc688f   Herbert Xu   crypto: gcm - Con...
880
  		return -ENOMEM;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
881

adcbc688f   Herbert Xu   crypto: gcm - Con...
882
883
  	spawn = aead_instance_ctx(inst);
  	crypto_set_aead_spawn(spawn, aead_crypto_instance(inst));
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
884
885
886
887
  	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...
888
  	alg = crypto_spawn_aead_alg(spawn);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
889
890
  
  	err = -EINVAL;
adcbc688f   Herbert Xu   crypto: gcm - Con...
891
892
  	/* Underlying IV size must be 12. */
  	if (crypto_aead_alg_ivsize(alg) != 12)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
893
894
895
  		goto out_drop_alg;
  
  	/* Not a stream cipher? */
adcbc688f   Herbert Xu   crypto: gcm - Con...
896
  	if (alg->base.cra_blocksize != 1)
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
897
898
899
  		goto out_drop_alg;
  
  	err = -ENAMETOOLONG;
adcbc688f   Herbert Xu   crypto: gcm - Con...
900
901
902
903
904
  	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...
905
906
  	    CRYPTO_MAX_ALG_NAME)
  		goto out_drop_alg;
7b05a373a   Herbert Xu   crypto: gcm - Use...
907
  	inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC;
adcbc688f   Herbert Xu   crypto: gcm - Con...
908
909
910
  	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...
911

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

adcbc688f   Herbert Xu   crypto: gcm - Con...
914
  	inst->alg.ivsize = 8;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
915
  	inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
adcbc688f   Herbert Xu   crypto: gcm - Con...
916
  	inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
917

adcbc688f   Herbert Xu   crypto: gcm - Con...
918
919
  	inst->alg.init = crypto_rfc4106_init_tfm;
  	inst->alg.exit = crypto_rfc4106_exit_tfm;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
920

adcbc688f   Herbert Xu   crypto: gcm - Con...
921
922
923
924
  	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...
925

7b05a373a   Herbert Xu   crypto: gcm - Use...
926
  	inst->free = crypto_rfc4106_free;
adcbc688f   Herbert Xu   crypto: gcm - Con...
927
928
929
  	err = aead_register_instance(tmpl, inst);
  	if (err)
  		goto out_drop_alg;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
930
931
  
  out:
adcbc688f   Herbert Xu   crypto: gcm - Con...
932
  	return err;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
933
934
935
936
937
  
  out_drop_alg:
  	crypto_drop_aead(spawn);
  out_free_inst:
  	kfree(inst);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
938
939
  	goto out;
  }
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
940
941
  static struct crypto_template crypto_rfc4106_tmpl = {
  	.name = "rfc4106",
adcbc688f   Herbert Xu   crypto: gcm - Con...
942
  	.create = crypto_rfc4106_create,
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
943
944
  	.module = THIS_MODULE,
  };
73c89c15b   Tobias Brunner   crypto: gcm - Add...
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
  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...
978
  static int crypto_rfc4543_crypt(struct aead_request *req, bool enc)
73c89c15b   Tobias Brunner   crypto: gcm - Add...
979
980
981
  {
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_rfc4543_ctx *ctx = crypto_aead_ctx(aead);
adcbc688f   Herbert Xu   crypto: gcm - Con...
982
  	struct crypto_rfc4543_req_ctx *rctx = aead_request_ctx(req);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
983
  	struct aead_request *subreq = &rctx->subreq;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
984
  	unsigned int authsize = crypto_aead_authsize(aead);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
985
986
  	u8 *iv = PTR_ALIGN((u8 *)(rctx + 1) + crypto_aead_reqsize(ctx->child),
  			   crypto_aead_alignmask(ctx->child) + 1);
adcbc688f   Herbert Xu   crypto: gcm - Con...
987
988
989
990
991
992
993
  	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...
994
995
996
  
  	memcpy(iv, ctx->nonce, 4);
  	memcpy(iv + 4, req->iv, 8);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
997
  	aead_request_set_tfm(subreq, ctx->child);
adcbc688f   Herbert Xu   crypto: gcm - Con...
998
999
1000
1001
1002
1003
1004
1005
  	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...
1006
  }
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1007
1008
1009
1010
1011
  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...
1012
1013
  	unsigned int nbytes = req->assoclen + req->cryptlen -
  			      (enc ? 0 : authsize);
16f37ecdd   Herbert Xu   crypto: gcm - Use...
1014
1015
1016
1017
1018
  	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...
1019

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

5e4b8c1fc   Herbert Xu   crypto: aead - Re...
1096
  	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
adcbc688f   Herbert Xu   crypto: gcm - Con...
1097
  		return -EINVAL;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1098
1099
  
  	ccm_name = crypto_attr_alg_name(tb[1]);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1100
  	if (IS_ERR(ccm_name))
adcbc688f   Herbert Xu   crypto: gcm - Con...
1101
  		return PTR_ERR(ccm_name);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1102

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

adcbc688f   Herbert Xu   crypto: gcm - Con...
1107
  	ctx = aead_instance_ctx(inst);
9489667d3   Jussi Kivilinna   crypto: gcm - mak...
1108
  	spawn = &ctx->aead;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1109
  	crypto_set_aead_spawn(spawn, aead_crypto_instance(inst));
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1110
1111
1112
1113
  	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...
1114
  	alg = crypto_spawn_aead_alg(spawn);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1115
1116
  
  	err = -EINVAL;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1117
1118
  	/* Underlying IV size must be 12. */
  	if (crypto_aead_alg_ivsize(alg) != 12)
17db85469   Herbert Xu   crypto: gcm - Use...
1119
  		goto out_drop_alg;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1120
1121
  
  	/* Not a stream cipher? */
adcbc688f   Herbert Xu   crypto: gcm - Con...
1122
  	if (alg->base.cra_blocksize != 1)
17db85469   Herbert Xu   crypto: gcm - Use...
1123
  		goto out_drop_alg;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1124
1125
  
  	err = -ENAMETOOLONG;
adcbc688f   Herbert Xu   crypto: gcm - Con...
1126
1127
1128
1129
1130
  	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...
1131
  	    CRYPTO_MAX_ALG_NAME)
17db85469   Herbert Xu   crypto: gcm - Use...
1132
  		goto out_drop_alg;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1133

adcbc688f   Herbert Xu   crypto: gcm - Con...
1134
1135
1136
1137
  	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...
1138

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

adcbc688f   Herbert Xu   crypto: gcm - Con...
1141
  	inst->alg.ivsize = 8;
16f37ecdd   Herbert Xu   crypto: gcm - Use...
1142
  	inst->alg.chunksize = crypto_aead_alg_chunksize(alg);
adcbc688f   Herbert Xu   crypto: gcm - Con...
1143
  	inst->alg.maxauthsize = crypto_aead_alg_maxauthsize(alg);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1144

adcbc688f   Herbert Xu   crypto: gcm - Con...
1145
1146
  	inst->alg.init = crypto_rfc4543_init_tfm;
  	inst->alg.exit = crypto_rfc4543_exit_tfm;
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1147

adcbc688f   Herbert Xu   crypto: gcm - Con...
1148
1149
1150
1151
  	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...
1152

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

73c89c15b   Tobias Brunner   crypto: gcm - Add...
1194
1195
  out_undo_rfc4106:
  	crypto_unregister_template(&crypto_rfc4106_tmpl);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
1196
1197
  out_undo_gcm:
  	crypto_unregister_template(&crypto_gcm_tmpl);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1198
1199
  out_undo_base:
  	crypto_unregister_template(&crypto_gcm_base_tmpl);
9382d97af   Huang Ying   crypto: gcm - Use...
1200
1201
1202
  out:
  	kfree(gcm_zeroes);
  	return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1203
1204
1205
1206
  }
  
  static void __exit crypto_gcm_module_exit(void)
  {
9382d97af   Huang Ying   crypto: gcm - Use...
1207
  	kfree(gcm_zeroes);
73c89c15b   Tobias Brunner   crypto: gcm - Add...
1208
  	crypto_unregister_template(&crypto_rfc4543_tmpl);
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
1209
  	crypto_unregister_template(&crypto_rfc4106_tmpl);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1210
  	crypto_unregister_template(&crypto_gcm_tmpl);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
1211
  	crypto_unregister_template(&crypto_gcm_base_tmpl);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
1212
1213
1214
1215
1216
1217
1218
1219
  }
  
  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...
1220
1221
1222
  MODULE_ALIAS_CRYPTO("gcm_base");
  MODULE_ALIAS_CRYPTO("rfc4106");
  MODULE_ALIAS_CRYPTO("rfc4543");
4943ba16b   Kees Cook   crypto: include c...
1223
  MODULE_ALIAS_CRYPTO("gcm");