162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Accelerated GHASH implementation with ARMv8 vmull.p64 instructions. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 - 2018 Linaro Ltd. 662306a36Sopenharmony_ci * Copyright (C) 2023 Google LLC. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/hwcap.h> 1062306a36Sopenharmony_ci#include <asm/neon.h> 1162306a36Sopenharmony_ci#include <asm/simd.h> 1262306a36Sopenharmony_ci#include <asm/unaligned.h> 1362306a36Sopenharmony_ci#include <crypto/aes.h> 1462306a36Sopenharmony_ci#include <crypto/gcm.h> 1562306a36Sopenharmony_ci#include <crypto/b128ops.h> 1662306a36Sopenharmony_ci#include <crypto/cryptd.h> 1762306a36Sopenharmony_ci#include <crypto/internal/aead.h> 1862306a36Sopenharmony_ci#include <crypto/internal/hash.h> 1962306a36Sopenharmony_ci#include <crypto/internal/simd.h> 2062306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 2162306a36Sopenharmony_ci#include <crypto/gf128mul.h> 2262306a36Sopenharmony_ci#include <crypto/scatterwalk.h> 2362306a36Sopenharmony_ci#include <linux/cpufeature.h> 2462306a36Sopenharmony_ci#include <linux/crypto.h> 2562306a36Sopenharmony_ci#include <linux/jump_label.h> 2662306a36Sopenharmony_ci#include <linux/module.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ciMODULE_DESCRIPTION("GHASH hash function using ARMv8 Crypto Extensions"); 2962306a36Sopenharmony_ciMODULE_AUTHOR("Ard Biesheuvel <ardb@kernel.org>"); 3062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 3162306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("ghash"); 3262306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("gcm(aes)"); 3362306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("rfc4106(gcm(aes))"); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define GHASH_BLOCK_SIZE 16 3662306a36Sopenharmony_ci#define GHASH_DIGEST_SIZE 16 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define RFC4106_NONCE_SIZE 4 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct ghash_key { 4162306a36Sopenharmony_ci be128 k; 4262306a36Sopenharmony_ci u64 h[][2]; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct gcm_key { 4662306a36Sopenharmony_ci u64 h[4][2]; 4762306a36Sopenharmony_ci u32 rk[AES_MAX_KEYLENGTH_U32]; 4862306a36Sopenharmony_ci int rounds; 4962306a36Sopenharmony_ci u8 nonce[]; // for RFC4106 nonce 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistruct ghash_desc_ctx { 5362306a36Sopenharmony_ci u64 digest[GHASH_DIGEST_SIZE/sizeof(u64)]; 5462306a36Sopenharmony_ci u8 buf[GHASH_BLOCK_SIZE]; 5562306a36Sopenharmony_ci u32 count; 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistruct ghash_async_ctx { 5962306a36Sopenharmony_ci struct cryptd_ahash *cryptd_tfm; 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciasmlinkage void pmull_ghash_update_p64(int blocks, u64 dg[], const char *src, 6362306a36Sopenharmony_ci u64 const h[][2], const char *head); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ciasmlinkage void pmull_ghash_update_p8(int blocks, u64 dg[], const char *src, 6662306a36Sopenharmony_ci u64 const h[][2], const char *head); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic __ro_after_init DEFINE_STATIC_KEY_FALSE(use_p64); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic int ghash_init(struct shash_desc *desc) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci *ctx = (struct ghash_desc_ctx){}; 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void ghash_do_update(int blocks, u64 dg[], const char *src, 7962306a36Sopenharmony_ci struct ghash_key *key, const char *head) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci if (likely(crypto_simd_usable())) { 8262306a36Sopenharmony_ci kernel_neon_begin(); 8362306a36Sopenharmony_ci if (static_branch_likely(&use_p64)) 8462306a36Sopenharmony_ci pmull_ghash_update_p64(blocks, dg, src, key->h, head); 8562306a36Sopenharmony_ci else 8662306a36Sopenharmony_ci pmull_ghash_update_p8(blocks, dg, src, key->h, head); 8762306a36Sopenharmony_ci kernel_neon_end(); 8862306a36Sopenharmony_ci } else { 8962306a36Sopenharmony_ci be128 dst = { cpu_to_be64(dg[1]), cpu_to_be64(dg[0]) }; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci do { 9262306a36Sopenharmony_ci const u8 *in = src; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (head) { 9562306a36Sopenharmony_ci in = head; 9662306a36Sopenharmony_ci blocks++; 9762306a36Sopenharmony_ci head = NULL; 9862306a36Sopenharmony_ci } else { 9962306a36Sopenharmony_ci src += GHASH_BLOCK_SIZE; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci crypto_xor((u8 *)&dst, in, GHASH_BLOCK_SIZE); 10362306a36Sopenharmony_ci gf128mul_lle(&dst, &key->k); 10462306a36Sopenharmony_ci } while (--blocks); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci dg[0] = be64_to_cpu(dst.b); 10762306a36Sopenharmony_ci dg[1] = be64_to_cpu(dst.a); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic int ghash_update(struct shash_desc *desc, const u8 *src, 11262306a36Sopenharmony_ci unsigned int len) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); 11562306a36Sopenharmony_ci unsigned int partial = ctx->count % GHASH_BLOCK_SIZE; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ctx->count += len; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci if ((partial + len) >= GHASH_BLOCK_SIZE) { 12062306a36Sopenharmony_ci struct ghash_key *key = crypto_shash_ctx(desc->tfm); 12162306a36Sopenharmony_ci int blocks; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (partial) { 12462306a36Sopenharmony_ci int p = GHASH_BLOCK_SIZE - partial; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci memcpy(ctx->buf + partial, src, p); 12762306a36Sopenharmony_ci src += p; 12862306a36Sopenharmony_ci len -= p; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci blocks = len / GHASH_BLOCK_SIZE; 13262306a36Sopenharmony_ci len %= GHASH_BLOCK_SIZE; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ghash_do_update(blocks, ctx->digest, src, key, 13562306a36Sopenharmony_ci partial ? ctx->buf : NULL); 13662306a36Sopenharmony_ci src += blocks * GHASH_BLOCK_SIZE; 13762306a36Sopenharmony_ci partial = 0; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci if (len) 14062306a36Sopenharmony_ci memcpy(ctx->buf + partial, src, len); 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int ghash_final(struct shash_desc *desc, u8 *dst) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci struct ghash_desc_ctx *ctx = shash_desc_ctx(desc); 14762306a36Sopenharmony_ci unsigned int partial = ctx->count % GHASH_BLOCK_SIZE; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (partial) { 15062306a36Sopenharmony_ci struct ghash_key *key = crypto_shash_ctx(desc->tfm); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci memset(ctx->buf + partial, 0, GHASH_BLOCK_SIZE - partial); 15362306a36Sopenharmony_ci ghash_do_update(1, ctx->digest, ctx->buf, key, NULL); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci put_unaligned_be64(ctx->digest[1], dst); 15662306a36Sopenharmony_ci put_unaligned_be64(ctx->digest[0], dst + 8); 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci *ctx = (struct ghash_desc_ctx){}; 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void ghash_reflect(u64 h[], const be128 *k) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci u64 carry = be64_to_cpu(k->a) >> 63; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci h[0] = (be64_to_cpu(k->b) << 1) | carry; 16762306a36Sopenharmony_ci h[1] = (be64_to_cpu(k->a) << 1) | (be64_to_cpu(k->b) >> 63); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (carry) 17062306a36Sopenharmony_ci h[1] ^= 0xc200000000000000UL; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int ghash_setkey(struct crypto_shash *tfm, 17462306a36Sopenharmony_ci const u8 *inkey, unsigned int keylen) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct ghash_key *key = crypto_shash_ctx(tfm); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (keylen != GHASH_BLOCK_SIZE) 17962306a36Sopenharmony_ci return -EINVAL; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* needed for the fallback */ 18262306a36Sopenharmony_ci memcpy(&key->k, inkey, GHASH_BLOCK_SIZE); 18362306a36Sopenharmony_ci ghash_reflect(key->h[0], &key->k); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (static_branch_likely(&use_p64)) { 18662306a36Sopenharmony_ci be128 h = key->k; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci gf128mul_lle(&h, &key->k); 18962306a36Sopenharmony_ci ghash_reflect(key->h[1], &h); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci gf128mul_lle(&h, &key->k); 19262306a36Sopenharmony_ci ghash_reflect(key->h[2], &h); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci gf128mul_lle(&h, &key->k); 19562306a36Sopenharmony_ci ghash_reflect(key->h[3], &h); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic struct shash_alg ghash_alg = { 20162306a36Sopenharmony_ci .digestsize = GHASH_DIGEST_SIZE, 20262306a36Sopenharmony_ci .init = ghash_init, 20362306a36Sopenharmony_ci .update = ghash_update, 20462306a36Sopenharmony_ci .final = ghash_final, 20562306a36Sopenharmony_ci .setkey = ghash_setkey, 20662306a36Sopenharmony_ci .descsize = sizeof(struct ghash_desc_ctx), 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci .base.cra_name = "ghash", 20962306a36Sopenharmony_ci .base.cra_driver_name = "ghash-ce-sync", 21062306a36Sopenharmony_ci .base.cra_priority = 300 - 1, 21162306a36Sopenharmony_ci .base.cra_blocksize = GHASH_BLOCK_SIZE, 21262306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct ghash_key) + sizeof(u64[2]), 21362306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic int ghash_async_init(struct ahash_request *req) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 21962306a36Sopenharmony_ci struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); 22062306a36Sopenharmony_ci struct ahash_request *cryptd_req = ahash_request_ctx(req); 22162306a36Sopenharmony_ci struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm; 22262306a36Sopenharmony_ci struct shash_desc *desc = cryptd_shash_desc(cryptd_req); 22362306a36Sopenharmony_ci struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci desc->tfm = child; 22662306a36Sopenharmony_ci return crypto_shash_init(desc); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int ghash_async_update(struct ahash_request *req) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct ahash_request *cryptd_req = ahash_request_ctx(req); 23262306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 23362306a36Sopenharmony_ci struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); 23462306a36Sopenharmony_ci struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (!crypto_simd_usable() || 23762306a36Sopenharmony_ci (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) { 23862306a36Sopenharmony_ci memcpy(cryptd_req, req, sizeof(*req)); 23962306a36Sopenharmony_ci ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base); 24062306a36Sopenharmony_ci return crypto_ahash_update(cryptd_req); 24162306a36Sopenharmony_ci } else { 24262306a36Sopenharmony_ci struct shash_desc *desc = cryptd_shash_desc(cryptd_req); 24362306a36Sopenharmony_ci return shash_ahash_update(req, desc); 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic int ghash_async_final(struct ahash_request *req) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct ahash_request *cryptd_req = ahash_request_ctx(req); 25062306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 25162306a36Sopenharmony_ci struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); 25262306a36Sopenharmony_ci struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (!crypto_simd_usable() || 25562306a36Sopenharmony_ci (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) { 25662306a36Sopenharmony_ci memcpy(cryptd_req, req, sizeof(*req)); 25762306a36Sopenharmony_ci ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base); 25862306a36Sopenharmony_ci return crypto_ahash_final(cryptd_req); 25962306a36Sopenharmony_ci } else { 26062306a36Sopenharmony_ci struct shash_desc *desc = cryptd_shash_desc(cryptd_req); 26162306a36Sopenharmony_ci return crypto_shash_final(desc, req->result); 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic int ghash_async_digest(struct ahash_request *req) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 26862306a36Sopenharmony_ci struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); 26962306a36Sopenharmony_ci struct ahash_request *cryptd_req = ahash_request_ctx(req); 27062306a36Sopenharmony_ci struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci if (!crypto_simd_usable() || 27362306a36Sopenharmony_ci (in_atomic() && cryptd_ahash_queued(cryptd_tfm))) { 27462306a36Sopenharmony_ci memcpy(cryptd_req, req, sizeof(*req)); 27562306a36Sopenharmony_ci ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base); 27662306a36Sopenharmony_ci return crypto_ahash_digest(cryptd_req); 27762306a36Sopenharmony_ci } else { 27862306a36Sopenharmony_ci struct shash_desc *desc = cryptd_shash_desc(cryptd_req); 27962306a36Sopenharmony_ci struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci desc->tfm = child; 28262306a36Sopenharmony_ci return shash_ahash_digest(req, desc); 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int ghash_async_import(struct ahash_request *req, const void *in) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct ahash_request *cryptd_req = ahash_request_ctx(req); 28962306a36Sopenharmony_ci struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); 29062306a36Sopenharmony_ci struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); 29162306a36Sopenharmony_ci struct shash_desc *desc = cryptd_shash_desc(cryptd_req); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci desc->tfm = cryptd_ahash_child(ctx->cryptd_tfm); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return crypto_shash_import(desc, in); 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int ghash_async_export(struct ahash_request *req, void *out) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci struct ahash_request *cryptd_req = ahash_request_ctx(req); 30162306a36Sopenharmony_ci struct shash_desc *desc = cryptd_shash_desc(cryptd_req); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return crypto_shash_export(desc, out); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key, 30762306a36Sopenharmony_ci unsigned int keylen) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm); 31062306a36Sopenharmony_ci struct crypto_ahash *child = &ctx->cryptd_tfm->base; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK); 31362306a36Sopenharmony_ci crypto_ahash_set_flags(child, crypto_ahash_get_flags(tfm) 31462306a36Sopenharmony_ci & CRYPTO_TFM_REQ_MASK); 31562306a36Sopenharmony_ci return crypto_ahash_setkey(child, key, keylen); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int ghash_async_init_tfm(struct crypto_tfm *tfm) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct cryptd_ahash *cryptd_tfm; 32162306a36Sopenharmony_ci struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci cryptd_tfm = cryptd_alloc_ahash("ghash-ce-sync", 0, 0); 32462306a36Sopenharmony_ci if (IS_ERR(cryptd_tfm)) 32562306a36Sopenharmony_ci return PTR_ERR(cryptd_tfm); 32662306a36Sopenharmony_ci ctx->cryptd_tfm = cryptd_tfm; 32762306a36Sopenharmony_ci crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), 32862306a36Sopenharmony_ci sizeof(struct ahash_request) + 32962306a36Sopenharmony_ci crypto_ahash_reqsize(&cryptd_tfm->base)); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return 0; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void ghash_async_exit_tfm(struct crypto_tfm *tfm) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci cryptd_free_ahash(ctx->cryptd_tfm); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic struct ahash_alg ghash_async_alg = { 34262306a36Sopenharmony_ci .init = ghash_async_init, 34362306a36Sopenharmony_ci .update = ghash_async_update, 34462306a36Sopenharmony_ci .final = ghash_async_final, 34562306a36Sopenharmony_ci .setkey = ghash_async_setkey, 34662306a36Sopenharmony_ci .digest = ghash_async_digest, 34762306a36Sopenharmony_ci .import = ghash_async_import, 34862306a36Sopenharmony_ci .export = ghash_async_export, 34962306a36Sopenharmony_ci .halg.digestsize = GHASH_DIGEST_SIZE, 35062306a36Sopenharmony_ci .halg.statesize = sizeof(struct ghash_desc_ctx), 35162306a36Sopenharmony_ci .halg.base = { 35262306a36Sopenharmony_ci .cra_name = "ghash", 35362306a36Sopenharmony_ci .cra_driver_name = "ghash-ce", 35462306a36Sopenharmony_ci .cra_priority = 300, 35562306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_ASYNC, 35662306a36Sopenharmony_ci .cra_blocksize = GHASH_BLOCK_SIZE, 35762306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct ghash_async_ctx), 35862306a36Sopenharmony_ci .cra_module = THIS_MODULE, 35962306a36Sopenharmony_ci .cra_init = ghash_async_init_tfm, 36062306a36Sopenharmony_ci .cra_exit = ghash_async_exit_tfm, 36162306a36Sopenharmony_ci }, 36262306a36Sopenharmony_ci}; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_civoid pmull_gcm_encrypt(int blocks, u64 dg[], const char *src, 36662306a36Sopenharmony_ci struct gcm_key const *k, char *dst, 36762306a36Sopenharmony_ci const char *iv, int rounds, u32 counter); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_civoid pmull_gcm_enc_final(int blocks, u64 dg[], char *tag, 37062306a36Sopenharmony_ci struct gcm_key const *k, char *head, 37162306a36Sopenharmony_ci const char *iv, int rounds, u32 counter); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_civoid pmull_gcm_decrypt(int bytes, u64 dg[], const char *src, 37462306a36Sopenharmony_ci struct gcm_key const *k, char *dst, 37562306a36Sopenharmony_ci const char *iv, int rounds, u32 counter); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciint pmull_gcm_dec_final(int bytes, u64 dg[], char *tag, 37862306a36Sopenharmony_ci struct gcm_key const *k, char *head, 37962306a36Sopenharmony_ci const char *iv, int rounds, u32 counter, 38062306a36Sopenharmony_ci const char *otag, int authsize); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int gcm_aes_setkey(struct crypto_aead *tfm, const u8 *inkey, 38362306a36Sopenharmony_ci unsigned int keylen) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct gcm_key *ctx = crypto_aead_ctx(tfm); 38662306a36Sopenharmony_ci struct crypto_aes_ctx aes_ctx; 38762306a36Sopenharmony_ci be128 h, k; 38862306a36Sopenharmony_ci int ret; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ret = aes_expandkey(&aes_ctx, inkey, keylen); 39162306a36Sopenharmony_ci if (ret) 39262306a36Sopenharmony_ci return -EINVAL; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci aes_encrypt(&aes_ctx, (u8 *)&k, (u8[AES_BLOCK_SIZE]){}); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci memcpy(ctx->rk, aes_ctx.key_enc, sizeof(ctx->rk)); 39762306a36Sopenharmony_ci ctx->rounds = 6 + keylen / 4; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci memzero_explicit(&aes_ctx, sizeof(aes_ctx)); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci ghash_reflect(ctx->h[0], &k); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci h = k; 40462306a36Sopenharmony_ci gf128mul_lle(&h, &k); 40562306a36Sopenharmony_ci ghash_reflect(ctx->h[1], &h); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci gf128mul_lle(&h, &k); 40862306a36Sopenharmony_ci ghash_reflect(ctx->h[2], &h); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci gf128mul_lle(&h, &k); 41162306a36Sopenharmony_ci ghash_reflect(ctx->h[3], &h); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int gcm_aes_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci return crypto_gcm_check_authsize(authsize); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void gcm_update_mac(u64 dg[], const u8 *src, int count, u8 buf[], 42262306a36Sopenharmony_ci int *buf_count, struct gcm_key *ctx) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci if (*buf_count > 0) { 42562306a36Sopenharmony_ci int buf_added = min(count, GHASH_BLOCK_SIZE - *buf_count); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci memcpy(&buf[*buf_count], src, buf_added); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci *buf_count += buf_added; 43062306a36Sopenharmony_ci src += buf_added; 43162306a36Sopenharmony_ci count -= buf_added; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (count >= GHASH_BLOCK_SIZE || *buf_count == GHASH_BLOCK_SIZE) { 43562306a36Sopenharmony_ci int blocks = count / GHASH_BLOCK_SIZE; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci pmull_ghash_update_p64(blocks, dg, src, ctx->h, 43862306a36Sopenharmony_ci *buf_count ? buf : NULL); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci src += blocks * GHASH_BLOCK_SIZE; 44162306a36Sopenharmony_ci count %= GHASH_BLOCK_SIZE; 44262306a36Sopenharmony_ci *buf_count = 0; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (count > 0) { 44662306a36Sopenharmony_ci memcpy(buf, src, count); 44762306a36Sopenharmony_ci *buf_count = count; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void gcm_calculate_auth_mac(struct aead_request *req, u64 dg[], u32 len) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 45462306a36Sopenharmony_ci struct gcm_key *ctx = crypto_aead_ctx(aead); 45562306a36Sopenharmony_ci u8 buf[GHASH_BLOCK_SIZE]; 45662306a36Sopenharmony_ci struct scatter_walk walk; 45762306a36Sopenharmony_ci int buf_count = 0; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci scatterwalk_start(&walk, req->src); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci do { 46262306a36Sopenharmony_ci u32 n = scatterwalk_clamp(&walk, len); 46362306a36Sopenharmony_ci u8 *p; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (!n) { 46662306a36Sopenharmony_ci scatterwalk_start(&walk, sg_next(walk.sg)); 46762306a36Sopenharmony_ci n = scatterwalk_clamp(&walk, len); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci p = scatterwalk_map(&walk); 47162306a36Sopenharmony_ci gcm_update_mac(dg, p, n, buf, &buf_count, ctx); 47262306a36Sopenharmony_ci scatterwalk_unmap(p); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (unlikely(len / SZ_4K > (len - n) / SZ_4K)) { 47562306a36Sopenharmony_ci kernel_neon_end(); 47662306a36Sopenharmony_ci kernel_neon_begin(); 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci len -= n; 48062306a36Sopenharmony_ci scatterwalk_advance(&walk, n); 48162306a36Sopenharmony_ci scatterwalk_done(&walk, 0, len); 48262306a36Sopenharmony_ci } while (len); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (buf_count) { 48562306a36Sopenharmony_ci memset(&buf[buf_count], 0, GHASH_BLOCK_SIZE - buf_count); 48662306a36Sopenharmony_ci pmull_ghash_update_p64(1, dg, buf, ctx->h, NULL); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic int gcm_encrypt(struct aead_request *req, const u8 *iv, u32 assoclen) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 49362306a36Sopenharmony_ci struct gcm_key *ctx = crypto_aead_ctx(aead); 49462306a36Sopenharmony_ci struct skcipher_walk walk; 49562306a36Sopenharmony_ci u8 buf[AES_BLOCK_SIZE]; 49662306a36Sopenharmony_ci u32 counter = 2; 49762306a36Sopenharmony_ci u64 dg[2] = {}; 49862306a36Sopenharmony_ci be128 lengths; 49962306a36Sopenharmony_ci const u8 *src; 50062306a36Sopenharmony_ci u8 *tag, *dst; 50162306a36Sopenharmony_ci int tail, err; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (WARN_ON_ONCE(!may_use_simd())) 50462306a36Sopenharmony_ci return -EBUSY; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci err = skcipher_walk_aead_encrypt(&walk, req, false); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci kernel_neon_begin(); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (assoclen) 51162306a36Sopenharmony_ci gcm_calculate_auth_mac(req, dg, assoclen); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci src = walk.src.virt.addr; 51462306a36Sopenharmony_ci dst = walk.dst.virt.addr; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci while (walk.nbytes >= AES_BLOCK_SIZE) { 51762306a36Sopenharmony_ci int nblocks = walk.nbytes / AES_BLOCK_SIZE; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci pmull_gcm_encrypt(nblocks, dg, src, ctx, dst, iv, 52062306a36Sopenharmony_ci ctx->rounds, counter); 52162306a36Sopenharmony_ci counter += nblocks; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (walk.nbytes == walk.total) { 52462306a36Sopenharmony_ci src += nblocks * AES_BLOCK_SIZE; 52562306a36Sopenharmony_ci dst += nblocks * AES_BLOCK_SIZE; 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci } 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci kernel_neon_end(); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci err = skcipher_walk_done(&walk, 53262306a36Sopenharmony_ci walk.nbytes % AES_BLOCK_SIZE); 53362306a36Sopenharmony_ci if (err) 53462306a36Sopenharmony_ci return err; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci src = walk.src.virt.addr; 53762306a36Sopenharmony_ci dst = walk.dst.virt.addr; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci kernel_neon_begin(); 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci lengths.a = cpu_to_be64(assoclen * 8); 54462306a36Sopenharmony_ci lengths.b = cpu_to_be64(req->cryptlen * 8); 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci tag = (u8 *)&lengths; 54762306a36Sopenharmony_ci tail = walk.nbytes % AES_BLOCK_SIZE; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* 55062306a36Sopenharmony_ci * Bounce via a buffer unless we are encrypting in place and src/dst 55162306a36Sopenharmony_ci * are not pointing to the start of the walk buffer. In that case, we 55262306a36Sopenharmony_ci * can do a NEON load/xor/store sequence in place as long as we move 55362306a36Sopenharmony_ci * the plain/ciphertext and keystream to the start of the register. If 55462306a36Sopenharmony_ci * not, do a memcpy() to the end of the buffer so we can reuse the same 55562306a36Sopenharmony_ci * logic. 55662306a36Sopenharmony_ci */ 55762306a36Sopenharmony_ci if (unlikely(tail && (tail == walk.nbytes || src != dst))) 55862306a36Sopenharmony_ci src = memcpy(buf + sizeof(buf) - tail, src, tail); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci pmull_gcm_enc_final(tail, dg, tag, ctx, (u8 *)src, iv, 56162306a36Sopenharmony_ci ctx->rounds, counter); 56262306a36Sopenharmony_ci kernel_neon_end(); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (unlikely(tail && src != dst)) 56562306a36Sopenharmony_ci memcpy(dst, src, tail); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (walk.nbytes) { 56862306a36Sopenharmony_ci err = skcipher_walk_done(&walk, 0); 56962306a36Sopenharmony_ci if (err) 57062306a36Sopenharmony_ci return err; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* copy authtag to end of dst */ 57462306a36Sopenharmony_ci scatterwalk_map_and_copy(tag, req->dst, req->assoclen + req->cryptlen, 57562306a36Sopenharmony_ci crypto_aead_authsize(aead), 1); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci return 0; 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic int gcm_decrypt(struct aead_request *req, const u8 *iv, u32 assoclen) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 58362306a36Sopenharmony_ci struct gcm_key *ctx = crypto_aead_ctx(aead); 58462306a36Sopenharmony_ci int authsize = crypto_aead_authsize(aead); 58562306a36Sopenharmony_ci struct skcipher_walk walk; 58662306a36Sopenharmony_ci u8 otag[AES_BLOCK_SIZE]; 58762306a36Sopenharmony_ci u8 buf[AES_BLOCK_SIZE]; 58862306a36Sopenharmony_ci u32 counter = 2; 58962306a36Sopenharmony_ci u64 dg[2] = {}; 59062306a36Sopenharmony_ci be128 lengths; 59162306a36Sopenharmony_ci const u8 *src; 59262306a36Sopenharmony_ci u8 *tag, *dst; 59362306a36Sopenharmony_ci int tail, err, ret; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci if (WARN_ON_ONCE(!may_use_simd())) 59662306a36Sopenharmony_ci return -EBUSY; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci scatterwalk_map_and_copy(otag, req->src, 59962306a36Sopenharmony_ci req->assoclen + req->cryptlen - authsize, 60062306a36Sopenharmony_ci authsize, 0); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci err = skcipher_walk_aead_decrypt(&walk, req, false); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci kernel_neon_begin(); 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci if (assoclen) 60762306a36Sopenharmony_ci gcm_calculate_auth_mac(req, dg, assoclen); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci src = walk.src.virt.addr; 61062306a36Sopenharmony_ci dst = walk.dst.virt.addr; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci while (walk.nbytes >= AES_BLOCK_SIZE) { 61362306a36Sopenharmony_ci int nblocks = walk.nbytes / AES_BLOCK_SIZE; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci pmull_gcm_decrypt(nblocks, dg, src, ctx, dst, iv, 61662306a36Sopenharmony_ci ctx->rounds, counter); 61762306a36Sopenharmony_ci counter += nblocks; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (walk.nbytes == walk.total) { 62062306a36Sopenharmony_ci src += nblocks * AES_BLOCK_SIZE; 62162306a36Sopenharmony_ci dst += nblocks * AES_BLOCK_SIZE; 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci kernel_neon_end(); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci err = skcipher_walk_done(&walk, 62862306a36Sopenharmony_ci walk.nbytes % AES_BLOCK_SIZE); 62962306a36Sopenharmony_ci if (err) 63062306a36Sopenharmony_ci return err; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci src = walk.src.virt.addr; 63362306a36Sopenharmony_ci dst = walk.dst.virt.addr; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci kernel_neon_begin(); 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci lengths.a = cpu_to_be64(assoclen * 8); 63962306a36Sopenharmony_ci lengths.b = cpu_to_be64((req->cryptlen - authsize) * 8); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci tag = (u8 *)&lengths; 64262306a36Sopenharmony_ci tail = walk.nbytes % AES_BLOCK_SIZE; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (unlikely(tail && (tail == walk.nbytes || src != dst))) 64562306a36Sopenharmony_ci src = memcpy(buf + sizeof(buf) - tail, src, tail); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci ret = pmull_gcm_dec_final(tail, dg, tag, ctx, (u8 *)src, iv, 64862306a36Sopenharmony_ci ctx->rounds, counter, otag, authsize); 64962306a36Sopenharmony_ci kernel_neon_end(); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (unlikely(tail && src != dst)) 65262306a36Sopenharmony_ci memcpy(dst, src, tail); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (walk.nbytes) { 65562306a36Sopenharmony_ci err = skcipher_walk_done(&walk, 0); 65662306a36Sopenharmony_ci if (err) 65762306a36Sopenharmony_ci return err; 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci return ret ? -EBADMSG : 0; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic int gcm_aes_encrypt(struct aead_request *req) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci return gcm_encrypt(req, req->iv, req->assoclen); 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int gcm_aes_decrypt(struct aead_request *req) 66962306a36Sopenharmony_ci{ 67062306a36Sopenharmony_ci return gcm_decrypt(req, req->iv, req->assoclen); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int rfc4106_setkey(struct crypto_aead *tfm, const u8 *inkey, 67462306a36Sopenharmony_ci unsigned int keylen) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct gcm_key *ctx = crypto_aead_ctx(tfm); 67762306a36Sopenharmony_ci int err; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci keylen -= RFC4106_NONCE_SIZE; 68062306a36Sopenharmony_ci err = gcm_aes_setkey(tfm, inkey, keylen); 68162306a36Sopenharmony_ci if (err) 68262306a36Sopenharmony_ci return err; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci memcpy(ctx->nonce, inkey + keylen, RFC4106_NONCE_SIZE); 68562306a36Sopenharmony_ci return 0; 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic int rfc4106_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci return crypto_rfc4106_check_authsize(authsize); 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic int rfc4106_encrypt(struct aead_request *req) 69462306a36Sopenharmony_ci{ 69562306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 69662306a36Sopenharmony_ci struct gcm_key *ctx = crypto_aead_ctx(aead); 69762306a36Sopenharmony_ci u8 iv[GCM_AES_IV_SIZE]; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci memcpy(iv, ctx->nonce, RFC4106_NONCE_SIZE); 70062306a36Sopenharmony_ci memcpy(iv + RFC4106_NONCE_SIZE, req->iv, GCM_RFC4106_IV_SIZE); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci return crypto_ipsec_check_assoclen(req->assoclen) ?: 70362306a36Sopenharmony_ci gcm_encrypt(req, iv, req->assoclen - GCM_RFC4106_IV_SIZE); 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic int rfc4106_decrypt(struct aead_request *req) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci struct crypto_aead *aead = crypto_aead_reqtfm(req); 70962306a36Sopenharmony_ci struct gcm_key *ctx = crypto_aead_ctx(aead); 71062306a36Sopenharmony_ci u8 iv[GCM_AES_IV_SIZE]; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci memcpy(iv, ctx->nonce, RFC4106_NONCE_SIZE); 71362306a36Sopenharmony_ci memcpy(iv + RFC4106_NONCE_SIZE, req->iv, GCM_RFC4106_IV_SIZE); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci return crypto_ipsec_check_assoclen(req->assoclen) ?: 71662306a36Sopenharmony_ci gcm_decrypt(req, iv, req->assoclen - GCM_RFC4106_IV_SIZE); 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic struct aead_alg gcm_aes_algs[] = {{ 72062306a36Sopenharmony_ci .ivsize = GCM_AES_IV_SIZE, 72162306a36Sopenharmony_ci .chunksize = AES_BLOCK_SIZE, 72262306a36Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 72362306a36Sopenharmony_ci .setkey = gcm_aes_setkey, 72462306a36Sopenharmony_ci .setauthsize = gcm_aes_setauthsize, 72562306a36Sopenharmony_ci .encrypt = gcm_aes_encrypt, 72662306a36Sopenharmony_ci .decrypt = gcm_aes_decrypt, 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci .base.cra_name = "gcm(aes)", 72962306a36Sopenharmony_ci .base.cra_driver_name = "gcm-aes-ce", 73062306a36Sopenharmony_ci .base.cra_priority = 400, 73162306a36Sopenharmony_ci .base.cra_blocksize = 1, 73262306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct gcm_key), 73362306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 73462306a36Sopenharmony_ci}, { 73562306a36Sopenharmony_ci .ivsize = GCM_RFC4106_IV_SIZE, 73662306a36Sopenharmony_ci .chunksize = AES_BLOCK_SIZE, 73762306a36Sopenharmony_ci .maxauthsize = AES_BLOCK_SIZE, 73862306a36Sopenharmony_ci .setkey = rfc4106_setkey, 73962306a36Sopenharmony_ci .setauthsize = rfc4106_setauthsize, 74062306a36Sopenharmony_ci .encrypt = rfc4106_encrypt, 74162306a36Sopenharmony_ci .decrypt = rfc4106_decrypt, 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci .base.cra_name = "rfc4106(gcm(aes))", 74462306a36Sopenharmony_ci .base.cra_driver_name = "rfc4106-gcm-aes-ce", 74562306a36Sopenharmony_ci .base.cra_priority = 400, 74662306a36Sopenharmony_ci .base.cra_blocksize = 1, 74762306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct gcm_key) + RFC4106_NONCE_SIZE, 74862306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 74962306a36Sopenharmony_ci}}; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_cistatic int __init ghash_ce_mod_init(void) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci int err; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci if (!(elf_hwcap & HWCAP_NEON)) 75662306a36Sopenharmony_ci return -ENODEV; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (elf_hwcap2 & HWCAP2_PMULL) { 75962306a36Sopenharmony_ci err = crypto_register_aeads(gcm_aes_algs, 76062306a36Sopenharmony_ci ARRAY_SIZE(gcm_aes_algs)); 76162306a36Sopenharmony_ci if (err) 76262306a36Sopenharmony_ci return err; 76362306a36Sopenharmony_ci ghash_alg.base.cra_ctxsize += 3 * sizeof(u64[2]); 76462306a36Sopenharmony_ci static_branch_enable(&use_p64); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci err = crypto_register_shash(&ghash_alg); 76862306a36Sopenharmony_ci if (err) 76962306a36Sopenharmony_ci goto err_aead; 77062306a36Sopenharmony_ci err = crypto_register_ahash(&ghash_async_alg); 77162306a36Sopenharmony_ci if (err) 77262306a36Sopenharmony_ci goto err_shash; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return 0; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cierr_shash: 77762306a36Sopenharmony_ci crypto_unregister_shash(&ghash_alg); 77862306a36Sopenharmony_cierr_aead: 77962306a36Sopenharmony_ci if (elf_hwcap2 & HWCAP2_PMULL) 78062306a36Sopenharmony_ci crypto_unregister_aeads(gcm_aes_algs, 78162306a36Sopenharmony_ci ARRAY_SIZE(gcm_aes_algs)); 78262306a36Sopenharmony_ci return err; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic void __exit ghash_ce_mod_exit(void) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci crypto_unregister_ahash(&ghash_async_alg); 78862306a36Sopenharmony_ci crypto_unregister_shash(&ghash_alg); 78962306a36Sopenharmony_ci if (elf_hwcap2 & HWCAP2_PMULL) 79062306a36Sopenharmony_ci crypto_unregister_aeads(gcm_aes_algs, 79162306a36Sopenharmony_ci ARRAY_SIZE(gcm_aes_algs)); 79262306a36Sopenharmony_ci} 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_cimodule_init(ghash_ce_mod_init); 79562306a36Sopenharmony_cimodule_exit(ghash_ce_mod_exit); 796