RHEL5/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 *
   8 * The HMAC implementation is derived from USAGI.
   9 * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
  10 *
  11 * This program is free software; you can redistribute it and/or modify it
  12 * under the terms of the GNU General Public License as published by the Free
  13 * Software Foundation; either version 2 of the License, or (at your option) 
  14 * any later version.
  15 *
  16 */
  17#include <linux/crypto.h>
  18#include <linux/mm.h>
  19#include <linux/highmem.h>
  20#include <linux/slab.h>
  21#include <linux/scatterlist.h>
  22#include "internal.h"
  23
  24static void hash_key(struct crypto_tfm *tfm, u8 *key, unsigned int keylen)
  25{
  26        struct scatterlist tmp;
  27        
  28        sg_set_buf(&tmp, key, keylen);
  29        crypto_digest_digest(tfm, &tmp, 1, key);
  30}
  31
  32int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
  33{
  34        int ret = 0;
  35
  36        BUG_ON(!crypto_tfm_alg_blocksize(tfm));
  37        
  38        tfm->crt_digest.dit_hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm),
  39                                                 GFP_KERNEL);
  40        if (tfm->crt_digest.dit_hmac_block == NULL)
  41                ret = -ENOMEM;
  42
  43        return ret;
  44                
  45}
  46
  47void crypto_free_hmac_block(struct crypto_tfm *tfm)
  48{
  49        kfree(tfm->crt_digest.dit_hmac_block);
  50}
  51
  52void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
  53{
  54        unsigned int i;
  55        struct scatterlist tmp;
  56        char *ipad = tfm->crt_digest.dit_hmac_block;
  57        
  58        if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
  59                hash_key(tfm, key, *keylen);
  60                *keylen = crypto_tfm_alg_digestsize(tfm);
  61        }
  62
  63        memset(ipad, 0, crypto_tfm_alg_blocksize(tfm));
  64        memcpy(ipad, key, *keylen);
  65
  66        for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
  67                ipad[i] ^= 0x36;
  68
  69        sg_set_buf(&tmp, ipad, crypto_tfm_alg_blocksize(tfm));
  70        
  71        crypto_digest_init(tfm);
  72        crypto_digest_update(tfm, &tmp, 1);
  73}
  74
  75void crypto_hmac_update(struct crypto_tfm *tfm,
  76                        struct scatterlist *sg, unsigned int nsg)
  77{
  78        crypto_digest_update(tfm, sg, nsg);
  79}
  80
  81void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
  82                       unsigned int *keylen, u8 *out)
  83{
  84        unsigned int i;
  85        struct scatterlist tmp;
  86        char *opad = tfm->crt_digest.dit_hmac_block;
  87        
  88        if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
  89                hash_key(tfm, key, *keylen);
  90                *keylen = crypto_tfm_alg_digestsize(tfm);
  91        }
  92
  93        crypto_digest_final(tfm, out);
  94
  95        memset(opad, 0, crypto_tfm_alg_blocksize(tfm));
  96        memcpy(opad, key, *keylen);
  97                
  98        for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
  99                opad[i] ^= 0x5c;
 100
 101        sg_set_buf(&tmp, opad, crypto_tfm_alg_blocksize(tfm));
 102
 103        crypto_digest_init(tfm);
 104        crypto_digest_update(tfm, &tmp, 1);
 105        
 106        sg_set_buf(&tmp, out, crypto_tfm_alg_digestsize(tfm));
 107        
 108        crypto_digest_update(tfm, &tmp, 1);
 109        crypto_digest_final(tfm, out);
 110}
 111
 112void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen,
 113                 struct scatterlist *sg, unsigned int nsg, u8 *out)
 114{
 115        crypto_hmac_init(tfm, key, keylen);
 116        crypto_hmac_update(tfm, sg, nsg);
 117        crypto_hmac_final(tfm, key, keylen, out);
 118}
 119
 120EXPORT_SYMBOL_GPL(crypto_hmac_init);
 121EXPORT_SYMBOL_GPL(crypto_hmac_update);
 122EXPORT_SYMBOL_GPL(crypto_hmac_final);
 123EXPORT_SYMBOL_GPL(crypto_hmac);
 124
 125