]> git.ipfire.org Git - thirdparty/kernel/stable.git/blame - crypto/pcbc.c
net: marvell: mvpp2: fix stuck in-band SGMII negotiation
[thirdparty/kernel/stable.git] / crypto / pcbc.c
CommitLineData
91652be5
DH
1/*
2 * PCBC: Propagating Cipher Block Chaining mode
3 *
4 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 *
7 * Derived from cbc.c
8 * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 *
15 */
16
6650c4de 17#include <crypto/algapi.h>
043a4400 18#include <crypto/internal/skcipher.h>
91652be5
DH
19#include <linux/err.h>
20#include <linux/init.h>
21#include <linux/kernel.h>
22#include <linux/module.h>
91652be5 23#include <linux/slab.h>
d8c34b94 24#include <linux/compiler.h>
91652be5
DH
25
26struct crypto_pcbc_ctx {
27 struct crypto_cipher *child;
91652be5
DH
28};
29
043a4400 30static int crypto_pcbc_setkey(struct crypto_skcipher *parent, const u8 *key,
91652be5
DH
31 unsigned int keylen)
32{
043a4400 33 struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(parent);
91652be5
DH
34 struct crypto_cipher *child = ctx->child;
35 int err;
36
37 crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
043a4400
HX
38 crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) &
39 CRYPTO_TFM_REQ_MASK);
91652be5 40 err = crypto_cipher_setkey(child, key, keylen);
043a4400
HX
41 crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) &
42 CRYPTO_TFM_RES_MASK);
91652be5
DH
43 return err;
44}
45
043a4400
HX
46static int crypto_pcbc_encrypt_segment(struct skcipher_request *req,
47 struct skcipher_walk *walk,
d0b9007a 48 struct crypto_cipher *tfm)
91652be5 49{
91652be5
DH
50 int bsize = crypto_cipher_blocksize(tfm);
51 unsigned int nbytes = walk->nbytes;
52 u8 *src = walk->src.virt.addr;
53 u8 *dst = walk->dst.virt.addr;
bb1ae0aa 54 u8 * const iv = walk->iv;
91652be5
DH
55
56 do {
d0b9007a 57 crypto_xor(iv, src, bsize);
043a4400 58 crypto_cipher_encrypt_one(tfm, dst, iv);
45fe93df 59 crypto_xor_cpy(iv, dst, src, bsize);
91652be5
DH
60
61 src += bsize;
62 dst += bsize;
63 } while ((nbytes -= bsize) >= bsize);
64
65 return nbytes;
66}
67
043a4400
HX
68static int crypto_pcbc_encrypt_inplace(struct skcipher_request *req,
69 struct skcipher_walk *walk,
d0b9007a 70 struct crypto_cipher *tfm)
91652be5 71{
91652be5
DH
72 int bsize = crypto_cipher_blocksize(tfm);
73 unsigned int nbytes = walk->nbytes;
74 u8 *src = walk->src.virt.addr;
bb1ae0aa 75 u8 * const iv = walk->iv;
6650c4de 76 u8 tmpbuf[MAX_CIPHER_BLOCKSIZE];
91652be5
DH
77
78 do {
79 memcpy(tmpbuf, src, bsize);
d0b9007a 80 crypto_xor(iv, src, bsize);
043a4400 81 crypto_cipher_encrypt_one(tfm, src, iv);
45fe93df 82 crypto_xor_cpy(iv, tmpbuf, src, bsize);
91652be5
DH
83
84 src += bsize;
85 } while ((nbytes -= bsize) >= bsize);
86
91652be5
DH
87 return nbytes;
88}
89
043a4400 90static int crypto_pcbc_encrypt(struct skcipher_request *req)
91652be5 91{
043a4400
HX
92 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
93 struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
91652be5 94 struct crypto_cipher *child = ctx->child;
043a4400
HX
95 struct skcipher_walk walk;
96 unsigned int nbytes;
91652be5
DH
97 int err;
98
043a4400 99 err = skcipher_walk_virt(&walk, req, false);
91652be5
DH
100
101 while ((nbytes = walk.nbytes)) {
102 if (walk.src.virt.addr == walk.dst.virt.addr)
043a4400 103 nbytes = crypto_pcbc_encrypt_inplace(req, &walk,
d0b9007a 104 child);
91652be5 105 else
043a4400 106 nbytes = crypto_pcbc_encrypt_segment(req, &walk,
d0b9007a 107 child);
043a4400 108 err = skcipher_walk_done(&walk, nbytes);
91652be5
DH
109 }
110
111 return err;
112}
113
043a4400
HX
114static int crypto_pcbc_decrypt_segment(struct skcipher_request *req,
115 struct skcipher_walk *walk,
d0b9007a 116 struct crypto_cipher *tfm)
91652be5 117{
91652be5
DH
118 int bsize = crypto_cipher_blocksize(tfm);
119 unsigned int nbytes = walk->nbytes;
120 u8 *src = walk->src.virt.addr;
121 u8 *dst = walk->dst.virt.addr;
bb1ae0aa 122 u8 * const iv = walk->iv;
91652be5
DH
123
124 do {
043a4400 125 crypto_cipher_decrypt_one(tfm, dst, src);
d0b9007a 126 crypto_xor(dst, iv, bsize);
45fe93df 127 crypto_xor_cpy(iv, dst, src, bsize);
91652be5
DH
128
129 src += bsize;
130 dst += bsize;
131 } while ((nbytes -= bsize) >= bsize);
132
91652be5
DH
133 return nbytes;
134}
135
043a4400
HX
136static int crypto_pcbc_decrypt_inplace(struct skcipher_request *req,
137 struct skcipher_walk *walk,
d0b9007a 138 struct crypto_cipher *tfm)
91652be5 139{
91652be5
DH
140 int bsize = crypto_cipher_blocksize(tfm);
141 unsigned int nbytes = walk->nbytes;
142 u8 *src = walk->src.virt.addr;
bb1ae0aa 143 u8 * const iv = walk->iv;
6650c4de 144 u8 tmpbuf[MAX_CIPHER_BLOCKSIZE] __aligned(__alignof__(u32));
91652be5
DH
145
146 do {
147 memcpy(tmpbuf, src, bsize);
043a4400 148 crypto_cipher_decrypt_one(tfm, src, src);
d0b9007a 149 crypto_xor(src, iv, bsize);
45fe93df 150 crypto_xor_cpy(iv, src, tmpbuf, bsize);
91652be5
DH
151
152 src += bsize;
153 } while ((nbytes -= bsize) >= bsize);
154
91652be5
DH
155 return nbytes;
156}
157
043a4400 158static int crypto_pcbc_decrypt(struct skcipher_request *req)
91652be5 159{
043a4400
HX
160 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
161 struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
91652be5 162 struct crypto_cipher *child = ctx->child;
043a4400
HX
163 struct skcipher_walk walk;
164 unsigned int nbytes;
91652be5
DH
165 int err;
166
043a4400 167 err = skcipher_walk_virt(&walk, req, false);
91652be5
DH
168
169 while ((nbytes = walk.nbytes)) {
170 if (walk.src.virt.addr == walk.dst.virt.addr)
043a4400 171 nbytes = crypto_pcbc_decrypt_inplace(req, &walk,
d0b9007a 172 child);
91652be5 173 else
043a4400 174 nbytes = crypto_pcbc_decrypt_segment(req, &walk,
d0b9007a 175 child);
043a4400 176 err = skcipher_walk_done(&walk, nbytes);
91652be5
DH
177 }
178
179 return err;
180}
181
043a4400 182static int crypto_pcbc_init_tfm(struct crypto_skcipher *tfm)
91652be5 183{
043a4400
HX
184 struct skcipher_instance *inst = skcipher_alg_instance(tfm);
185 struct crypto_spawn *spawn = skcipher_instance_ctx(inst);
186 struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
2e306ee0 187 struct crypto_cipher *cipher;
91652be5 188
2e306ee0
HX
189 cipher = crypto_spawn_cipher(spawn);
190 if (IS_ERR(cipher))
191 return PTR_ERR(cipher);
91652be5 192
2e306ee0 193 ctx->child = cipher;
91652be5
DH
194 return 0;
195}
196
043a4400 197static void crypto_pcbc_exit_tfm(struct crypto_skcipher *tfm)
91652be5 198{
043a4400
HX
199 struct crypto_pcbc_ctx *ctx = crypto_skcipher_ctx(tfm);
200
91652be5
DH
201 crypto_free_cipher(ctx->child);
202}
203
043a4400
HX
204static void crypto_pcbc_free(struct skcipher_instance *inst)
205{
206 crypto_drop_skcipher(skcipher_instance_ctx(inst));
207 kfree(inst);
208}
209
210static int crypto_pcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
91652be5 211{
043a4400
HX
212 struct skcipher_instance *inst;
213 struct crypto_attr_type *algt;
214 struct crypto_spawn *spawn;
91652be5 215 struct crypto_alg *alg;
ebc610e5
HX
216 int err;
217
043a4400
HX
218 algt = crypto_get_attr_type(tb);
219 if (IS_ERR(algt))
220 return PTR_ERR(algt);
221
222 if (((algt->type ^ CRYPTO_ALG_TYPE_SKCIPHER) & algt->mask) &
223 ~CRYPTO_ALG_INTERNAL)
224 return -EINVAL;
91652be5 225
043a4400
HX
226 inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
227 if (!inst)
228 return -ENOMEM;
229
230 alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER |
231 (algt->type & CRYPTO_ALG_INTERNAL),
232 CRYPTO_ALG_TYPE_MASK |
233 (algt->mask & CRYPTO_ALG_INTERNAL));
234 err = PTR_ERR(alg);
91652be5 235 if (IS_ERR(alg))
043a4400
HX
236 goto err_free_inst;
237
238 spawn = skcipher_instance_ctx(inst);
239 err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst),
240 CRYPTO_ALG_TYPE_MASK);
043a4400 241 if (err)
2f946051 242 goto err_put_alg;
91652be5 243
043a4400
HX
244 err = crypto_inst_setname(skcipher_crypto_instance(inst), "pcbc", alg);
245 if (err)
246 goto err_drop_spawn;
91652be5 247
043a4400
HX
248 inst->alg.base.cra_flags = alg->cra_flags & CRYPTO_ALG_INTERNAL;
249 inst->alg.base.cra_priority = alg->cra_priority;
250 inst->alg.base.cra_blocksize = alg->cra_blocksize;
251 inst->alg.base.cra_alignmask = alg->cra_alignmask;
91652be5 252
043a4400
HX
253 inst->alg.ivsize = alg->cra_blocksize;
254 inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize;
255 inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize;
91652be5 256
043a4400 257 inst->alg.base.cra_ctxsize = sizeof(struct crypto_pcbc_ctx);
91652be5 258
043a4400
HX
259 inst->alg.init = crypto_pcbc_init_tfm;
260 inst->alg.exit = crypto_pcbc_exit_tfm;
91652be5 261
043a4400
HX
262 inst->alg.setkey = crypto_pcbc_setkey;
263 inst->alg.encrypt = crypto_pcbc_encrypt;
264 inst->alg.decrypt = crypto_pcbc_decrypt;
91652be5 265
043a4400 266 inst->free = crypto_pcbc_free;
91652be5 267
043a4400
HX
268 err = skcipher_register_instance(tmpl, inst);
269 if (err)
270 goto err_drop_spawn;
2f946051 271 crypto_mod_put(alg);
043a4400
HX
272
273out:
274 return err;
275
276err_drop_spawn:
277 crypto_drop_spawn(spawn);
2f946051
PB
278err_put_alg:
279 crypto_mod_put(alg);
043a4400 280err_free_inst:
91652be5 281 kfree(inst);
043a4400 282 goto out;
91652be5
DH
283}
284
285static struct crypto_template crypto_pcbc_tmpl = {
286 .name = "pcbc",
043a4400 287 .create = crypto_pcbc_create,
91652be5
DH
288 .module = THIS_MODULE,
289};
290
291static int __init crypto_pcbc_module_init(void)
292{
293 return crypto_register_template(&crypto_pcbc_tmpl);
294}
295
296static void __exit crypto_pcbc_module_exit(void)
297{
298 crypto_unregister_template(&crypto_pcbc_tmpl);
299}
300
301module_init(crypto_pcbc_module_init);
302module_exit(crypto_pcbc_module_exit);
303
304MODULE_LICENSE("GPL");
305MODULE_DESCRIPTION("PCBC block cipher algorithm");
4943ba16 306MODULE_ALIAS_CRYPTO("pcbc");