blob: 6539b387668f07cfb2cffdc437a3d6b9eaefc476 [file] [log] [blame]
Herbert Xudb131ef2006-09-21 11:44:08 +10001/*
2 * CBC: Cipher Block Chaining mode
3 *
4 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 */
12
Herbert Xu79c65d12016-11-22 20:08:39 +080013#include <crypto/internal/skcipher.h>
Herbert Xudb131ef2006-09-21 11:44:08 +100014#include <linux/err.h>
15#include <linux/init.h>
16#include <linux/kernel.h>
Herbert Xu50b65442007-11-20 17:36:00 +080017#include <linux/log2.h>
Herbert Xudb131ef2006-09-21 11:44:08 +100018#include <linux/module.h>
Herbert Xudb131ef2006-09-21 11:44:08 +100019#include <linux/slab.h>
20
21struct crypto_cbc_ctx {
22 struct crypto_cipher *child;
Herbert Xudb131ef2006-09-21 11:44:08 +100023};
24
Herbert Xu79c65d12016-11-22 20:08:39 +080025static int crypto_cbc_setkey(struct crypto_skcipher *parent, const u8 *key,
Herbert Xudb131ef2006-09-21 11:44:08 +100026 unsigned int keylen)
27{
Herbert Xu79c65d12016-11-22 20:08:39 +080028 struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(parent);
Herbert Xudb131ef2006-09-21 11:44:08 +100029 struct crypto_cipher *child = ctx->child;
30 int err;
31
32 crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
Herbert Xu79c65d12016-11-22 20:08:39 +080033 crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) &
Herbert Xudb131ef2006-09-21 11:44:08 +100034 CRYPTO_TFM_REQ_MASK);
35 err = crypto_cipher_setkey(child, key, keylen);
Herbert Xu79c65d12016-11-22 20:08:39 +080036 crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) &
37 CRYPTO_TFM_RES_MASK);
Herbert Xudb131ef2006-09-21 11:44:08 +100038 return err;
39}
40
Herbert Xu79c65d12016-11-22 20:08:39 +080041static inline int crypto_cbc_encrypt_segment(
42 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
43 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
Herbert Xudb131ef2006-09-21 11:44:08 +100044{
Herbert Xu79c65d12016-11-22 20:08:39 +080045 unsigned int bsize = crypto_skcipher_blocksize(tfm);
Herbert Xudb131ef2006-09-21 11:44:08 +100046 unsigned int nbytes = walk->nbytes;
47 u8 *src = walk->src.virt.addr;
48 u8 *dst = walk->dst.virt.addr;
49 u8 *iv = walk->iv;
50
51 do {
Herbert Xu3c7f0762007-11-20 17:33:39 +080052 crypto_xor(iv, src, bsize);
Herbert Xu79c65d12016-11-22 20:08:39 +080053 fn(tfm, iv, dst);
Herbert Xudb131ef2006-09-21 11:44:08 +100054 memcpy(iv, dst, bsize);
55
56 src += bsize;
57 dst += bsize;
58 } while ((nbytes -= bsize) >= bsize);
59
60 return nbytes;
61}
62
Herbert Xu79c65d12016-11-22 20:08:39 +080063static inline int crypto_cbc_encrypt_inplace(
64 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
65 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
Herbert Xudb131ef2006-09-21 11:44:08 +100066{
Herbert Xu79c65d12016-11-22 20:08:39 +080067 unsigned int bsize = crypto_skcipher_blocksize(tfm);
Herbert Xudb131ef2006-09-21 11:44:08 +100068 unsigned int nbytes = walk->nbytes;
69 u8 *src = walk->src.virt.addr;
70 u8 *iv = walk->iv;
71
72 do {
Herbert Xu3c7f0762007-11-20 17:33:39 +080073 crypto_xor(src, iv, bsize);
Herbert Xu79c65d12016-11-22 20:08:39 +080074 fn(tfm, src, src);
Herbert Xudb131ef2006-09-21 11:44:08 +100075 iv = src;
76
77 src += bsize;
78 } while ((nbytes -= bsize) >= bsize);
79
80 memcpy(walk->iv, iv, bsize);
81
82 return nbytes;
83}
84
Herbert Xu79c65d12016-11-22 20:08:39 +080085static inline int crypto_cbc_encrypt_walk(struct skcipher_request *req,
86 void (*fn)(struct crypto_skcipher *,
87 const u8 *, u8 *))
Herbert Xudb131ef2006-09-21 11:44:08 +100088{
Herbert Xu79c65d12016-11-22 20:08:39 +080089 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
90 struct skcipher_walk walk;
Herbert Xudb131ef2006-09-21 11:44:08 +100091 int err;
92
Herbert Xu79c65d12016-11-22 20:08:39 +080093 err = skcipher_walk_virt(&walk, req, false);
Herbert Xudb131ef2006-09-21 11:44:08 +100094
Herbert Xu79c65d12016-11-22 20:08:39 +080095 while (walk.nbytes) {
Herbert Xudb131ef2006-09-21 11:44:08 +100096 if (walk.src.virt.addr == walk.dst.virt.addr)
Herbert Xu79c65d12016-11-22 20:08:39 +080097 err = crypto_cbc_encrypt_inplace(&walk, tfm, fn);
Herbert Xudb131ef2006-09-21 11:44:08 +100098 else
Herbert Xu79c65d12016-11-22 20:08:39 +080099 err = crypto_cbc_encrypt_segment(&walk, tfm, fn);
100 err = skcipher_walk_done(&walk, err);
Herbert Xudb131ef2006-09-21 11:44:08 +1000101 }
102
103 return err;
104}
105
Herbert Xu79c65d12016-11-22 20:08:39 +0800106static inline void crypto_cbc_encrypt_one(struct crypto_skcipher *tfm,
107 const u8 *src, u8 *dst)
Herbert Xudb131ef2006-09-21 11:44:08 +1000108{
Herbert Xu79c65d12016-11-22 20:08:39 +0800109 struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
110
111 crypto_cipher_encrypt_one(ctx->child, dst, src);
112}
113
114static int crypto_cbc_encrypt(struct skcipher_request *req)
115{
116 return crypto_cbc_encrypt_walk(req, crypto_cbc_encrypt_one);
117}
118
119static inline int crypto_cbc_decrypt_segment(
120 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
121 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
122{
123 unsigned int bsize = crypto_skcipher_blocksize(tfm);
Herbert Xudb131ef2006-09-21 11:44:08 +1000124 unsigned int nbytes = walk->nbytes;
125 u8 *src = walk->src.virt.addr;
126 u8 *dst = walk->dst.virt.addr;
127 u8 *iv = walk->iv;
128
129 do {
Herbert Xu79c65d12016-11-22 20:08:39 +0800130 fn(tfm, src, dst);
Herbert Xu3c7f0762007-11-20 17:33:39 +0800131 crypto_xor(dst, iv, bsize);
Herbert Xudb131ef2006-09-21 11:44:08 +1000132 iv = src;
133
134 src += bsize;
135 dst += bsize;
136 } while ((nbytes -= bsize) >= bsize);
137
138 memcpy(walk->iv, iv, bsize);
139
140 return nbytes;
141}
142
Herbert Xu79c65d12016-11-22 20:08:39 +0800143static inline int crypto_cbc_decrypt_inplace(
144 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
145 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
Herbert Xudb131ef2006-09-21 11:44:08 +1000146{
Herbert Xu79c65d12016-11-22 20:08:39 +0800147 unsigned int bsize = crypto_skcipher_blocksize(tfm);
Herbert Xudb131ef2006-09-21 11:44:08 +1000148 unsigned int nbytes = walk->nbytes;
149 u8 *src = walk->src.virt.addr;
Herbert Xu50b65442007-11-20 17:36:00 +0800150 u8 last_iv[bsize];
Herbert Xudb131ef2006-09-21 11:44:08 +1000151
152 /* Start of the last block. */
Herbert Xu50b65442007-11-20 17:36:00 +0800153 src += nbytes - (nbytes & (bsize - 1)) - bsize;
154 memcpy(last_iv, src, bsize);
Herbert Xudb131ef2006-09-21 11:44:08 +1000155
156 for (;;) {
Herbert Xu79c65d12016-11-22 20:08:39 +0800157 fn(tfm, src, src);
Herbert Xudb131ef2006-09-21 11:44:08 +1000158 if ((nbytes -= bsize) < bsize)
159 break;
Herbert Xu3c7f0762007-11-20 17:33:39 +0800160 crypto_xor(src, src - bsize, bsize);
Herbert Xudb131ef2006-09-21 11:44:08 +1000161 src -= bsize;
162 }
163
Herbert Xu50b65442007-11-20 17:36:00 +0800164 crypto_xor(src, walk->iv, bsize);
165 memcpy(walk->iv, last_iv, bsize);
Herbert Xudb131ef2006-09-21 11:44:08 +1000166
167 return nbytes;
168}
169
Herbert Xu79c65d12016-11-22 20:08:39 +0800170static inline int crypto_cbc_decrypt_blocks(
171 struct skcipher_walk *walk, struct crypto_skcipher *tfm,
172 void (*fn)(struct crypto_skcipher *, const u8 *, u8 *))
Herbert Xudb131ef2006-09-21 11:44:08 +1000173{
Herbert Xu79c65d12016-11-22 20:08:39 +0800174 if (walk->src.virt.addr == walk->dst.virt.addr)
175 return crypto_cbc_decrypt_inplace(walk, tfm, fn);
176 else
177 return crypto_cbc_decrypt_segment(walk, tfm, fn);
178}
179
180static inline void crypto_cbc_decrypt_one(struct crypto_skcipher *tfm,
181 const u8 *src, u8 *dst)
182{
183 struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
184
185 crypto_cipher_decrypt_one(ctx->child, dst, src);
186}
187
188static int crypto_cbc_decrypt(struct skcipher_request *req)
189{
190 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
191 struct skcipher_walk walk;
Herbert Xudb131ef2006-09-21 11:44:08 +1000192 int err;
193
Herbert Xu79c65d12016-11-22 20:08:39 +0800194 err = skcipher_walk_virt(&walk, req, false);
Herbert Xudb131ef2006-09-21 11:44:08 +1000195
Herbert Xu79c65d12016-11-22 20:08:39 +0800196 while (walk.nbytes) {
197 err = crypto_cbc_decrypt_blocks(&walk, tfm,
198 crypto_cbc_decrypt_one);
199 err = skcipher_walk_done(&walk, err);
Herbert Xudb131ef2006-09-21 11:44:08 +1000200 }
201
202 return err;
203}
204
Herbert Xu79c65d12016-11-22 20:08:39 +0800205static int crypto_cbc_init_tfm(struct crypto_skcipher *tfm)
Herbert Xudb131ef2006-09-21 11:44:08 +1000206{
Herbert Xu79c65d12016-11-22 20:08:39 +0800207 struct skcipher_instance *inst = skcipher_alg_instance(tfm);
208 struct crypto_spawn *spawn = skcipher_instance_ctx(inst);
209 struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
Herbert Xu2e306ee2006-12-17 10:05:58 +1100210 struct crypto_cipher *cipher;
Herbert Xudb131ef2006-09-21 11:44:08 +1000211
Herbert Xu2e306ee2006-12-17 10:05:58 +1100212 cipher = crypto_spawn_cipher(spawn);
213 if (IS_ERR(cipher))
214 return PTR_ERR(cipher);
Herbert Xudb131ef2006-09-21 11:44:08 +1000215
Herbert Xu2e306ee2006-12-17 10:05:58 +1100216 ctx->child = cipher;
Herbert Xudb131ef2006-09-21 11:44:08 +1000217 return 0;
218}
219
Herbert Xu79c65d12016-11-22 20:08:39 +0800220static void crypto_cbc_exit_tfm(struct crypto_skcipher *tfm)
Herbert Xudb131ef2006-09-21 11:44:08 +1000221{
Herbert Xu79c65d12016-11-22 20:08:39 +0800222 struct crypto_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
223
Herbert Xudb131ef2006-09-21 11:44:08 +1000224 crypto_free_cipher(ctx->child);
225}
226
Herbert Xu79c65d12016-11-22 20:08:39 +0800227static void crypto_cbc_free(struct skcipher_instance *inst)
Herbert Xudb131ef2006-09-21 11:44:08 +1000228{
Herbert Xu79c65d12016-11-22 20:08:39 +0800229 crypto_drop_skcipher(skcipher_instance_ctx(inst));
230 kfree(inst);
231}
232
233static int crypto_cbc_create(struct crypto_template *tmpl, struct rtattr **tb)
234{
235 struct skcipher_instance *inst;
236 struct crypto_spawn *spawn;
Herbert Xudb131ef2006-09-21 11:44:08 +1000237 struct crypto_alg *alg;
Herbert Xuebc610e2007-01-01 18:37:02 +1100238 int err;
Herbert Xudb131ef2006-09-21 11:44:08 +1000239
Herbert Xu79c65d12016-11-22 20:08:39 +0800240 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER);
Herbert Xuebc610e2007-01-01 18:37:02 +1100241 if (err)
Herbert Xu79c65d12016-11-22 20:08:39 +0800242 return err;
243
244 inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
245 if (!inst)
246 return -ENOMEM;
Herbert Xuebc610e2007-01-01 18:37:02 +1100247
248 alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER,
249 CRYPTO_ALG_TYPE_MASK);
Herbert Xu79c65d12016-11-22 20:08:39 +0800250 err = PTR_ERR(alg);
Herbert Xudb131ef2006-09-21 11:44:08 +1000251 if (IS_ERR(alg))
Herbert Xu79c65d12016-11-22 20:08:39 +0800252 goto err_free_inst;
Herbert Xudb131ef2006-09-21 11:44:08 +1000253
Herbert Xu79c65d12016-11-22 20:08:39 +0800254 spawn = skcipher_instance_ctx(inst);
255 err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst),
256 CRYPTO_ALG_TYPE_MASK);
257 crypto_mod_put(alg);
258 if (err)
259 goto err_free_inst;
260
261 err = crypto_inst_setname(skcipher_crypto_instance(inst), "cbc", alg);
262 if (err)
263 goto err_drop_spawn;
264
265 err = -EINVAL;
Herbert Xu50b65442007-11-20 17:36:00 +0800266 if (!is_power_of_2(alg->cra_blocksize))
Herbert Xu79c65d12016-11-22 20:08:39 +0800267 goto err_drop_spawn;
Herbert Xu50b65442007-11-20 17:36:00 +0800268
Herbert Xu79c65d12016-11-22 20:08:39 +0800269 inst->alg.base.cra_priority = alg->cra_priority;
270 inst->alg.base.cra_blocksize = alg->cra_blocksize;
271 inst->alg.base.cra_alignmask = alg->cra_alignmask;
Herbert Xudb131ef2006-09-21 11:44:08 +1000272
Herbert Xu3c7f0762007-11-20 17:33:39 +0800273 /* We access the data as u32s when xoring. */
Herbert Xu79c65d12016-11-22 20:08:39 +0800274 inst->alg.base.cra_alignmask |= __alignof__(u32) - 1;
Herbert Xu3c7f0762007-11-20 17:33:39 +0800275
Herbert Xu79c65d12016-11-22 20:08:39 +0800276 inst->alg.ivsize = alg->cra_blocksize;
277 inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize;
278 inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize;
Herbert Xudb131ef2006-09-21 11:44:08 +1000279
Herbert Xu79c65d12016-11-22 20:08:39 +0800280 inst->alg.base.cra_ctxsize = sizeof(struct crypto_cbc_ctx);
Herbert Xudb131ef2006-09-21 11:44:08 +1000281
Herbert Xu79c65d12016-11-22 20:08:39 +0800282 inst->alg.init = crypto_cbc_init_tfm;
283 inst->alg.exit = crypto_cbc_exit_tfm;
Herbert Xudb131ef2006-09-21 11:44:08 +1000284
Herbert Xu79c65d12016-11-22 20:08:39 +0800285 inst->alg.setkey = crypto_cbc_setkey;
286 inst->alg.encrypt = crypto_cbc_encrypt;
287 inst->alg.decrypt = crypto_cbc_decrypt;
Herbert Xudb131ef2006-09-21 11:44:08 +1000288
Herbert Xu79c65d12016-11-22 20:08:39 +0800289 inst->free = crypto_cbc_free;
Herbert Xudb131ef2006-09-21 11:44:08 +1000290
Herbert Xu79c65d12016-11-22 20:08:39 +0800291 err = skcipher_register_instance(tmpl, inst);
292 if (err)
293 goto err_drop_spawn;
294
295out:
296 return err;
297
298err_drop_spawn:
299 crypto_drop_spawn(spawn);
300err_free_inst:
Herbert Xudb131ef2006-09-21 11:44:08 +1000301 kfree(inst);
Herbert Xu79c65d12016-11-22 20:08:39 +0800302 goto out;
Herbert Xudb131ef2006-09-21 11:44:08 +1000303}
304
305static struct crypto_template crypto_cbc_tmpl = {
306 .name = "cbc",
Herbert Xu79c65d12016-11-22 20:08:39 +0800307 .create = crypto_cbc_create,
Herbert Xudb131ef2006-09-21 11:44:08 +1000308 .module = THIS_MODULE,
309};
310
311static int __init crypto_cbc_module_init(void)
312{
313 return crypto_register_template(&crypto_cbc_tmpl);
314}
315
316static void __exit crypto_cbc_module_exit(void)
317{
318 crypto_unregister_template(&crypto_cbc_tmpl);
319}
320
321module_init(crypto_cbc_module_init);
322module_exit(crypto_cbc_module_exit);
323
324MODULE_LICENSE("GPL");
325MODULE_DESCRIPTION("CBC block cipher algorithm");
Kees Cook4943ba12014-11-24 16:32:38 -0800326MODULE_ALIAS_CRYPTO("cbc");