summaryrefslogtreecommitdiffstats
path: root/crypto/cfb.c
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2018-03-01 17:36:17 -0500
committerHerbert Xu <herbert@gondor.apana.org.au>2018-03-09 09:45:49 -0500
commita7d85e06ed8033f263451f3aef4159024e7dae5f (patch)
tree4f5dc50bb388a34c718c3e6be2ed8b4d017feb96 /crypto/cfb.c
parent6584eacb7cc7885509d4a27120a48ae1e404dc4c (diff)
crypto: cfb - add support for Cipher FeedBack mode
TPM security routines require encryption and decryption with AES in CFB mode, so add it to the Linux Crypto schemes. CFB is basically a one time pad where the pad is generated initially from the encrypted IV and then subsequently from the encrypted previous block of ciphertext. The pad is XOR'd into the plain text to get the final ciphertext. https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/cfb.c')
-rw-r--r--crypto/cfb.c353
1 files changed, 353 insertions, 0 deletions
diff --git a/crypto/cfb.c b/crypto/cfb.c
new file mode 100644
index 000000000000..94ee39bed758
--- /dev/null
+++ b/crypto/cfb.c
@@ -0,0 +1,353 @@
1//SPDX-License-Identifier: GPL-2.0
2/*
3 * CFB: Cipher FeedBack mode
4 *
5 * Copyright (c) 2018 James.Bottomley@HansenPartnership.com
6 *
7 * CFB is a stream cipher mode which is layered on to a block
8 * encryption scheme. It works very much like a one time pad where
9 * the pad is generated initially from the encrypted IV and then
10 * subsequently from the encrypted previous block of ciphertext. The
11 * pad is XOR'd into the plain text to get the final ciphertext.
12 *
13 * The scheme of CFB is best described by wikipedia:
14 *
15 * https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB
16 *
17 * Note that since the pad for both encryption and decryption is
18 * generated by an encryption operation, CFB never uses the block
19 * decryption function.
20 */
21
22#include <crypto/algapi.h>
23#include <crypto/internal/skcipher.h>
24#include <linux/err.h>
25#include <linux/init.h>
26#include <linux/kernel.h>
27#include <linux/module.h>
28#include <linux/slab.h>
29#include <linux/string.h>
30#include <linux/types.h>
31
32struct crypto_cfb_ctx {
33 struct crypto_cipher *child;
34};
35
36static unsigned int crypto_cfb_bsize(struct crypto_skcipher *tfm)
37{
38 struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
39 struct crypto_cipher *child = ctx->child;
40
41 return crypto_cipher_blocksize(child);
42}
43
44static void crypto_cfb_encrypt_one(struct crypto_skcipher *tfm,
45 const u8 *src, u8 *dst)
46{
47 struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
48
49 crypto_cipher_encrypt_one(ctx->child, dst, src);
50}
51
52/* final encrypt and decrypt is the same */
53static void crypto_cfb_final(struct skcipher_walk *walk,
54 struct crypto_skcipher *tfm)
55{
56 const unsigned int bsize = crypto_cfb_bsize(tfm);
57 const unsigned long alignmask = crypto_skcipher_alignmask(tfm);
58 u8 tmp[bsize + alignmask];
59 u8 *stream = PTR_ALIGN(tmp + 0, alignmask + 1);
60 u8 *src = walk->src.virt.addr;
61 u8 *dst = walk->dst.virt.addr;
62 u8 *iv = walk->iv;
63 unsigned int nbytes = walk->nbytes;
64
65 crypto_cfb_encrypt_one(tfm, iv, stream);
66 crypto_xor_cpy(dst, stream, src, nbytes);
67}
68
69static int crypto_cfb_encrypt_segment(struct skcipher_walk *walk,
70 struct crypto_skcipher *tfm)
71{
72 const unsigned int bsize = crypto_cfb_bsize(tfm);
73 unsigned int nbytes = walk->nbytes;
74 u8 *src = walk->src.virt.addr;
75 u8 *dst = walk->dst.virt.addr;
76 u8 *iv = walk->iv;
77
78 do {
79 crypto_cfb_encrypt_one(tfm, iv, dst);
80 crypto_xor(dst, src, bsize);
81 memcpy(iv, dst, bsize);
82
83 src += bsize;
84 dst += bsize;
85 } while ((nbytes -= bsize) >= bsize);
86
87 return nbytes;
88}
89
90static int crypto_cfb_encrypt_inplace(struct skcipher_walk *walk,
91 struct crypto_skcipher *tfm)
92{
93 const unsigned int bsize = crypto_cfb_bsize(tfm);
94 unsigned int nbytes = walk->nbytes;
95 u8 *src = walk->src.virt.addr;
96 u8 *iv = walk->iv;
97 u8 tmp[bsize];
98
99 do {
100 crypto_cfb_encrypt_one(tfm, iv, tmp);
101 crypto_xor(src, tmp, bsize);
102 iv = src;
103
104 src += bsize;
105 } while ((nbytes -= bsize) >= bsize);
106
107 memcpy(walk->iv, iv, bsize);
108
109 return nbytes;
110}
111
112static int crypto_cfb_encrypt(struct skcipher_request *req)
113{
114 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
115 struct skcipher_walk walk;
116 unsigned int bsize = crypto_cfb_bsize(tfm);
117 int err;
118
119 err = skcipher_walk_virt(&walk, req, false);
120
121 while (walk.nbytes >= bsize) {
122 if (walk.src.virt.addr == walk.dst.virt.addr)
123 err = crypto_cfb_encrypt_inplace(&walk, tfm);
124 else
125 err = crypto_cfb_encrypt_segment(&walk, tfm);
126 err = skcipher_walk_done(&walk, err);
127 }
128
129 if (walk.nbytes) {
130 crypto_cfb_final(&walk, tfm);
131 err = skcipher_walk_done(&walk, 0);
132 }
133
134 return err;
135}
136
137static int crypto_cfb_decrypt_segment(struct skcipher_walk *walk,
138 struct crypto_skcipher *tfm)
139{
140 const unsigned int bsize = crypto_cfb_bsize(tfm);
141 unsigned int nbytes = walk->nbytes;
142 u8 *src = walk->src.virt.addr;
143 u8 *dst = walk->dst.virt.addr;
144 u8 *iv = walk->iv;
145
146 do {
147 crypto_cfb_encrypt_one(tfm, iv, dst);
148 crypto_xor(dst, iv, bsize);
149 iv = src;
150
151 src += bsize;
152 dst += bsize;
153 } while ((nbytes -= bsize) >= bsize);
154
155 memcpy(walk->iv, iv, bsize);
156
157 return nbytes;
158}
159
160static int crypto_cfb_decrypt_inplace(struct skcipher_walk *walk,
161 struct crypto_skcipher *tfm)
162{
163 const unsigned int bsize = crypto_cfb_bsize(tfm);
164 unsigned int nbytes = walk->nbytes;
165 u8 *src = walk->src.virt.addr;
166 u8 *iv = walk->iv;
167 u8 tmp[bsize];
168
169 do {
170 crypto_cfb_encrypt_one(tfm, iv, tmp);
171 memcpy(iv, src, bsize);
172 crypto_xor(src, tmp, bsize);
173 src += bsize;
174 } while ((nbytes -= bsize) >= bsize);
175
176 memcpy(walk->iv, iv, bsize);
177
178 return nbytes;
179}
180
181static int crypto_cfb_decrypt_blocks(struct skcipher_walk *walk,
182 struct crypto_skcipher *tfm)
183{
184 if (walk->src.virt.addr == walk->dst.virt.addr)
185 return crypto_cfb_decrypt_inplace(walk, tfm);
186 else
187 return crypto_cfb_decrypt_segment(walk, tfm);
188}
189
190static int crypto_cfb_setkey(struct crypto_skcipher *parent, const u8 *key,
191 unsigned int keylen)
192{
193 struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(parent);
194 struct crypto_cipher *child = ctx->child;
195 int err;
196
197 crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
198 crypto_cipher_set_flags(child, crypto_skcipher_get_flags(parent) &
199 CRYPTO_TFM_REQ_MASK);
200 err = crypto_cipher_setkey(child, key, keylen);
201 crypto_skcipher_set_flags(parent, crypto_cipher_get_flags(child) &
202 CRYPTO_TFM_RES_MASK);
203 return err;
204}
205
206static int crypto_cfb_decrypt(struct skcipher_request *req)
207{
208 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
209 struct skcipher_walk walk;
210 const unsigned int bsize = crypto_cfb_bsize(tfm);
211 int err;
212
213 err = skcipher_walk_virt(&walk, req, false);
214
215 while (walk.nbytes >= bsize) {
216 err = crypto_cfb_decrypt_blocks(&walk, tfm);
217 err = skcipher_walk_done(&walk, err);
218 }
219
220 if (walk.nbytes) {
221 crypto_cfb_final(&walk, tfm);
222 err = skcipher_walk_done(&walk, 0);
223 }
224
225 return err;
226}
227
228static int crypto_cfb_init_tfm(struct crypto_skcipher *tfm)
229{
230 struct skcipher_instance *inst = skcipher_alg_instance(tfm);
231 struct crypto_spawn *spawn = skcipher_instance_ctx(inst);
232 struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
233 struct crypto_cipher *cipher;
234
235 cipher = crypto_spawn_cipher(spawn);
236 if (IS_ERR(cipher))
237 return PTR_ERR(cipher);
238
239 ctx->child = cipher;
240 return 0;
241}
242
243static void crypto_cfb_exit_tfm(struct crypto_skcipher *tfm)
244{
245 struct crypto_cfb_ctx *ctx = crypto_skcipher_ctx(tfm);
246
247 crypto_free_cipher(ctx->child);
248}
249
250static void crypto_cfb_free(struct skcipher_instance *inst)
251{
252 crypto_drop_skcipher(skcipher_instance_ctx(inst));
253 kfree(inst);
254}
255
256static int crypto_cfb_create(struct crypto_template *tmpl, struct rtattr **tb)
257{
258 struct skcipher_instance *inst;
259 struct crypto_attr_type *algt;
260 struct crypto_spawn *spawn;
261 struct crypto_alg *alg;
262 u32 mask;
263 int err;
264
265 err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SKCIPHER);
266 if (err)
267 return err;
268
269 inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
270 if (!inst)
271 return -ENOMEM;
272
273 algt = crypto_get_attr_type(tb);
274 err = PTR_ERR(algt);
275 if (IS_ERR(algt))
276 goto err_free_inst;
277
278 mask = CRYPTO_ALG_TYPE_MASK |
279 crypto_requires_off(algt->type, algt->mask,
280 CRYPTO_ALG_NEED_FALLBACK);
281
282 alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_CIPHER, mask);
283 err = PTR_ERR(alg);
284 if (IS_ERR(alg))
285 goto err_free_inst;
286
287 spawn = skcipher_instance_ctx(inst);
288 err = crypto_init_spawn(spawn, alg, skcipher_crypto_instance(inst),
289 CRYPTO_ALG_TYPE_MASK);
290 crypto_mod_put(alg);
291 if (err)
292 goto err_free_inst;
293
294 err = crypto_inst_setname(skcipher_crypto_instance(inst), "cfb", alg);
295 if (err)
296 goto err_drop_spawn;
297
298 inst->alg.base.cra_priority = alg->cra_priority;
299 /* we're a stream cipher independend of the crypto cra_blocksize */
300 inst->alg.base.cra_blocksize = 1;
301 inst->alg.base.cra_alignmask = alg->cra_alignmask;
302
303 inst->alg.ivsize = alg->cra_blocksize;
304 inst->alg.min_keysize = alg->cra_cipher.cia_min_keysize;
305 inst->alg.max_keysize = alg->cra_cipher.cia_max_keysize;
306
307 inst->alg.base.cra_ctxsize = sizeof(struct crypto_cfb_ctx);
308
309 inst->alg.init = crypto_cfb_init_tfm;
310 inst->alg.exit = crypto_cfb_exit_tfm;
311
312 inst->alg.setkey = crypto_cfb_setkey;
313 inst->alg.encrypt = crypto_cfb_encrypt;
314 inst->alg.decrypt = crypto_cfb_decrypt;
315
316 inst->free = crypto_cfb_free;
317
318 err = skcipher_register_instance(tmpl, inst);
319 if (err)
320 goto err_drop_spawn;
321
322out:
323 return err;
324
325err_drop_spawn:
326 crypto_drop_spawn(spawn);
327err_free_inst:
328 kfree(inst);
329 goto out;
330}
331
332static struct crypto_template crypto_cfb_tmpl = {
333 .name = "cfb",
334 .create = crypto_cfb_create,
335 .module = THIS_MODULE,
336};
337
338static int __init crypto_cfb_module_init(void)
339{
340 return crypto_register_template(&crypto_cfb_tmpl);
341}
342
343static void __exit crypto_cfb_module_exit(void)
344{
345 crypto_unregister_template(&crypto_cfb_tmpl);
346}
347
348module_init(crypto_cfb_module_init);
349module_exit(crypto_cfb_module_exit);
350
351MODULE_LICENSE("GPL");
352MODULE_DESCRIPTION("CFB block cipher algorithm");
353MODULE_ALIAS_CRYPTO("cfb");