// SPDX-License-Identifier: GPL-2.0-only
/*
* Accelerated GHASH implementation with Intel PCLMULQDQ - NI
* instructions . This file contains glue code .
*
* Copyright ( c ) 2009 Intel Corp .
* Author : Huang Ying < ying . huang @ intel . com >
*/
#include <asm /cpu_device_id.h>
#include <asm /simd.h>
#include <crypto/b128ops.h>
#include <crypto/ghash.h>
#include <crypto/internal/hash.h>
#include <crypto/utils.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/unaligned.h>
asmlinkage void clmul_ghash_mul(char *dst, const le128 *shash);
asmlinkage int clmul_ghash_update(char *dst, const char *src,
unsigned int srclen, const le128 *shash);
struct x86_ghash_ctx {
le128 shash;
};
static int ghash_init(struct shash_desc *desc)
{
struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
memset(dctx, 0 , sizeof (*dctx));
return 0 ;
}
static int ghash_setkey(struct crypto_shash *tfm,
const u8 *key, unsigned int keylen)
{
struct x86_ghash_ctx *ctx = crypto_shash_ctx(tfm);
u64 a, b;
if (keylen != GHASH_BLOCK_SIZE)
return -EINVAL;
/*
* GHASH maps bits to polynomial coefficients backwards , which makes it
* hard to implement . But it can be shown that the GHASH multiplication
*
* D * K ( mod x ^ 128 + x ^ 7 + x ^ 2 + x + 1 )
*
* ( where D is a data block and K is the key ) is equivalent to :
*
* bitreflect ( D ) * bitreflect ( K ) * x ^ ( - 127 )
* ( mod x ^ 128 + x ^ 127 + x ^ 126 + x ^ 121 + 1 )
*
* So , the code below precomputes :
*
* bitreflect ( K ) * x ^ ( - 127 ) ( mod x ^ 128 + x ^ 127 + x ^ 126 + x ^ 121 + 1 )
*
* . . . but in Montgomery form ( so that Montgomery multiplication can be
* used ) , i . e . with an extra x ^ 128 factor , which means actually :
*
* bitreflect ( K ) * x ( mod x ^ 128 + x ^ 127 + x ^ 126 + x ^ 121 + 1 )
*
* The within - a - byte part of bitreflect ( ) cancels out GHASH ' s built - in
* reflection , and thus bitreflect ( ) is actually a byteswap .
*/
a = get_unaligned_be64(key);
b = get_unaligned_be64(key + 8 );
ctx->shash.a = cpu_to_le64((a << 1 ) | (b >> 63 ));
ctx->shash.b = cpu_to_le64((b << 1 ) | (a >> 63 ));
if (a >> 63 )
ctx->shash.a ^= cpu_to_le64((u64)0 xc2 << 56 );
return 0 ;
}
static int ghash_update(struct shash_desc *desc,
const u8 *src, unsigned int srclen)
{
struct x86_ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
u8 *dst = dctx->buffer;
int remain;
kernel_fpu_begin();
remain = clmul_ghash_update(dst, src, srclen, &ctx->shash);
kernel_fpu_end();
return remain;
}
static void ghash_flush(struct x86_ghash_ctx *ctx, struct ghash_desc_ctx *dctx,
const u8 *src, unsigned int len)
{
u8 *dst = dctx->buffer;
kernel_fpu_begin();
if (len) {
crypto_xor(dst, src, len);
clmul_ghash_mul(dst, &ctx->shash);
}
kernel_fpu_end();
}
static int ghash_finup(struct shash_desc *desc, const u8 *src,
unsigned int len, u8 *dst)
{
struct x86_ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
u8 *buf = dctx->buffer;
ghash_flush(ctx, dctx, src, len);
memcpy(dst, buf, GHASH_BLOCK_SIZE);
return 0 ;
}
static struct shash_alg ghash_alg = {
.digestsize = GHASH_DIGEST_SIZE,
.init = ghash_init,
.update = ghash_update,
.finup = ghash_finup,
.setkey = ghash_setkey,
.descsize = sizeof (struct ghash_desc_ctx),
.base = {
.cra_name = "ghash" ,
.cra_driver_name = "ghash-pclmulqdqni" ,
.cra_priority = 400 ,
.cra_flags = CRYPTO_AHASH_ALG_BLOCK_ONLY,
.cra_blocksize = GHASH_BLOCK_SIZE,
.cra_ctxsize = sizeof (struct x86_ghash_ctx),
.cra_module = THIS_MODULE,
},
};
static const struct x86_cpu_id pcmul_cpu_id[] = {
X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL), /* Pickle-Mickle-Duck */
{}
};
MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);
static int __init ghash_pclmulqdqni_mod_init(void )
{
if (!x86_match_cpu(pcmul_cpu_id))
return -ENODEV;
return crypto_register_shash(&ghash_alg);
}
static void __exit ghash_pclmulqdqni_mod_exit(void )
{
crypto_unregister_shash(&ghash_alg);
}
module_init(ghash_pclmulqdqni_mod_init);
module_exit(ghash_pclmulqdqni_mod_exit);
MODULE_LICENSE("GPL" );
MODULE_DESCRIPTION("GHASH hash function, accelerated by PCLMULQDQ-NI" );
MODULE_ALIAS_CRYPTO("ghash" );
Messung V0.5 in Prozent C=98 H=95 G=96
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-09-28)
¤
*© Formatika GbR, Deutschland