Blame view

crypto/gcm.c 19.8 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>
42c271c6c   Herbert Xu   [CRYPTO] scatterw...
13
  #include <crypto/scatterwalk.h>
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
14
  #include <linux/completion.h>
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
15
16
17
18
19
  #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...
20
  struct gcm_instance_ctx {
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
21
  	struct crypto_skcipher_spawn ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
22
23
24
25
26
27
  };
  
  struct crypto_gcm_ctx {
  	struct crypto_ablkcipher *ctr;
  	struct gf128mul_4k *gf128;
  };
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
28
29
30
31
  struct crypto_rfc4106_ctx {
  	struct crypto_aead *child;
  	u8 nonce[4];
  };
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
32
33
34
35
36
37
38
39
40
  struct crypto_gcm_ghash_ctx {
  	u32 bytes;
  	u32 flags;
  	struct gf128mul_4k *gf128;
  	u8 buffer[16];
  };
  
  struct crypto_gcm_req_priv_ctx {
  	u8 auth_tag[16];
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
41
  	u8 iauth_tag[16];
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
42
43
  	struct scatterlist src[2];
  	struct scatterlist dst[2];
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
44
  	struct crypto_gcm_ghash_ctx ghash;
7f6813786   Herbert Xu   [CRYPTO] gcm: Put...
45
  	struct ablkcipher_request abreq;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
46
  };
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
47
48
49
50
  struct crypto_gcm_setkey_result {
  	int err;
  	struct completion completion;
  };
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
51
52
53
54
55
56
57
  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);
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
  static void crypto_gcm_ghash_init(struct crypto_gcm_ghash_ctx *ctx, u32 flags,
  				  struct gf128mul_4k *gf128)
  {
  	ctx->bytes = 0;
  	ctx->flags = flags;
  	ctx->gf128 = gf128;
  	memset(ctx->buffer, 0, 16);
  }
  
  static void crypto_gcm_ghash_update(struct crypto_gcm_ghash_ctx *ctx,
  				    const u8 *src, unsigned int srclen)
  {
  	u8 *dst = ctx->buffer;
  
  	if (ctx->bytes) {
  		int n = min(srclen, ctx->bytes);
  		u8 *pos = dst + (16 - ctx->bytes);
  
  		ctx->bytes -= n;
  		srclen -= n;
  
  		while (n--)
  			*pos++ ^= *src++;
  
  		if (!ctx->bytes)
  			gf128mul_4k_lle((be128 *)dst, ctx->gf128);
  	}
  
  	while (srclen >= 16) {
  		crypto_xor(dst, src, 16);
  		gf128mul_4k_lle((be128 *)dst, ctx->gf128);
  		src += 16;
  		srclen -= 16;
  	}
  
  	if (srclen) {
  		ctx->bytes = 16 - srclen;
  		while (srclen--)
  			*dst++ ^= *src++;
  	}
  }
  
  static void crypto_gcm_ghash_update_sg(struct crypto_gcm_ghash_ctx *ctx,
  				       struct scatterlist *sg, int len)
  {
  	struct scatter_walk walk;
  	u8 *src;
  	int n;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
106
107
  	if (!len)
  		return;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
108
109
110
111
112
113
  	scatterwalk_start(&walk, sg);
  
  	while (len) {
  		n = scatterwalk_clamp(&walk, len);
  
  		if (!n) {
b2ab4a57b   Herbert Xu   [CRYPTO] scatterw...
114
  			scatterwalk_start(&walk, scatterwalk_sg_next(walk.sg));
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  			n = scatterwalk_clamp(&walk, len);
  		}
  
  		src = scatterwalk_map(&walk, 0);
  
  		crypto_gcm_ghash_update(ctx, src, n);
  		len -= n;
  
  		scatterwalk_unmap(src, 0);
  		scatterwalk_advance(&walk, n);
  		scatterwalk_done(&walk, 0, len);
  		if (len)
  			crypto_yield(ctx->flags);
  	}
  }
  
  static void crypto_gcm_ghash_flush(struct crypto_gcm_ghash_ctx *ctx)
  {
  	u8 *dst = ctx->buffer;
  
  	if (ctx->bytes) {
  		u8 *tmp = dst + (16 - ctx->bytes);
  
  		while (ctx->bytes--)
  			*tmp++ ^= 0;
  
  		gf128mul_4k_lle((be128 *)dst, ctx->gf128);
  	}
  
  	ctx->bytes = 0;
  }
  
  static void crypto_gcm_ghash_final_xor(struct crypto_gcm_ghash_ctx *ctx,
  				       unsigned int authlen,
  				       unsigned int cryptlen, u8 *dst)
  {
  	u8 *buf = ctx->buffer;
  	u128 lengths;
  
  	lengths.a = cpu_to_be64(authlen * 8);
  	lengths.b = cpu_to_be64(cryptlen * 8);
  
  	crypto_gcm_ghash_flush(ctx);
  	crypto_xor(buf, (u8 *)&lengths, 16);
  	gf128mul_4k_lle((be128 *)buf, ctx->gf128);
  	crypto_xor(dst, buf, 16);
  }
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
162
  static void crypto_gcm_setkey_done(struct crypto_async_request *req, int err)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
