18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * The AEGIS-128 Authenticated-Encryption Algorithm 48c2ecf20Sopenharmony_ci * Glue for AES-NI + SSE2 implementation 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2017-2018 Ondrej Mosnacek <omosnacek@gmail.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2017-2018 Red Hat, Inc. All rights reserved. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 118c2ecf20Sopenharmony_ci#include <crypto/internal/simd.h> 128c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 138c2ecf20Sopenharmony_ci#include <crypto/scatterwalk.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <asm/fpu/api.h> 168c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define AEGIS128_BLOCK_ALIGN 16 198c2ecf20Sopenharmony_ci#define AEGIS128_BLOCK_SIZE 16 208c2ecf20Sopenharmony_ci#define AEGIS128_NONCE_SIZE 16 218c2ecf20Sopenharmony_ci#define AEGIS128_STATE_BLOCKS 5 228c2ecf20Sopenharmony_ci#define AEGIS128_KEY_SIZE 16 238c2ecf20Sopenharmony_ci#define AEGIS128_MIN_AUTH_SIZE 8 248c2ecf20Sopenharmony_ci#define AEGIS128_MAX_AUTH_SIZE 16 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciasmlinkage void crypto_aegis128_aesni_init(void *state, void *key, void *iv); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciasmlinkage void crypto_aegis128_aesni_ad( 298c2ecf20Sopenharmony_ci void *state, unsigned int length, const void *data); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciasmlinkage void crypto_aegis128_aesni_enc( 328c2ecf20Sopenharmony_ci void *state, unsigned int length, const void *src, void *dst); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ciasmlinkage void crypto_aegis128_aesni_dec( 358c2ecf20Sopenharmony_ci void *state, unsigned int length, const void *src, void *dst); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ciasmlinkage void crypto_aegis128_aesni_enc_tail( 388c2ecf20Sopenharmony_ci void *state, unsigned int length, const void *src, void *dst); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ciasmlinkage void crypto_aegis128_aesni_dec_tail( 418c2ecf20Sopenharmony_ci void *state, unsigned int length, const void *src, void *dst); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciasmlinkage void crypto_aegis128_aesni_final( 448c2ecf20Sopenharmony_ci void *state, void *tag_xor, unsigned int cryptlen, 458c2ecf20Sopenharmony_ci unsigned int assoclen); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct aegis_block { 488c2ecf20Sopenharmony_ci u8 bytes[AEGIS128_BLOCK_SIZE] __aligned(AEGIS128_BLOCK_ALIGN); 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct aegis_state { 528c2ecf20Sopenharmony_ci struct aegis_block blocks[AEGIS128_STATE_BLOCKS]; 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct aegis_ctx { 568c2ecf20Sopenharmony_ci struct aegis_block key; 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct aegis_crypt_ops { 608c2ecf20Sopenharmony_ci int (*skcipher_walk_init)(struct skcipher_walk *walk, 618c2ecf20Sopenharmony_ci struct aead_request *req, bool atomic); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci void (*crypt_blocks)(void *state, unsigned int length, const void *src, 648c2ecf20Sopenharmony_ci void *dst); 658c2ecf20Sopenharmony_ci void (*crypt_tail)(void *state, unsigned int length, const void *src, 668c2ecf20Sopenharmony_ci void *dst); 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void crypto_aegis128_aesni_process_ad( 708c2ecf20Sopenharmony_ci struct aegis_state *state, struct scatterlist *sg_src, 718c2ecf20Sopenharmony_ci unsigned int assoclen) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct scatter_walk walk; 748c2ecf20Sopenharmony_ci struct aegis_block buf; 758c2ecf20Sopenharmony_ci unsigned int pos = 0; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci scatterwalk_start(&walk, sg_src); 788c2ecf20Sopenharmony_ci while (assoclen != 0) { 798c2ecf20Sopenharmony_ci unsigned int size = scatterwalk_clamp(&walk, assoclen); 808c2ecf20Sopenharmony_ci unsigned int left = size; 818c2ecf20Sopenharmony_ci void *mapped = scatterwalk_map(&walk); 828c2ecf20Sopenharmony_ci const u8 *src = (const u8 *)mapped; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci if (pos + size >= AEGIS128_BLOCK_SIZE) { 858c2ecf20Sopenharmony_ci if (pos > 0) { 868c2ecf20Sopenharmony_ci unsigned int fill = AEGIS128_BLOCK_SIZE - pos; 878c2ecf20Sopenharmony_ci memcpy(buf.bytes + pos, src, fill); 888c2ecf20Sopenharmony_ci crypto_aegis128_aesni_ad(state, 898c2ecf20Sopenharmony_ci AEGIS128_BLOCK_SIZE, 908c2ecf20Sopenharmony_ci buf.bytes); 918c2ecf20Sopenharmony_ci pos = 0; 928c2ecf20Sopenharmony_ci left -= fill; 938c2ecf20Sopenharmony_ci src += fill; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci crypto_aegis128_aesni_ad(state, left, src); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci src += left & ~(AEGIS128_BLOCK_SIZE - 1); 998c2ecf20Sopenharmony_ci left &= AEGIS128_BLOCK_SIZE - 1; 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci memcpy(buf.bytes + pos, src, left); 1038c2ecf20Sopenharmony_ci pos += left; 1048c2ecf20Sopenharmony_ci assoclen -= size; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci scatterwalk_unmap(mapped); 1078c2ecf20Sopenharmony_ci scatterwalk_advance(&walk, size); 1088c2ecf20Sopenharmony_ci scatterwalk_done(&walk, 0, assoclen); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (pos > 0) { 1128c2ecf20Sopenharmony_ci memset(buf.bytes + pos, 0, AEGIS128_BLOCK_SIZE - pos); 1138c2ecf20Sopenharmony_ci crypto_aegis128_aesni_ad(state, AEGIS128_BLOCK_SIZE, buf.bytes); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic void crypto_aegis128_aesni_process_crypt( 1188c2ecf20Sopenharmony_ci struct aegis_state *state, struct skcipher_walk *walk, 1198c2ecf20Sopenharmony_ci const struct aegis_crypt_ops *ops) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci while (walk->nbytes >= AEGIS128_BLOCK_SIZE) { 1228c2ecf20Sopenharmony_ci ops->crypt_blocks(state, 1238c2ecf20Sopenharmony_ci round_down(walk->nbytes, AEGIS128_BLOCK_SIZE), 1248c2ecf20Sopenharmony_ci walk->src.virt.addr, walk->dst.virt.addr); 1258c2ecf20Sopenharmony_ci skcipher_walk_done(walk, walk->nbytes % AEGIS128_BLOCK_SIZE); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (walk->nbytes) { 1298c2ecf20Sopenharmony_ci ops->crypt_tail(state, walk->nbytes, walk->src.virt.addr, 1308c2ecf20Sopenharmony_ci walk->dst.virt.addr); 1318c2ecf20Sopenharmony_ci skcipher_walk_done(walk, 0); 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic struct aegis_ctx *crypto_aegis128_aesni_ctx(struct crypto_aead *aead) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci u8 *ctx = crypto_aead_ctx(aead); 1388c2ecf20Sopenharmony_ci ctx = PTR_ALIGN(ctx, __alignof__(struct aegis_ctx)); 1398c2ecf20Sopenharmony_ci return (void *)ctx; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int crypto_aegis128_aesni_setkey(struct crypto_aead *aead, const u8 *key, 1438c2ecf20Sopenharmony_ci unsigned int keylen) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct aegis_ctx *ctx = crypto_aegis128_aesni_ctx(aead); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (keylen != AEGIS128_KEY_SIZE) 1488c2ecf20Sopenharmony_ci return -EINVAL; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci memcpy(ctx->key.bytes, key, AEGIS128_KEY_SIZE); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int crypto_aegis128_aesni_setauthsize(struct crypto_aead *tfm, 1568c2ecf20Sopenharmony_ci unsigned int authsize) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci if (authsize > AEGIS128_MAX_AUTH_SIZE) 1598c2ecf20Sopenharmony_ci return -EINVAL; 1608c2ecf20Sopenharmony_ci if (authsize < AEGIS128_MIN_AUTH_SIZE) 1618c2ecf20Sopenharmony_ci return -EINVAL; 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic void crypto_aegis128_aesni_crypt(struct aead_request *req, 1668c2ecf20Sopenharmony_ci struct aegis_block *tag_xor, 1678c2ecf20Sopenharmony_ci unsigned int cryptlen, 1688c2ecf20Sopenharmony_ci const struct aegis_crypt_ops *ops) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 1718c2ecf20Sopenharmony_ci struct aegis_ctx *ctx = crypto_aegis128_aesni_ctx(tfm); 1728c2ecf20Sopenharmony_ci struct skcipher_walk walk; 1738c2ecf20Sopenharmony_ci struct aegis_state state; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci ops->skcipher_walk_init(&walk, req, true); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci kernel_fpu_begin(); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci crypto_aegis128_aesni_init(&state, ctx->key.bytes, req->iv); 1808c2ecf20Sopenharmony_ci crypto_aegis128_aesni_process_ad(&state, req->src, req->assoclen); 1818c2ecf20Sopenharmony_ci crypto_aegis128_aesni_process_crypt(&state, &walk, ops); 1828c2ecf20Sopenharmony_ci crypto_aegis128_aesni_final(&state, tag_xor, req->assoclen, cryptlen); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci kernel_fpu_end(); 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int crypto_aegis128_aesni_encrypt(struct aead_request *req) 1888c2ecf20Sopenharmony_ci{ 1898c2ecf20Sopenharmony_ci static const struct aegis_crypt_ops OPS = { 1908c2ecf20Sopenharmony_ci .skcipher_walk_init = skcipher_walk_aead_encrypt, 1918c2ecf20Sopenharmony_ci .crypt_blocks = crypto_aegis128_aesni_enc, 1928c2ecf20Sopenharmony_ci .crypt_tail = crypto_aegis128_aesni_enc_tail, 1938c2ecf20Sopenharmony_ci }; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 1968c2ecf20Sopenharmony_ci struct aegis_block tag = {}; 1978c2ecf20Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(tfm); 1988c2ecf20Sopenharmony_ci unsigned int cryptlen = req->cryptlen; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci crypto_aegis128_aesni_crypt(req, &tag, cryptlen, &OPS); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(tag.bytes, req->dst, 2038c2ecf20Sopenharmony_ci req->assoclen + cryptlen, authsize, 1); 2048c2ecf20Sopenharmony_ci return 0; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic int crypto_aegis128_aesni_decrypt(struct aead_request *req) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci static const struct aegis_block zeros = {}; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci static const struct aegis_crypt_ops OPS = { 2128c2ecf20Sopenharmony_ci .skcipher_walk_init = skcipher_walk_aead_decrypt, 2138c2ecf20Sopenharmony_ci .crypt_blocks = crypto_aegis128_aesni_dec, 2148c2ecf20Sopenharmony_ci .crypt_tail = crypto_aegis128_aesni_dec_tail, 2158c2ecf20Sopenharmony_ci }; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 2188c2ecf20Sopenharmony_ci struct aegis_block tag; 2198c2ecf20Sopenharmony_ci unsigned int authsize = crypto_aead_authsize(tfm); 2208c2ecf20Sopenharmony_ci unsigned int cryptlen = req->cryptlen - authsize; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci scatterwalk_map_and_copy(tag.bytes, req->src, 2238c2ecf20Sopenharmony_ci req->assoclen + cryptlen, authsize, 0); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci crypto_aegis128_aesni_crypt(req, &tag, cryptlen, &OPS); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci return crypto_memneq(tag.bytes, zeros.bytes, authsize) ? -EBADMSG : 0; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int crypto_aegis128_aesni_init_tfm(struct crypto_aead *aead) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic void crypto_aegis128_aesni_exit_tfm(struct crypto_aead *aead) 2368c2ecf20Sopenharmony_ci{ 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_cistatic struct aead_alg crypto_aegis128_aesni_alg = { 2408c2ecf20Sopenharmony_ci .setkey = crypto_aegis128_aesni_setkey, 2418c2ecf20Sopenharmony_ci .setauthsize = crypto_aegis128_aesni_setauthsize, 2428c2ecf20Sopenharmony_ci .encrypt = crypto_aegis128_aesni_encrypt, 2438c2ecf20Sopenharmony_ci .decrypt = crypto_aegis128_aesni_decrypt, 2448c2ecf20Sopenharmony_ci .init = crypto_aegis128_aesni_init_tfm, 2458c2ecf20Sopenharmony_ci .exit = crypto_aegis128_aesni_exit_tfm, 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci .ivsize = AEGIS128_NONCE_SIZE, 2488c2ecf20Sopenharmony_ci .maxauthsize = AEGIS128_MAX_AUTH_SIZE, 2498c2ecf20Sopenharmony_ci .chunksize = AEGIS128_BLOCK_SIZE, 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci .base = { 2528c2ecf20Sopenharmony_ci .cra_flags = CRYPTO_ALG_INTERNAL, 2538c2ecf20Sopenharmony_ci .cra_blocksize = 1, 2548c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct aegis_ctx) + 2558c2ecf20Sopenharmony_ci __alignof__(struct aegis_ctx), 2568c2ecf20Sopenharmony_ci .cra_alignmask = 0, 2578c2ecf20Sopenharmony_ci .cra_priority = 400, 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci .cra_name = "__aegis128", 2608c2ecf20Sopenharmony_ci .cra_driver_name = "__aegis128-aesni", 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic struct simd_aead_alg *simd_alg; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic int __init crypto_aegis128_aesni_module_init(void) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_XMM2) || 2718c2ecf20Sopenharmony_ci !boot_cpu_has(X86_FEATURE_AES) || 2728c2ecf20Sopenharmony_ci !cpu_has_xfeatures(XFEATURE_MASK_SSE, NULL)) 2738c2ecf20Sopenharmony_ci return -ENODEV; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return simd_register_aeads_compat(&crypto_aegis128_aesni_alg, 1, 2768c2ecf20Sopenharmony_ci &simd_alg); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic void __exit crypto_aegis128_aesni_module_exit(void) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci simd_unregister_aeads(&crypto_aegis128_aesni_alg, 1, &simd_alg); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cimodule_init(crypto_aegis128_aesni_module_init); 2858c2ecf20Sopenharmony_cimodule_exit(crypto_aegis128_aesni_module_exit); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2888c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ondrej Mosnacek <omosnacek@gmail.com>"); 2898c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AEGIS-128 AEAD algorithm -- AESNI+SSE2 implementation"); 2908c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("aegis128"); 2918c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("aegis128-aesni"); 292