Blame view

crypto/pcbc.c 7.71 KB
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * PCBC: Propagating Cipher Block Chaining mode
   *
   * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
   * Written by David Howells (dhowells@redhat.com)
   *
   * Derived from cbc.c
   * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the Free
   * Software Foundation; either version 2 of the License, or (at your option)
   * any later version.
   *
   */
6650c4de6   Salvatore Mesoraca   crypto: remove se...
16
  #include <crypto/algapi.h>
043a44001   Herbert Xu   crypto: pcbc - Co...
17
  #include <crypto/internal/skcipher.h>
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
18
19
20
21
  #include <linux/err.h>
  #include <linux/init.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
22
  #include <linux/slab.h>
d8c34b949   Gideon Israel Dsouza   crypto: Replaced ...
23
  #include <linux/compiler.h>
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
24
25
26
  
  struct crypto_pcbc_ctx {
  	struct crypto_cipher *child;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
27
  };
043a44001   Herbert Xu   crypto: pcbc - Co...
28
  static int crypto_pcbc_setkey(struct crypto_skcipher *parent, const u8 *key,
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
29
30
  			      unsigned int keylen)
  {
043a44001   Herbert Xu   crypto: pcbc - Co...
31
  	struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(parent);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
32
33
34
35
  	struct crypto_cipher *child = ctx->child;
  	int err;
  
  	crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
043a44001   Herbert Xu   crypto: pcbc - Co...
36
37
  	crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) &
  				       CRYPTO_TFM_REQ_MASK);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
38
  	err = crypto_cipher_setkey(child, key, keylen);
043a44001   Herbert Xu   crypto: pcbc - Co...
39
40
  	crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) &
  					  CRYPTO_TFM_RES_MASK);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
41
42
  	return err;
  }
043a44001   Herbert Xu   crypto: pcbc - Co...
43
44
  static int crypto_pcbc_encrypt_segment(struct skcipher_request *req,
  				       struct skcipher_walk *walk,
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
45
  				       struct crypto_cipher *tfm)
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
46
  {
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
47
48
49
50
  	int bsize = crypto_cipher_blocksize(tfm);
  	unsigned int nbytes = walk->nbytes;
  	u8 *src = walk->src.virt.addr;
  	u8 *dst = walk->dst.virt.addr;
bb1ae0aad   Eric Biggers   crypto: pcbc - re...
51
  	u8 * const iv = walk->iv;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
52
53
  
  	do {
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
54
  		crypto_xor(iv, src, bsize);
043a44001   Herbert Xu   crypto: pcbc - Co...
55
  		crypto_cipher_encrypt_one(tfm, dst, iv);
45fe93dff   Ard Biesheuvel   crypto: algapi - ...
56
  		crypto_xor_cpy(iv, dst, src, bsize);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
57
58
59
60
61
62
63
  
  		src += bsize;
  		dst += bsize;
  	} while ((nbytes -= bsize) >= bsize);
  
  	return nbytes;
  }
043a44001   Herbert Xu   crypto: pcbc - Co...
64
65
  static int crypto_pcbc_encrypt_inplace(struct skcipher_request *req,
  				       struct skcipher_walk *walk,
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
66
  				       struct crypto_cipher *tfm)
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
67
  {
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
68
69
70
  	int bsize = crypto_cipher_blocksize(tfm);
  	unsigned int nbytes = walk->nbytes;
  	u8 *src = walk->src.virt.addr;
bb1ae0aad   Eric Biggers   crypto: pcbc - re...
71
  	u8 * const iv = walk->iv;
6650c4de6   Salvatore Mesoraca   crypto: remove se...
72
  	u8 tmpbuf[MAX_CIPHER_BLOCKSIZE];
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
73
74
75
  
  	do {
  		memcpy(tmpbuf, src, bsize);
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
76
  		crypto_xor(iv, src, bsize);
043a44001   Herbert Xu   crypto: pcbc - Co...
77
  		crypto_cipher_encrypt_one(tfm, src, iv);
45fe93dff   Ard Biesheuvel   crypto: algapi - ...
78
  		crypto_xor_cpy(iv, tmpbuf, src, bsize);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
79
80
81
  
  		src += bsize;
  	} while ((nbytes -= bsize) >= bsize);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
82
83
  	return nbytes;
  }
