162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * XCTR: XOR Counter mode - Adapted from ctr.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com> 662306a36Sopenharmony_ci * Copyright 2021 Google LLC 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * XCTR mode is a blockcipher mode of operation used to implement HCTR2. XCTR is 1162306a36Sopenharmony_ci * closely related to the CTR mode of operation; the main difference is that CTR 1262306a36Sopenharmony_ci * generates the keystream using E(CTR + IV) whereas XCTR generates the 1362306a36Sopenharmony_ci * keystream using E(CTR ^ IV). This allows implementations to avoid dealing 1462306a36Sopenharmony_ci * with multi-limb integers (as is required in CTR mode). XCTR is also specified 1562306a36Sopenharmony_ci * using little-endian arithmetic which makes it slightly faster on LE machines. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * See the HCTR2 paper for more details: 1862306a36Sopenharmony_ci * Length-preserving encryption with HCTR2 1962306a36Sopenharmony_ci * (https://eprint.iacr.org/2021/1441.pdf) 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/slab.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* For now this implementation is limited to 16-byte blocks for simplicity */ 3262306a36Sopenharmony_ci#define XCTR_BLOCKSIZE 16 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic void crypto_xctr_crypt_final(struct skcipher_walk *walk, 3562306a36Sopenharmony_ci struct crypto_cipher *tfm, u32 byte_ctr) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci u8 keystream[XCTR_BLOCKSIZE]; 3862306a36Sopenharmony_ci const u8 *src = walk->src.virt.addr; 3962306a36Sopenharmony_ci u8 *dst = walk->dst.virt.addr; 4062306a36Sopenharmony_ci unsigned int nbytes = walk->nbytes; 4162306a36Sopenharmony_ci __le32 ctr32 = cpu_to_le32(byte_ctr / XCTR_BLOCKSIZE + 1); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32)); 4462306a36Sopenharmony_ci crypto_cipher_encrypt_one(tfm, keystream, walk->iv); 4562306a36Sopenharmony_ci crypto_xor_cpy(dst, keystream, src, nbytes); 4662306a36Sopenharmony_ci crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32)); 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int crypto_xctr_crypt_segment(struct skcipher_walk *walk, 5062306a36Sopenharmony_ci struct crypto_cipher *tfm, u32 byte_ctr) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = 5362306a36Sopenharmony_ci crypto_cipher_alg(tfm)->cia_encrypt; 5462306a36Sopenharmony_ci const u8 *src = walk->src.virt.addr; 5562306a36Sopenharmony_ci u8 *dst = walk->dst.virt.addr; 5662306a36Sopenharmony_ci unsigned int nbytes = walk->nbytes; 5762306a36Sopenharmony_ci __le32 ctr32 = cpu_to_le32(byte_ctr / XCTR_BLOCKSIZE + 1); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci do { 6062306a36Sopenharmony_ci crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32)); 6162306a36Sopenharmony_ci fn(crypto_cipher_tfm(tfm), dst, walk->iv); 6262306a36Sopenharmony_ci crypto_xor(dst, src, XCTR_BLOCKSIZE); 6362306a36Sopenharmony_ci crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32)); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci le32_add_cpu(&ctr32, 1); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci src += XCTR_BLOCKSIZE; 6862306a36Sopenharmony_ci dst += XCTR_BLOCKSIZE; 6962306a36Sopenharmony_ci } while ((nbytes -= XCTR_BLOCKSIZE) >= XCTR_BLOCKSIZE); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci return nbytes; 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic int crypto_xctr_crypt_inplace(struct skcipher_walk *walk, 7562306a36Sopenharmony_ci struct crypto_cipher *tfm, u32 byte_ctr) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci void (*fn)(struct crypto_tfm *, u8 *, const u8 *) = 7862306a36Sopenharmony_ci crypto_cipher_alg(tfm)->cia_encrypt; 7962306a36Sopenharmony_ci unsigned long alignmask = crypto_cipher_alignmask(tfm); 8062306a36Sopenharmony_ci unsigned int nbytes = walk->nbytes; 8162306a36Sopenharmony_ci u8 *data = walk->src.virt.addr; 8262306a36Sopenharmony_ci u8 tmp[XCTR_BLOCKSIZE + MAX_CIPHER_ALIGNMASK]; 8362306a36Sopenharmony_ci u8 *keystream = PTR_ALIGN(tmp + 0, alignmask + 1); 8462306a36Sopenharmony_ci __le32 ctr32 = cpu_to_le32(byte_ctr / XCTR_BLOCKSIZE + 1); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci do { 8762306a36Sopenharmony_ci crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32)); 8862306a36Sopenharmony_ci fn(crypto_cipher_tfm(tfm), keystream, walk->iv); 8962306a36Sopenharmony_ci crypto_xor(data, keystream, XCTR_BLOCKSIZE); 9062306a36Sopenharmony_ci crypto_xor(walk->iv, (u8 *)&ctr32, sizeof(ctr32)); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci le32_add_cpu(&ctr32, 1); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci data += XCTR_BLOCKSIZE; 9562306a36Sopenharmony_ci } while ((nbytes -= XCTR_BLOCKSIZE) >= XCTR_BLOCKSIZE); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return nbytes; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_cistatic int crypto_xctr_crypt(struct skcipher_request *req) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 10362306a36Sopenharmony_ci struct crypto_cipher *cipher = skcipher_cipher_simple(tfm); 10462306a36Sopenharmony_ci struct skcipher_walk walk; 10562306a36Sopenharmony_ci unsigned int nbytes; 10662306a36Sopenharmony_ci int err; 10762306a36Sopenharmony_ci u32 byte_ctr = 0; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci while (walk.nbytes >= XCTR_BLOCKSIZE) { 11262306a36Sopenharmony_ci if (walk.src.virt.addr == walk.dst.virt.addr) 11362306a36Sopenharmony_ci nbytes = crypto_xctr_crypt_inplace(&walk, cipher, 11462306a36Sopenharmony_ci byte_ctr); 11562306a36Sopenharmony_ci else 11662306a36Sopenharmony_ci nbytes = crypto_xctr_crypt_segment(&walk, cipher, 11762306a36Sopenharmony_ci byte_ctr); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci byte_ctr += walk.nbytes - nbytes; 12062306a36Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes); 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (walk.nbytes) { 12462306a36Sopenharmony_ci crypto_xctr_crypt_final(&walk, cipher, byte_ctr); 12562306a36Sopenharmony_ci err = skcipher_walk_done(&walk, 0); 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return err; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic int crypto_xctr_create(struct crypto_template *tmpl, struct rtattr **tb) 13262306a36Sopenharmony_ci{ 13362306a36Sopenharmony_ci struct skcipher_instance *inst; 13462306a36Sopenharmony_ci struct crypto_alg *alg; 13562306a36Sopenharmony_ci int err; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci inst = skcipher_alloc_instance_simple(tmpl, tb); 13862306a36Sopenharmony_ci if (IS_ERR(inst)) 13962306a36Sopenharmony_ci return PTR_ERR(inst); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci alg = skcipher_ialg_simple(inst); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* Block size must be 16 bytes. */ 14462306a36Sopenharmony_ci err = -EINVAL; 14562306a36Sopenharmony_ci if (alg->cra_blocksize != XCTR_BLOCKSIZE) 14662306a36Sopenharmony_ci goto out_free_inst; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* XCTR mode is a stream cipher. */ 14962306a36Sopenharmony_ci inst->alg.base.cra_blocksize = 1; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * To simplify the implementation, configure the skcipher walk to only 15362306a36Sopenharmony_ci * give a partial block at the very end, never earlier. 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci inst->alg.chunksize = alg->cra_blocksize; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci inst->alg.encrypt = crypto_xctr_crypt; 15862306a36Sopenharmony_ci inst->alg.decrypt = crypto_xctr_crypt; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci err = skcipher_register_instance(tmpl, inst); 16162306a36Sopenharmony_ci if (err) { 16262306a36Sopenharmony_ciout_free_inst: 16362306a36Sopenharmony_ci inst->free(inst); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return err; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic struct crypto_template crypto_xctr_tmpl = { 17062306a36Sopenharmony_ci .name = "xctr", 17162306a36Sopenharmony_ci .create = crypto_xctr_create, 17262306a36Sopenharmony_ci .module = THIS_MODULE, 17362306a36Sopenharmony_ci}; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic int __init crypto_xctr_module_init(void) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci return crypto_register_template(&crypto_xctr_tmpl); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void __exit crypto_xctr_module_exit(void) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci crypto_unregister_template(&crypto_xctr_tmpl); 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cisubsys_initcall(crypto_xctr_module_init); 18662306a36Sopenharmony_cimodule_exit(crypto_xctr_module_exit); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 18962306a36Sopenharmony_ciMODULE_DESCRIPTION("XCTR block cipher mode of operation"); 19062306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("xctr"); 19162306a36Sopenharmony_ciMODULE_IMPORT_NS(CRYPTO_INTERNAL); 192