linux/arch/s390/crypto/ghash_s390.c
<<
>>
Prefs
   1/*
   2 * Cryptographic API.
   3 *
   4 * s390 implementation of the GHASH algorithm for GCM (Galois/Counter Mode).
   5 *
   6 * Copyright IBM Corp. 2011
   7 * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
   8 */
   9
  10#include <crypto/internal/hash.h>
  11#include <linux/module.h>
  12#include <linux/cpufeature.h>
  13#include <asm/cpacf.h>
  14
  15#define GHASH_BLOCK_SIZE        16
  16#define GHASH_DIGEST_SIZE       16
  17
  18struct ghash_ctx {
  19        u8 key[GHASH_BLOCK_SIZE];
  20};
  21
  22struct ghash_desc_ctx {
  23        u8 icv[GHASH_BLOCK_SIZE];
  24        u8 key[GHASH_BLOCK_SIZE];
  25        u8 buffer[GHASH_BLOCK_SIZE];
  26        u32 bytes;
  27};
  28
  29static int ghash_init(struct shash_desc *desc)
  30{
  31        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
  32        struct ghash_ctx *ctx = crypto_shash_ctx(desc->tfm);
  33
  34        memset(dctx, 0, sizeof(*dctx));
  35        memcpy(dctx->key, ctx->key, GHASH_BLOCK_SIZE);
  36
  37        return 0;
  38}
  39
  40static int ghash_setkey(struct crypto_shash *tfm,
  41                        const u8 *key, unsigned int keylen)
  42{
  43        struct ghash_ctx *ctx = crypto_shash_ctx(tfm);
  44
  45        if (keylen != GHASH_BLOCK_SIZE) {
  46                crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
  47                return -EINVAL;
  48        }
  49
  50        memcpy(ctx->key, key, GHASH_BLOCK_SIZE);
  51
  52        return 0;
  53}
  54
  55static int ghash_update(struct shash_desc *desc,
  56                         const u8 *src, unsigned int srclen)
  57{
  58        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
  59        unsigned int n;
  60        u8 *buf = dctx->buffer;
  61
  62        if (dctx->bytes) {
  63                u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes);
  64
  65                n = min(srclen, dctx->bytes);
  66                dctx->bytes -= n;
  67                srclen -= n;
  68
  69                memcpy(pos, src, n);
  70                src += n;
  71
  72                if (!dctx->bytes) {
  73                        cpacf_kimd(CPACF_KIMD_GHASH, dctx, buf,
  74                                   GHASH_BLOCK_SIZE);
  75                }
  76        }
  77
  78        n = srclen & ~(GHASH_BLOCK_SIZE - 1);
  79        if (n) {
  80                cpacf_kimd(CPACF_KIMD_GHASH, dctx, src, n);
  81                src += n;
  82                srclen -= n;
  83        }
  84
  85        if (srclen) {
  86                dctx->bytes = GHASH_BLOCK_SIZE - srclen;
  87                memcpy(buf, src, srclen);
  88        }
  89
  90        return 0;
  91}
  92
  93static int ghash_flush(struct ghash_desc_ctx *dctx)
  94{
  95        u8 *buf = dctx->buffer;
  96
  97        if (dctx->bytes) {
  98                u8 *pos = buf + (GHASH_BLOCK_SIZE - dctx->bytes);
  99
 100                memset(pos, 0, dctx->bytes);
 101                cpacf_kimd(CPACF_KIMD_GHASH, dctx, buf, GHASH_BLOCK_SIZE);
 102                dctx->bytes = 0;
 103        }
 104
 105        return 0;
 106}
 107
 108static int ghash_final(struct shash_desc *desc, u8 *dst)
 109{
 110        struct ghash_desc_ctx *dctx = shash_desc_ctx(desc);
 111        int ret;
 112
 113        ret = ghash_flush(dctx);
 114        if (!ret)
 115                memcpy(dst, dctx->icv, GHASH_BLOCK_SIZE);
 116        return ret;
 117}
 118
 119static struct shash_alg ghash_alg = {
 120        .digestsize     = GHASH_DIGEST_SIZE,
 121        .init           = ghash_init,
 122        .update         = ghash_update,
 123        .final          = ghash_final,
 124        .setkey         = ghash_setkey,
 125        .descsize       = sizeof(struct ghash_desc_ctx),
 126        .base           = {
 127                .cra_name               = "ghash",
 128                .cra_driver_name        = "ghash-s390",
 129                .cra_priority           = 300,
 130                .cra_flags              = CRYPTO_ALG_TYPE_SHASH,
 131                .cra_blocksize          = GHASH_BLOCK_SIZE,
 132                .cra_ctxsize            = sizeof(struct ghash_ctx),
 133                .cra_module             = THIS_MODULE,
 134        },
 135};
 136
 137static int __init ghash_mod_init(void)
 138{
 139        if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_GHASH))
 140                return -EOPNOTSUPP;
 141
 142        return crypto_register_shash(&ghash_alg);
 143}
 144
 145static void __exit ghash_mod_exit(void)
 146{
 147        crypto_unregister_shash(&ghash_alg);
 148}
 149
 150module_cpu_feature_match(MSA, ghash_mod_init);
 151module_exit(ghash_mod_exit);
 152
 153MODULE_ALIAS_CRYPTO("ghash");
 154
 155MODULE_LICENSE("GPL");
 156MODULE_DESCRIPTION("GHASH Message Digest Algorithm, s390 implementation");
 157