043a44001   Herbert Xu   crypto: pcbc - Co...
84
  static int crypto_pcbc_encrypt(struct skcipher_request *req)
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
85
  {
043a44001   Herbert Xu   crypto: pcbc - Co...
86
87
  	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  	struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
88
  	struct crypto_cipher *child = ctx->child;
043a44001   Herbert Xu   crypto: pcbc - Co...
89
90
  	struct skcipher_walk walk;
  	unsigned int nbytes;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
91
  	int err;
043a44001   Herbert Xu   crypto: pcbc - Co...
92
  	err = skcipher_walk_virt(&walk, req, false);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
93
94
95
  
  	while ((nbytes = walk.nbytes)) {
  		if (walk.src.virt.addr == walk.dst.virt.addr)
043a44001   Herbert Xu   crypto: pcbc - Co...
96
  			nbytes = crypto_pcbc_encrypt_inplace(req, &walk,
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
97
  							     child);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
98
  		else
043a44001   Herbert Xu   crypto: pcbc - Co...
99
  			nbytes = crypto_pcbc_encrypt_segment(req, &walk,
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
100
  							     child);
043a44001   Herbert Xu   crypto: pcbc - Co...
101
  		err = skcipher_walk_done(&walk, nbytes);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
102
103
104
105
  	}
  
  	return err;
  }
043a44001   Herbert Xu   crypto: pcbc - Co...
106
107
  static int crypto_pcbc_decrypt_segment(struct skcipher_request *req,
  				       struct skcipher_walk *walk,
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
108
  				       struct crypto_cipher *tfm)
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
109
  {
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
110
111
112
113
  	int bsize = crypto_cipher_blocksize(tfm);
  	unsigned int nbytes = walk->nbytes;
  	u8 *src = walk->src.virt.addr;
  	u8 *dst = walk->dst.virt.addr;
bb1ae0aad   Eric Biggers   crypto: pcbc - re...
114
  	u8 * const iv = walk->iv;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
115
116
  
  	do {
043a44001   Herbert Xu   crypto: pcbc - Co...
117
  		crypto_cipher_decrypt_one(tfm, dst, src);
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
118
  		crypto_xor(dst, iv, bsize);
45fe93dff   Ard Biesheuvel   crypto: algapi - ...
119
  		crypto_xor_cpy(iv, dst, src, bsize);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
120
121
122
123
  
  		src += bsize;
  		dst += bsize;
  	} while ((nbytes -= bsize) >= bsize);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
124
125
  	return nbytes;
  }
043a44001   Herbert Xu   crypto: pcbc - Co...
126
127
  static int crypto_pcbc_decrypt_inplace(struct skcipher_request *req,
  				       struct skcipher_walk *walk,
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
128
  				       struct crypto_cipher *tfm)
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
129
  {
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
130
131
132
  	int bsize = crypto_cipher_blocksize(tfm);
  	unsigned int nbytes = walk->nbytes;
  	u8 *src = walk->src.virt.addr;
bb1ae0aad   Eric Biggers   crypto: pcbc - re...
133
  	u8 * const iv = walk->iv;
6650c4de6   Salvatore Mesoraca   crypto: remove se...
134
  	u8 tmpbuf[MAX_CIPHER_BLOCKSIZE] __aligned(__alignof__(u32));
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
135
136
137
  
  	do {
  		memcpy(tmpbuf, src, bsize);
043a44001   Herbert Xu   crypto: pcbc - Co...
138
  		crypto_cipher_decrypt_one(tfm, src, src);
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
139
  		crypto_xor(src, iv, bsize);
45fe93dff   Ard Biesheuvel   crypto: algapi - ...
140
  		crypto_xor_cpy(iv, src, tmpbuf, bsize);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
141
142
143
  
  		src += bsize;
  	} while ((nbytes -= bsize) >= bsize);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
144
145
  	return nbytes;
  }
