linux/crypto/ghash-generic.c
<<
>>
Prefs
   1/*
   2 * GHASH: digest algorithm for GCM (Galois/Counter Mode).
   3 *
   4 * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
   5 * Copyright (c) 2009 Intel Corp.
   6 *   Author: Huang Ying <ying.huang@intel.com>
   7 *
   8 * The algorithm implementation is copied from gcm.c.
   9 *
  10 * This program is free software; you can redistribute it and/or modify it
  11 * under the terms of the GNU General Public License version 2 as published
  12 * by the Free Software Foundation.
  13 */
  14
  15#include <crypto/algapi.h>
  16#include <crypto/gf128mul.h>
  17#include <crypto/internal/hash.h>
  18#include <linux/crypto.h>
  19#include <linux/init.h>
  20#include <linux/kernel.h>
  21#include <linux/module.h>
  22
  23#define GHASH_BLOCK_SIZE        16
  24#define GHASH_DIGEST_SIZE       16
  25
  26struct ghash_ctx {
  27        struct gf128mul_4k *gf128;
  28};
  29
  30struct ghash_desc_ctx {
  31        u8 buffer[GHASH_BLOCK_SIZE];
  32        u32 bytes;
  33};
  34
  35static int ghash_init(struct shash_desc *desc)
  36{
  37        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
  38
  39        memset(dctx, 0, sizeof(*dctx));
  40
  41        return 0;
  42}
  43
  44static int ghash_setkey(struct crypto_shash *tfm,
  45                        const u8 *key, unsigned int keylen)
  46{
  47        struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
  48
  49        if (keylen != GHASH_BLOCK_SIZE) {
  50                crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
  51                return -EINVAL;
  52        }
  53
  54        if (ctx->gf128)
  55                gf128mul_free_4k(ctx->gf128);
  56        ctx->gf128 = gf128mul_init_4k_lle((be128 *)key);
  57        if (!ctx->gf128)
  58                return -ENOMEM;
  59
  60        return 0;
  61}
  62
  63static int ghash_update(struct shash_desc *desc,
  64                         const u8 *src, unsigned int srclen)
  65{
  66        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
  67        struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
  68        u8 *dst = dctx->buffer;
  69
  70        if (dctx->bytes) {
  71                int n = min(srclen, dctx->bytes);
  72                u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
  73
  74                dctx->bytes -= n;
  75                srclen -= n;
  76
  77                while (n--)
  78                        *pos++ ^= *src++;
  79
  80                if (!dctx->bytes)
  81                        gf128mul_4k_lle((be128 *)dst, ctx->gf128);
  82        }
  83
  84        while (srclen >= GHASH_BLOCK_SIZE) {
  85                crypto_xor(dst, src, GHASH_BLOCK_SIZE);
  86                gf128mul_4k_lle((be128 *)dst, ctx->gf128);
  87                src += GHASH_BLOCK_SIZE;
  88                srclen -= GHASH_BLOCK_SIZE;
  89        }
  90
  91        if (srclen) {
  92                dctx->bytes = GHASH_BLOCK_SIZE - srclen;
  93                while (srclen--)
  94                        *dst++ ^= *src++;
  95        }
  96
  97        return 0;
  98}
  99
 100static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
 101{
 102        u8 *dst = dctx->buffer;
 103
 104        if (dctx->bytes) {
 105                u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
 106
 107                while (dctx->bytes--)
 108                        *tmp++ ^= 0;
 109
 110                gf128mul_4k_lle((be128 *)dst, ctx->gf128);
 111        }
 112
 113        dctx->bytes = 0;
 114}
 115
 116static int ghash_final(struct shash_desc *desc, u8 *dst)
 117{
 118        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 119        struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
 120        u8 *buf = dctx->buffer;
 121
 122        ghash_flush(ctx, dctx);
 123        memcpy(dst, buf, GHASH_BLOCK_SIZE);
 124
 125        return 0;
 126}
 127
 128static void ghash_exit_tfm(struct crypto_tfm *tfm)
 129{
 130        struct ghash_ctx *ctx = crypto_tfm_ctx(tfm);
 131        if (ctx->gf128)
 132                gf128mul_free_4k(ctx->gf128);
 133}
 134
 135static struct shash_alg ghash_alg = {
 136        .digestsize     = GHASH_DIGEST_SIZE,
 137        .init           = ghash_init,
 138        .update         = ghash_update,
 139        .final          = ghash_final,
 140        .setkey         = ghash_setkey,
 141        .descsize       = sizeof(struct ghash_desc_ctx),
 142        .base           = {
 143                .cra_name               = "ghash",
 144                .cra_driver_name        = "ghash-generic",
 145                .cra_priority           = 100,
 146                .cra_flags              = CRYPTO_ALG_TYPE_SHASH,
 147                .cra_blocksize          = GHASH_BLOCK_SIZE,
 148                .cra_ctxsize            = sizeof(struct ghash_ctx),
 149                .cra_module             = THIS_MODULE,
 150                .cra_list               = LIST_HEAD_INIT(ghash_alg.base.cra_list),
 151                .cra_exit               = ghash_exit_tfm,
 152        },
 153};
 154
 155static int __init ghash_mod_init(void)
 156{
 157        return crypto_register_shash(&ghash_alg);
 158}
 159
 160static void __exit ghash_mod_exit(void)
 161{
 162        crypto_unregister_shash(&ghash_alg);
 163}
 164
 165module_init(ghash_mod_init);
 166module_exit(ghash_mod_exit);
 167
 168MODULE_LICENSE("GPL");
 169MODULE_DESCRIPTION("GHASH Message Digest Algorithm");
 170MODULE_ALIAS("ghash");
 171