163
  {
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
164
  	struct crypto_gcm_setkey_result *result = req->data;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
165

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
166
167
168
169
170
  	if (err == -EINPROGRESS)
  		return;
  
  	result->err = err;
  	complete(&result->completion);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
171
172
173
174
175
176
177
  }
  
  static int crypto_gcm_setkey(struct crypto_aead *aead, const u8 *key,
  			     unsigned int keylen)
  {
  	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
  	struct crypto_ablkcipher *ctr = ctx->ctr;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
178
179
180
181
182
183
184
185
186
187
  	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...
188
189
190
191
192
193
194
  
  	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...
195
  		return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
196
197
198
  
  	crypto_aead_set_flags(aead, crypto_ablkcipher_get_flags(ctr) &
  				       CRYPTO_TFM_RES_MASK);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
  	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...
221
222
223
224
225
  	if (err)
  		goto out;
  
  	if (ctx->gf128 != NULL)
  		gf128mul_free_4k(ctx->gf128);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
226
  	ctx->gf128 = gf128mul_init_4k_lle(&data->hash);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
227
228
229
  
  	if (ctx->gf128 == NULL)
  		err = -ENOMEM;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
230
231
  out:
  	kfree(data);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
232
233
  	return err;
  }
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
  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...
252
253
254
  static void crypto_gcm_init_crypt(struct ablkcipher_request *ablk_req,
  				  struct aead_request *req,
  				  unsigned int cryptlen)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
255
256
257
  {
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_gcm_ctx *ctx = crypto_aead_ctx(aead);
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
258
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
259
  	u32 flags = req->base.tfm->crt_flags;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
260
  	struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
  	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...
278
279
  
  	ablkcipher_request_set_tfm(ablk_req, ctx->ctr);
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
280
281
282
  	ablkcipher_request_set_crypt(ablk_req, pctx->src, dst,
  				     cryptlen + sizeof(pctx->auth_tag),
  				     req->iv);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
283
284
  
  	crypto_gcm_ghash_init(ghash, flags, ctx->gf128);
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
285
286
  	crypto_gcm_ghash_update_sg(ghash, req->assoc, req->assoclen);
  	crypto_gcm_ghash_flush(ghash);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
287
  }
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
288
  static int crypto_gcm_hash(struct aead_request *req)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
289
  {
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
290
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
291
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
292
293
294
295
296
297
  	u8 *auth_tag = pctx->auth_tag;
  	struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
  
  	crypto_gcm_ghash_update_sg(ghash, req->dst, req->cryptlen);
  	crypto_gcm_ghash_final_xor(ghash, req->assoclen, req->cryptlen,
  				   auth_tag);
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
298
299
300
301
302
303
304
305
306
307
308
  	scatterwalk_map_and_copy(auth_tag, req->dst, req->cryptlen,
  				 crypto_aead_authsize(aead), 1);
  	return 0;
  }
  
  static void crypto_gcm_encrypt_done(struct crypto_async_request *areq, int err)
  {
  	struct aead_request *req = areq->data;
  
  	if (!err)
  		err = crypto_gcm_hash(req);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
309
310
311
312
313
  	aead_request_complete(req, err);
  }
  
  static int crypto_gcm_encrypt(struct aead_request *req)
  {
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
314
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
7f6813786   Herbert Xu   [CRYPTO] gcm: Put...
315
  	struct ablkcipher_request *abreq = &pctx->abreq;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
316
317
318
319
320
  	int err;
  
  	crypto_gcm_init_crypt(abreq, req, req->cryptlen);
  	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
  					crypto_gcm_encrypt_done, req);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
321

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
322
  	err = crypto_ablkcipher_encrypt(abreq);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
323
324
  	if (err)
  		return err;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
325
  	return crypto_gcm_hash(req);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
