162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* Glue code for CAMELLIA encryption optimized for sparc64 crypto opcodes. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2012 David S. Miller <davem@davemloft.net> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/crypto.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/mm.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <crypto/algapi.h> 1562306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <asm/fpumacro.h> 1862306a36Sopenharmony_ci#include <asm/pstate.h> 1962306a36Sopenharmony_ci#include <asm/elf.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "opcodes.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define CAMELLIA_MIN_KEY_SIZE 16 2462306a36Sopenharmony_ci#define CAMELLIA_MAX_KEY_SIZE 32 2562306a36Sopenharmony_ci#define CAMELLIA_BLOCK_SIZE 16 2662306a36Sopenharmony_ci#define CAMELLIA_TABLE_BYTE_LEN 272 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistruct camellia_sparc64_ctx { 2962306a36Sopenharmony_ci u64 encrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)]; 3062306a36Sopenharmony_ci u64 decrypt_key[CAMELLIA_TABLE_BYTE_LEN / sizeof(u64)]; 3162306a36Sopenharmony_ci int key_len; 3262306a36Sopenharmony_ci}; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ciextern void camellia_sparc64_key_expand(const u32 *in_key, u64 *encrypt_key, 3562306a36Sopenharmony_ci unsigned int key_len, u64 *decrypt_key); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic int camellia_set_key(struct crypto_tfm *tfm, const u8 *_in_key, 3862306a36Sopenharmony_ci unsigned int key_len) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); 4162306a36Sopenharmony_ci const u32 *in_key = (const u32 *) _in_key; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (key_len != 16 && key_len != 24 && key_len != 32) 4462306a36Sopenharmony_ci return -EINVAL; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci ctx->key_len = key_len; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci camellia_sparc64_key_expand(in_key, &ctx->encrypt_key[0], 4962306a36Sopenharmony_ci key_len, &ctx->decrypt_key[0]); 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int camellia_set_key_skcipher(struct crypto_skcipher *tfm, 5462306a36Sopenharmony_ci const u8 *in_key, unsigned int key_len) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci return camellia_set_key(crypto_skcipher_tfm(tfm), in_key, key_len); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciextern void camellia_sparc64_crypt(const u64 *key, const u32 *input, 6062306a36Sopenharmony_ci u32 *output, unsigned int key_len); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void camellia_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci camellia_sparc64_crypt(&ctx->encrypt_key[0], 6762306a36Sopenharmony_ci (const u32 *) src, 6862306a36Sopenharmony_ci (u32 *) dst, ctx->key_len); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic void camellia_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci struct camellia_sparc64_ctx *ctx = crypto_tfm_ctx(tfm); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci camellia_sparc64_crypt(&ctx->decrypt_key[0], 7662306a36Sopenharmony_ci (const u32 *) src, 7762306a36Sopenharmony_ci (u32 *) dst, ctx->key_len); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciextern void camellia_sparc64_load_keys(const u64 *key, unsigned int key_len); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_citypedef void ecb_crypt_op(const u64 *input, u64 *output, unsigned int len, 8362306a36Sopenharmony_ci const u64 *key); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ciextern ecb_crypt_op camellia_sparc64_ecb_crypt_3_grand_rounds; 8662306a36Sopenharmony_ciextern ecb_crypt_op camellia_sparc64_ecb_crypt_4_grand_rounds; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic int __ecb_crypt(struct skcipher_request *req, bool encrypt) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 9162306a36Sopenharmony_ci const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm); 9262306a36Sopenharmony_ci struct skcipher_walk walk; 9362306a36Sopenharmony_ci ecb_crypt_op *op; 9462306a36Sopenharmony_ci const u64 *key; 9562306a36Sopenharmony_ci unsigned int nbytes; 9662306a36Sopenharmony_ci int err; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci op = camellia_sparc64_ecb_crypt_3_grand_rounds; 9962306a36Sopenharmony_ci if (ctx->key_len != 16) 10062306a36Sopenharmony_ci op = camellia_sparc64_ecb_crypt_4_grand_rounds; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, true); 10362306a36Sopenharmony_ci if (err) 10462306a36Sopenharmony_ci return err; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (encrypt) 10762306a36Sopenharmony_ci key = &ctx->encrypt_key[0]; 10862306a36Sopenharmony_ci else 10962306a36Sopenharmony_ci key = &ctx->decrypt_key[0]; 11062306a36Sopenharmony_ci camellia_sparc64_load_keys(key, ctx->key_len); 11162306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 11262306a36Sopenharmony_ci op(walk.src.virt.addr, walk.dst.virt.addr, 11362306a36Sopenharmony_ci round_down(nbytes, CAMELLIA_BLOCK_SIZE), key); 11462306a36Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes % CAMELLIA_BLOCK_SIZE); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci fprs_write(0); 11762306a36Sopenharmony_ci return err; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int ecb_encrypt(struct skcipher_request *req) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci return __ecb_crypt(req, true); 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic int ecb_decrypt(struct skcipher_request *req) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci return __ecb_crypt(req, false); 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_citypedef void cbc_crypt_op(const u64 *input, u64 *output, unsigned int len, 13162306a36Sopenharmony_ci const u64 *key, u64 *iv); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ciextern cbc_crypt_op camellia_sparc64_cbc_encrypt_3_grand_rounds; 13462306a36Sopenharmony_ciextern cbc_crypt_op camellia_sparc64_cbc_encrypt_4_grand_rounds; 13562306a36Sopenharmony_ciextern cbc_crypt_op camellia_sparc64_cbc_decrypt_3_grand_rounds; 13662306a36Sopenharmony_ciextern cbc_crypt_op camellia_sparc64_cbc_decrypt_4_grand_rounds; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int cbc_encrypt(struct skcipher_request *req) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 14162306a36Sopenharmony_ci const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm); 14262306a36Sopenharmony_ci struct skcipher_walk walk; 14362306a36Sopenharmony_ci cbc_crypt_op *op; 14462306a36Sopenharmony_ci const u64 *key; 14562306a36Sopenharmony_ci unsigned int nbytes; 14662306a36Sopenharmony_ci int err; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci op = camellia_sparc64_cbc_encrypt_3_grand_rounds; 14962306a36Sopenharmony_ci if (ctx->key_len != 16) 15062306a36Sopenharmony_ci op = camellia_sparc64_cbc_encrypt_4_grand_rounds; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, true); 15362306a36Sopenharmony_ci if (err) 15462306a36Sopenharmony_ci return err; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci key = &ctx->encrypt_key[0]; 15762306a36Sopenharmony_ci camellia_sparc64_load_keys(key, ctx->key_len); 15862306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 15962306a36Sopenharmony_ci op(walk.src.virt.addr, walk.dst.virt.addr, 16062306a36Sopenharmony_ci round_down(nbytes, CAMELLIA_BLOCK_SIZE), key, walk.iv); 16162306a36Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes % CAMELLIA_BLOCK_SIZE); 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci fprs_write(0); 16462306a36Sopenharmony_ci return err; 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_cistatic int cbc_decrypt(struct skcipher_request *req) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 17062306a36Sopenharmony_ci const struct camellia_sparc64_ctx *ctx = crypto_skcipher_ctx(tfm); 17162306a36Sopenharmony_ci struct skcipher_walk walk; 17262306a36Sopenharmony_ci cbc_crypt_op *op; 17362306a36Sopenharmony_ci const u64 *key; 17462306a36Sopenharmony_ci unsigned int nbytes; 17562306a36Sopenharmony_ci int err; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci op = camellia_sparc64_cbc_decrypt_3_grand_rounds; 17862306a36Sopenharmony_ci if (ctx->key_len != 16) 17962306a36Sopenharmony_ci op = camellia_sparc64_cbc_decrypt_4_grand_rounds; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci err = skcipher_walk_virt(&walk, req, true); 18262306a36Sopenharmony_ci if (err) 18362306a36Sopenharmony_ci return err; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci key = &ctx->decrypt_key[0]; 18662306a36Sopenharmony_ci camellia_sparc64_load_keys(key, ctx->key_len); 18762306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 18862306a36Sopenharmony_ci op(walk.src.virt.addr, walk.dst.virt.addr, 18962306a36Sopenharmony_ci round_down(nbytes, CAMELLIA_BLOCK_SIZE), key, walk.iv); 19062306a36Sopenharmony_ci err = skcipher_walk_done(&walk, nbytes % CAMELLIA_BLOCK_SIZE); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci fprs_write(0); 19362306a36Sopenharmony_ci return err; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic struct crypto_alg cipher_alg = { 19762306a36Sopenharmony_ci .cra_name = "camellia", 19862306a36Sopenharmony_ci .cra_driver_name = "camellia-sparc64", 19962306a36Sopenharmony_ci .cra_priority = SPARC_CR_OPCODE_PRIORITY, 20062306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 20162306a36Sopenharmony_ci .cra_blocksize = CAMELLIA_BLOCK_SIZE, 20262306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct camellia_sparc64_ctx), 20362306a36Sopenharmony_ci .cra_alignmask = 3, 20462306a36Sopenharmony_ci .cra_module = THIS_MODULE, 20562306a36Sopenharmony_ci .cra_u = { 20662306a36Sopenharmony_ci .cipher = { 20762306a36Sopenharmony_ci .cia_min_keysize = CAMELLIA_MIN_KEY_SIZE, 20862306a36Sopenharmony_ci .cia_max_keysize = CAMELLIA_MAX_KEY_SIZE, 20962306a36Sopenharmony_ci .cia_setkey = camellia_set_key, 21062306a36Sopenharmony_ci .cia_encrypt = camellia_encrypt, 21162306a36Sopenharmony_ci .cia_decrypt = camellia_decrypt 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic struct skcipher_alg skcipher_algs[] = { 21762306a36Sopenharmony_ci { 21862306a36Sopenharmony_ci .base.cra_name = "ecb(camellia)", 21962306a36Sopenharmony_ci .base.cra_driver_name = "ecb-camellia-sparc64", 22062306a36Sopenharmony_ci .base.cra_priority = SPARC_CR_OPCODE_PRIORITY, 22162306a36Sopenharmony_ci .base.cra_blocksize = CAMELLIA_BLOCK_SIZE, 22262306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct camellia_sparc64_ctx), 22362306a36Sopenharmony_ci .base.cra_alignmask = 7, 22462306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 22562306a36Sopenharmony_ci .min_keysize = CAMELLIA_MIN_KEY_SIZE, 22662306a36Sopenharmony_ci .max_keysize = CAMELLIA_MAX_KEY_SIZE, 22762306a36Sopenharmony_ci .setkey = camellia_set_key_skcipher, 22862306a36Sopenharmony_ci .encrypt = ecb_encrypt, 22962306a36Sopenharmony_ci .decrypt = ecb_decrypt, 23062306a36Sopenharmony_ci }, { 23162306a36Sopenharmony_ci .base.cra_name = "cbc(camellia)", 23262306a36Sopenharmony_ci .base.cra_driver_name = "cbc-camellia-sparc64", 23362306a36Sopenharmony_ci .base.cra_priority = SPARC_CR_OPCODE_PRIORITY, 23462306a36Sopenharmony_ci .base.cra_blocksize = CAMELLIA_BLOCK_SIZE, 23562306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct camellia_sparc64_ctx), 23662306a36Sopenharmony_ci .base.cra_alignmask = 7, 23762306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 23862306a36Sopenharmony_ci .min_keysize = CAMELLIA_MIN_KEY_SIZE, 23962306a36Sopenharmony_ci .max_keysize = CAMELLIA_MAX_KEY_SIZE, 24062306a36Sopenharmony_ci .ivsize = CAMELLIA_BLOCK_SIZE, 24162306a36Sopenharmony_ci .setkey = camellia_set_key_skcipher, 24262306a36Sopenharmony_ci .encrypt = cbc_encrypt, 24362306a36Sopenharmony_ci .decrypt = cbc_decrypt, 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci}; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic bool __init sparc64_has_camellia_opcode(void) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci unsigned long cfr; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci if (!(sparc64_elf_hwcap & HWCAP_SPARC_CRYPTO)) 25262306a36Sopenharmony_ci return false; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci __asm__ __volatile__("rd %%asr26, %0" : "=r" (cfr)); 25562306a36Sopenharmony_ci if (!(cfr & CFR_CAMELLIA)) 25662306a36Sopenharmony_ci return false; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return true; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_cistatic int __init camellia_sparc64_mod_init(void) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci int err; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (!sparc64_has_camellia_opcode()) { 26662306a36Sopenharmony_ci pr_info("sparc64 camellia opcodes not available.\n"); 26762306a36Sopenharmony_ci return -ENODEV; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci pr_info("Using sparc64 camellia opcodes optimized CAMELLIA implementation\n"); 27062306a36Sopenharmony_ci err = crypto_register_alg(&cipher_alg); 27162306a36Sopenharmony_ci if (err) 27262306a36Sopenharmony_ci return err; 27362306a36Sopenharmony_ci err = crypto_register_skciphers(skcipher_algs, 27462306a36Sopenharmony_ci ARRAY_SIZE(skcipher_algs)); 27562306a36Sopenharmony_ci if (err) 27662306a36Sopenharmony_ci crypto_unregister_alg(&cipher_alg); 27762306a36Sopenharmony_ci return err; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic void __exit camellia_sparc64_mod_fini(void) 28162306a36Sopenharmony_ci{ 28262306a36Sopenharmony_ci crypto_unregister_alg(&cipher_alg); 28362306a36Sopenharmony_ci crypto_unregister_skciphers(skcipher_algs, ARRAY_SIZE(skcipher_algs)); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cimodule_init(camellia_sparc64_mod_init); 28762306a36Sopenharmony_cimodule_exit(camellia_sparc64_mod_fini); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 29062306a36Sopenharmony_ciMODULE_DESCRIPTION("Camellia Cipher Algorithm, sparc64 camellia opcode accelerated"); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("camellia"); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci#include "crop_devid.c" 295