162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * CFB: Cipher FeedBack mode 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2018 James.Bottomley@HansenPartnership.com 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * CFB is a stream cipher mode which is layered on to a block 862306a36Sopenharmony_ci * encryption scheme. It works very much like a one time pad where 962306a36Sopenharmony_ci * the pad is generated initially from the encrypted IV and then 1062306a36Sopenharmony_ci * subsequently from the encrypted previous block of ciphertext. The 1162306a36Sopenharmony_ci * pad is XOR'd into the plain text to get the final ciphertext. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The scheme of CFB is best described by wikipedia: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#CFB 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Note that since the pad for both encryption and decryption is 1862306a36Sopenharmony_ci * generated by an encryption operation, CFB never uses the block 1962306a36Sopenharmony_ci * decryption function. 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <crypto/algapi.h> 2362306a36Sopenharmony_ci#include <crypto/internal/cipher.h> 2462306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2562306a36Sopenharmony_ci#include <linux/err.h> 2662306a36Sopenharmony_ci#include <linux/init.h> 2762306a36Sopenharmony_ci#include <linux/kernel.h> 2862306a36Sopenharmony_ci#include <linux/module.h> 2962306a36Sopenharmony_ci#include <linux/string.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic unsigned int crypto_cfb_bsize(struct crypto_skcipher *tfm) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci return crypto_cipher_blocksize(skcipher_cipher_simple(tfm)); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic void crypto_cfb_encrypt_one(struct crypto_skcipher *tfm, 3762306a36Sopenharmony_ci const u8 *src, u8 *dst) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci crypto_cipher_encrypt_one(skcipher_cipher_simple(tfm), dst, src); 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* final encrypt and decrypt is the same */ 4362306a36Sopenharmony_cistatic void crypto_cfb_final(struct skcipher_walk *walk, 4462306a36Sopenharmony_ci struct crypto_skcipher *tfm) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci const unsigned long alignmask = crypto_skcipher_alignmask(tfm); 4762306a36Sopenharmony_ci u8 tmp[MAX_CIPHER_BLOCKSIZE + MAX_CIPHER_ALIGNMASK]; 4862306a36Sopenharmony_ci u8 *stream = PTR_ALIGN(tmp + 0, alignmask + 1); 4962306a36Sopenharmony_ci u8 *src = walk->src.virt.addr; 5062306a36Sopenharmony_ci u8 *dst = walk->dst.virt.addr; 5162306a36Sopenharmony_ci u8 *iv = walk->iv; 5262306a36Sopenharmony_ci unsigned int nbytes = walk->nbytes; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci crypto_cfb_encrypt_one(tfm, iv, stream); 5562306a36Sopenharmony_ci crypto_xor_cpy(dst, stream, src, nbytes); 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int crypto_cfb_encrypt_segment(struct skcipher_walk *walk, 5962306a36Sopenharmony_ci struct crypto_skcipher *tfm) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci const unsigned int bsize = crypto_cfb_bsize(tfm); 6262306a36Sopenharmony_ci unsigned int nbytes = walk->nbytes; 6362306a36Sopenharmony_ci u8 *src = walk->src.virt.addr; 6462306a36Sopenharmony_ci u8 *dst = walk->dst.virt.addr; 6562306a36Sopenharmony_ci u8 *iv = walk->iv; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci do { 6862306a36Sopenharmony_ci crypto_cfb_encrypt_one(tfm, iv, dst); 6962306a36Sopenharmony_ci crypto_xor(dst, src, bsize); 7062306a36Sopenharmony_ci iv = dst; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci src += bsize; 7362306a36Sopenharmony_ci dst += bsize; 7462306a36Sopenharmony_ci } while ((nbytes -= bsize) >= bsize); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci memcpy(walk->iv, iv, bsize); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci return nbytes; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic int crypto_cfb_encrypt_inplace(struct skcipher_walk *walk, 8262306a36Sopenharmony_ci struct crypto_skcipher *tfm) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci const unsigned int bsize = crypto_cfb_bsize(tfm); 8562306a36Sopenharmony_ci unsigned int nbytes = walk->nbytes; 8662306a36Sopenharmony_ci u8 *src = walk->src.virt.addr; 8762306a36Sopenharmony_ci u8 *iv = walk->iv; 8862306a36Sopenharmony_ci u8 tmp[MAX_CIPHER_BLOCKSIZE]; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci do { 9162306a36Sopenharmony_ci crypto_cfb_encrypt_one(tfm, iv, tmp); 9262306a36Sopenharmony_ci crypto_xor(src, tmp, bsize); 9362306a36Sopenharmony_ci iv = src; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci src += bsize; 9662306a36Sopenharmony_ci } while ((nbytes -= bsize) >= bsize); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci memcpy(walk->iv, iv, bsize); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci return nbytes; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic int crypto_cfb_encrypt(struct skcipher_request *req) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 10662306a36Sopenharmony_ci struct skcipher_walk walk; 10762306a36Sopenharmony_ci unsigned int bsize = crypto_cfb_bsize(tfm); 10862306a36Sopenharmony_ci int err; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci while (walk.nbytes >= bsize) { 11362306a36Sopenharmony_ci if (walk.src.virt.addr == walk.dst.virt.addr) 11462306a36Sopenharmony_ci err = crypto_cfb_encrypt_inplace(&walk, tfm); 11562306a36Sopenharmony_ci else 11662306a36Sopenharmony_ci err = crypto_cfb_encrypt_segment(&walk, tfm); 11762306a36Sopenharmony_ci err = skcipher_walk_done(&walk, err); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (walk.nbytes) { 12162306a36Sopenharmony_ci crypto_cfb_final(&walk, tfm); 12262306a36Sopenharmony_ci err = skcipher_walk_done(&walk, 0); 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci return err; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic int crypto_cfb_decrypt_segment(struct skcipher_walk *walk, 12962306a36Sopenharmony_ci struct crypto_skcipher *tfm) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci const unsigned int bsize = crypto_cfb_bsize(tfm); 13262306a36Sopenharmony_ci unsigned int nbytes = walk->nbytes; 13362306a36Sopenharmony_ci u8 *src = walk->src.virt.addr; 13462306a36Sopenharmony_ci u8 *dst = walk->dst.virt.addr; 13562306a36Sopenharmony_ci u8 *iv = walk->iv; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci do { 13862306a36Sopenharmony_ci crypto_cfb_encrypt_one(tfm, iv, dst); 13962306a36Sopenharmony_ci crypto_xor(dst, src, bsize); 14062306a36Sopenharmony_ci iv = src; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci src += bsize; 14362306a36Sopenharmony_ci dst += bsize; 14462306a36Sopenharmony_ci } while ((nbytes -= bsize) >= bsize); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci memcpy(walk->iv, iv, bsize); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return nbytes; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic int crypto_cfb_decrypt_inplace(struct skcipher_walk *walk, 15262306a36Sopenharmony_ci struct crypto_skcipher *tfm) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci const unsigned int bsize = crypto_cfb_bsize(tfm); 15562306a36Sopenharmony_ci unsigned int nbytes = walk->nbytes; 15662306a36Sopenharmony_ci u8 *src = walk->src.virt.addr; 15762306a36Sopenharmony_ci u8 * const iv = walk->iv; 15862306a36Sopenharmony_ci u8 tmp[MAX_CIPHER_BLOCKSIZE]; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci do { 16162306a36Sopenharmony_ci crypto_cfb_encrypt_one(tfm, iv, tmp); 16262306a36Sopenharmony_ci memcpy(iv, src, bsize); 16362306a36Sopenharmony_ci crypto_xor(src, tmp, bsize); 16462306a36Sopenharmony_ci src += bsize; 16562306a36Sopenharmony_ci } while ((nbytes -= bsize) >= bsize); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return nbytes; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic int crypto_cfb_decrypt_blocks(struct skcipher_walk *walk, 17162306a36Sopenharmony_ci struct crypto_skcipher *tfm) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci if (walk->src.virt.addr == walk->dst.virt.addr) 17462306a36Sopenharmony_ci return crypto_cfb_decrypt_inplace(walk, tfm); 17562306a36Sopenharmony_ci else 17662306a36Sopenharmony_ci return crypto_cfb_decrypt_segment(walk, tfm); 17762306a36Sopenharmony_ci} 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic int crypto_cfb_decrypt(struct skcipher_request *req) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 18262306a36Sopenharmony_ci struct skcipher_walk walk; 18362306a36Sopenharmony_ci const unsigned int bsize = crypto_cfb_bsize(tfm); 18462306a36Sopenharmony_ci int err; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci while (walk.nbytes >= bsize) { 18962306a36Sopenharmony_ci err = crypto_cfb_decrypt_blocks(&walk, tfm); 19062306a36Sopenharmony_ci err = skcipher_walk_done(&walk, err); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (walk.nbytes) { 19462306a36Sopenharmony_ci crypto_cfb_final(&walk, tfm); 19562306a36Sopenharmony_ci err = skcipher_walk_done(&walk, 0); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return err; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic int crypto_cfb_create(struct crypto_template *tmpl, struct rtattr **tb) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct skcipher_instance *inst; 20462306a36Sopenharmony_ci struct crypto_alg *alg; 20562306a36Sopenharmony_ci int err; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci inst = skcipher_alloc_instance_simple(tmpl, tb); 20862306a36Sopenharmony_ci if (IS_ERR(inst)) 20962306a36Sopenharmony_ci return PTR_ERR(inst); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci alg = skcipher_ialg_simple(inst); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* CFB mode is a stream cipher. */ 21462306a36Sopenharmony_ci inst->alg.base.cra_blocksize = 1; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * To simplify the implementation, configure the skcipher walk to only 21862306a36Sopenharmony_ci * give a partial block at the very end, never earlier. 21962306a36Sopenharmony_ci */ 22062306a36Sopenharmony_ci inst->alg.chunksize = alg->cra_blocksize; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci inst->alg.encrypt = crypto_cfb_encrypt; 22362306a36Sopenharmony_ci inst->alg.decrypt = crypto_cfb_decrypt; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci err = skcipher_register_instance(tmpl, inst); 22662306a36Sopenharmony_ci if (err) 22762306a36Sopenharmony_ci inst->free(inst); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return err; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic struct crypto_template crypto_cfb_tmpl = { 23362306a36Sopenharmony_ci .name = "cfb", 23462306a36Sopenharmony_ci .create = crypto_cfb_create, 23562306a36Sopenharmony_ci .module = THIS_MODULE, 23662306a36Sopenharmony_ci}; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic int __init crypto_cfb_module_init(void) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci return crypto_register_template(&crypto_cfb_tmpl); 24162306a36Sopenharmony_ci} 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistatic void __exit crypto_cfb_module_exit(void) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci crypto_unregister_template(&crypto_cfb_tmpl); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cisubsys_initcall(crypto_cfb_module_init); 24962306a36Sopenharmony_cimodule_exit(crypto_cfb_module_exit); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 25262306a36Sopenharmony_ciMODULE_DESCRIPTION("CFB block cipher mode of operation"); 25362306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("cfb"); 25462306a36Sopenharmony_ciMODULE_IMPORT_NS(CRYPTO_INTERNAL); 255