326
  }
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
  static int crypto_gcm_verify(struct aead_request *req)
  {
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
  	struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
  	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;
  
  	crypto_gcm_ghash_final_xor(ghash, req->assoclen, cryptlen, auth_tag);
  
  	authsize = crypto_aead_authsize(aead);
  	scatterwalk_map_and_copy(iauth_tag, req->src, cryptlen, authsize, 0);
  	return memcmp(iauth_tag, auth_tag, authsize) ? -EBADMSG : 0;
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
343
344
  static void crypto_gcm_decrypt_done(struct crypto_async_request *areq, int err)
  {
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
345
346
347
348
349
350
  	struct aead_request *req = areq->data;
  
  	if (!err)
  		err = crypto_gcm_verify(req);
  
  	aead_request_complete(req, err);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
351
352
353
354
  }
  
  static int crypto_gcm_decrypt(struct aead_request *req)
  {
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
355
  	struct crypto_aead *aead = crypto_aead_reqtfm(req);
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
356
  	struct crypto_gcm_req_priv_ctx *pctx = crypto_gcm_reqctx(req);
7f6813786   Herbert Xu   [CRYPTO] gcm: Put...
357
  	struct ablkcipher_request *abreq = &pctx->abreq;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
358
  	struct crypto_gcm_ghash_ctx *ghash = &pctx->ghash;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
359
360
  	unsigned int cryptlen = req->cryptlen;
  	unsigned int authsize = crypto_aead_authsize(aead);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
361
  	int err;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
362
  	if (cryptlen < authsize)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
363
  		return -EINVAL;
6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
364
  	cryptlen -= authsize;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
365

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
366
367
368
  	crypto_gcm_init_crypt(abreq, req, cryptlen);
  	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
  					crypto_gcm_decrypt_done, req);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
369

6160b2899   Herbert Xu   [CRYPTO] gcm: Fix...
370
  	crypto_gcm_ghash_update_sg(ghash, req->src, cryptlen);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
371

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
372
373
374
  	err = crypto_ablkcipher_decrypt(abreq);
  	if (err)
  		return err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
375

84c911523   Herbert Xu   [CRYPTO] gcm: Add...
376
  	return crypto_gcm_verify(req);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
377
378
379
380
381
382
383
384
385
386
  }
  
  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;
  	unsigned long align;
  	int err;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
387
  	ctr = crypto_spawn_skcipher(&ictx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
388
389
390
391
392
393
  	err = PTR_ERR(ctr);
  	if (IS_ERR(ctr))
  		return err;
  
  	ctx->ctr = ctr;
  	ctx->gf128 = NULL;
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
394
  	align = crypto_tfm_alg_alignmask(tfm);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
395
  	align &= ~(crypto_tfm_ctx_alignment() - 1);
7f6813786   Herbert Xu   [CRYPTO] gcm: Put...
396
397
398
  	tfm->crt_aead.reqsize = align +
  				sizeof(struct crypto_gcm_req_priv_ctx) +
  				crypto_ablkcipher_reqsize(ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
399
400
401
402
403
404
405
406
407
408
409
410
411
  
  	return 0;
  }
  
  static void crypto_gcm_exit_tfm(struct crypto_tfm *tfm)
  {
  	struct crypto_gcm_ctx *ctx = crypto_tfm_ctx(tfm);
  
  	if (ctx->gf128 != NULL)
  		gf128mul_free_4k(ctx->gf128);
  
  	crypto_free_ablkcipher(ctx->ctr);
  }
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
412
413
414
  static struct crypto_instance *crypto_gcm_alloc_common(struct rtattr **tb,
  						       const char *full_name,
  						       const char *ctr_name)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
415
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
416
  	struct crypto_attr_type *algt;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
417
418
  	struct crypto_instance *inst;
  	struct crypto_alg *ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
419
420
  	struct gcm_instance_ctx *ctx;
  	int err;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
421

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
422
423
424
  	algt = crypto_get_attr_type(tb);
  	err = PTR_ERR(algt);
  	if (IS_ERR(algt))
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
425
  		return ERR_PTR(err);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
426
427
  	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
  		return ERR_PTR(-EINVAL);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
428

1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
429
430
431
  	inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
  	if (!inst)
  		return ERR_PTR(-ENOMEM);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
432

1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
433
434
435
436
437
438
439
440
441
  	ctx = crypto_instance_ctx(inst);
  	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)
  		goto err_free_inst;
  
  	ctr = crypto_skcipher_spawn_alg(&ctx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
442

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
443
  	/* We only support 16-byte blocks. */
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
444
  	if (ctr->cra_ablkcipher.ivsize != 16)
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
445
446
447
448
449
  		goto out_put_ctr;
  
  	/* Not a stream cipher? */
  	err = -EINVAL;
  	if (ctr->cra_blocksize != 1)
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
450
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
451
  	err = -ENAMETOOLONG;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
452
453
454
  	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
  		     "gcm_base(%s)", ctr->cra_driver_name) >=
  	    CRYPTO_MAX_ALG_NAME)
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
455
  		goto out_put_ctr;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
