18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * GHASH: hash function for GCM (Galois/Counter Mode). 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi> 68c2ecf20Sopenharmony_ci * Copyright (c) 2009 Intel Corp. 78c2ecf20Sopenharmony_ci * Author: Huang Ying <ying.huang@intel.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci/* 118c2ecf20Sopenharmony_ci * GHASH is a keyed hash function used in GCM authentication tag generation. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * The original GCM paper [1] presents GHASH as a function GHASH(H, A, C) which 148c2ecf20Sopenharmony_ci * takes a 16-byte hash key H, additional authenticated data A, and a ciphertext 158c2ecf20Sopenharmony_ci * C. It formats A and C into a single byte string X, interprets X as a 168c2ecf20Sopenharmony_ci * polynomial over GF(2^128), and evaluates this polynomial at the point H. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * However, the NIST standard for GCM [2] presents GHASH as GHASH(H, X) where X 198c2ecf20Sopenharmony_ci * is the already-formatted byte string containing both A and C. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * "ghash" in the Linux crypto API uses the 'X' (pre-formatted) convention, 228c2ecf20Sopenharmony_ci * since the API supports only a single data stream per hash. Thus, the 238c2ecf20Sopenharmony_ci * formatting of 'A' and 'C' is done in the "gcm" template, not in "ghash". 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * The reason "ghash" is separate from "gcm" is to allow "gcm" to use an 268c2ecf20Sopenharmony_ci * accelerated "ghash" when a standalone accelerated "gcm(aes)" is unavailable. 278c2ecf20Sopenharmony_ci * It is generally inappropriate to use "ghash" for other purposes, since it is 288c2ecf20Sopenharmony_ci * an "ε-almost-XOR-universal hash function", not a cryptographic hash function. 298c2ecf20Sopenharmony_ci * It can only be used securely in crypto modes specially designed to use it. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * [1] The Galois/Counter Mode of Operation (GCM) 328c2ecf20Sopenharmony_ci * (http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.694.695&rep=rep1&type=pdf) 338c2ecf20Sopenharmony_ci * [2] Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC 348c2ecf20Sopenharmony_ci * (https://csrc.nist.gov/publications/detail/sp/800-38d/final) 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include <crypto/algapi.h> 388c2ecf20Sopenharmony_ci#include <crypto/gf128mul.h> 398c2ecf20Sopenharmony_ci#include <crypto/ghash.h> 408c2ecf20Sopenharmony_ci#include <crypto/internal/hash.h> 418c2ecf20Sopenharmony_ci#include <linux/crypto.h> 428c2ecf20Sopenharmony_ci#include <linux/init.h> 438c2ecf20Sopenharmony_ci#include <linux/kernel.h> 448c2ecf20Sopenharmony_ci#include <linux/module.h> 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int ghash_init(struct shash_desc *desc) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci memset(dctx, 0, sizeof(*dctx)); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic int ghash_setkey(struct crypto_shash *tfm, 568c2ecf20Sopenharmony_ci const u8 *key, unsigned int keylen) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct ghash_ctx *ctx = crypto_shash_ctx(tfm); 598c2ecf20Sopenharmony_ci be128 k; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (keylen != GHASH_BLOCK_SIZE) 628c2ecf20Sopenharmony_ci return -EINVAL; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci if (ctx->gf128) 658c2ecf20Sopenharmony_ci gf128mul_free_4k(ctx->gf128); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(k) != GHASH_BLOCK_SIZE); 688c2ecf20Sopenharmony_ci memcpy(&k, key, GHASH_BLOCK_SIZE); /* avoid violating alignment rules */ 698c2ecf20Sopenharmony_ci ctx->gf128 = gf128mul_init_4k_lle(&k); 708c2ecf20Sopenharmony_ci memzero_explicit(&k, GHASH_BLOCK_SIZE); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (!ctx->gf128) 738c2ecf20Sopenharmony_ci return -ENOMEM; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci return 0; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int ghash_update(struct shash_desc *desc, 798c2ecf20Sopenharmony_ci const u8 *src, unsigned int srclen) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 828c2ecf20Sopenharmony_ci struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); 838c2ecf20Sopenharmony_ci u8 *dst = dctx->buffer; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (dctx->bytes) { 868c2ecf20Sopenharmony_ci int n = min(srclen, dctx->bytes); 878c2ecf20Sopenharmony_ci u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci dctx->bytes -= n; 908c2ecf20Sopenharmony_ci srclen -= n; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci while (n--) 938c2ecf20Sopenharmony_ci *pos++ ^= *src++; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (!dctx->bytes) 968c2ecf20Sopenharmony_ci gf128mul_4k_lle((be128 *)dst, ctx->gf128); 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci while (srclen >= GHASH_BLOCK_SIZE) { 1008c2ecf20Sopenharmony_ci crypto_xor(dst, src, GHASH_BLOCK_SIZE); 1018c2ecf20Sopenharmony_ci gf128mul_4k_lle((be128 *)dst, ctx->gf128); 1028c2ecf20Sopenharmony_ci src += GHASH_BLOCK_SIZE; 1038c2ecf20Sopenharmony_ci srclen -= GHASH_BLOCK_SIZE; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (srclen) { 1078c2ecf20Sopenharmony_ci dctx->bytes = GHASH_BLOCK_SIZE - srclen; 1088c2ecf20Sopenharmony_ci while (srclen--) 1098c2ecf20Sopenharmony_ci *dst++ ^= *src++; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return 0; 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci u8 *dst = dctx->buffer; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if (dctx->bytes) { 1208c2ecf20Sopenharmony_ci u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci while (dctx->bytes--) 1238c2ecf20Sopenharmony_ci *tmp++ ^= 0; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci gf128mul_4k_lle((be128 *)dst, ctx->gf128); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci dctx->bytes = 0; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int ghash_final(struct shash_desc *desc, u8 *dst) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 1348c2ecf20Sopenharmony_ci struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); 1358c2ecf20Sopenharmony_ci u8 *buf = dctx->buffer; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ghash_flush(ctx, dctx); 1388c2ecf20Sopenharmony_ci memcpy(dst, buf, GHASH_BLOCK_SIZE); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void ghash_exit_tfm(struct crypto_tfm *tfm) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct ghash_ctx *ctx = crypto_tfm_ctx(tfm); 1468c2ecf20Sopenharmony_ci if (ctx->gf128) 1478c2ecf20Sopenharmony_ci gf128mul_free_4k(ctx->gf128); 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic struct shash_alg ghash_alg = { 1518c2ecf20Sopenharmony_ci .digestsize = GHASH_DIGEST_SIZE, 1528c2ecf20Sopenharmony_ci .init = ghash_init, 1538c2ecf20Sopenharmony_ci .update = ghash_update, 1548c2ecf20Sopenharmony_ci .final = ghash_final, 1558c2ecf20Sopenharmony_ci .setkey = ghash_setkey, 1568c2ecf20Sopenharmony_ci .descsize = sizeof(struct ghash_desc_ctx), 1578c2ecf20Sopenharmony_ci .base = { 1588c2ecf20Sopenharmony_ci .cra_name = "ghash", 1598c2ecf20Sopenharmony_ci .cra_driver_name = "ghash-generic", 1608c2ecf20Sopenharmony_ci .cra_priority = 100, 1618c2ecf20Sopenharmony_ci .cra_blocksize = GHASH_BLOCK_SIZE, 1628c2ecf20Sopenharmony_ci .cra_ctxsize = sizeof(struct ghash_ctx), 1638c2ecf20Sopenharmony_ci .cra_module = THIS_MODULE, 1648c2ecf20Sopenharmony_ci .cra_exit = ghash_exit_tfm, 1658c2ecf20Sopenharmony_ci }, 1668c2ecf20Sopenharmony_ci}; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int __init ghash_mod_init(void) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci return crypto_register_shash(&ghash_alg); 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void __exit ghash_mod_exit(void) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci crypto_unregister_shash(&ghash_alg); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cisubsys_initcall(ghash_mod_init); 1798c2ecf20Sopenharmony_cimodule_exit(ghash_mod_exit); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1828c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GHASH hash function"); 1838c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("ghash"); 1848c2ecf20Sopenharmony_ciMODULE_ALIAS_CRYPTO("ghash-generic"); 185