043a44001   Herbert Xu   crypto: pcbc - Co...
146
  static int crypto_pcbc_decrypt(struct skcipher_request *req)
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
147
  {
043a44001   Herbert Xu   crypto: pcbc - Co...
148
149
  	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  	struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
150
  	struct crypto_cipher *child = ctx->child;
043a44001   Herbert Xu   crypto: pcbc - Co...
151
152
  	struct skcipher_walk walk;
  	unsigned int nbytes;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
153
  	int err;
043a44001   Herbert Xu   crypto: pcbc - Co...
154
  	err = skcipher_walk_virt(&walk, req, false);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
155
156
157
  
  	while ((nbytes = walk.nbytes)) {
  		if (walk.src.virt.addr == walk.dst.virt.addr)
043a44001   Herbert Xu   crypto: pcbc - Co...
158
  			nbytes = crypto_pcbc_decrypt_inplace(req, &walk,
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
159
  							     child);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
160
  		else
043a44001   Herbert Xu   crypto: pcbc - Co...
161
  			nbytes = crypto_pcbc_decrypt_segment(req, &walk,
d0b9007a2   Herbert Xu   [CRYPTO] pcbc: Us...
162
  							     child);
043a44001   Herbert Xu   crypto: pcbc - Co...
163
  		err = skcipher_walk_done(&walk, nbytes);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
164
165
166
167
  	}
  
  	return err;
  }
043a44001   Herbert Xu   crypto: pcbc - Co...
168
  static int crypto_pcbc_init_tfm(struct crypto_skcipher *tfm)
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
169
  {
043a44001   Herbert Xu   crypto: pcbc - Co...
170
171
172
  	struct skcipher_instance *inst = skcipher_alg_instance(tfm);
  	struct crypto_spawn *spawn = skcipher_instance_ctx(inst);
  	struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
2e306ee01   Herbert Xu   [CRYPTO] api: Add...
173
  	struct crypto_cipher *cipher;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
174

2e306ee01   Herbert Xu   [CRYPTO] api: Add...
175
176
177
  	cipher = crypto_spawn_cipher(spawn);
  	if (IS_ERR(cipher))
  		return PTR_ERR(cipher);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
178

2e306ee01   Herbert Xu   [CRYPTO] api: Add...
179
  	ctx->child = cipher;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
180
181
  	return 0;
  }
043a44001   Herbert Xu   crypto: pcbc - Co...
182
  static void crypto_pcbc_exit_tfm(struct crypto_skcipher *tfm)
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
183
  {
043a44001   Herbert Xu   crypto: pcbc - Co...
184
  	struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
185
186
  	crypto_free_cipher(ctx->child);
  }
043a44001   Herbert Xu   crypto: pcbc - Co...
187
188
189
190
191
192
193
  static void crypto_pcbc_free(struct skcipher_instance *inst)
  {
  	crypto_drop_skcipher(skcipher_instance_ctx(inst));
  	kfree(inst);
  }
  
  static int crypto_pcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
194
  {
043a44001   Herbert Xu   crypto: pcbc - Co...
195
196
197
  	struct skcipher_instance *inst;
  	struct crypto_attr_type *algt;
  	struct crypto_spawn *spawn;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
198
  	struct crypto_alg *alg;
ebc610e5b   Herbert Xu   [CRYPTO] template...
199
  	int err;
043a44001   Herbert Xu   crypto: pcbc - Co...
200
201
202
203
204
205
206
  	algt = crypto_get_attr_type(tb);
  	if (IS_ERR(algt))
  		return PTR_ERR(algt);
  
  	if (((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask) &
  	    ~CRYPTO_ALG_INTERNAL)
  		return -EINVAL;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
207

043a44001   Herbert Xu   crypto: pcbc - Co...
208
209
210
211
212
213
214
215
216
  	inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
  	if (!inst)
  		return -ENOMEM;
  
  	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER |
  				      (algt->type & CRYPTO_ALG_INTERNAL),
  				  CRYPTO_ALG_TYPE_MASK |
  				  (algt->mask & CRYPTO_ALG_INTERNAL));
  	err = PTR_ERR(alg);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
217
  	if (IS_ERR(alg))
043a44001   Herbert Xu   crypto: pcbc - Co...
218
219
220
221
222
  		goto err_free_inst;
  
  	spawn = skcipher_instance_ctx(inst);
  	err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst),
  				CRYPTO_ALG_TYPE_MASK);
