1a7d85e06SJames Bottomley // SPDX-License-Identifier: GPL-2.0
2a7d85e06SJames Bottomley /*
3a7d85e06SJames Bottomley * CFB: Cipher FeedBack mode
4a7d85e06SJames Bottomley *
5a7d85e06SJames Bottomley * Copyright (c) 2018 James.Bottomley@HansenPartnership.com
6a7d85e06SJames Bottomley *
7a7d85e06SJames Bottomley * CFB is a stream cipher mode which is layered on to a block
8a7d85e06SJames Bottomley * encryption scheme. It works very much like a one time pad where
9a7d85e06SJames Bottomley * the pad is generated initially from the encrypted IV and then
10a7d85e06SJames Bottomley * subsequently from the encrypted previous block of ciphertext. The
11a7d85e06SJames Bottomley * pad is XOR'd into the plain text to get the final ciphertext.
12a7d85e06SJames Bottomley *
13a7d85e06SJames Bottomley * The scheme of CFB is best described by wikipedia:
14a7d85e06SJames Bottomley *
15a7d85e06SJames Bottomley * https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB
16a7d85e06SJames Bottomley *
17a7d85e06SJames Bottomley * Note that since the pad for both encryption and decryption is
18a7d85e06SJames Bottomley * generated by an encryption operation, CFB never uses the block
19a7d85e06SJames Bottomley * decryption function.
20a7d85e06SJames Bottomley */
21a7d85e06SJames Bottomley
22a7d85e06SJames Bottomley #include <crypto/algapi.h>
23*0eb76ba2SArd Biesheuvel #include <crypto/internal/cipher.h>
24a7d85e06SJames Bottomley #include <crypto/internal/skcipher.h>
25a7d85e06SJames Bottomley #include <linux/err.h>
26a7d85e06SJames Bottomley #include <linux/init.h>
27a7d85e06SJames Bottomley #include <linux/kernel.h>
28a7d85e06SJames Bottomley #include <linux/module.h>
29a7d85e06SJames Bottomley #include <linux/string.h>
30a7d85e06SJames Bottomley
crypto_cfb_bsize(struct crypto_skcipher * tfm)31a7d85e06SJames Bottomley static unsigned int crypto_cfb_bsize(struct crypto_skcipher *tfm)
32a7d85e06SJames Bottomley {
3303b8302dSEric Biggers return crypto_cipher_blocksize(skcipher_cipher_simple(tfm));
34a7d85e06SJames Bottomley }
35a7d85e06SJames Bottomley
crypto_cfb_encrypt_one(struct crypto_skcipher * tfm,const u8 * src,u8 * dst)36a7d85e06SJames Bottomley static void crypto_cfb_encrypt_one(struct crypto_skcipher *tfm,
37a7d85e06SJames Bottomley const u8 *src, u8 *dst)
38a7d85e06SJames Bottomley {
3903b8302dSEric Biggers crypto_cipher_encrypt_one(skcipher_cipher_simple(tfm), dst, src);
40a7d85e06SJames Bottomley }
41a7d85e06SJames Bottomley
42a7d85e06SJames Bottomley /* final encrypt and decrypt is the same */
crypto_cfb_final(struct skcipher_walk * walk,struct crypto_skcipher * tfm)43a7d85e06SJames Bottomley static void crypto_cfb_final(struct skcipher_walk *walk,
44a7d85e06SJames Bottomley struct crypto_skcipher *tfm)
45a7d85e06SJames Bottomley {
46a7d85e06SJames Bottomley const unsigned long alignmask = crypto_skcipher_alignmask(tfm);
476650c4deSSalvatore Mesoraca u8 tmp[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK];
48a7d85e06SJames Bottomley u8 *stream = PTR_ALIGN(tmp + 0, alignmask + 1);
49a7d85e06SJames Bottomley u8 *src = walk->src.virt.addr;
50a7d85e06SJames Bottomley u8 *dst = walk->dst.virt.addr;
51a7d85e06SJames Bottomley u8 *iv = walk->iv;
52a7d85e06SJames Bottomley unsigned int nbytes = walk->nbytes;
53a7d85e06SJames Bottomley
54a7d85e06SJames Bottomley crypto_cfb_encrypt_one(tfm, iv, stream);
55a7d85e06SJames Bottomley crypto_xor_cpy(dst, stream, src, nbytes);
56a7d85e06SJames Bottomley }
57a7d85e06SJames Bottomley
crypto_cfb_encrypt_segment(struct skcipher_walk * walk,struct crypto_skcipher * tfm)58a7d85e06SJames Bottomley static int crypto_cfb_encrypt_segment(struct skcipher_walk *walk,
59a7d85e06SJames Bottomley struct crypto_skcipher *tfm)
60a7d85e06SJames Bottomley {
61a7d85e06SJames Bottomley const unsigned int bsize = crypto_cfb_bsize(tfm);
62a7d85e06SJames Bottomley unsigned int nbytes = walk->nbytes;
63a7d85e06SJames Bottomley u8 *src = walk->src.virt.addr;
64a7d85e06SJames Bottomley u8 *dst = walk->dst.virt.addr;
65a7d85e06SJames Bottomley u8 *iv = walk->iv;
66a7d85e06SJames Bottomley
67a7d85e06SJames Bottomley do {
68a7d85e06SJames Bottomley crypto_cfb_encrypt_one(tfm, iv, dst);
69a7d85e06SJames Bottomley crypto_xor(dst, src, bsize);
706c2e322bSEric Biggers iv = dst;
71a7d85e06SJames Bottomley
72a7d85e06SJames Bottomley src += bsize;
73a7d85e06SJames Bottomley dst += bsize;
74a7d85e06SJames Bottomley } while ((nbytes -= bsize) >= bsize);
75a7d85e06SJames Bottomley
766c2e322bSEric Biggers memcpy(walk->iv, iv, bsize);
776c2e322bSEric Biggers
78a7d85e06SJames Bottomley return nbytes;
79a7d85e06SJames Bottomley }
80a7d85e06SJames Bottomley
crypto_cfb_encrypt_inplace(struct skcipher_walk * walk,struct crypto_skcipher * tfm)81a7d85e06SJames Bottomley static int crypto_cfb_encrypt_inplace(struct skcipher_walk *walk,
82a7d85e06SJames Bottomley struct crypto_skcipher *tfm)
83a7d85e06SJames Bottomley {
84a7d85e06SJames Bottomley const unsigned int bsize = crypto_cfb_bsize(tfm);
85a7d85e06SJames Bottomley unsigned int nbytes = walk->nbytes;
86a7d85e06SJames Bottomley u8 *src = walk->src.virt.addr;
87a7d85e06SJames Bottomley u8 *iv = walk->iv;
886650c4deSSalvatore Mesoraca u8 tmp[MAX_CIPHER_BLOCKSIZE];
89a7d85e06SJames Bottomley
90a7d85e06SJames Bottomley do {
91a7d85e06SJames Bottomley crypto_cfb_encrypt_one(tfm, iv, tmp);
92a7d85e06SJames Bottomley crypto_xor(src, tmp, bsize);
93a7d85e06SJames Bottomley iv = src;
94a7d85e06SJames Bottomley
95a7d85e06SJames Bottomley src += bsize;
96a7d85e06SJames Bottomley } while ((nbytes -= bsize) >= bsize);
97a7d85e06SJames Bottomley
98a7d85e06SJames Bottomley memcpy(walk->iv, iv, bsize);
99a7d85e06SJames Bottomley
100a7d85e06SJames Bottomley return nbytes;
101a7d85e06SJames Bottomley }
102a7d85e06SJames Bottomley
crypto_cfb_encrypt(struct skcipher_request * req)103a7d85e06SJames Bottomley static int crypto_cfb_encrypt(struct skcipher_request *req)
104a7d85e06SJames Bottomley {
105a7d85e06SJames Bottomley struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
106a7d85e06SJames Bottomley struct skcipher_walk walk;
107a7d85e06SJames Bottomley unsigned int bsize = crypto_cfb_bsize(tfm);
108a7d85e06SJames Bottomley int err;
109a7d85e06SJames Bottomley
110a7d85e06SJames Bottomley err = skcipher_walk_virt(&walk, req, false);
111a7d85e06SJames Bottomley
112a7d85e06SJames Bottomley while (walk.nbytes >= bsize) {
113a7d85e06SJames Bottomley if (walk.src.virt.addr == walk.dst.virt.addr)
114a7d85e06SJames Bottomley err = crypto_cfb_encrypt_inplace(&walk, tfm);
115a7d85e06SJames Bottomley else
116a7d85e06SJames Bottomley err = crypto_cfb_encrypt_segment(&walk, tfm);
117a7d85e06SJames Bottomley err = skcipher_walk_done(&walk, err);
118a7d85e06SJames Bottomley }
119a7d85e06SJames Bottomley
120a7d85e06SJames Bottomley if (walk.nbytes) {
121a7d85e06SJames Bottomley crypto_cfb_final(&walk, tfm);
122a7d85e06SJames Bottomley err = skcipher_walk_done(&walk, 0);
123a7d85e06SJames Bottomley }
124a7d85e06SJames Bottomley
125a7d85e06SJames Bottomley return err;
126a7d85e06SJames Bottomley }
127a7d85e06SJames Bottomley
crypto_cfb_decrypt_segment(struct skcipher_walk * walk,struct crypto_skcipher * tfm)128a7d85e06SJames Bottomley static int crypto_cfb_decrypt_segment(struct skcipher_walk *walk,
129a7d85e06SJames Bottomley struct crypto_skcipher *tfm)
130a7d85e06SJames Bottomley {
131a7d85e06SJames Bottomley const unsigned int bsize = crypto_cfb_bsize(tfm);
132a7d85e06SJames Bottomley unsigned int nbytes = walk->nbytes;
133a7d85e06SJames Bottomley u8 *src = walk->src.virt.addr;
134a7d85e06SJames Bottomley u8 *dst = walk->dst.virt.addr;
135a7d85e06SJames Bottomley u8 *iv = walk->iv;
136a7d85e06SJames Bottomley
137a7d85e06SJames Bottomley do {
138a7d85e06SJames Bottomley crypto_cfb_encrypt_one(tfm, iv, dst);
139fa460073SDmitry Eremin-Solenikov crypto_xor(dst, src, bsize);
140a7d85e06SJames Bottomley iv = src;
141a7d85e06SJames Bottomley
142a7d85e06SJames Bottomley src += bsize;
143a7d85e06SJames Bottomley dst += bsize;
144a7d85e06SJames Bottomley } while ((nbytes -= bsize) >= bsize);
145a7d85e06SJames Bottomley
146a7d85e06SJames Bottomley memcpy(walk->iv, iv, bsize);
147a7d85e06SJames Bottomley
148a7d85e06SJames Bottomley return nbytes;
149a7d85e06SJames Bottomley }
150a7d85e06SJames Bottomley
crypto_cfb_decrypt_inplace(struct skcipher_walk * walk,struct crypto_skcipher * tfm)151a7d85e06SJames Bottomley static int crypto_cfb_decrypt_inplace(struct skcipher_walk *walk,
152a7d85e06SJames Bottomley struct crypto_skcipher *tfm)
153a7d85e06SJames Bottomley {
154a7d85e06SJames Bottomley const unsigned int bsize = crypto_cfb_bsize(tfm);
155a7d85e06SJames Bottomley unsigned int nbytes = walk->nbytes;
156a7d85e06SJames Bottomley u8 *src = walk->src.virt.addr;
1576c2e322bSEric Biggers u8 * const iv = walk->iv;
1586650c4deSSalvatore Mesoraca u8 tmp[MAX_CIPHER_BLOCKSIZE];
159a7d85e06SJames Bottomley
160a7d85e06SJames Bottomley do {
161a7d85e06SJames Bottomley crypto_cfb_encrypt_one(tfm, iv, tmp);
162a7d85e06SJames Bottomley memcpy(iv, src, bsize);
163a7d85e06SJames Bottomley crypto_xor(src, tmp, bsize);
164a7d85e06SJames Bottomley src += bsize;
165a7d85e06SJames Bottomley } while ((nbytes -= bsize) >= bsize);
166a7d85e06SJames Bottomley
167a7d85e06SJames Bottomley return nbytes;
168a7d85e06SJames Bottomley }
169a7d85e06SJames Bottomley
crypto_cfb_decrypt_blocks(struct skcipher_walk * walk,struct crypto_skcipher * tfm)170a7d85e06SJames Bottomley static int crypto_cfb_decrypt_blocks(struct skcipher_walk *walk,
171a7d85e06SJames Bottomley struct crypto_skcipher *tfm)
172a7d85e06SJames Bottomley {
173a7d85e06SJames Bottomley if (walk->src.virt.addr == walk->dst.virt.addr)
174a7d85e06SJames Bottomley return crypto_cfb_decrypt_inplace(walk, tfm);
175a7d85e06SJames Bottomley else
176a7d85e06SJames Bottomley return crypto_cfb_decrypt_segment(walk, tfm);
177a7d85e06SJames Bottomley }
178a7d85e06SJames Bottomley
crypto_cfb_decrypt(struct skcipher_request * req)179a7d85e06SJames Bottomley static int crypto_cfb_decrypt(struct skcipher_request *req)
180a7d85e06SJames Bottomley {
181a7d85e06SJames Bottomley struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
182a7d85e06SJames Bottomley struct skcipher_walk walk;
183a7d85e06SJames Bottomley const unsigned int bsize = crypto_cfb_bsize(tfm);
184a7d85e06SJames Bottomley int err;
185a7d85e06SJames Bottomley
186a7d85e06SJames Bottomley err = skcipher_walk_virt(&walk, req, false);
187a7d85e06SJames Bottomley
188a7d85e06SJames Bottomley while (walk.nbytes >= bsize) {
189a7d85e06SJames Bottomley err = crypto_cfb_decrypt_blocks(&walk, tfm);
190a7d85e06SJames Bottomley err = skcipher_walk_done(&walk, err);
191a7d85e06SJames Bottomley }
192a7d85e06SJames Bottomley
193a7d85e06SJames Bottomley if (walk.nbytes) {
194a7d85e06SJames Bottomley crypto_cfb_final(&walk, tfm);
195a7d85e06SJames Bottomley err = skcipher_walk_done(&walk, 0);
196a7d85e06SJames Bottomley }
197a7d85e06SJames Bottomley
198a7d85e06SJames Bottomley return err;
199a7d85e06SJames Bottomley }
200a7d85e06SJames Bottomley
crypto_cfb_create(struct crypto_template * tmpl,struct rtattr ** tb)201a7d85e06SJames Bottomley static int crypto_cfb_create(struct crypto_template *tmpl, struct rtattr **tb)
202a7d85e06SJames Bottomley {
203a7d85e06SJames Bottomley struct skcipher_instance *inst;
204a7d85e06SJames Bottomley struct crypto_alg *alg;
205a7d85e06SJames Bottomley int err;
206a7d85e06SJames Bottomley
207b3c16bfcSHerbert Xu inst = skcipher_alloc_instance_simple(tmpl, tb);
20803b8302dSEric Biggers if (IS_ERR(inst))
20903b8302dSEric Biggers return PTR_ERR(inst);
210a7d85e06SJames Bottomley
211b3c16bfcSHerbert Xu alg = skcipher_ialg_simple(inst);
212b3c16bfcSHerbert Xu
21303b8302dSEric Biggers /* CFB mode is a stream cipher. */
214a7d85e06SJames Bottomley inst->alg.base.cra_blocksize = 1;
215a7d85e06SJames Bottomley
216394a9e04SEric Biggers /*
217394a9e04SEric Biggers * To simplify the implementation, configure the skcipher walk to only
218394a9e04SEric Biggers * give a partial block at the very end, never earlier.
219394a9e04SEric Biggers */
220394a9e04SEric Biggers inst->alg.chunksize = alg->cra_blocksize;
221394a9e04SEric Biggers
222a7d85e06SJames Bottomley inst->alg.encrypt = crypto_cfb_encrypt;
223a7d85e06SJames Bottomley inst->alg.decrypt = crypto_cfb_decrypt;
224a7d85e06SJames Bottomley
225a7d85e06SJames Bottomley err = skcipher_register_instance(tmpl, inst);
226a7d85e06SJames Bottomley if (err)
22703b8302dSEric Biggers inst->free(inst);
228a7d85e06SJames Bottomley
229a7d85e06SJames Bottomley return err;
230a7d85e06SJames Bottomley }
231a7d85e06SJames Bottomley
232a7d85e06SJames Bottomley static struct crypto_template crypto_cfb_tmpl = {
233a7d85e06SJames Bottomley .name = "cfb",
234a7d85e06SJames Bottomley .create = crypto_cfb_create,
235a7d85e06SJames Bottomley .module = THIS_MODULE,
236a7d85e06SJames Bottomley };
237a7d85e06SJames Bottomley
crypto_cfb_module_init(void)238a7d85e06SJames Bottomley static int __init crypto_cfb_module_init(void)
239a7d85e06SJames Bottomley {
240a7d85e06SJames Bottomley return crypto_register_template(&crypto_cfb_tmpl);
241a7d85e06SJames Bottomley }
242a7d85e06SJames Bottomley
crypto_cfb_module_exit(void)243a7d85e06SJames Bottomley static void __exit crypto_cfb_module_exit(void)
244a7d85e06SJames Bottomley {
245a7d85e06SJames Bottomley crypto_unregister_template(&crypto_cfb_tmpl);
246a7d85e06SJames Bottomley }
247a7d85e06SJames Bottomley
248c4741b23SEric Biggers subsys_initcall(crypto_cfb_module_init);
249a7d85e06SJames Bottomley module_exit(crypto_cfb_module_exit);
250a7d85e06SJames Bottomley
251a7d85e06SJames Bottomley MODULE_LICENSE("GPL");
25203b8302dSEric Biggers MODULE_DESCRIPTION("CFB block cipher mode of operation");
253a7d85e06SJames Bottomley MODULE_ALIAS_CRYPTO("cfb");
254*0eb76ba2SArd Biesheuvel MODULE_IMPORT_NS(CRYPTO_INTERNAL);
255