mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
100 lines
2.5 KiB
100 lines
2.5 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
/* |
|
* s390 ChaCha stream cipher. |
|
* |
|
* Copyright IBM Corp. 2021 |
|
*/ |
|
|
|
#define KMSG_COMPONENT "chacha_s390" |
|
#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt |
|
|
|
#include <crypto/internal/chacha.h> |
|
#include <crypto/internal/skcipher.h> |
|
#include <crypto/algapi.h> |
|
#include <linux/cpufeature.h> |
|
#include <linux/kernel.h> |
|
#include <linux/module.h> |
|
#include <linux/sizes.h> |
|
#include <asm/fpu/api.h> |
|
#include "chacha-s390.h" |
|
|
|
static void chacha20_crypt_s390(u32 *state, u8 *dst, const u8 *src, |
|
unsigned int nbytes, const u32 *key, |
|
u32 *counter) |
|
{ |
|
struct kernel_fpu vxstate; |
|
|
|
kernel_fpu_begin(&vxstate, KERNEL_VXR); |
|
chacha20_vx(dst, src, nbytes, key, counter); |
|
kernel_fpu_end(&vxstate, KERNEL_VXR); |
|
|
|
*counter += round_up(nbytes, CHACHA_BLOCK_SIZE) / CHACHA_BLOCK_SIZE; |
|
} |
|
|
|
static int chacha20_s390(struct skcipher_request *req) |
|
{ |
|
struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); |
|
struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); |
|
u32 state[CHACHA_STATE_WORDS] __aligned(16); |
|
struct skcipher_walk walk; |
|
unsigned int nbytes; |
|
int rc; |
|
|
|
rc = skcipher_walk_virt(&walk, req, false); |
|
chacha_init_generic(state, ctx->key, req->iv); |
|
|
|
while (walk.nbytes > 0) { |
|
nbytes = walk.nbytes; |
|
if (nbytes < walk.total) |
|
nbytes = round_down(nbytes, walk.stride); |
|
|
|
if (nbytes <= CHACHA_BLOCK_SIZE) { |
|
chacha_crypt_generic(state, walk.dst.virt.addr, |
|
walk.src.virt.addr, nbytes, |
|
ctx->nrounds); |
|
} else { |
|
chacha20_crypt_s390(state, walk.dst.virt.addr, |
|
walk.src.virt.addr, nbytes, |
|
&state[4], &state[12]); |
|
} |
|
rc = skcipher_walk_done(&walk, walk.nbytes - nbytes); |
|
} |
|
return rc; |
|
} |
|
|
|
static struct skcipher_alg chacha_algs[] = { |
|
{ |
|
.base.cra_name = "chacha20", |
|
.base.cra_driver_name = "chacha20-s390", |
|
.base.cra_priority = 900, |
|
.base.cra_blocksize = 1, |
|
.base.cra_ctxsize = sizeof(struct chacha_ctx), |
|
.base.cra_module = THIS_MODULE, |
|
|
|
.min_keysize = CHACHA_KEY_SIZE, |
|
.max_keysize = CHACHA_KEY_SIZE, |
|
.ivsize = CHACHA_IV_SIZE, |
|
.chunksize = CHACHA_BLOCK_SIZE, |
|
.setkey = chacha20_setkey, |
|
.encrypt = chacha20_s390, |
|
.decrypt = chacha20_s390, |
|
} |
|
}; |
|
|
|
static int __init chacha_mod_init(void) |
|
{ |
|
return crypto_register_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs)); |
|
} |
|
|
|
static void __exit chacha_mod_fini(void) |
|
{ |
|
crypto_unregister_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs)); |
|
} |
|
|
|
module_cpu_feature_match(VXRS, chacha_mod_init); |
|
module_exit(chacha_mod_fini); |
|
|
|
MODULE_DESCRIPTION("ChaCha20 stream cipher"); |
|
MODULE_LICENSE("GPL v2"); |
|
|
|
MODULE_ALIAS_CRYPTO("chacha20");
|
|
|