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/internal/hash.h>
  20#include <crypto/scatterwalk.h>
  21#include <linux/err.h>
  22#include <linux/init.h>
  23#include <linux/kernel.h>
  24#include <linux/module.h>
  25#include <linux/scatterlist.h>
  26#include <linux/slab.h>
  27#include <linux/string.h>
  28
  29struct hmac_ctx {
  30        struct crypto_hash *child;
  31};
  32
  33static inline void *align_ptr(void *p, unsigned int align)
  34{
  35        return (void *)ALIGN((unsigned long)p, align);
  36}
  37
  38static inline struct hmac_ctx *hmac_ctx(struct crypto_hash *tfm)
  39{
  40        return align_ptr(crypto_hash_ctx_aligned(tfm) +
  41                         crypto_hash_blocksize(tfm) * 2 +
  42                         crypto_hash_digestsize(tfm), sizeof(void *));
  43}
  44
  45static int hmac_setkey(struct crypto_hash *parent,
  46                       const u8 *inkey, unsigned int keylen)
  47{
  48        int bs = crypto_hash_blocksize(parent);
  49        int ds = crypto_hash_digestsize(parent);
  50        char *ipad = crypto_hash_ctx_aligned(parent);
  51        char *opad = ipad + bs;
  52        char *digest = opad + bs;
  53        struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
  54        struct crypto_hash *tfm = ctx->child;
  55        unsigned int i;
  56
  57        if (keylen > bs) {
  58                struct hash_desc desc;
  59                struct scatterlist tmp;
  60                int tmplen;
  61                int err;
  62
  63                desc.tfm = tfm;
  64                desc.flags = crypto_hash_get_flags(parent);
  65                desc.flags &= CRYPTO_TFM_REQ_MAY_SLEEP;
  66
  67                err = crypto_hash_init(&desc);
  68                if (err)
  69                        return err;
  70
  71                tmplen = bs * 2 + ds;
  72                sg_init_one(&tmp, ipad, tmplen);
  73
  74                for (; keylen > tmplen; inkey += tmplen, keylen -= tmplen) {
  75                        memcpy(ipad, inkey, tmplen);
  76                        err = crypto_hash_update(&desc, &tmp, tmplen);
  77                        if (err)
  78                                return err;
  79                }
  80
  81                if (keylen) {
  82                        memcpy(ipad, inkey, keylen);
  83                        err = crypto_hash_update(&desc, &tmp, keylen);
  84                        if (err)
  85                                return err;
  86                }
  87
  88                err = crypto_hash_final(&desc, digest);
  89                if (err)
  90                        return err;
  91
  92                inkey = digest;
  93                keylen = ds;
  94        }
  95
  96        memcpy(ipad, inkey, keylen);
  97        memset(ipad + keylen, 0, bs - keylen);
  98        memcpy(opad, ipad, bs);
  99
 100        for (i = 0; i < bs; i++) {
 101                ipad[i] ^= 0x36;
 102                opad[i] ^= 0x5c;
 103        }
 104
 105        return 0;
 106}
 107
 108static int hmac_init(struct hash_desc *pdesc)
 109{
 110        struct crypto_hash *parent = pdesc->tfm;
 111        int bs = crypto_hash_blocksize(parent);
 112        int ds = crypto_hash_digestsize(parent);
 113        char *ipad = crypto_hash_ctx_aligned(parent);
 114        struct hmac_ctx *ctx = align_ptr(ipad + bs * 2 + ds, sizeof(void *));
 115        struct hash_desc desc;
 116        struct scatterlist tmp;
 117        int err;
 118
 119        desc.tfm = ctx->child;
 120        desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
 121        sg_init_one(&tmp, ipad, bs);
 122
 123        err = crypto_hash_init(&desc);
 124        if (unlikely(err))
 125                return err;
 126
 127        return crypto_hash_update(&desc, &tmp, bs);
 128}
 129
 130static int hmac_update(struct hash_desc *pdesc,
 131                       struct scatterlist *sg, unsigned int nbytes)
 132{
 133        struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm);
 134        struct hash_desc desc;
 135
 136        desc.tfm = ctx->child;
 137        desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
 138
 139        return crypto_hash_update(&desc, sg, nbytes);
 140}
 141
 142static int hmac_final(struct hash_desc *pdesc, u8 *out)
 143{
 144        struct crypto_hash *parent = pdesc->tfm;
 145        int bs = crypto_hash_blocksize(parent);
 146        int ds = crypto_hash_digestsize(parent);
 147        char *opad = crypto_hash_ctx_aligned(parent) + bs;
 148        char *digest = opad + bs;
 149        struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
 150        struct hash_desc desc;
 151        struct scatterlist tmp;
 152        int err;
 153
 154        desc.tfm = ctx->child;
 155        desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
 156        sg_init_one(&tmp, opad, bs + ds);
 157
 158        err = crypto_hash_final(&desc, digest);
 159        if (unlikely(err))
 160                return err;
 161
 162        return crypto_hash_digest(&desc, &tmp, bs + ds, out);
 163}
 164
 165static int hmac_digest(struct hash_desc *pdesc, struct scatterlist *sg,
 166                       unsigned int nbytes, u8 *out)
 167{
 168        struct crypto_hash *parent = pdesc->tfm;
 169        int bs = crypto_hash_blocksize(parent);
 170        int ds = crypto_hash_digestsize(parent);
 171        char *ipad = crypto_hash_ctx_aligned(parent);
 172        char *opad = ipad + bs;
 173        char *digest = opad + bs;
 174        struct hmac_ctx *ctx = align_ptr(digest + ds, sizeof(void *));
 175        struct hash_desc desc;
 176        struct scatterlist sg1[2];
 177        struct scatterlist sg2[1];
 178        int err;
 179
 180        desc.tfm = ctx->child;
 181        desc.flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP;
 182
 183        sg_init_table(sg1, 2);
 184        sg_set_buf(sg1, ipad, bs);
 185        scatterwalk_sg_chain(sg1, 2, sg);
 186
 187        sg_init_table(sg2, 1);
 188        sg_set_buf(sg2, opad, bs + ds);
 189
 190        err = crypto_hash_digest(&desc, sg1, nbytes + bs, digest);
 191        if (unlikely(err))
 192                return err;
 193
 194        return crypto_hash_digest(&desc, sg2, bs + ds, out);
 195}
 196
 197static int hmac_init_tfm(struct crypto_tfm *tfm)
 198{
 199        struct crypto_hash *hash;
 200        struct crypto_instance *inst = (void *)tfm->__crt_alg;
 201        struct crypto_spawn *spawn = crypto_instance_ctx(inst);
 202        struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
 203
 204        hash = crypto_spawn_hash(spawn);
 205        if (IS_ERR(hash))
 206                return PTR_ERR(hash);
 207
 208        ctx->child = hash;
 209        return 0;
 210}
 211
 212static void hmac_exit_tfm(struct crypto_tfm *tfm)
 213{
 214        struct hmac_ctx *ctx = hmac_ctx(__crypto_hash_cast(tfm));
 215        crypto_free_hash(ctx->child);
 216}
 217
 218static void hmac_free(struct crypto_instance *inst)
 219{
 220        crypto_drop_spawn(crypto_instance_ctx(inst));
 221        kfree(inst);
 222}
 223
 224static struct crypto_instance *hmac_alloc(struct rtattr **tb)
 225{
 226        struct crypto_instance *inst;
 227        struct crypto_alg *alg;
 228        int err;
 229        int ds;
 230
 231        err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_HASH);
 232        if (err)
 233                return ERR_PTR(err);
 234
 235        alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
 236                                  CRYPTO_ALG_TYPE_HASH_MASK);
 237        if (IS_ERR(alg))
 238                return ERR_CAST(alg);
 239
 240        inst = ERR_PTR(-EINVAL);
 241        ds = alg->cra_type == &crypto_hash_type ?
 242             alg->cra_hash.digestsize :
 243             alg->cra_type ?
 244             __crypto_shash_alg(alg)->digestsize :
 245             alg->cra_digest.dia_digestsize;
 246        if (ds > alg->cra_blocksize)
 247                goto out_put_alg;
 248
 249        inst = crypto_alloc_instance("hmac", alg);
 250        if (IS_ERR(inst))
 251                goto out_put_alg;
 252
 253        inst->alg.cra_flags = CRYPTO_ALG_TYPE_HASH;
 254        inst->alg.cra_priority = alg->cra_priority;
 255        inst->alg.cra_blocksize = alg->cra_blocksize;
 256        inst->alg.cra_alignmask = alg->cra_alignmask;
 257        inst->alg.cra_type = &crypto_hash_type;
 258
 259        inst->alg.cra_hash.digestsize = ds;
 260
 261        inst->alg.cra_ctxsize = sizeof(struct hmac_ctx) +
 262                                ALIGN(inst->alg.cra_blocksize * 2 + ds,
 263                                      sizeof(void *));
 264
 265        inst->alg.cra_init = hmac_init_tfm;
 266        inst->alg.cra_exit = hmac_exit_tfm;
 267
 268        inst->alg.cra_hash.init = hmac_init;
 269        inst->alg.cra_hash.update = hmac_update;
 270        inst->alg.cra_hash.final = hmac_final;
 271        inst->alg.cra_hash.digest = hmac_digest;
 272        inst->alg.cra_hash.setkey = hmac_setkey;
 273
 274out_put_alg:
 275        crypto_mod_put(alg);
 276        return inst;
 277}
 278
 279static struct crypto_template hmac_tmpl = {
 280        .name = "hmac",
 281        .alloc = hmac_alloc,
 282        .free = hmac_free,
 283        .module = THIS_MODULE,
 284};
 285
 286static int __init hmac_module_init(void)
 287{
 288        return crypto_register_template(&hmac_tmpl);
 289}
 290
 291static void __exit hmac_module_exit(void)
 292{
 293        crypto_unregister_template(&hmac_tmpl);
 294}
 295
 296module_init(hmac_module_init);
 297module_exit(hmac_module_exit);
 298
 299MODULE_LICENSE("GPL");
 300MODULE_DESCRIPTION("HMAC hash algorithm");
 301