mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

Use the Crypto API partial block handling. Also remove the unnecessary SIMD fallback path. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
163 lines
4.2 KiB
C
163 lines
4.2 KiB
C
// 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)0xc2 << 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");
|