linux/crypto/hmac.c
<<
>>
Prefs
   1/*
   2 * Cryptographic API.
   3 *
   4 * HMAC: Keyed-Hashing for Message Authentication (RFC2104).
   5 *
   6 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
   7 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
   8 *
   9 * The HMAC implementation is derived from USAGI.
  10 * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
  11 *
  12 * This program is free software; you can redistribute it and/or modify it
  13 * under the terms of the GNU General Public License as published by the Free
  14 * Software Foundation; either version 2 of the License, or (at your option)
  15 * any later version.
  16 *
  17 */
  18
  19#include <crypto/algapi.h>
  20#include <linux/err.h>
  21#include <linux/init.h>
  22#include <linux/kernel.h>
  23#include <linux/module.h>
  24#include <linux/scatterlist.h>
  25#include <linux/slab.h>
  26#include <linux/string.h>
  27
  28struct hmac_ctx {
  29        struct crypto_hash *child;
  30};
  31
  32static inline void *align_ptr(void *p, unsigned int align)
  33{
  34        return (void *)ALIGN((unsigned long)p, align);
  35}
  36
  37static inline struct hmac_ctx *hmac_ctx(struct crypto_hash *tfm)
  38{
  39        return align_ptr(crypto_hash_ctx_aligned(tfm) +
  40                         crypto_hash_blocksize(tfm) * 2 +
  41                         crypto_hash_digestsize(tfm), sizeof(void *));
  42}
  43
  44static int hmac_setkey(struct crypto_hash *parent,
  45                       const u8 *inkey, unsigned int keylen)
  46{
  47        int bs = crypto_hash_blocksize(parent);
  48        int ds = crypto_hash_digestsize(parent);
  49        char *ipad = crypto_hash_ctx_aligned(parent);
  50        char *opad = ipad + bs;
  51        char *digest = opad + bs;
  52        struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
  53        struct crypto_hash *tfm = ctx->child;
  54        unsigned int i;
  55
  56        if (keylen > bs) {
  57                struct hash_desc desc;
  58                struct scatterlist tmp;
  59                int err;
  60
  61                desc.tfm = tfm;
  62                desc.flags = crypto_hash_get_flags(parent);
  63                desc.flags &= CRYPTO_TFM_REQ_MAY_SLEEP;
  64                sg_set_buf(&tmp, inkey, keylen);
  65
  66                err = crypto_hash_digest(&desc, &tmp, keylen, digest);
  67                if (err)
  68                        return err;
  69
  70                inkey = digest;
  71                keylen = ds;
  72        }
  73
  74        memcpy(ipad, inkey, keylen);
  75        memset(ipad + keylen, 0, bs - keylen);
  76        memcpy(opad, ipad, bs);
  77
  78        for (i = 0; i < bs; i++) {
  79                ipad[i] ^= 0x36;
  80                opad[i] ^= 0x5c;
  81        }
  82
  83        return 0;
  84}
  85
  86static int hmac_init(struct hash_desc *pdesc)
  87{
  88        struct crypto_hash *parent = pdesc->tfm;
  89        int bs = crypto_hash_blocksize(parent);
  90        int ds = crypto_hash_digestsize(parent);
  91        char *ipad = crypto_hash_ctx_aligned(parent);
  92        struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, sizeof(void *));
  93        struct hash_desc desc;
  94        struct scatterlist tmp;
  95        int err;
  96
  97        desc.tfm = ctx->child;
  98        desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
  99        sg_set_buf(&tmp, ipad, bs);
 100
 101        err = crypto_hash_init(&desc);
 102        if (unlikely(err))
 103                return err;
 104
 105        return crypto_hash_update(&desc, &tmp, bs);
 106}
 107
 108static int hmac_update(struct hash_desc *pdesc,
 109                       struct scatterlist *sg, unsigned int nbytes)
 110{
 111        struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm);
 112        struct hash_desc desc;
 113
 114        desc.tfm = ctx->child;
 115        desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
 116
 117        return crypto_hash_update(&desc, sg, nbytes);
 118}
 119
 120static int hmac_final(struct hash_desc *pdesc, u8 *out)
 121{
 122        struct crypto_hash *parent = pdesc->tfm;
 123        int bs = crypto_hash_blocksize(parent);
 124        int ds = crypto_hash_digestsize(parent);
 125        char *opad = crypto_hash_ctx_aligned(parent) + bs;
 126        char *digest = opad + bs;
 127        struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
 128        struct hash_desc desc;
 129        struct scatterlist tmp;
 130        int err;
 131
 132        desc.tfm = ctx->child;
 133        desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
 134        sg_set_buf(&tmp, opad, bs + ds);
 135
 136        err = crypto_hash_final(&desc, digest);
 137        if (unlikely(err))
 138                return err;
 139
 140        return crypto_hash_digest(&desc, &tmp, bs + ds, out);
 141}
 142
 143static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
 144                       unsigned int nbytes, u8 *out)
 145{
 146        struct crypto_hash *parent = pdesc->tfm;
 147        int bs = crypto_hash_blocksize(parent);
 148        int ds = crypto_hash_digestsize(parent);
 149        char *ipad = crypto_hash_ctx_aligned(parent);
 150        char *opad = ipad + bs;
 151        char *digest = opad + bs;
 152        struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
 153        struct hash_desc desc;
 154        struct scatterlist sg1[2];
 155        struct scatterlist sg2[1];
 156        int err;
 157
 158        desc.tfm = ctx->child;
 159        desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
 160
 161        sg_set_buf(sg1, ipad, bs);
 162        sg1[1].page = (void *)sg;
 163        sg1[1].length = 0;
 164        sg_set_buf(sg2, opad, bs + ds);
 165
 166        err = crypto_hash_digest(&desc, sg1, nbytes + bs, digest);
 167        if (unlikely(err))
 168                return err;
 169
 170        return crypto_hash_digest(&desc, sg2, bs + ds, out);
 171}
 172
 173static int hmac_init_tfm(struct crypto_tfm *tfm)
 174{
 175        struct crypto_instance *inst = (void *)tfm->__crt_alg;
 176        struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 177        struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
 178
 179        tfm = crypto_spawn_tfm(spawn);
 180        if (IS_ERR(tfm))
 181                return PTR_ERR(tfm);
 182
 183        ctx->child = crypto_hash_cast(tfm);
 184        return 0;
 185}
 186
 187static void hmac_exit_tfm(struct crypto_tfm *tfm)
 188{
 189        struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
 190        crypto_free_hash(ctx->child);
 191}
 192
 193static void hmac_free(struct crypto_instance *inst)
 194{
 195        crypto_drop_spawn(crypto_instance_ctx(inst));
 196        kfree(inst);
 197}
 198
 199static struct crypto_instance *hmac_alloc(void *param, unsigned int len)
 200{
 201        struct crypto_instance *inst;
 202        struct crypto_alg *alg;
 203
 204        alg = crypto_get_attr_alg(param, len, CRYPTO_ALG_TYPE_HASH,
 205                                  CRYPTO_ALG_TYPE_HASH_MASK | CRYPTO_ALG_ASYNC);
 206        if (IS_ERR(alg))
 207                return ERR_PTR(PTR_ERR(alg));
 208
 209        inst = crypto_alloc_instance("hmac", alg);
 210        if (IS_ERR(inst))
 211                goto out_put_alg;
 212
 213        inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
 214        inst->alg.cra_priority = alg->cra_priority;
 215        inst->alg.cra_blocksize = alg->cra_blocksize;
 216        inst->alg.cra_alignmask = alg->cra_alignmask;
 217        inst->alg.cra_type = &crypto_hash_type;
 218
 219        inst->alg.cra_hash.digestsize =
 220                (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
 221                CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
 222                                       alg->cra_digest.dia_digestsize;
 223
 224        inst->alg.cra_ctxsize = sizeof(struct hmac_ctx) +
 225                                ALIGN(inst->alg.cra_blocksize * 2 +
 226                                      inst->alg.cra_hash.digestsize,
 227                                      sizeof(void *));
 228
 229        inst->alg.cra_init = hmac_init_tfm;
 230        inst->alg.cra_exit = hmac_exit_tfm;
 231
 232        inst->alg.cra_hash.init = hmac_init;
 233        inst->alg.cra_hash.update = hmac_update;
 234        inst->alg.cra_hash.final = hmac_final;
 235        inst->alg.cra_hash.digest = hmac_digest;
 236        inst->alg.cra_hash.setkey = hmac_setkey;
 237
 238out_put_alg:
 239        crypto_mod_put(alg);
 240        return inst;
 241}
 242
 243static struct crypto_template hmac_tmpl = {
 244        .name = "hmac",
 245        .alloc = hmac_alloc,
 246        .free = hmac_free,
 247        .module = THIS_MODULE,
 248};
 249
 250static int __init hmac_module_init(void)
 251{
 252        return crypto_register_template(&hmac_tmpl);
 253}
 254
 255static void __exit hmac_module_exit(void)
 256{
 257        crypto_unregister_template(&hmac_tmpl);
 258}
 259
 260module_init(hmac_module_init);
 261module_exit(hmac_module_exit);
 262
 263MODULE_LICENSE("GPL");
 264MODULE_DESCRIPTION("HMAC hash algorithm");
 265
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.