Path: blob/master/arch/x86/crypto/ghash-clmulni-intel_glue.c
10817 views
/*1* Accelerated GHASH implementation with Intel PCLMULQDQ-NI2* instructions. This file contains glue code.3*4* Copyright (c) 2009 Intel Corp.5* Author: Huang Ying <[email protected]>6*7* This program is free software; you can redistribute it and/or modify it8* under the terms of the GNU General Public License version 2 as published9* by the Free Software Foundation.10*/1112#include <linux/err.h>13#include <linux/module.h>14#include <linux/init.h>15#include <linux/kernel.h>16#include <linux/crypto.h>17#include <crypto/algapi.h>18#include <crypto/cryptd.h>19#include <crypto/gf128mul.h>20#include <crypto/internal/hash.h>21#include <asm/i387.h>2223#define GHASH_BLOCK_SIZE 1624#define GHASH_DIGEST_SIZE 162526void clmul_ghash_mul(char *dst, const be128 *shash);2728void clmul_ghash_update(char *dst, const char *src, unsigned int srclen,29const be128 *shash);3031void clmul_ghash_setkey(be128 *shash, const u8 *key);3233struct ghash_async_ctx {34struct cryptd_ahash *cryptd_tfm;35};3637struct ghash_ctx {38be128 shash;39};4041struct ghash_desc_ctx {42u8 buffer[GHASH_BLOCK_SIZE];43u32 bytes;44};4546static int ghash_init(struct shash_desc *desc)47{48struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);4950memset(dctx, 0, sizeof(*dctx));5152return 0;53}5455static int ghash_setkey(struct crypto_shash *tfm,56const u8 *key, unsigned int keylen)57{58struct ghash_ctx *ctx = crypto_shash_ctx(tfm);5960if (keylen != GHASH_BLOCK_SIZE) {61crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);62return -EINVAL;63}6465clmul_ghash_setkey(&ctx->shash, key);6667return 0;68}6970static int ghash_update(struct shash_desc *desc,71const u8 *src, unsigned int srclen)72{73struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);74struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);75u8 *dst = dctx->buffer;7677kernel_fpu_begin();78if (dctx->bytes) {79int n = min(srclen, dctx->bytes);80u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);8182dctx->bytes -= n;83srclen -= n;8485while (n--)86*pos++ ^= *src++;8788if (!dctx->bytes)89clmul_ghash_mul(dst, &ctx->shash);90}9192clmul_ghash_update(dst, src, srclen, &ctx->shash);93kernel_fpu_end();9495if (srclen & 0xf) {96src += srclen - (srclen & 0xf);97srclen &= 0xf;98dctx->bytes = GHASH_BLOCK_SIZE - srclen;99while (srclen--)100*dst++ ^= *src++;101}102103return 0;104}105106static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)107{108u8 *dst = dctx->buffer;109110if (dctx->bytes) {111u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);112113while (dctx->bytes--)114*tmp++ ^= 0;115116kernel_fpu_begin();117clmul_ghash_mul(dst, &ctx->shash);118kernel_fpu_end();119}120121dctx->bytes = 0;122}123124static int ghash_final(struct shash_desc *desc, u8 *dst)125{126struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);127struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);128u8 *buf = dctx->buffer;129130ghash_flush(ctx, dctx);131memcpy(dst, buf, GHASH_BLOCK_SIZE);132133return 0;134}135136static struct shash_alg ghash_alg = {137.digestsize = GHASH_DIGEST_SIZE,138.init = ghash_init,139.update = ghash_update,140.final = ghash_final,141.setkey = ghash_setkey,142.descsize = sizeof(struct ghash_desc_ctx),143.base = {144.cra_name = "__ghash",145.cra_driver_name = "__ghash-pclmulqdqni",146.cra_priority = 0,147.cra_flags = CRYPTO_ALG_TYPE_SHASH,148.cra_blocksize = GHASH_BLOCK_SIZE,149.cra_ctxsize = sizeof(struct ghash_ctx),150.cra_module = THIS_MODULE,151.cra_list = LIST_HEAD_INIT(ghash_alg.base.cra_list),152},153};154155static int ghash_async_init(struct ahash_request *req)156{157struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);158struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);159struct ahash_request *cryptd_req = ahash_request_ctx(req);160struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;161162if (!irq_fpu_usable()) {163memcpy(cryptd_req, req, sizeof(*req));164ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);165return crypto_ahash_init(cryptd_req);166} else {167struct shash_desc *desc = cryptd_shash_desc(cryptd_req);168struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);169170desc->tfm = child;171desc->flags = req->base.flags;172return crypto_shash_init(desc);173}174}175176static int ghash_async_update(struct ahash_request *req)177{178struct ahash_request *cryptd_req = ahash_request_ctx(req);179180if (!irq_fpu_usable()) {181struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);182struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);183struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;184185memcpy(cryptd_req, req, sizeof(*req));186ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);187return crypto_ahash_update(cryptd_req);188} else {189struct shash_desc *desc = cryptd_shash_desc(cryptd_req);190return shash_ahash_update(req, desc);191}192}193194static int ghash_async_final(struct ahash_request *req)195{196struct ahash_request *cryptd_req = ahash_request_ctx(req);197198if (!irq_fpu_usable()) {199struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);200struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);201struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;202203memcpy(cryptd_req, req, sizeof(*req));204ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);205return crypto_ahash_final(cryptd_req);206} else {207struct shash_desc *desc = cryptd_shash_desc(cryptd_req);208return crypto_shash_final(desc, req->result);209}210}211212static int ghash_async_digest(struct ahash_request *req)213{214struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);215struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);216struct ahash_request *cryptd_req = ahash_request_ctx(req);217struct cryptd_ahash *cryptd_tfm = ctx->cryptd_tfm;218219if (!irq_fpu_usable()) {220memcpy(cryptd_req, req, sizeof(*req));221ahash_request_set_tfm(cryptd_req, &cryptd_tfm->base);222return crypto_ahash_digest(cryptd_req);223} else {224struct shash_desc *desc = cryptd_shash_desc(cryptd_req);225struct crypto_shash *child = cryptd_ahash_child(cryptd_tfm);226227desc->tfm = child;228desc->flags = req->base.flags;229return shash_ahash_digest(req, desc);230}231}232233static int ghash_async_setkey(struct crypto_ahash *tfm, const u8 *key,234unsigned int keylen)235{236struct ghash_async_ctx *ctx = crypto_ahash_ctx(tfm);237struct crypto_ahash *child = &ctx->cryptd_tfm->base;238int err;239240crypto_ahash_clear_flags(child, CRYPTO_TFM_REQ_MASK);241crypto_ahash_set_flags(child, crypto_ahash_get_flags(tfm)242& CRYPTO_TFM_REQ_MASK);243err = crypto_ahash_setkey(child, key, keylen);244crypto_ahash_set_flags(tfm, crypto_ahash_get_flags(child)245& CRYPTO_TFM_RES_MASK);246247return 0;248}249250static int ghash_async_init_tfm(struct crypto_tfm *tfm)251{252struct cryptd_ahash *cryptd_tfm;253struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);254255cryptd_tfm = cryptd_alloc_ahash("__ghash-pclmulqdqni", 0, 0);256if (IS_ERR(cryptd_tfm))257return PTR_ERR(cryptd_tfm);258ctx->cryptd_tfm = cryptd_tfm;259crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),260sizeof(struct ahash_request) +261crypto_ahash_reqsize(&cryptd_tfm->base));262263return 0;264}265266static void ghash_async_exit_tfm(struct crypto_tfm *tfm)267{268struct ghash_async_ctx *ctx = crypto_tfm_ctx(tfm);269270cryptd_free_ahash(ctx->cryptd_tfm);271}272273static struct ahash_alg ghash_async_alg = {274.init = ghash_async_init,275.update = ghash_async_update,276.final = ghash_async_final,277.setkey = ghash_async_setkey,278.digest = ghash_async_digest,279.halg = {280.digestsize = GHASH_DIGEST_SIZE,281.base = {282.cra_name = "ghash",283.cra_driver_name = "ghash-clmulni",284.cra_priority = 400,285.cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,286.cra_blocksize = GHASH_BLOCK_SIZE,287.cra_type = &crypto_ahash_type,288.cra_module = THIS_MODULE,289.cra_list = LIST_HEAD_INIT(ghash_async_alg.halg.base.cra_list),290.cra_init = ghash_async_init_tfm,291.cra_exit = ghash_async_exit_tfm,292},293},294};295296static int __init ghash_pclmulqdqni_mod_init(void)297{298int err;299300if (!cpu_has_pclmulqdq) {301printk(KERN_INFO "Intel PCLMULQDQ-NI instructions are not"302" detected.\n");303return -ENODEV;304}305306err = crypto_register_shash(&ghash_alg);307if (err)308goto err_out;309err = crypto_register_ahash(&ghash_async_alg);310if (err)311goto err_shash;312313return 0;314315err_shash:316crypto_unregister_shash(&ghash_alg);317err_out:318return err;319}320321static void __exit ghash_pclmulqdqni_mod_exit(void)322{323crypto_unregister_ahash(&ghash_async_alg);324crypto_unregister_shash(&ghash_alg);325}326327module_init(ghash_pclmulqdqni_mod_init);328module_exit(ghash_pclmulqdqni_mod_exit);329330MODULE_LICENSE("GPL");331MODULE_DESCRIPTION("GHASH Message Digest Algorithm, "332"acclerated by PCLMULQDQ-NI");333MODULE_ALIAS("ghash");334335336