1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * ChaCha20 using the RISC-V vector crypto extensions 4 * 5 * Copyright (C) 2023 SiFive, Inc. 6 * Author: Jerry Shih <jerry.shih@sifive.com> 7 */ 8 9 #include <asm/simd.h> 10 #include <asm/vector.h> 11 #include <crypto/internal/chacha.h> 12 #include <crypto/internal/skcipher.h> 13 #include <linux/linkage.h> 14 #include <linux/module.h> 15 16 asmlinkage void chacha20_zvkb(const u32 key[8], const u8 *in, u8 *out, 17 size_t len, const u32 iv[4]); 18 19 static int riscv64_chacha20_crypt(struct skcipher_request *req) 20 { 21 u32 iv[CHACHA_IV_SIZE / sizeof(u32)]; 22 u8 block_buffer[CHACHA_BLOCK_SIZE]; 23 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 24 const struct chacha_ctx *ctx = crypto_skcipher_ctx(tfm); 25 struct skcipher_walk walk; 26 unsigned int nbytes; 27 unsigned int tail_bytes; 28 int err; 29 30 iv[0] = get_unaligned_le32(req->iv); 31 iv[1] = get_unaligned_le32(req->iv + 4); 32 iv[2] = get_unaligned_le32(req->iv + 8); 33 iv[3] = get_unaligned_le32(req->iv + 12); 34 35 err = skcipher_walk_virt(&walk, req, false); 36 while (walk.nbytes) { 37 nbytes = walk.nbytes & ~(CHACHA_BLOCK_SIZE - 1); 38 tail_bytes = walk.nbytes & (CHACHA_BLOCK_SIZE - 1); 39 kernel_vector_begin(); 40 if (nbytes) { 41 chacha20_zvkb(ctx->key, walk.src.virt.addr, 42 walk.dst.virt.addr, nbytes, iv); 43 iv[0] += nbytes / CHACHA_BLOCK_SIZE; 44 } 45 if (walk.nbytes == walk.total && tail_bytes > 0) { 46 memcpy(block_buffer, walk.src.virt.addr + nbytes, 47 tail_bytes); 48 chacha20_zvkb(ctx->key, block_buffer, block_buffer, 49 CHACHA_BLOCK_SIZE, iv); 50 memcpy(walk.dst.virt.addr + nbytes, block_buffer, 51 tail_bytes); 52 tail_bytes = 0; 53 } 54 kernel_vector_end(); 55 56 err = skcipher_walk_done(&walk, tail_bytes); 57 } 58 59 return err; 60 } 61 62 static struct skcipher_alg riscv64_chacha_alg = { 63 .setkey = chacha20_setkey, 64 .encrypt = riscv64_chacha20_crypt, 65 .decrypt = riscv64_chacha20_crypt, 66 .min_keysize = CHACHA_KEY_SIZE, 67 .max_keysize = CHACHA_KEY_SIZE, 68 .ivsize = CHACHA_IV_SIZE, 69 .chunksize = CHACHA_BLOCK_SIZE, 70 .walksize = 4 * CHACHA_BLOCK_SIZE, 71 .base = { 72 .cra_blocksize = 1, 73 .cra_ctxsize = sizeof(struct chacha_ctx), 74 .cra_priority = 300, 75 .cra_name = "chacha20", 76 .cra_driver_name = "chacha20-riscv64-zvkb", 77 .cra_module = THIS_MODULE, 78 }, 79 }; 80 81 static int __init riscv64_chacha_mod_init(void) 82 { 83 if (riscv_isa_extension_available(NULL, ZVKB) && 84 riscv_vector_vlen() >= 128) 85 return crypto_register_skcipher(&riscv64_chacha_alg); 86 87 return -ENODEV; 88 } 89 90 static void __exit riscv64_chacha_mod_exit(void) 91 { 92 crypto_unregister_skcipher(&riscv64_chacha_alg); 93 } 94 95 module_init(riscv64_chacha_mod_init); 96 module_exit(riscv64_chacha_mod_exit); 97 98 MODULE_DESCRIPTION("ChaCha20 (RISC-V accelerated)"); 99 MODULE_AUTHOR("Jerry Shih <jerry.shih@sifive.com>"); 100 MODULE_LICENSE("GPL"); 101 MODULE_ALIAS_CRYPTO("chacha20"); 102