18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * MIPS accelerated ChaCha and XChaCha stream ciphers, 48c2ecf20Sopenharmony_ci * including ChaCha20 (RFC7539) 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2019 Linaro, Ltd. <ard.biesheuvel@linaro.org> 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 108c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 118c2ecf20Sopenharmony_ci#include <crypto/internal/chacha.h> 128c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciasmlinkage void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src, 178c2ecf20Sopenharmony_ci unsigned int bytes, int nrounds); 188c2ecf20Sopenharmony_ciEXPORT_SYMBOL(chacha_crypt_arch); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ciasmlinkage void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds); 218c2ecf20Sopenharmony_ciEXPORT_SYMBOL(hchacha_block_arch); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_civoid chacha_init_arch(u32 *state, const u32 *key, const u8 *iv) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci chacha_init_generic(state, key, iv); 268c2ecf20Sopenharmony_ci} 278c2ecf20Sopenharmony_ciEXPORT_SYMBOL(chacha_init_arch); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic int chacha_mips_stream_xor(struct skcipher_request *req, 308c2ecf20Sopenharmony_ci const struct chacha_ctx *ctx, const u8 *iv) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct skcipher_walk walk; 338c2ecf20Sopenharmony_ci u32 state[16]; 348c2ecf20Sopenharmony_ci int err; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci err = skcipher_walk_virt(&walk, req, false); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci chacha_init_generic(state, ctx->key, iv); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci while (walk.nbytes > 0) { 418c2ecf20Sopenharmony_ci unsigned int nbytes = walk.nbytes; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (nbytes < walk.total) 448c2ecf20Sopenharmony_ci nbytes = round_down(nbytes, walk.stride); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci chacha_crypt(state, walk.dst.virt.addr, walk.src.virt.addr, 478c2ecf20Sopenharmony_ci nbytes, ctx->nrounds); 488c2ecf20Sopenharmony_ci err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci return err; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic int chacha_mips(struct skcipher_request *req) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 578c2ecf20Sopenharmony_ci struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return chacha_mips_stream_xor(req, ctx, req->iv); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int xchacha_mips(struct skcipher_request *req) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 658c2ecf20Sopenharmony_ci struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); 668c2ecf20Sopenharmony_ci struct chacha_ctx subctx; 678c2ecf20Sopenharmony_ci u32 state[16]; 688c2ecf20Sopenharmony_ci u8 real_iv[16]; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci chacha_init_generic(state, ctx->key, req->iv); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci hchacha_block(state, subctx.key, ctx->nrounds); 738c2ecf20Sopenharmony_ci subctx.nrounds = ctx->nrounds; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci memcpy(&real_iv[0], req->iv + 24, 8); 768c2ecf20Sopenharmony_ci memcpy(&real_iv[8], req->iv + 16, 8); 778c2ecf20Sopenharmony_ci return chacha_mips_stream_xor(req, &subctx, real_iv); 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic struct skcipher_alg algs[] = { 818c2ecf20Sopenharmony_ci { 828c2ecf20Sopenharmony_ci .base.cra_name = "chacha20", 838c2ecf20Sopenharmony_ci .base.cra_driver_name = "chacha20-mips", 848c2ecf20Sopenharmony_ci .base.cra_priority = 200, 858c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 868c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct chacha_ctx), 878c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci .min_keysize = CHACHA_KEY_SIZE, 908c2ecf20Sopenharmony_ci .max_keysize = CHACHA_KEY_SIZE, 918c2ecf20Sopenharmony_ci .ivsize = CHACHA_IV_SIZE, 928c2ecf20Sopenharmony_ci .chunksize = CHACHA_BLOCK_SIZE, 938c2ecf20Sopenharmony_ci .setkey = chacha20_setkey, 948c2ecf20Sopenharmony_ci .encrypt = chacha_mips, 958c2ecf20Sopenharmony_ci .decrypt = chacha_mips, 968c2ecf20Sopenharmony_ci }, { 978c2ecf20Sopenharmony_ci .base.cra_name = "xchacha20", 988c2ecf20Sopenharmony_ci .base.cra_driver_name = "xchacha20-mips", 998c2ecf20Sopenharmony_ci .base.cra_priority = 200, 1008c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 1018c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct chacha_ctx), 1028c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci .min_keysize = CHACHA_KEY_SIZE, 1058c2ecf20Sopenharmony_ci .max_keysize = CHACHA_KEY_SIZE, 1068c2ecf20Sopenharmony_ci .ivsize = XCHACHA_IV_SIZE, 1078c2ecf20Sopenharmony_ci .chunksize = CHACHA_BLOCK_SIZE, 1088c2ecf20Sopenharmony_ci .setkey = chacha20_setkey, 1098c2ecf20Sopenharmony_ci .encrypt = xchacha_mips, 1108c2ecf20Sopenharmony_ci .decrypt = xchacha_mips, 1118c2ecf20Sopenharmony_ci }, { 1128c2ecf20Sopenharmony_ci .base.cra_name = "xchacha12", 1138c2ecf20Sopenharmony_ci .base.cra_driver_name = "xchacha12-mips", 1148c2ecf20Sopenharmony_ci .base.cra_priority = 200, 1158c2ecf20Sopenharmony_ci .base.cra_blocksize = 1, 1168c2ecf20Sopenharmony_ci .base.cra_ctxsize = sizeof(struct chacha_ctx), 1178c2ecf20Sopenharmony_ci .base.cra_module = THIS_MODULE, 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci .min_keysize = CHACHA_KEY_SIZE, 1208c2ecf20Sopenharmony_ci .max_keysize = CHACHA_KEY_SIZE, 1218c2ecf20Sopenharmony_ci .ivsize = XCHACHA_IV_SIZE, 1228c2ecf20Sopenharmony_ci .chunksize = CHACHA_BLOCK_SIZE, 1238c2ecf20Sopenharmony_ci .setkey = chacha12_setkey, 1248c2ecf20Sopenharmony_ci .encrypt = xchacha_mips, 1258c2ecf20Sopenharmony_ci .decrypt = xchacha_mips, 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic int __init chacha_simd_mod_init(void) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci return IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) ? 1328c2ecf20Sopenharmony_ci crypto_register_skciphers(algs, ARRAY_SIZE(algs)) : 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic void __exit chacha_simd_mod_fini(void) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER)) 1388c2ecf20Sopenharmony_ci crypto_unregister_skciphers(algs, ARRAY_SIZE(algs)); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cimodule_init(chacha_simd_mod_init); 1428c2ecf20Sopenharmony_cimodule_exit(chacha_simd_mod_fini); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (MIPS accelerated)"); 1458c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); 1468c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1478c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("chacha20"); 1488c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("chacha20-mips"); 1498c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("xchacha20"); 1508c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("xchacha20-mips"); 1518c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("xchacha12"); 1528c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("xchacha12-mips"); 153