12cdc6899SHuang Ying /* 22cdc6899SHuang Ying * GHASH: digest algorithm for GCM (Galois/Counter Mode). 32cdc6899SHuang Ying * 42cdc6899SHuang Ying * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi> 52cdc6899SHuang Ying * Copyright (c) 2009 Intel Corp. 62cdc6899SHuang Ying * Author: Huang Ying <ying.huang@intel.com> 72cdc6899SHuang Ying * 82cdc6899SHuang Ying * The algorithm implementation is copied from gcm.c. 92cdc6899SHuang Ying * 102cdc6899SHuang Ying * This program is free software; you can redistribute it and/or modify it 112cdc6899SHuang Ying * under the terms of the GNU General Public License version 2 as published 122cdc6899SHuang Ying * by the Free Software Foundation. 132cdc6899SHuang Ying */ 142cdc6899SHuang Ying 152cdc6899SHuang Ying #include <crypto/algapi.h> 162cdc6899SHuang Ying #include <crypto/gf128mul.h> 172cdc6899SHuang Ying #include <crypto/internal/hash.h> 182cdc6899SHuang Ying #include <linux/crypto.h> 192cdc6899SHuang Ying #include <linux/init.h> 202cdc6899SHuang Ying #include <linux/kernel.h> 212cdc6899SHuang Ying #include <linux/module.h> 222cdc6899SHuang Ying 232cdc6899SHuang Ying #define GHASH_BLOCK_SIZE 16 242cdc6899SHuang Ying #define GHASH_DIGEST_SIZE 16 252cdc6899SHuang Ying 262cdc6899SHuang Ying struct ghash_ctx { 272cdc6899SHuang Ying struct gf128mul_4k *gf128; 282cdc6899SHuang Ying }; 292cdc6899SHuang Ying 302cdc6899SHuang Ying struct ghash_desc_ctx { 312cdc6899SHuang Ying u8 buffer[GHASH_BLOCK_SIZE]; 322cdc6899SHuang Ying u32 bytes; 332cdc6899SHuang Ying }; 342cdc6899SHuang Ying 352cdc6899SHuang Ying static int ghash_init(struct shash_desc *desc) 362cdc6899SHuang Ying { 372cdc6899SHuang Ying struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 382cdc6899SHuang Ying 392cdc6899SHuang Ying memset(dctx, 0, sizeof(*dctx)); 402cdc6899SHuang Ying 412cdc6899SHuang Ying return 0; 422cdc6899SHuang Ying } 432cdc6899SHuang Ying 442cdc6899SHuang Ying static int ghash_setkey(struct crypto_shash *tfm, 452cdc6899SHuang Ying const u8 *key, unsigned int keylen) 462cdc6899SHuang Ying { 472cdc6899SHuang Ying struct ghash_ctx *ctx = crypto_shash_ctx(tfm); 482cdc6899SHuang Ying 492cdc6899SHuang Ying if (keylen != GHASH_BLOCK_SIZE) { 502cdc6899SHuang Ying crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); 512cdc6899SHuang Ying return -EINVAL; 522cdc6899SHuang Ying } 532cdc6899SHuang Ying 542cdc6899SHuang Ying if (ctx->gf128) 552cdc6899SHuang Ying gf128mul_free_4k(ctx->gf128); 562cdc6899SHuang Ying ctx->gf128 = gf128mul_init_4k_lle((be128 *)key); 572cdc6899SHuang Ying if (!ctx->gf128) 582cdc6899SHuang Ying return -ENOMEM; 592cdc6899SHuang Ying 602cdc6899SHuang Ying return 0; 612cdc6899SHuang Ying } 622cdc6899SHuang Ying 632cdc6899SHuang Ying static int ghash_update(struct shash_desc *desc, 642cdc6899SHuang Ying const u8 *src, unsigned int srclen) 652cdc6899SHuang Ying { 662cdc6899SHuang Ying struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 672cdc6899SHuang Ying struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); 682cdc6899SHuang Ying u8 *dst = dctx->buffer; 692cdc6899SHuang Ying 707ed47b7dSNick Bowler if (!ctx->gf128) 717ed47b7dSNick Bowler return -ENOKEY; 727ed47b7dSNick Bowler 732cdc6899SHuang Ying if (dctx->bytes) { 742cdc6899SHuang Ying int n = min(srclen, dctx->bytes); 752cdc6899SHuang Ying u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes); 762cdc6899SHuang Ying 772cdc6899SHuang Ying dctx->bytes -= n; 782cdc6899SHuang Ying srclen -= n; 792cdc6899SHuang Ying 802cdc6899SHuang Ying while (n--) 812cdc6899SHuang Ying *pos++ ^= *src++; 822cdc6899SHuang Ying 832cdc6899SHuang Ying if (!dctx->bytes) 842cdc6899SHuang Ying gf128mul_4k_lle((be128 *)dst, ctx->gf128); 852cdc6899SHuang Ying } 862cdc6899SHuang Ying 872cdc6899SHuang Ying while (srclen >= GHASH_BLOCK_SIZE) { 882cdc6899SHuang Ying crypto_xor(dst, src, GHASH_BLOCK_SIZE); 892cdc6899SHuang Ying gf128mul_4k_lle((be128 *)dst, ctx->gf128); 902cdc6899SHuang Ying src += GHASH_BLOCK_SIZE; 912cdc6899SHuang Ying srclen -= GHASH_BLOCK_SIZE; 922cdc6899SHuang Ying } 932cdc6899SHuang Ying 942cdc6899SHuang Ying if (srclen) { 952cdc6899SHuang Ying dctx->bytes = GHASH_BLOCK_SIZE - srclen; 962cdc6899SHuang Ying while (srclen--) 972cdc6899SHuang Ying *dst++ ^= *src++; 982cdc6899SHuang Ying } 992cdc6899SHuang Ying 1002cdc6899SHuang Ying return 0; 1012cdc6899SHuang Ying } 1022cdc6899SHuang Ying 1032cdc6899SHuang Ying static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx) 1042cdc6899SHuang Ying { 1052cdc6899SHuang Ying u8 *dst = dctx->buffer; 1062cdc6899SHuang Ying 1072cdc6899SHuang Ying if (dctx->bytes) { 1082cdc6899SHuang Ying u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes); 1092cdc6899SHuang Ying 1102cdc6899SHuang Ying while (dctx->bytes--) 1112cdc6899SHuang Ying *tmp++ ^= 0; 1122cdc6899SHuang Ying 1132cdc6899SHuang Ying gf128mul_4k_lle((be128 *)dst, ctx->gf128); 1142cdc6899SHuang Ying } 1152cdc6899SHuang Ying 1162cdc6899SHuang Ying dctx->bytes = 0; 1172cdc6899SHuang Ying } 1182cdc6899SHuang Ying 1192cdc6899SHuang Ying static int ghash_final(struct shash_desc *desc, u8 *dst) 1202cdc6899SHuang Ying { 1212cdc6899SHuang Ying struct ghash_desc_ctx *dctx = shash_desc_ctx(desc); 1222cdc6899SHuang Ying struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm); 1232cdc6899SHuang Ying u8 *buf = dctx->buffer; 1242cdc6899SHuang Ying 1257ed47b7dSNick Bowler if (!ctx->gf128) 1267ed47b7dSNick Bowler return -ENOKEY; 1277ed47b7dSNick Bowler 1282cdc6899SHuang Ying ghash_flush(ctx, dctx); 1292cdc6899SHuang Ying memcpy(dst, buf, GHASH_BLOCK_SIZE); 1302cdc6899SHuang Ying 1312cdc6899SHuang Ying return 0; 1322cdc6899SHuang Ying } 1332cdc6899SHuang Ying 1342cdc6899SHuang Ying static void ghash_exit_tfm(struct crypto_tfm *tfm) 1352cdc6899SHuang Ying { 1362cdc6899SHuang Ying struct ghash_ctx *ctx = crypto_tfm_ctx(tfm); 1372cdc6899SHuang Ying if (ctx->gf128) 1382cdc6899SHuang Ying gf128mul_free_4k(ctx->gf128); 1392cdc6899SHuang Ying } 1402cdc6899SHuang Ying 1412cdc6899SHuang Ying static struct shash_alg ghash_alg = { 1422cdc6899SHuang Ying .digestsize = GHASH_DIGEST_SIZE, 1432cdc6899SHuang Ying .init = ghash_init, 1442cdc6899SHuang Ying .update = ghash_update, 1452cdc6899SHuang Ying .final = ghash_final, 1462cdc6899SHuang Ying .setkey = ghash_setkey, 1472cdc6899SHuang Ying .descsize = sizeof(struct ghash_desc_ctx), 1482cdc6899SHuang Ying .base = { 1492cdc6899SHuang Ying .cra_name = "ghash", 1502cdc6899SHuang Ying .cra_driver_name = "ghash-generic", 1512cdc6899SHuang Ying .cra_priority = 100, 1522cdc6899SHuang Ying .cra_flags = CRYPTO_ALG_TYPE_SHASH, 1532cdc6899SHuang Ying .cra_blocksize = GHASH_BLOCK_SIZE, 1542cdc6899SHuang Ying .cra_ctxsize = sizeof(struct ghash_ctx), 1552cdc6899SHuang Ying .cra_module = THIS_MODULE, 1562cdc6899SHuang Ying .cra_exit = ghash_exit_tfm, 1572cdc6899SHuang Ying }, 1582cdc6899SHuang Ying }; 1592cdc6899SHuang Ying 1602cdc6899SHuang Ying static int __init ghash_mod_init(void) 1612cdc6899SHuang Ying { 1622cdc6899SHuang Ying return crypto_register_shash(&ghash_alg); 1632cdc6899SHuang Ying } 1642cdc6899SHuang Ying 1652cdc6899SHuang Ying static void __exit ghash_mod_exit(void) 1662cdc6899SHuang Ying { 1672cdc6899SHuang Ying crypto_unregister_shash(&ghash_alg); 1682cdc6899SHuang Ying } 1692cdc6899SHuang Ying 1702cdc6899SHuang Ying module_init(ghash_mod_init); 1712cdc6899SHuang Ying module_exit(ghash_mod_exit); 1722cdc6899SHuang Ying 1732cdc6899SHuang Ying MODULE_LICENSE("GPL"); 1742cdc6899SHuang Ying MODULE_DESCRIPTION("GHASH Message Digest Algorithm"); 1755d26a105SKees Cook MODULE_ALIAS_CRYPTO("ghash"); 1763e14dcf7SMathias Krause MODULE_ALIAS_CRYPTO("ghash-generic"); 177