Path: blob/master/arch/x86/crypto/polyval-clmulni_glue.c
26424 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Glue code for POLYVAL using PCMULQDQ-NI3*4* Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <[email protected]>5* Copyright (c) 2009 Intel Corp.6* Author: Huang Ying <[email protected]>7* Copyright 2021 Google LLC8*/910/*11* Glue code based on ghash-clmulni-intel_glue.c.12*13* This implementation of POLYVAL uses montgomery multiplication14* accelerated by PCLMULQDQ-NI to implement the finite field15* operations.16*/1718#include <asm/cpu_device_id.h>19#include <asm/fpu/api.h>20#include <crypto/internal/hash.h>21#include <crypto/polyval.h>22#include <crypto/utils.h>23#include <linux/errno.h>24#include <linux/kernel.h>25#include <linux/module.h>26#include <linux/string.h>2728#define POLYVAL_ALIGN 1629#define POLYVAL_ALIGN_ATTR __aligned(POLYVAL_ALIGN)30#define POLYVAL_ALIGN_EXTRA ((POLYVAL_ALIGN - 1) & ~(CRYPTO_MINALIGN - 1))31#define POLYVAL_CTX_SIZE (sizeof(struct polyval_tfm_ctx) + POLYVAL_ALIGN_EXTRA)32#define NUM_KEY_POWERS 83334struct polyval_tfm_ctx {35/*36* These powers must be in the order h^8, ..., h^1.37*/38u8 key_powers[NUM_KEY_POWERS][POLYVAL_BLOCK_SIZE] POLYVAL_ALIGN_ATTR;39};4041struct polyval_desc_ctx {42u8 buffer[POLYVAL_BLOCK_SIZE];43};4445asmlinkage void clmul_polyval_update(const struct polyval_tfm_ctx *keys,46const u8 *in, size_t nblocks, u8 *accumulator);47asmlinkage void clmul_polyval_mul(u8 *op1, const u8 *op2);4849static inline struct polyval_tfm_ctx *polyval_tfm_ctx(struct crypto_shash *tfm)50{51return PTR_ALIGN(crypto_shash_ctx(tfm), POLYVAL_ALIGN);52}5354static void internal_polyval_update(const struct polyval_tfm_ctx *keys,55const u8 *in, size_t nblocks, u8 *accumulator)56{57kernel_fpu_begin();58clmul_polyval_update(keys, in, nblocks, accumulator);59kernel_fpu_end();60}6162static void internal_polyval_mul(u8 *op1, const u8 *op2)63{64kernel_fpu_begin();65clmul_polyval_mul(op1, op2);66kernel_fpu_end();67}6869static int polyval_x86_setkey(struct crypto_shash *tfm,70const u8 *key, unsigned int keylen)71{72struct polyval_tfm_ctx *tctx = polyval_tfm_ctx(tfm);73int i;7475if (keylen != POLYVAL_BLOCK_SIZE)76return -EINVAL;7778memcpy(tctx->key_powers[NUM_KEY_POWERS-1], key, POLYVAL_BLOCK_SIZE);7980for (i = NUM_KEY_POWERS-2; i >= 0; i--) {81memcpy(tctx->key_powers[i], key, POLYVAL_BLOCK_SIZE);82internal_polyval_mul(tctx->key_powers[i],83tctx->key_powers[i+1]);84}8586return 0;87}8889static int polyval_x86_init(struct shash_desc *desc)90{91struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);9293memset(dctx, 0, sizeof(*dctx));9495return 0;96}9798static int polyval_x86_update(struct shash_desc *desc,99const u8 *src, unsigned int srclen)100{101struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);102const struct polyval_tfm_ctx *tctx = polyval_tfm_ctx(desc->tfm);103unsigned int nblocks;104105do {106/* Allow rescheduling every 4K bytes. */107nblocks = min(srclen, 4096U) / POLYVAL_BLOCK_SIZE;108internal_polyval_update(tctx, src, nblocks, dctx->buffer);109srclen -= nblocks * POLYVAL_BLOCK_SIZE;110src += nblocks * POLYVAL_BLOCK_SIZE;111} while (srclen >= POLYVAL_BLOCK_SIZE);112113return srclen;114}115116static int polyval_x86_finup(struct shash_desc *desc, const u8 *src,117unsigned int len, u8 *dst)118{119struct polyval_desc_ctx *dctx = shash_desc_ctx(desc);120const struct polyval_tfm_ctx *tctx = polyval_tfm_ctx(desc->tfm);121122if (len) {123crypto_xor(dctx->buffer, src, len);124internal_polyval_mul(dctx->buffer,125tctx->key_powers[NUM_KEY_POWERS-1]);126}127128memcpy(dst, dctx->buffer, POLYVAL_BLOCK_SIZE);129130return 0;131}132133static struct shash_alg polyval_alg = {134.digestsize = POLYVAL_DIGEST_SIZE,135.init = polyval_x86_init,136.update = polyval_x86_update,137.finup = polyval_x86_finup,138.setkey = polyval_x86_setkey,139.descsize = sizeof(struct polyval_desc_ctx),140.base = {141.cra_name = "polyval",142.cra_driver_name = "polyval-clmulni",143.cra_priority = 200,144.cra_flags = CRYPTO_AHASH_ALG_BLOCK_ONLY,145.cra_blocksize = POLYVAL_BLOCK_SIZE,146.cra_ctxsize = POLYVAL_CTX_SIZE,147.cra_module = THIS_MODULE,148},149};150151__maybe_unused static const struct x86_cpu_id pcmul_cpu_id[] = {152X86_MATCH_FEATURE(X86_FEATURE_PCLMULQDQ, NULL),153{}154};155MODULE_DEVICE_TABLE(x86cpu, pcmul_cpu_id);156157static int __init polyval_clmulni_mod_init(void)158{159if (!x86_match_cpu(pcmul_cpu_id))160return -ENODEV;161162if (!boot_cpu_has(X86_FEATURE_AVX))163return -ENODEV;164165return crypto_register_shash(&polyval_alg);166}167168static void __exit polyval_clmulni_mod_exit(void)169{170crypto_unregister_shash(&polyval_alg);171}172173module_init(polyval_clmulni_mod_init);174module_exit(polyval_clmulni_mod_exit);175176MODULE_LICENSE("GPL");177MODULE_DESCRIPTION("POLYVAL hash function accelerated by PCLMULQDQ-NI");178MODULE_ALIAS_CRYPTO("polyval");179MODULE_ALIAS_CRYPTO("polyval-clmulni");180181182