xref: /openbmc/linux/crypto/ofb.c (revision 0eb76ba2)
1e497c518SGilad Ben-Yossef // SPDX-License-Identifier: GPL-2.0
2e497c518SGilad Ben-Yossef 
3e497c518SGilad Ben-Yossef /*
4e497c518SGilad Ben-Yossef  * OFB: Output FeedBack mode
5e497c518SGilad Ben-Yossef  *
6e497c518SGilad Ben-Yossef  * Copyright (C) 2018 ARM Limited or its affiliates.
7e497c518SGilad Ben-Yossef  * All rights reserved.
8e497c518SGilad Ben-Yossef  */
9e497c518SGilad Ben-Yossef 
10e497c518SGilad Ben-Yossef #include <crypto/algapi.h>
11*0eb76ba2SArd Biesheuvel #include <crypto/internal/cipher.h>
12e497c518SGilad Ben-Yossef #include <crypto/internal/skcipher.h>
13e497c518SGilad Ben-Yossef #include <linux/err.h>
14e497c518SGilad Ben-Yossef #include <linux/init.h>
15e497c518SGilad Ben-Yossef #include <linux/kernel.h>
16e497c518SGilad Ben-Yossef #include <linux/module.h>
17e497c518SGilad Ben-Yossef 
crypto_ofb_crypt(struct skcipher_request * req)18b3e3e2dbSEric Biggers static int crypto_ofb_crypt(struct skcipher_request *req)
19e497c518SGilad Ben-Yossef {
20b3e3e2dbSEric Biggers 	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
2121f3ca6cSEric Biggers 	struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
22b3e3e2dbSEric Biggers 	const unsigned int bsize = crypto_cipher_blocksize(cipher);
23b3e3e2dbSEric Biggers 	struct skcipher_walk walk;
24b3e3e2dbSEric Biggers 	int err;
25e497c518SGilad Ben-Yossef 
26b3e3e2dbSEric Biggers 	err = skcipher_walk_virt(&walk, req, false);
27b3e3e2dbSEric Biggers 
28b3e3e2dbSEric Biggers 	while (walk.nbytes >= bsize) {
29b3e3e2dbSEric Biggers 		const u8 *src = walk.src.virt.addr;
30b3e3e2dbSEric Biggers 		u8 *dst = walk.dst.virt.addr;
31b3e3e2dbSEric Biggers 		u8 * const iv = walk.iv;
32b3e3e2dbSEric Biggers 		unsigned int nbytes = walk.nbytes;
33e497c518SGilad Ben-Yossef 
34e497c518SGilad Ben-Yossef 		do {
35b3e3e2dbSEric Biggers 			crypto_cipher_encrypt_one(cipher, iv, iv);
36b3e3e2dbSEric Biggers 			crypto_xor_cpy(dst, src, iv, bsize);
37b3e3e2dbSEric Biggers 			dst += bsize;
38b3e3e2dbSEric Biggers 			src += bsize;
39b3e3e2dbSEric Biggers 		} while ((nbytes -= bsize) >= bsize);
40b3e3e2dbSEric Biggers 
41b3e3e2dbSEric Biggers 		err = skcipher_walk_done(&walk, nbytes);
42e497c518SGilad Ben-Yossef 	}
43e497c518SGilad Ben-Yossef 
44b3e3e2dbSEric Biggers 	if (walk.nbytes) {
45b3e3e2dbSEric Biggers 		crypto_cipher_encrypt_one(cipher, walk.iv, walk.iv);
46b3e3e2dbSEric Biggers 		crypto_xor_cpy(walk.dst.virt.addr, walk.src.virt.addr, walk.iv,
47b3e3e2dbSEric Biggers 			       walk.nbytes);
48b3e3e2dbSEric Biggers 		err = skcipher_walk_done(&walk, 0);
49e497c518SGilad Ben-Yossef 	}
50b3e3e2dbSEric Biggers 	return err;
51e497c518SGilad Ben-Yossef }
52e497c518SGilad Ben-Yossef 
crypto_ofb_create(struct crypto_template * tmpl,struct rtattr ** tb)53e497c518SGilad Ben-Yossef static int crypto_ofb_create(struct crypto_template *tmpl, struct rtattr **tb)
54e497c518SGilad Ben-Yossef {
55e497c518SGilad Ben-Yossef 	struct skcipher_instance *inst;
56e497c518SGilad Ben-Yossef 	struct crypto_alg *alg;
57e497c518SGilad Ben-Yossef 	int err;
58e497c518SGilad Ben-Yossef 
59b3c16bfcSHerbert Xu 	inst = skcipher_alloc_instance_simple(tmpl, tb);
6021f3ca6cSEric Biggers 	if (IS_ERR(inst))
6121f3ca6cSEric Biggers 		return PTR_ERR(inst);
62e497c518SGilad Ben-Yossef 
63b3c16bfcSHerbert Xu 	alg = skcipher_ialg_simple(inst);
64b3c16bfcSHerbert Xu 
65b3e3e2dbSEric Biggers 	/* OFB mode is a stream cipher. */
66b3e3e2dbSEric Biggers 	inst->alg.base.cra_blocksize = 1;
67e497c518SGilad Ben-Yossef 
68b3e3e2dbSEric Biggers 	/*
69b3e3e2dbSEric Biggers 	 * To simplify the implementation, configure the skcipher walk to only
70b3e3e2dbSEric Biggers 	 * give a partial block at the very end, never earlier.
71b3e3e2dbSEric Biggers 	 */
72b3e3e2dbSEric Biggers 	inst->alg.chunksize = alg->cra_blocksize;
73b3e3e2dbSEric Biggers 
74b3e3e2dbSEric Biggers 	inst->alg.encrypt = crypto_ofb_crypt;
75b3e3e2dbSEric Biggers 	inst->alg.decrypt = crypto_ofb_crypt;
76e497c518SGilad Ben-Yossef 
77e497c518SGilad Ben-Yossef 	err = skcipher_register_instance(tmpl, inst);
78e497c518SGilad Ben-Yossef 	if (err)
7921f3ca6cSEric Biggers 		inst->free(inst);
80e497c518SGilad Ben-Yossef 
81e497c518SGilad Ben-Yossef 	return err;
82e497c518SGilad Ben-Yossef }
83e497c518SGilad Ben-Yossef 
84e497c518SGilad Ben-Yossef static struct crypto_template crypto_ofb_tmpl = {
85e497c518SGilad Ben-Yossef 	.name = "ofb",
86e497c518SGilad Ben-Yossef 	.create = crypto_ofb_create,
87e497c518SGilad Ben-Yossef 	.module = THIS_MODULE,
88e497c518SGilad Ben-Yossef };
89e497c518SGilad Ben-Yossef 
crypto_ofb_module_init(void)90e497c518SGilad Ben-Yossef static int __init crypto_ofb_module_init(void)
91e497c518SGilad Ben-Yossef {
92e497c518SGilad Ben-Yossef 	return crypto_register_template(&crypto_ofb_tmpl);
93e497c518SGilad Ben-Yossef }
94e497c518SGilad Ben-Yossef 
crypto_ofb_module_exit(void)95e497c518SGilad Ben-Yossef static void __exit crypto_ofb_module_exit(void)
96e497c518SGilad Ben-Yossef {
97e497c518SGilad Ben-Yossef 	crypto_unregister_template(&crypto_ofb_tmpl);
98e497c518SGilad Ben-Yossef }
99e497c518SGilad Ben-Yossef 
100c4741b23SEric Biggers subsys_initcall(crypto_ofb_module_init);
101e497c518SGilad Ben-Yossef module_exit(crypto_ofb_module_exit);
102e497c518SGilad Ben-Yossef 
103e497c518SGilad Ben-Yossef MODULE_LICENSE("GPL");
10421f3ca6cSEric Biggers MODULE_DESCRIPTION("OFB block cipher mode of operation");
105e497c518SGilad Ben-Yossef MODULE_ALIAS_CRYPTO("ofb");
106*0eb76ba2SArd Biesheuvel MODULE_IMPORT_NS(CRYPTO_INTERNAL);
107