Back to home page

LXR

 
 

    


0001 /*
0002  * GHASH: digest algorithm for GCM (Galois/Counter Mode).
0003  *
0004  * Copyright (c) 2007 Nokia Siemens Networks - Mikko Herranen <mh1@iki.fi>
0005  * Copyright (c) 2009 Intel Corp.
0006  *   Author: Huang Ying <ying.huang@intel.com>
0007  *
0008  * The algorithm implementation is copied from gcm.c.
0009  *
0010  * This program is free software; you can redistribute it and/or modify it
0011  * under the terms of the GNU General Public License version 2 as published
0012  * by the Free Software Foundation.
0013  */
0014 
0015 #include <crypto/algapi.h>
0016 #include <crypto/gf128mul.h>
0017 #include <crypto/ghash.h>
0018 #include <crypto/internal/hash.h>
0019 #include <linux/crypto.h>
0020 #include <linux/init.h>
0021 #include <linux/kernel.h>
0022 #include <linux/module.h>
0023 
0024 static int ghash_init(struct shash_desc *desc)
0025 {
0026     struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
0027 
0028     memset(dctx, 0, sizeof(*dctx));
0029 
0030     return 0;
0031 }
0032 
0033 static int ghash_setkey(struct crypto_shash *tfm,
0034             const u8 *key, unsigned int keylen)
0035 {
0036     struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
0037 
0038     if (keylen != GHASH_BLOCK_SIZE) {
0039         crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
0040         return -EINVAL;
0041     }
0042 
0043     if (ctx->gf128)
0044         gf128mul_free_4k(ctx->gf128);
0045     ctx->gf128 = gf128mul_init_4k_lle((be128 *)key);
0046     if (!ctx->gf128)
0047         return -ENOMEM;
0048 
0049     return 0;
0050 }
0051 
0052 static int ghash_update(struct shash_desc *desc,
0053              const u8 *src, unsigned int srclen)
0054 {
0055     struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
0056     struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
0057     u8 *dst = dctx->buffer;
0058 
0059     if (!ctx->gf128)
0060         return -ENOKEY;
0061 
0062     if (dctx->bytes) {
0063         int n = min(srclen, dctx->bytes);
0064         u8 *pos = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
0065 
0066         dctx->bytes -= n;
0067         srclen -= n;
0068 
0069         while (n--)
0070             *pos++ ^= *src++;
0071 
0072         if (!dctx->bytes)
0073             gf128mul_4k_lle((be128 *)dst, ctx->gf128);
0074     }
0075 
0076     while (srclen >= GHASH_BLOCK_SIZE) {
0077         crypto_xor(dst, src, GHASH_BLOCK_SIZE);
0078         gf128mul_4k_lle((be128 *)dst, ctx->gf128);
0079         src += GHASH_BLOCK_SIZE;
0080         srclen -= GHASH_BLOCK_SIZE;
0081     }
0082 
0083     if (srclen) {
0084         dctx->bytes = GHASH_BLOCK_SIZE - srclen;
0085         while (srclen--)
0086             *dst++ ^= *src++;
0087     }
0088 
0089     return 0;
0090 }
0091 
0092 static void ghash_flush(struct ghash_ctx *ctx, struct ghash_desc_ctx *dctx)
0093 {
0094     u8 *dst = dctx->buffer;
0095 
0096     if (dctx->bytes) {
0097         u8 *tmp = dst + (GHASH_BLOCK_SIZE - dctx->bytes);
0098 
0099         while (dctx->bytes--)
0100             *tmp++ ^= 0;
0101 
0102         gf128mul_4k_lle((be128 *)dst, ctx->gf128);
0103     }
0104 
0105     dctx->bytes = 0;
0106 }
0107 
0108 static int ghash_final(struct shash_desc *desc, u8 *dst)
0109 {
0110     struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
0111     struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
0112     u8 *buf = dctx->buffer;
0113 
0114     if (!ctx->gf128)
0115         return -ENOKEY;
0116 
0117     ghash_flush(ctx, dctx);
0118     memcpy(dst, buf, GHASH_BLOCK_SIZE);
0119 
0120     return 0;
0121 }
0122 
0123 static void ghash_exit_tfm(struct crypto_tfm *tfm)
0124 {
0125     struct ghash_ctx *ctx = crypto_tfm_ctx(tfm);
0126     if (ctx->gf128)
0127         gf128mul_free_4k(ctx->gf128);
0128 }
0129 
0130 static struct shash_alg ghash_alg = {
0131     .digestsize = GHASH_DIGEST_SIZE,
0132     .init       = ghash_init,
0133     .update     = ghash_update,
0134     .final      = ghash_final,
0135     .setkey     = ghash_setkey,
0136     .descsize   = sizeof(struct ghash_desc_ctx),
0137     .base       = {
0138         .cra_name       = "ghash",
0139         .cra_driver_name    = "ghash-generic",
0140         .cra_priority       = 100,
0141         .cra_flags      = CRYPTO_ALG_TYPE_SHASH,
0142         .cra_blocksize      = GHASH_BLOCK_SIZE,
0143         .cra_ctxsize        = sizeof(struct ghash_ctx),
0144         .cra_module     = THIS_MODULE,
0145         .cra_exit       = ghash_exit_tfm,
0146     },
0147 };
0148 
0149 static int __init ghash_mod_init(void)
0150 {
0151     return crypto_register_shash(&ghash_alg);
0152 }
0153 
0154 static void __exit ghash_mod_exit(void)
0155 {
0156     crypto_unregister_shash(&ghash_alg);
0157 }
0158 
0159 module_init(ghash_mod_init);
0160 module_exit(ghash_mod_exit);
0161 
0162 MODULE_LICENSE("GPL");
0163 MODULE_DESCRIPTION("GHASH Message Digest Algorithm");
0164 MODULE_ALIAS_CRYPTO("ghash");
0165 MODULE_ALIAS_CRYPTO("ghash-generic");