456

d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
457
  	memcpy(inst->alg.cra_name, full_name, CRYPTO_MAX_ALG_NAME);
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
458
459
  	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
  	inst->alg.cra_flags |= ctr->cra_flags & CRYPTO_ALG_ASYNC;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
460
  	inst->alg.cra_priority = ctr->cra_priority;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
461
  	inst->alg.cra_blocksize = 1;
2589469d7   Herbert Xu   [CRYPTO] gcm: Fix...
462
  	inst->alg.cra_alignmask = ctr->cra_alignmask | (__alignof__(u64) - 1);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
463
  	inst->alg.cra_type = &crypto_aead_type;
84c911523   Herbert Xu   [CRYPTO] gcm: Add...
464
  	inst->alg.cra_aead.ivsize = 16;
7ba683a6d   Herbert Xu   [CRYPTO] aead: Ma...
465
  	inst->alg.cra_aead.maxauthsize = 16;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
466
467
468
469
  	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...
470
  	inst->alg.cra_aead.setauthsize = crypto_gcm_setauthsize;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
471
472
473
474
  	inst->alg.cra_aead.encrypt = crypto_gcm_encrypt;
  	inst->alg.cra_aead.decrypt = crypto_gcm_decrypt;
  
  out:
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
475
  	return inst;
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
476
477
478
  
  out_put_ctr:
  	crypto_drop_skcipher(&ctx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
479
480
  err_free_inst:
  	kfree(inst);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
481
482
483
  	inst = ERR_PTR(err);
  	goto out;
  }
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
  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);
  
  	return crypto_gcm_alloc_common(tb, full_name, ctr_name);
  }
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
506
507
508
  static void crypto_gcm_free(struct crypto_instance *inst)
  {
  	struct gcm_instance_ctx *ctx = crypto_instance_ctx(inst);
1472e5eba   Herbert Xu   [CRYPTO] gcm: Use...
509
  	crypto_drop_skcipher(&ctx->ctr);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
510
511
512
513
514
515
516
517
518
  	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...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  static struct crypto_instance *crypto_gcm_base_alloc(struct rtattr **tb)
  {
  	int err;
  	const char *ctr_name;
  	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);
  
  	if (snprintf(full_name, CRYPTO_MAX_ALG_NAME, "gcm_base(%s)",
  		     ctr_name) >= CRYPTO_MAX_ALG_NAME)
  		return ERR_PTR(-ENAMETOOLONG);
  
  	return crypto_gcm_alloc_common(tb, full_name, ctr_name);
  }
  
  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...
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
  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...
747
748
  static int __init crypto_gcm_module_init(void)
  {
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
749
750
751
752
753
754
755
756
757
  	int err;
  
  	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...
758
759
760
  	err = crypto_register_template(&crypto_rfc4106_tmpl);
  	if (err)
  		goto out_undo_gcm;
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
761
762
  out:
  	return err;
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
763
764
  out_undo_gcm:
  	crypto_unregister_template(&crypto_gcm_tmpl);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
765
766
767
  out_undo_base:
  	crypto_unregister_template(&crypto_gcm_base_tmpl);
  	goto out;
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
768
769
770
771
  }
  
  static void __exit crypto_gcm_module_exit(void)
  {
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
772
  	crypto_unregister_template(&crypto_rfc4106_tmpl);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
773
  	crypto_unregister_template(&crypto_gcm_tmpl);
d00aa19b5   Herbert Xu   [CRYPTO] gcm: All...
774
  	crypto_unregister_template(&crypto_gcm_base_tmpl);
28db8e3e3   Mikko Herranen   [CRYPTO] gcm: New...
775
776
777
778
779
780
781
782
  }
  
  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...
783
  MODULE_ALIAS("gcm_base");
dadbc53d0   Herbert Xu   [CRYPTO] gcm: Int...
784
  MODULE_ALIAS("rfc4106");