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_init_one(&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_init_one(&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_init_one(&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_init_table(sg1, 2);
 162        sg_set_buf(sg1, ipad, bs);
 163        sg_set_page(&sg1[1], (void *) sg, 0, 0);
 164
 165        sg_init_table(sg2, 1);
 166        sg_set_buf(sg2, opad, bs + ds);
 167
 168        err = crypto_hash_digest(&desc, sg1, nbytes + bs, digest);
 169        if (unlikely(err))
 170                return err;
 171
 172        return crypto_hash_digest(&desc, sg2, bs + ds, out);
 173}
 174
 175static int hmac_init_tfm(struct crypto_tfm *tfm)
 176{
 177        struct crypto_hash *hash;
 178        struct crypto_instance *inst = (void *)tfm->__crt_alg;
 179        struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 180        struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
 181
 182        hash = crypto_spawn_hash(spawn);
 183        if (IS_ERR(hash))
 184                return PTR_ERR(hash);
 185
 186        ctx->child = hash;
 187        return 0;
 188}
 189
 190static void hmac_exit_tfm(struct crypto_tfm *tfm)
 191{
 192        struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
 193        crypto_free_hash(ctx->child);
 194}
 195
 196static void hmac_free(struct crypto_instance *inst)
 197{
 198        crypto_drop_spawn(crypto_instance_ctx(inst));
 199        kfree(inst);
 200}
 201
 202static struct crypto_instance *hmac_alloc(struct rtattr **tb)
 203{
 204        struct crypto_instance *inst;
 205        struct crypto_alg *alg;
 206        int err;
 207
 208        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
 209        if (err)
 210                return ERR_PTR(err);
 211
 212        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
 213                                  CRYPTO_ALG_TYPE_HASH_MASK);
 214        if (IS_ERR(alg))
 215                return ERR_PTR(PTR_ERR(alg));
 216
 217        inst = crypto_alloc_instance("hmac", alg);
 218        if (IS_ERR(inst))
 219                goto out_put_alg;
 220
 221        inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
 222        inst->alg.cra_priority = alg->cra_priority;
 223        inst->alg.cra_blocksize = alg->cra_blocksize;
 224        inst->alg.cra_alignmask = alg->cra_alignmask;
 225        inst->alg.cra_type = &crypto_hash_type;
 226
 227        inst->alg.cra_hash.digestsize =
 228                (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
 229                CRYPTO_ALG_TYPE_HASH ? alg->cra_hash.digestsize :
 230                                       alg->cra_digest.dia_digestsize;
 231
 232        inst->alg.cra_ctxsize = sizeof(struct hmac_ctx) +
 233                                ALIGN(inst->alg.cra_blocksize * 2 +
 234                                      inst->alg.cra_hash.digestsize,
 235                                      sizeof(void *));
 236
 237        inst->alg.cra_init = hmac_init_tfm;
 238        inst->alg.cra_exit = hmac_exit_tfm;
 239
 240        inst->alg.cra_hash.init = hmac_init;
 241        inst->alg.cra_hash.update = hmac_update;
 242        inst->alg.cra_hash.final = hmac_final;
 243        inst->alg.cra_hash.digest = hmac_digest;
 244        inst->alg.cra_hash.setkey = hmac_setkey;
 245
 246out_put_alg:
 247        crypto_mod_put(alg);
 248        return inst;
 249}
 250
 251static struct crypto_template hmac_tmpl = {
 252        .name = "hmac",
 253        .alloc = hmac_alloc,
 254        .free = hmac_free,
 255        .module = THIS_MODULE,
 256};
 257
 258static int __init hmac_module_init(void)
 259{
 260        return crypto_register_template(&hmac_tmpl);
 261}
 262
 263static void __exit hmac_module_exit(void)
 264{
 265        crypto_unregister_template(&hmac_tmpl);
 266}
 267
 268module_init(hmac_module_init);
 269module_exit(hmac_module_exit);
 270
 271MODULE_LICENSE("GPL");
 272MODULE_DESCRIPTION("HMAC hash algorithm");
 273