Path: blob/master/arch/x86/crypto/ghash-clmulni-intel_glue.c
26424 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Accelerated GHASH implementation with Intel PCLMULQDQ-NI3* instructions. This file contains glue code.4*5* Copyright (c) 2009 Intel Corp.6* Author: Huang Ying <[email protected]>7*/89#include <asm/cpu_device_id.h>10#include <asm/simd.h>11#include <crypto/b128ops.h>12#include <crypto/ghash.h>13#include <crypto/internal/hash.h>14#include <crypto/utils.h>15#include <linux/errno.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/string.h>19#include <linux/unaligned.h>2021asmlinkage void clmul_ghash_mul(char *dst, const le128 *shash);2223asmlinkage int clmul_ghash_update(char *dst, const char *src,24unsigned int srclen, const le128 *shash);2526struct x86_ghash_ctx {27le128 shash;28};2930static int ghash_init(struct shash_desc *desc)31{32struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);3334memset(dctx, 0, sizeof(*dctx));3536return 0;37}3839static int ghash_setkey(struct crypto_shash *tfm,40const u8 *key, unsigned int keylen)41{42struct x86_ghash_ctx *ctx = crypto_shash_ctx(tfm);43u64 a, b;4445if (keylen != GHASH_BLOCK_SIZE)46return -EINVAL;4748/*49* GHASH maps bits to polynomial coefficients backwards, which makes it50* hard to implement. But it can be shown that the GHASH multiplication51*52* D * K (mod x^128 + x^7 + x^2 + x + 1)53*54* (where D is a data block and K is the key) is equivalent to:55*56* bitreflect(D) * bitreflect(K) * x^(-127)57* (mod x^128 + x^127 + x^126 + x^121 + 1)58*59* So, the code below precomputes:60*61* bitreflect(K) * x^(-127) (mod x^128 + x^127 + x^126 + x^121 + 1)62*63* ... but in Montgomery form (so that Montgomery multiplication can be64* used), i.e. with an extra x^128 factor, which means actually:65*66* bitreflect(K) * x (mod x^128 + x^127 + x^126 + x^121 + 1)67*68* The within-a-byte part of bitreflect() cancels out GHASH's built-in69* reflection, and thus bitreflect() is actually a byteswap.70*/71a = get_unaligned_be64(key);72b = get_unaligned_be64(key + 8);73ctx->shash.a = cpu_to_le64((a << 1) | (b >> 63));74ctx->shash.b = cpu_to_le64((b << 1) | (a >> 63));75if (a >> 63)76ctx->shash.a ^= cpu_to_le64((u64)0xc2 << 56);77return 0;78}7980static int ghash_update(struct shash_desc *desc,81const u8 *src, unsigned int srclen)82{83struct x86_ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);84struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);85u8 *dst = dctx->buffer;86int remain;8788kernel_fpu_begin();89remain = clmul_ghash_update(dst, src, srclen, &ctx->shash);90kernel_fpu_end();91return remain;92}9394static void ghash_flush(struct x86_ghash_ctx *ctx, struct ghash_desc_ctx *dctx,95const u8 *src, unsigned int len)96{97u8 *dst = dctx->buffer;9899kernel_fpu_begin();100if (len) {101crypto_xor(dst, src, len);102clmul_ghash_mul(dst, &ctx->shash);103}104kernel_fpu_end();105}106107static int ghash_finup(struct shash_desc *desc, const u8 *src,108unsigned int len, u8 *dst)109{110struct x86_ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);111struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);112u8 *buf = dctx->buffer;113114ghash_flush(ctx, dctx, src, len);115memcpy(dst, buf, GHASH_BLOCK_SIZE);116117return 0;118}119120static struct shash_alg ghash_alg = {121.digestsize = GHASH_DIGEST_SIZE,122.init = ghash_init,123.update = ghash_update,124.finup = ghash_finup,125.setkey = ghash_setkey,126.descsize = sizeof(struct ghash_desc_ctx),127.base = {128.cra_name = "ghash",129.cra_driver_name = "ghash-pclmulqdqni",130.cra_priority = 400,131.cra_flags = CRYPTO_AHASH_ALG_BLOCK_ONLY,132.cra_blocksize = GHASH_BLOCK_SIZE,133.cra_ctxsize = sizeof(struct x86_ghash_ctx),134.cra_module = THIS_MODULE,135},136};137138static const struct x86_cpu_id pcmul_cpu_id[] = {139X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL), /* Pickle-Mickle-Duck */140{}141};142MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);143144static int __init ghash_pclmulqdqni_mod_init(void)145{146if (!x86_match_cpu(pcmul_cpu_id))147return -ENODEV;148149return crypto_register_shash(&ghash_alg);150}151152static void __exit ghash_pclmulqdqni_mod_exit(void)153{154crypto_unregister_shash(&ghash_alg);155}156157module_init(ghash_pclmulqdqni_mod_init);158module_exit(ghash_pclmulqdqni_mod_exit);159160MODULE_LICENSE("GPL");161MODULE_DESCRIPTION("GHASH hash function, accelerated by PCLMULQDQ-NI");162MODULE_ALIAS_CRYPTO("ghash");163164165