162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * POLYVAL: hash function for HCTR2. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi> 662306a36Sopenharmony_ci * Copyright (c) 2009 Intel Corp. 762306a36Sopenharmony_ci * Author: Huang Ying <ying.huang@intel.com> 862306a36Sopenharmony_ci * Copyright 2021 Google LLC 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * Code based on crypto/ghash-generic.c 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * POLYVAL is a keyed hash function similar to GHASH. POLYVAL uses a different 1562306a36Sopenharmony_ci * modulus for finite field multiplication which makes hardware accelerated 1662306a36Sopenharmony_ci * implementations on little-endian machines faster. POLYVAL is used in the 1762306a36Sopenharmony_ci * kernel to implement HCTR2, but was originally specified for AES-GCM-SIV 1862306a36Sopenharmony_ci * (RFC 8452). 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * For more information see: 2162306a36Sopenharmony_ci * Length-preserving encryption with HCTR2: 2262306a36Sopenharmony_ci * https://eprint.iacr.org/2021/1441.pdf 2362306a36Sopenharmony_ci * AES-GCM-SIV: Nonce Misuse-Resistant Authenticated Encryption: 2462306a36Sopenharmony_ci * https://datatracker.ietf.org/doc/html/rfc8452 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Like GHASH, POLYVAL is not a cryptographic hash function and should 2762306a36Sopenharmony_ci * not be used outside of crypto modes explicitly designed to use POLYVAL. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * This implementation uses a convenient trick involving the GHASH and POLYVAL 3062306a36Sopenharmony_ci * fields. This trick allows multiplication in the POLYVAL field to be 3162306a36Sopenharmony_ci * implemented by using multiplication in the GHASH field as a subroutine. An 3262306a36Sopenharmony_ci * element of the POLYVAL field can be converted to an element of the GHASH 3362306a36Sopenharmony_ci * field by computing x*REVERSE(a), where REVERSE reverses the byte-ordering of 3462306a36Sopenharmony_ci * a. Similarly, an element of the GHASH field can be converted back to the 3562306a36Sopenharmony_ci * POLYVAL field by computing REVERSE(x^{-1}*a). For more information, see: 3662306a36Sopenharmony_ci * https://datatracker.ietf.org/doc/html/rfc8452#appendix-A 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * By using this trick, we do not need to implement the POLYVAL field for the 3962306a36Sopenharmony_ci * generic implementation. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * Warning: this generic implementation is not intended to be used in practice 4262306a36Sopenharmony_ci * and is not constant time. For practical use, a hardware accelerated 4362306a36Sopenharmony_ci * implementation of POLYVAL should be used instead. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include <asm/unaligned.h> 4862306a36Sopenharmony_ci#include <crypto/algapi.h> 4962306a36Sopenharmony_ci#include <crypto/gf128mul.h> 5062306a36Sopenharmony_ci#include <crypto/polyval.h> 5162306a36Sopenharmony_ci#include <crypto/internal/hash.h> 5262306a36Sopenharmony_ci#include <linux/crypto.h> 5362306a36Sopenharmony_ci#include <linux/init.h> 5462306a36Sopenharmony_ci#include <linux/kernel.h> 5562306a36Sopenharmony_ci#include <linux/module.h> 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct polyval_tfm_ctx { 5862306a36Sopenharmony_ci struct gf128mul_4k *gf128; 5962306a36Sopenharmony_ci}; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistruct polyval_desc_ctx { 6262306a36Sopenharmony_ci union { 6362306a36Sopenharmony_ci u8 buffer[POLYVAL_BLOCK_SIZE]; 6462306a36Sopenharmony_ci be128 buffer128; 6562306a36Sopenharmony_ci }; 6662306a36Sopenharmony_ci u32 bytes; 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void copy_and_reverse(u8 dst[POLYVAL_BLOCK_SIZE], 7062306a36Sopenharmony_ci const u8 src[POLYVAL_BLOCK_SIZE]) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci u64 a = get_unaligned((const u64 *)&src[0]); 7362306a36Sopenharmony_ci u64 b = get_unaligned((const u64 *)&src[8]); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci put_unaligned(swab64(a), (u64 *)&dst[8]); 7662306a36Sopenharmony_ci put_unaligned(swab64(b), (u64 *)&dst[0]); 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* 8062306a36Sopenharmony_ci * Performs multiplication in the POLYVAL field using the GHASH field as a 8162306a36Sopenharmony_ci * subroutine. This function is used as a fallback for hardware accelerated 8262306a36Sopenharmony_ci * implementations when simd registers are unavailable. 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * Note: This function is not used for polyval-generic, instead we use the 4k 8562306a36Sopenharmony_ci * lookup table implementation for finite field multiplication. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_civoid polyval_mul_non4k(u8 *op1, const u8 *op2) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci be128 a, b; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci // Assume one argument is in Montgomery form and one is not. 9262306a36Sopenharmony_ci copy_and_reverse((u8 *)&a, op1); 9362306a36Sopenharmony_ci copy_and_reverse((u8 *)&b, op2); 9462306a36Sopenharmony_ci gf128mul_x_lle(&a, &a); 9562306a36Sopenharmony_ci gf128mul_lle(&a, &b); 9662306a36Sopenharmony_ci copy_and_reverse(op1, (u8 *)&a); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(polyval_mul_non4k); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * Perform a POLYVAL update using non4k multiplication. This function is used 10262306a36Sopenharmony_ci * as a fallback for hardware accelerated implementations when simd registers 10362306a36Sopenharmony_ci * are unavailable. 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * Note: This function is not used for polyval-generic, instead we use the 4k 10662306a36Sopenharmony_ci * lookup table implementation of finite field multiplication. 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_civoid polyval_update_non4k(const u8 *key, const u8 *in, 10962306a36Sopenharmony_ci size_t nblocks, u8 *accumulator) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci while (nblocks--) { 11262306a36Sopenharmony_ci crypto_xor(accumulator, in, POLYVAL_BLOCK_SIZE); 11362306a36Sopenharmony_ci polyval_mul_non4k(accumulator, key); 11462306a36Sopenharmony_ci in += POLYVAL_BLOCK_SIZE; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(polyval_update_non4k); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic int polyval_setkey(struct crypto_shash *tfm, 12062306a36Sopenharmony_ci const u8 *key, unsigned int keylen) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct polyval_tfm_ctx *ctx = crypto_shash_ctx(tfm); 12362306a36Sopenharmony_ci be128 k; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (keylen != POLYVAL_BLOCK_SIZE) 12662306a36Sopenharmony_ci return -EINVAL; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci gf128mul_free_4k(ctx->gf128); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(k) != POLYVAL_BLOCK_SIZE); 13162306a36Sopenharmony_ci copy_and_reverse((u8 *)&k, key); 13262306a36Sopenharmony_ci gf128mul_x_lle(&k, &k); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ctx->gf128 = gf128mul_init_4k_lle(&k); 13562306a36Sopenharmony_ci memzero_explicit(&k, POLYVAL_BLOCK_SIZE); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci if (!ctx->gf128) 13862306a36Sopenharmony_ci return -ENOMEM; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return 0; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic int polyval_init(struct shash_desc *desc) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct polyval_desc_ctx *dctx = shash_desc_ctx(desc); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci memset(dctx, 0, sizeof(*dctx)); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int polyval_update(struct shash_desc *desc, 15362306a36Sopenharmony_ci const u8 *src, unsigned int srclen) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct polyval_desc_ctx *dctx = shash_desc_ctx(desc); 15662306a36Sopenharmony_ci const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm); 15762306a36Sopenharmony_ci u8 *pos; 15862306a36Sopenharmony_ci u8 tmp[POLYVAL_BLOCK_SIZE]; 15962306a36Sopenharmony_ci int n; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (dctx->bytes) { 16262306a36Sopenharmony_ci n = min(srclen, dctx->bytes); 16362306a36Sopenharmony_ci pos = dctx->buffer + dctx->bytes - 1; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci dctx->bytes -= n; 16662306a36Sopenharmony_ci srclen -= n; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci while (n--) 16962306a36Sopenharmony_ci *pos-- ^= *src++; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (!dctx->bytes) 17262306a36Sopenharmony_ci gf128mul_4k_lle(&dctx->buffer128, ctx->gf128); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci while (srclen >= POLYVAL_BLOCK_SIZE) { 17662306a36Sopenharmony_ci copy_and_reverse(tmp, src); 17762306a36Sopenharmony_ci crypto_xor(dctx->buffer, tmp, POLYVAL_BLOCK_SIZE); 17862306a36Sopenharmony_ci gf128mul_4k_lle(&dctx->buffer128, ctx->gf128); 17962306a36Sopenharmony_ci src += POLYVAL_BLOCK_SIZE; 18062306a36Sopenharmony_ci srclen -= POLYVAL_BLOCK_SIZE; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (srclen) { 18462306a36Sopenharmony_ci dctx->bytes = POLYVAL_BLOCK_SIZE - srclen; 18562306a36Sopenharmony_ci pos = dctx->buffer + POLYVAL_BLOCK_SIZE - 1; 18662306a36Sopenharmony_ci while (srclen--) 18762306a36Sopenharmony_ci *pos-- ^= *src++; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return 0; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic int polyval_final(struct shash_desc *desc, u8 *dst) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci struct polyval_desc_ctx *dctx = shash_desc_ctx(desc); 19662306a36Sopenharmony_ci const struct polyval_tfm_ctx *ctx = crypto_shash_ctx(desc->tfm); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (dctx->bytes) 19962306a36Sopenharmony_ci gf128mul_4k_lle(&dctx->buffer128, ctx->gf128); 20062306a36Sopenharmony_ci copy_and_reverse(dst, dctx->buffer); 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void polyval_exit_tfm(struct crypto_tfm *tfm) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct polyval_tfm_ctx *ctx = crypto_tfm_ctx(tfm); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci gf128mul_free_4k(ctx->gf128); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic struct shash_alg polyval_alg = { 21262306a36Sopenharmony_ci .digestsize = POLYVAL_DIGEST_SIZE, 21362306a36Sopenharmony_ci .init = polyval_init, 21462306a36Sopenharmony_ci .update = polyval_update, 21562306a36Sopenharmony_ci .final = polyval_final, 21662306a36Sopenharmony_ci .setkey = polyval_setkey, 21762306a36Sopenharmony_ci .descsize = sizeof(struct polyval_desc_ctx), 21862306a36Sopenharmony_ci .base = { 21962306a36Sopenharmony_ci .cra_name = "polyval", 22062306a36Sopenharmony_ci .cra_driver_name = "polyval-generic", 22162306a36Sopenharmony_ci .cra_priority = 100, 22262306a36Sopenharmony_ci .cra_blocksize = POLYVAL_BLOCK_SIZE, 22362306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct polyval_tfm_ctx), 22462306a36Sopenharmony_ci .cra_module = THIS_MODULE, 22562306a36Sopenharmony_ci .cra_exit = polyval_exit_tfm, 22662306a36Sopenharmony_ci }, 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int __init polyval_mod_init(void) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci return crypto_register_shash(&polyval_alg); 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic void __exit polyval_mod_exit(void) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci crypto_unregister_shash(&polyval_alg); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cisubsys_initcall(polyval_mod_init); 24062306a36Sopenharmony_cimodule_exit(polyval_mod_exit); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 24362306a36Sopenharmony_ciMODULE_DESCRIPTION("POLYVAL hash function"); 24462306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("polyval"); 24562306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("polyval-generic"); 246