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

camellia_glue.c (8255B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Glue code for CAMELLIA encryption optimized for sparc64 crypto opcodes.
      3 *
      4 * Copyright (C) 2012 David S. Miller <davem@davemloft.net>
      5 */
      6
      7#define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
      8
      9#include <linux/crypto.h>
     10#include <linux/init.h>
     11#include <linux/module.h>
     12#include <linux/mm.h>
     13#include <linux/types.h>
     14#include <crypto/algapi.h>
     15#include <crypto/internal/skcipher.h>
     16
     17#include <asm/fpumacro.h>
     18#include <asm/pstate.h>
     19#include <asm/elf.h>
     20
     21#include "opcodes.h"
     22
     23#define CAMELLIA_MIN_KEY_SIZE        16
     24#define CAMELLIA_MAX_KEY_SIZE        32
     25#define CAMELLIA_BLOCK_SIZE          16
     26#define CAMELLIA_TABLE_BYTE_LEN     272
     27
     28struct camellia_sparc64_ctx {
     29	u64 encrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)];
     30	u64 decrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)];
     31	int key_len;
     32};
     33
     34extern void camellia_sparc64_key_expand(const u32 *in_key, u64 *encrypt_key,
     35					unsigned int key_len, u64 *decrypt_key);
     36
     37static int camellia_set_key(struct crypto_tfm *tfm, const u8 *_in_key,
     38			    unsigned int key_len)
     39{
     40	struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
     41	const u32 *in_key = (const u32 *) _in_key;
     42
     43	if (key_len != 16 && key_len != 24 && key_len != 32)
     44		return -EINVAL;
     45
     46	ctx->key_len = key_len;
     47
     48	camellia_sparc64_key_expand(in_key, &ctx->encrypt_key[0],
     49				    key_len, &ctx->decrypt_key[0]);
     50	return 0;
     51}
     52
     53static int camellia_set_key_skcipher(struct crypto_skcipher *tfm,
     54				     const u8 *in_key, unsigned int key_len)
     55{
     56	return camellia_set_key(crypto_skcipher_tfm(tfm), in_key, key_len);
     57}
     58
     59extern void camellia_sparc64_crypt(const u64 *key, const u32 *input,
     60				   u32 *output, unsigned int key_len);
     61
     62static void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
     63{
     64	struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
     65
     66	camellia_sparc64_crypt(&ctx->encrypt_key[0],
     67			       (const u32 *) src,
     68			       (u32 *) dst, ctx->key_len);
     69}
     70
     71static void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
     72{
     73	struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm);
     74
     75	camellia_sparc64_crypt(&ctx->decrypt_key[0],
     76			       (const u32 *) src,
     77			       (u32 *) dst, ctx->key_len);
     78}
     79
     80extern void camellia_sparc64_load_keys(const u64 *key, unsigned int key_len);
     81
     82typedef void ecb_crypt_op(const u64 *input, u64 *output, unsigned int len,
     83			  const u64 *key);
     84
     85extern ecb_crypt_op camellia_sparc64_ecb_crypt_3_grand_rounds;
     86extern ecb_crypt_op camellia_sparc64_ecb_crypt_4_grand_rounds;
     87
     88static int __ecb_crypt(struct skcipher_request *req, bool encrypt)
     89{
     90	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
     91	const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
     92	struct skcipher_walk walk;
     93	ecb_crypt_op *op;
     94	const u64 *key;
     95	unsigned int nbytes;
     96	int err;
     97
     98	op = camellia_sparc64_ecb_crypt_3_grand_rounds;
     99	if (ctx->key_len != 16)
    100		op = camellia_sparc64_ecb_crypt_4_grand_rounds;
    101
    102	err = skcipher_walk_virt(&walk, req, true);
    103	if (err)
    104		return err;
    105
    106	if (encrypt)
    107		key = &ctx->encrypt_key[0];
    108	else
    109		key = &ctx->decrypt_key[0];
    110	camellia_sparc64_load_keys(key, ctx->key_len);
    111	while ((nbytes = walk.nbytes) != 0) {
    112		op(walk.src.virt.addr, walk.dst.virt.addr,
    113		   round_down(nbytes, CAMELLIA_BLOCK_SIZE), key);
    114		err = skcipher_walk_done(&walk, nbytes % CAMELLIA_BLOCK_SIZE);
    115	}
    116	fprs_write(0);
    117	return err;
    118}
    119
    120static int ecb_encrypt(struct skcipher_request *req)
    121{
    122	return __ecb_crypt(req, true);
    123}
    124
    125static int ecb_decrypt(struct skcipher_request *req)
    126{
    127	return __ecb_crypt(req, false);
    128}
    129
    130typedef void cbc_crypt_op(const u64 *input, u64 *output, unsigned int len,
    131			  const u64 *key, u64 *iv);
    132
    133extern cbc_crypt_op camellia_sparc64_cbc_encrypt_3_grand_rounds;
    134extern cbc_crypt_op camellia_sparc64_cbc_encrypt_4_grand_rounds;
    135extern cbc_crypt_op camellia_sparc64_cbc_decrypt_3_grand_rounds;
    136extern cbc_crypt_op camellia_sparc64_cbc_decrypt_4_grand_rounds;
    137
    138static int cbc_encrypt(struct skcipher_request *req)
    139{
    140	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
    141	const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
    142	struct skcipher_walk walk;
    143	cbc_crypt_op *op;
    144	const u64 *key;
    145	unsigned int nbytes;
    146	int err;
    147
    148	op = camellia_sparc64_cbc_encrypt_3_grand_rounds;
    149	if (ctx->key_len != 16)
    150		op = camellia_sparc64_cbc_encrypt_4_grand_rounds;
    151
    152	err = skcipher_walk_virt(&walk, req, true);
    153	if (err)
    154		return err;
    155
    156	key = &ctx->encrypt_key[0];
    157	camellia_sparc64_load_keys(key, ctx->key_len);
    158	while ((nbytes = walk.nbytes) != 0) {
    159		op(walk.src.virt.addr, walk.dst.virt.addr,
    160		   round_down(nbytes, CAMELLIA_BLOCK_SIZE), key, walk.iv);
    161		err = skcipher_walk_done(&walk, nbytes % CAMELLIA_BLOCK_SIZE);
    162	}
    163	fprs_write(0);
    164	return err;
    165}
    166
    167static int cbc_decrypt(struct skcipher_request *req)
    168{
    169	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
    170	const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm);
    171	struct skcipher_walk walk;
    172	cbc_crypt_op *op;
    173	const u64 *key;
    174	unsigned int nbytes;
    175	int err;
    176
    177	op = camellia_sparc64_cbc_decrypt_3_grand_rounds;
    178	if (ctx->key_len != 16)
    179		op = camellia_sparc64_cbc_decrypt_4_grand_rounds;
    180
    181	err = skcipher_walk_virt(&walk, req, true);
    182	if (err)
    183		return err;
    184
    185	key = &ctx->decrypt_key[0];
    186	camellia_sparc64_load_keys(key, ctx->key_len);
    187	while ((nbytes = walk.nbytes) != 0) {
    188		op(walk.src.virt.addr, walk.dst.virt.addr,
    189		   round_down(nbytes, CAMELLIA_BLOCK_SIZE), key, walk.iv);
    190		err = skcipher_walk_done(&walk, nbytes % CAMELLIA_BLOCK_SIZE);
    191	}
    192	fprs_write(0);
    193	return err;
    194}
    195
    196static struct crypto_alg cipher_alg = {
    197	.cra_name		= "camellia",
    198	.cra_driver_name	= "camellia-sparc64",
    199	.cra_priority		= SPARC_CR_OPCODE_PRIORITY,
    200	.cra_flags		= CRYPTO_ALG_TYPE_CIPHER,
    201	.cra_blocksize		= CAMELLIA_BLOCK_SIZE,
    202	.cra_ctxsize		= sizeof(struct camellia_sparc64_ctx),
    203	.cra_alignmask		= 3,
    204	.cra_module		= THIS_MODULE,
    205	.cra_u	= {
    206		.cipher	= {
    207			.cia_min_keysize	= CAMELLIA_MIN_KEY_SIZE,
    208			.cia_max_keysize	= CAMELLIA_MAX_KEY_SIZE,
    209			.cia_setkey		= camellia_set_key,
    210			.cia_encrypt		= camellia_encrypt,
    211			.cia_decrypt		= camellia_decrypt
    212		}
    213	}
    214};
    215
    216static struct skcipher_alg skcipher_algs[] = {
    217	{
    218		.base.cra_name		= "ecb(camellia)",
    219		.base.cra_driver_name	= "ecb-camellia-sparc64",
    220		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
    221		.base.cra_blocksize	= CAMELLIA_BLOCK_SIZE,
    222		.base.cra_ctxsize	= sizeof(struct camellia_sparc64_ctx),
    223		.base.cra_alignmask	= 7,
    224		.base.cra_module	= THIS_MODULE,
    225		.min_keysize		= CAMELLIA_MIN_KEY_SIZE,
    226		.max_keysize		= CAMELLIA_MAX_KEY_SIZE,
    227		.setkey			= camellia_set_key_skcipher,
    228		.encrypt		= ecb_encrypt,
    229		.decrypt		= ecb_decrypt,
    230	}, {
    231		.base.cra_name		= "cbc(camellia)",
    232		.base.cra_driver_name	= "cbc-camellia-sparc64",
    233		.base.cra_priority	= SPARC_CR_OPCODE_PRIORITY,
    234		.base.cra_blocksize	= CAMELLIA_BLOCK_SIZE,
    235		.base.cra_ctxsize	= sizeof(struct camellia_sparc64_ctx),
    236		.base.cra_alignmask	= 7,
    237		.base.cra_module	= THIS_MODULE,
    238		.min_keysize		= CAMELLIA_MIN_KEY_SIZE,
    239		.max_keysize		= CAMELLIA_MAX_KEY_SIZE,
    240		.ivsize			= CAMELLIA_BLOCK_SIZE,
    241		.setkey			= camellia_set_key_skcipher,
    242		.encrypt		= cbc_encrypt,
    243		.decrypt		= cbc_decrypt,
    244	}
    245};
    246
    247static bool __init sparc64_has_camellia_opcode(void)
    248{
    249	unsigned long cfr;
    250
    251	if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO))
    252		return false;
    253
    254	__asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr));
    255	if (!(cfr & CFR_CAMELLIA))
    256		return false;
    257
    258	return true;
    259}
    260
    261static int __init camellia_sparc64_mod_init(void)
    262{
    263	int err;
    264
    265	if (!sparc64_has_camellia_opcode()) {
    266		pr_info("sparc64 camellia opcodes not available.\n");
    267		return -ENODEV;
    268	}
    269	pr_info("Using sparc64 camellia opcodes optimized CAMELLIA implementation\n");
    270	err = crypto_register_alg(&cipher_alg);
    271	if (err)
    272		return err;
    273	err = crypto_register_skciphers(skcipher_algs,
    274					ARRAY_SIZE(skcipher_algs));
    275	if (err)
    276		crypto_unregister_alg(&cipher_alg);
    277	return err;
    278}
    279
    280static void __exit camellia_sparc64_mod_fini(void)
    281{
    282	crypto_unregister_alg(&cipher_alg);
    283	crypto_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs));
    284}
    285
    286module_init(camellia_sparc64_mod_init);
    287module_exit(camellia_sparc64_mod_fini);
    288
    289MODULE_LICENSE("GPL");
    290MODULE_DESCRIPTION("Camellia Cipher Algorithm, sparc64 camellia opcode accelerated");
    291
    292MODULE_ALIAS_CRYPTO("camellia");
    293
    294#include "crop_devid.c"