cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pcbc.c (4831B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * PCBC: Propagating Cipher Block Chaining mode
      4 *
      5 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
      6 * Written by David Howells (dhowells@redhat.com)
      7 *
      8 * Derived from cbc.c
      9 * - Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
     10 */
     11
     12#include <crypto/algapi.h>
     13#include <crypto/internal/cipher.h>
     14#include <crypto/internal/skcipher.h>
     15#include <linux/err.h>
     16#include <linux/init.h>
     17#include <linux/kernel.h>
     18#include <linux/module.h>
     19
     20static int crypto_pcbc_encrypt_segment(struct skcipher_request *req,
     21				       struct skcipher_walk *walk,
     22				       struct crypto_cipher *tfm)
     23{
     24	int bsize = crypto_cipher_blocksize(tfm);
     25	unsigned int nbytes = walk->nbytes;
     26	u8 *src = walk->src.virt.addr;
     27	u8 *dst = walk->dst.virt.addr;
     28	u8 * const iv = walk->iv;
     29
     30	do {
     31		crypto_xor(iv, src, bsize);
     32		crypto_cipher_encrypt_one(tfm, dst, iv);
     33		crypto_xor_cpy(iv, dst, src, bsize);
     34
     35		src += bsize;
     36		dst += bsize;
     37	} while ((nbytes -= bsize) >= bsize);
     38
     39	return nbytes;
     40}
     41
     42static int crypto_pcbc_encrypt_inplace(struct skcipher_request *req,
     43				       struct skcipher_walk *walk,
     44				       struct crypto_cipher *tfm)
     45{
     46	int bsize = crypto_cipher_blocksize(tfm);
     47	unsigned int nbytes = walk->nbytes;
     48	u8 *src = walk->src.virt.addr;
     49	u8 * const iv = walk->iv;
     50	u8 tmpbuf[MAX_CIPHER_BLOCKSIZE];
     51
     52	do {
     53		memcpy(tmpbuf, src, bsize);
     54		crypto_xor(iv, src, bsize);
     55		crypto_cipher_encrypt_one(tfm, src, iv);
     56		crypto_xor_cpy(iv, tmpbuf, src, bsize);
     57
     58		src += bsize;
     59	} while ((nbytes -= bsize) >= bsize);
     60
     61	return nbytes;
     62}
     63
     64static int crypto_pcbc_encrypt(struct skcipher_request *req)
     65{
     66	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
     67	struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
     68	struct skcipher_walk walk;
     69	unsigned int nbytes;
     70	int err;
     71
     72	err = skcipher_walk_virt(&walk, req, false);
     73
     74	while ((nbytes = walk.nbytes)) {
     75		if (walk.src.virt.addr == walk.dst.virt.addr)
     76			nbytes = crypto_pcbc_encrypt_inplace(req, &walk,
     77							     cipher);
     78		else
     79			nbytes = crypto_pcbc_encrypt_segment(req, &walk,
     80							     cipher);
     81		err = skcipher_walk_done(&walk, nbytes);
     82	}
     83
     84	return err;
     85}
     86
     87static int crypto_pcbc_decrypt_segment(struct skcipher_request *req,
     88				       struct skcipher_walk *walk,
     89				       struct crypto_cipher *tfm)
     90{
     91	int bsize = crypto_cipher_blocksize(tfm);
     92	unsigned int nbytes = walk->nbytes;
     93	u8 *src = walk->src.virt.addr;
     94	u8 *dst = walk->dst.virt.addr;
     95	u8 * const iv = walk->iv;
     96
     97	do {
     98		crypto_cipher_decrypt_one(tfm, dst, src);
     99		crypto_xor(dst, iv, bsize);
    100		crypto_xor_cpy(iv, dst, src, bsize);
    101
    102		src += bsize;
    103		dst += bsize;
    104	} while ((nbytes -= bsize) >= bsize);
    105
    106	return nbytes;
    107}
    108
    109static int crypto_pcbc_decrypt_inplace(struct skcipher_request *req,
    110				       struct skcipher_walk *walk,
    111				       struct crypto_cipher *tfm)
    112{
    113	int bsize = crypto_cipher_blocksize(tfm);
    114	unsigned int nbytes = walk->nbytes;
    115	u8 *src = walk->src.virt.addr;
    116	u8 * const iv = walk->iv;
    117	u8 tmpbuf[MAX_CIPHER_BLOCKSIZE] __aligned(__alignof__(u32));
    118
    119	do {
    120		memcpy(tmpbuf, src, bsize);
    121		crypto_cipher_decrypt_one(tfm, src, src);
    122		crypto_xor(src, iv, bsize);
    123		crypto_xor_cpy(iv, src, tmpbuf, bsize);
    124
    125		src += bsize;
    126	} while ((nbytes -= bsize) >= bsize);
    127
    128	return nbytes;
    129}
    130
    131static int crypto_pcbc_decrypt(struct skcipher_request *req)
    132{
    133	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
    134	struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);
    135	struct skcipher_walk walk;
    136	unsigned int nbytes;
    137	int err;
    138
    139	err = skcipher_walk_virt(&walk, req, false);
    140
    141	while ((nbytes = walk.nbytes)) {
    142		if (walk.src.virt.addr == walk.dst.virt.addr)
    143			nbytes = crypto_pcbc_decrypt_inplace(req, &walk,
    144							     cipher);
    145		else
    146			nbytes = crypto_pcbc_decrypt_segment(req, &walk,
    147							     cipher);
    148		err = skcipher_walk_done(&walk, nbytes);
    149	}
    150
    151	return err;
    152}
    153
    154static int crypto_pcbc_create(struct crypto_template *tmpl, struct rtattr **tb)
    155{
    156	struct skcipher_instance *inst;
    157	int err;
    158
    159	inst = skcipher_alloc_instance_simple(tmpl, tb);
    160	if (IS_ERR(inst))
    161		return PTR_ERR(inst);
    162
    163	inst->alg.encrypt = crypto_pcbc_encrypt;
    164	inst->alg.decrypt = crypto_pcbc_decrypt;
    165
    166	err = skcipher_register_instance(tmpl, inst);
    167	if (err)
    168		inst->free(inst);
    169
    170	return err;
    171}
    172
    173static struct crypto_template crypto_pcbc_tmpl = {
    174	.name = "pcbc",
    175	.create = crypto_pcbc_create,
    176	.module = THIS_MODULE,
    177};
    178
    179static int __init crypto_pcbc_module_init(void)
    180{
    181	return crypto_register_template(&crypto_pcbc_tmpl);
    182}
    183
    184static void __exit crypto_pcbc_module_exit(void)
    185{
    186	crypto_unregister_template(&crypto_pcbc_tmpl);
    187}
    188
    189subsys_initcall(crypto_pcbc_module_init);
    190module_exit(crypto_pcbc_module_exit);
    191
    192MODULE_LICENSE("GPL");
    193MODULE_DESCRIPTION("PCBC block cipher mode of operation");
    194MODULE_ALIAS_CRYPTO("pcbc");
    195MODULE_IMPORT_NS(CRYPTO_INTERNAL);