Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.13 126 lines 3.4 kB view raw
1/* 2 * ChaCha20 256-bit cipher algorithm, RFC7539, arm64 NEON functions 3 * 4 * Copyright (C) 2016 Linaro, Ltd. <ard.biesheuvel@linaro.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Based on: 11 * ChaCha20 256-bit cipher algorithm, RFC7539, SIMD glue code 12 * 13 * Copyright (C) 2015 Martin Willi 14 * 15 * This program is free software; you can redistribute it and/or modify 16 * it under the terms of the GNU General Public License as published by 17 * the Free Software Foundation; either version 2 of the License, or 18 * (at your option) any later version. 19 */ 20 21#include <crypto/algapi.h> 22#include <crypto/chacha20.h> 23#include <crypto/internal/skcipher.h> 24#include <linux/kernel.h> 25#include <linux/module.h> 26 27#include <asm/hwcap.h> 28#include <asm/neon.h> 29 30asmlinkage void chacha20_block_xor_neon(u32 *state, u8 *dst, const u8 *src); 31asmlinkage void chacha20_4block_xor_neon(u32 *state, u8 *dst, const u8 *src); 32 33static void chacha20_doneon(u32 *state, u8 *dst, const u8 *src, 34 unsigned int bytes) 35{ 36 u8 buf[CHACHA20_BLOCK_SIZE]; 37 38 while (bytes >= CHACHA20_BLOCK_SIZE * 4) { 39 chacha20_4block_xor_neon(state, dst, src); 40 bytes -= CHACHA20_BLOCK_SIZE * 4; 41 src += CHACHA20_BLOCK_SIZE * 4; 42 dst += CHACHA20_BLOCK_SIZE * 4; 43 state[12] += 4; 44 } 45 while (bytes >= CHACHA20_BLOCK_SIZE) { 46 chacha20_block_xor_neon(state, dst, src); 47 bytes -= CHACHA20_BLOCK_SIZE; 48 src += CHACHA20_BLOCK_SIZE; 49 dst += CHACHA20_BLOCK_SIZE; 50 state[12]++; 51 } 52 if (bytes) { 53 memcpy(buf, src, bytes); 54 chacha20_block_xor_neon(state, buf, buf); 55 memcpy(dst, buf, bytes); 56 } 57} 58 59static int chacha20_neon(struct skcipher_request *req) 60{ 61 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 62 struct chacha20_ctx *ctx = crypto_skcipher_ctx(tfm); 63 struct skcipher_walk walk; 64 u32 state[16]; 65 int err; 66 67 if (req->cryptlen <= CHACHA20_BLOCK_SIZE) 68 return crypto_chacha20_crypt(req); 69 70 err = skcipher_walk_virt(&walk, req, true); 71 72 crypto_chacha20_init(state, ctx, walk.iv); 73 74 kernel_neon_begin(); 75 while (walk.nbytes > 0) { 76 unsigned int nbytes = walk.nbytes; 77 78 if (nbytes < walk.total) 79 nbytes = round_down(nbytes, walk.stride); 80 81 chacha20_doneon(state, walk.dst.virt.addr, walk.src.virt.addr, 82 nbytes); 83 err = skcipher_walk_done(&walk, walk.nbytes - nbytes); 84 } 85 kernel_neon_end(); 86 87 return err; 88} 89 90static struct skcipher_alg alg = { 91 .base.cra_name = "chacha20", 92 .base.cra_driver_name = "chacha20-neon", 93 .base.cra_priority = 300, 94 .base.cra_blocksize = 1, 95 .base.cra_ctxsize = sizeof(struct chacha20_ctx), 96 .base.cra_module = THIS_MODULE, 97 98 .min_keysize = CHACHA20_KEY_SIZE, 99 .max_keysize = CHACHA20_KEY_SIZE, 100 .ivsize = CHACHA20_IV_SIZE, 101 .chunksize = CHACHA20_BLOCK_SIZE, 102 .walksize = 4 * CHACHA20_BLOCK_SIZE, 103 .setkey = crypto_chacha20_setkey, 104 .encrypt = chacha20_neon, 105 .decrypt = chacha20_neon, 106}; 107 108static int __init chacha20_simd_mod_init(void) 109{ 110 if (!(elf_hwcap & HWCAP_ASIMD)) 111 return -ENODEV; 112 113 return crypto_register_skcipher(&alg); 114} 115 116static void __exit chacha20_simd_mod_fini(void) 117{ 118 crypto_unregister_skcipher(&alg); 119} 120 121module_init(chacha20_simd_mod_init); 122module_exit(chacha20_simd_mod_fini); 123 124MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>"); 125MODULE_LICENSE("GPL v2"); 126MODULE_ALIAS_CRYPTO("chacha20");