RHEL4/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 <asm/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        tmp.page = virt_to_page(key);
  29        tmp.offset = offset_in_page(key);
  30        tmp.length = keylen;
  31        crypto_digest_digest(tfm, &tmp, 1, key);
  32                
  33}
  34
  35int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
  36{
  37        int ret = 0;
  38
  39        BUG_ON(!crypto_tfm_alg_blocksize(tfm));
  40        
  41        tfm->crt_digest.dit_hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm),
  42                                                 GFP_KERNEL);
  43        if (tfm->crt_digest.dit_hmac_block == NULL)
  44                ret = -ENOMEM;
  45
  46        return ret;
  47                
  48}
  49
  50void crypto_free_hmac_block(struct crypto_tfm *tfm)
  51{
  52        if (tfm->crt_digest.dit_hmac_block)
  53                kfree(tfm->crt_digest.dit_hmac_block);
  54}
  55
  56void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
  57{
  58        unsigned int i;
  59        struct scatterlist tmp;
  60        char *ipad = tfm->crt_digest.dit_hmac_block;
  61        
  62        if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
  63                hash_key(tfm, key, *keylen);
  64                *keylen = crypto_tfm_alg_digestsize(tfm);
  65        }
  66
  67        memset(ipad, 0, crypto_tfm_alg_blocksize(tfm));
  68        memcpy(ipad, key, *keylen);
  69
  70        for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
  71                ipad[i] ^= 0x36;
  72
  73        tmp.page = virt_to_page(ipad);
  74        tmp.offset = offset_in_page(ipad);
  75        tmp.length = crypto_tfm_alg_blocksize(tfm);
  76        
  77        crypto_digest_init(tfm);
  78        crypto_digest_update(tfm, &tmp, 1);
  79}
  80
  81void crypto_hmac_update(struct crypto_tfm *tfm,
  82                        struct scatterlist *sg, unsigned int nsg)
  83{
  84        crypto_digest_update(tfm, sg, nsg);
  85}
  86
  87void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
  88                       unsigned int *keylen, u8 *out)
  89{
  90        unsigned int i;
  91        struct scatterlist tmp;
  92        char *opad = tfm->crt_digest.dit_hmac_block;
  93        
  94        if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
  95                hash_key(tfm, key, *keylen);
  96                *keylen = crypto_tfm_alg_digestsize(tfm);
  97        }
  98
  99        crypto_digest_final(tfm, out);
 100
 101        memset(opad, 0, crypto_tfm_alg_blocksize(tfm));
 102        memcpy(opad, key, *keylen);
 103                
 104        for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
 105                opad[i] ^= 0x5c;
 106
 107        tmp.page = virt_to_page(opad);
 108        tmp.offset = offset_in_page(opad);
 109        tmp.length = crypto_tfm_alg_blocksize(tfm);
 110
 111        crypto_digest_init(tfm);
 112        crypto_digest_update(tfm, &tmp, 1);
 113        
 114        tmp.page = virt_to_page(out);
 115        tmp.offset = offset_in_page(out);
 116        tmp.length = crypto_tfm_alg_digestsize(tfm);
 117        
 118        crypto_digest_update(tfm, &tmp, 1);
 119        crypto_digest_final(tfm, out);
 120}
 121
 122void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen,
 123                 struct scatterlist *sg, unsigned int nsg, u8 *out)
 124{
 125        crypto_hmac_init(tfm, key, keylen);
 126        crypto_hmac_update(tfm, sg, nsg);
 127        crypto_hmac_final(tfm, key, keylen, out);
 128}
 129
 130EXPORT_SYMBOL_GPL(crypto_hmac_init);
 131EXPORT_SYMBOL_GPL(crypto_hmac_update);
 132EXPORT_SYMBOL_GPL(crypto_hmac_final);
 133EXPORT_SYMBOL_GPL(crypto_hmac);
 134
 135