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 (!ctx->gf128)
  71                return -ENOKEY;
  72
  73        if (dctx->bytes) {
  74                int n = min(srclen, dctx->bytes);
  75                u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
  76
  77                dctx->bytes -= n;
  78                srclen -= n;
  79
  80                while (n--)
  81                        *pos++ ^= *src++;
  82
  83                if (!dctx->bytes)
  84                        gf128mul_4k_lle((be128 *)dst, ctx->gf128);
  85        }
  86
  87        while (srclen >= GHASH_BLOCK_SIZE) {
  88                crypto_xor(dst, src, GHASH_BLOCK_SIZE);
  89                gf128mul_4k_lle((be128 *)dst, ctx->gf128);
  90                src += GHASH_BLOCK_SIZE;
  91                srclen -= GHASH_BLOCK_SIZE;
  92        }
  93
  94        if (srclen) {
  95                dctx->bytes = GHASH_BLOCK_SIZE - srclen;
  96                while (srclen--)
  97                        *dst++ ^= *src++;
  98        }
  99
 100        return 0;
 101}
 102
 103static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
 104{
 105        u8 *dst = dctx->buffer;
 106
 107        if (dctx->bytes) {
 108                u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
 109
 110                while (dctx->bytes--)
 111                        *tmp++ ^= 0;
 112
 113                gf128mul_4k_lle((be128 *)dst, ctx->gf128);
 114        }
 115
 116        dctx->bytes = 0;
 117}
 118
 119static int ghash_final(struct shash_desc *desc, u8 *dst)
 120{
 121        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 122        struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
 123        u8 *buf = dctx->buffer;
 124
 125        if (!ctx->gf128)
 126                return -ENOKEY;
 127
 128        ghash_flush(ctx, dctx);
 129        memcpy(dst, buf, GHASH_BLOCK_SIZE);
 130
 131        return 0;
 132}
 133
 134static void ghash_exit_tfm(struct crypto_tfm *tfm)
 135{
 136        struct ghash_ctx *ctx = crypto_tfm_ctx(tfm);
 137        if (ctx->gf128)
 138                gf128mul_free_4k(ctx->gf128);
 139}
 140
 141static struct shash_alg ghash_alg = {
 142        .digestsize     = GHASH_DIGEST_SIZE,
 143        .init           = ghash_init,
 144        .update         = ghash_update,
 145        .final          = ghash_final,
 146        .setkey         = ghash_setkey,
 147        .descsize       = sizeof(struct ghash_desc_ctx),
 148        .base           = {
 149                .cra_name               = "ghash",
 150                .cra_driver_name        = "ghash-generic",
 151                .cra_priority           = 100,
 152                .cra_flags              = CRYPTO_ALG_TYPE_SHASH,
 153                .cra_blocksize          = GHASH_BLOCK_SIZE,
 154                .cra_ctxsize            = sizeof(struct ghash_ctx),
 155                .cra_module             = THIS_MODULE,
 156                .cra_exit               = ghash_exit_tfm,
 157        },
 158};
 159
 160static int __init ghash_mod_init(void)
 161{
 162        return crypto_register_shash(&ghash_alg);
 163}
 164
 165static void __exit ghash_mod_exit(void)
 166{
 167        crypto_unregister_shash(&ghash_alg);
 168}
 169
 170module_init(ghash_mod_init);
 171module_exit(ghash_mod_exit);
 172
 173MODULE_LICENSE("GPL");
 174MODULE_DESCRIPTION("GHASH Message Digest Algorithm");
 175MODULE_ALIAS("ghash");
 176