043a44001   Herbert Xu   crypto: pcbc - Co...
223
  	if (err)
2f9460519   Pan Bian   crypto: do not fr...
224
  		goto err_put_alg;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
225

043a44001   Herbert Xu   crypto: pcbc - Co...
226
227
228
  	err = crypto_inst_setname(skcipher_crypto_instance(inst), "pcbc", alg);
  	if (err)
  		goto err_drop_spawn;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
229

043a44001   Herbert Xu   crypto: pcbc - Co...
230
231
232
233
  	inst->alg.base.cra_flags = alg->cra_flags & CRYPTO_ALG_INTERNAL;
  	inst->alg.base.cra_priority = alg->cra_priority;
  	inst->alg.base.cra_blocksize = alg->cra_blocksize;
  	inst->alg.base.cra_alignmask = alg->cra_alignmask;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
234

043a44001   Herbert Xu   crypto: pcbc - Co...
235
236
237
  	inst->alg.ivsize = alg->cra_blocksize;
  	inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize;
  	inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
238

043a44001   Herbert Xu   crypto: pcbc - Co...
239
  	inst->alg.base.cra_ctxsize = sizeof(struct crypto_pcbc_ctx);
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
240

043a44001   Herbert Xu   crypto: pcbc - Co...
241
242
  	inst->alg.init = crypto_pcbc_init_tfm;
  	inst->alg.exit = crypto_pcbc_exit_tfm;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
243

043a44001   Herbert Xu   crypto: pcbc - Co...
244
245
246
  	inst->alg.setkey = crypto_pcbc_setkey;
  	inst->alg.encrypt = crypto_pcbc_encrypt;
  	inst->alg.decrypt = crypto_pcbc_decrypt;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
247

043a44001   Herbert Xu   crypto: pcbc - Co...
248
  	inst->free = crypto_pcbc_free;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
249

043a44001   Herbert Xu   crypto: pcbc - Co...
250
251
252
  	err = skcipher_register_instance(tmpl, inst);
  	if (err)
  		goto err_drop_spawn;
2f9460519   Pan Bian   crypto: do not fr...
253
  	crypto_mod_put(alg);
043a44001   Herbert Xu   crypto: pcbc - Co...
254
255
256
257
258
259
  
  out:
  	return err;
  
  err_drop_spawn:
  	crypto_drop_spawn(spawn);
2f9460519   Pan Bian   crypto: do not fr...
260
261
  err_put_alg:
  	crypto_mod_put(alg);
043a44001   Herbert Xu   crypto: pcbc - Co...
262
  err_free_inst:
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
263
  	kfree(inst);
043a44001   Herbert Xu   crypto: pcbc - Co...
264
  	goto out;
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
265
266
267
268
  }
  
  static struct crypto_template crypto_pcbc_tmpl = {
  	.name = "pcbc",
043a44001   Herbert Xu   crypto: pcbc - Co...
269
  	.create = crypto_pcbc_create,
91652be5d   David Howells   [CRYPTO] pcbc: Ad...
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
  	.module = THIS_MODULE,
  };
  
  static int __init crypto_pcbc_module_init(void)
  {
  	return crypto_register_template(&crypto_pcbc_tmpl);
  }
  
  static void __exit crypto_pcbc_module_exit(void)
  {
  	crypto_unregister_template(&crypto_pcbc_tmpl);
  }
  
  module_init(crypto_pcbc_module_init);
  module_exit(crypto_pcbc_module_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("PCBC block cipher algorithm");
4943ba16b   Kees Cook   crypto: include c...
288
  MODULE_ALIAS_CRYPTO("pcbc");