Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * s390 ChaCha stream cipher.
0004  *
0005  * Copyright IBM Corp. 2021
0006  */
0007 
0008 #define KMSG_COMPONENT "chacha_s390"
0009 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0010 
0011 #include <crypto/internal/chacha.h>
0012 #include <crypto/internal/skcipher.h>
0013 #include <crypto/algapi.h>
0014 #include <linux/cpufeature.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/sizes.h>
0018 #include <asm/fpu/api.h>
0019 #include "chacha-s390.h"
0020 
0021 static void chacha20_crypt_s390(u32 *state, u8 *dst, const u8 *src,
0022                 unsigned int nbytes, const u32 *key,
0023                 u32 *counter)
0024 {
0025     struct kernel_fpu vxstate;
0026 
0027     kernel_fpu_begin(&vxstate, KERNEL_VXR);
0028     chacha20_vx(dst, src, nbytes, key, counter);
0029     kernel_fpu_end(&vxstate, KERNEL_VXR);
0030 
0031     *counter += round_up(nbytes, CHACHA_BLOCK_SIZE) / CHACHA_BLOCK_SIZE;
0032 }
0033 
0034 static int chacha20_s390(struct skcipher_request *req)
0035 {
0036     struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
0037     struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm);
0038     u32 state[CHACHA_STATE_WORDS] __aligned(16);
0039     struct skcipher_walk walk;
0040     unsigned int nbytes;
0041     int rc;
0042 
0043     rc = skcipher_walk_virt(&walk, req, false);
0044     chacha_init_generic(state, ctx->key, req->iv);
0045 
0046     while (walk.nbytes > 0) {
0047         nbytes = walk.nbytes;
0048         if (nbytes < walk.total)
0049             nbytes = round_down(nbytes, walk.stride);
0050 
0051         if (nbytes <= CHACHA_BLOCK_SIZE) {
0052             chacha_crypt_generic(state, walk.dst.virt.addr,
0053                          walk.src.virt.addr, nbytes,
0054                          ctx->nrounds);
0055         } else {
0056             chacha20_crypt_s390(state, walk.dst.virt.addr,
0057                         walk.src.virt.addr, nbytes,
0058                         &state[4], &state[12]);
0059         }
0060         rc = skcipher_walk_done(&walk, walk.nbytes - nbytes);
0061     }
0062     return rc;
0063 }
0064 
0065 void hchacha_block_arch(const u32 *state, u32 *stream, int nrounds)
0066 {
0067     /* TODO: implement hchacha_block_arch() in assembly */
0068     hchacha_block_generic(state, stream, nrounds);
0069 }
0070 EXPORT_SYMBOL(hchacha_block_arch);
0071 
0072 void chacha_init_arch(u32 *state, const u32 *key, const u8 *iv)
0073 {
0074     chacha_init_generic(state, key, iv);
0075 }
0076 EXPORT_SYMBOL(chacha_init_arch);
0077 
0078 void chacha_crypt_arch(u32 *state, u8 *dst, const u8 *src,
0079                unsigned int bytes, int nrounds)
0080 {
0081     /* s390 chacha20 implementation has 20 rounds hard-coded,
0082      * it cannot handle a block of data or less, but otherwise
0083      * it can handle data of arbitrary size
0084      */
0085     if (bytes <= CHACHA_BLOCK_SIZE || nrounds != 20)
0086         chacha_crypt_generic(state, dst, src, bytes, nrounds);
0087     else
0088         chacha20_crypt_s390(state, dst, src, bytes,
0089                     &state[4], &state[12]);
0090 }
0091 EXPORT_SYMBOL(chacha_crypt_arch);
0092 
0093 static struct skcipher_alg chacha_algs[] = {
0094     {
0095         .base.cra_name      = "chacha20",
0096         .base.cra_driver_name   = "chacha20-s390",
0097         .base.cra_priority  = 900,
0098         .base.cra_blocksize = 1,
0099         .base.cra_ctxsize   = sizeof(struct chacha_ctx),
0100         .base.cra_module    = THIS_MODULE,
0101 
0102         .min_keysize        = CHACHA_KEY_SIZE,
0103         .max_keysize        = CHACHA_KEY_SIZE,
0104         .ivsize         = CHACHA_IV_SIZE,
0105         .chunksize      = CHACHA_BLOCK_SIZE,
0106         .setkey         = chacha20_setkey,
0107         .encrypt        = chacha20_s390,
0108         .decrypt        = chacha20_s390,
0109     }
0110 };
0111 
0112 static int __init chacha_mod_init(void)
0113 {
0114     return IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER) ?
0115         crypto_register_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs)) : 0;
0116 }
0117 
0118 static void __exit chacha_mod_fini(void)
0119 {
0120     if (IS_REACHABLE(CONFIG_CRYPTO_SKCIPHER))
0121         crypto_unregister_skciphers(chacha_algs, ARRAY_SIZE(chacha_algs));
0122 }
0123 
0124 module_cpu_feature_match(S390_CPU_FEATURE_VXRS, chacha_mod_init);
0125 module_exit(chacha_mod_fini);
0126 
0127 MODULE_DESCRIPTION("ChaCha20 stream cipher");
0128 MODULE_LICENSE("GPL v2");
0129 
0130 MODULE_ALIAS_CRYPTO("chacha20");