Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

file 228 lines (207 sloc) 6.043 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
/**************************** hmac.c ****************************/
/******************** See RFC 4634 for details ******************/
/*
* Description:
* This file implements the HMAC algorithm (Keyed-Hashing for
* Message Authentication, RFC2104), expressed in terms of the
* various SHA algorithms.
*/

#include "sha.h"

/*
* hmac
*
* Description:
* This function will compute an HMAC message digest.
*
* Parameters:
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* key: [in]
* The secret shared key.
* key_len: [in]
* The length of the secret shared key.
* message_array: [in]
* An array of characters representing the message.
* length: [in]
* The length of the message in message_array
* digest: [out]
* Where the digest is returned.
* NOTE: The length of the digest is determined by
* the value of whichSha.
*
* Returns:
* sha Error Code.
*
*/
int hmac(SHAversion whichSha, const unsigned char *text, int text_len,
    const unsigned char *key, int key_len,
    uint8_t digest[USHAMaxHashSize])
{
  HMACContext ctx;
  return hmacReset(&ctx, whichSha, key, key_len) ||
         hmacInput(&ctx, text, text_len) ||
         hmacResult(&ctx, digest);
}

/*
* hmacReset
*
* Description:
* This function will initialize the hmacContext in preparation
* for computing a new HMAC message digest.
*
* Parameters:
* context: [in/out]
* The context to reset.
* whichSha: [in]
* One of SHA1, SHA224, SHA256, SHA384, SHA512
* key: [in]
* The secret shared key.
* key_len: [in]
* The length of the secret shared key.
*
* Returns:
* sha Error Code.
*
*/
int hmacReset(HMACContext *ctx, enum SHAversion whichSha,
    const unsigned char *key, int key_len)
{
  int i, blocksize, hashsize;

  /* inner padding - key XORd with ipad */
  unsigned char k_ipad[USHA_Max_Message_Block_Size];

  /* temporary buffer when keylen > blocksize */
  unsigned char tempkey[USHAMaxHashSize];

  if (!ctx) return shaNull;

  blocksize = ctx->blockSize = USHABlockSize(whichSha);
  hashsize = ctx->hashSize = USHAHashSize(whichSha);

  ctx->whichSha = whichSha;

  /*
* If key is longer than the hash blocksize,
* reset it to key = HASH(key).
*/
  if (key_len > blocksize) {
    USHAContext tctx;
    int err = USHAReset(&tctx, whichSha) ||
              USHAInput(&tctx, key, key_len) ||
              USHAResult(&tctx, tempkey);
    if (err != shaSuccess) return err;

    key = tempkey;
    key_len = hashsize;
  }

  /*
* The HMAC transform looks like:
*
* SHA(K XOR opad, SHA(K XOR ipad, text))
*
* where K is an n byte key.
* ipad is the byte 0x36 repeated blocksize times
* opad is the byte 0x5c repeated blocksize times
* and text is the data being protected.
*/

  /* store key into the pads, XOR'd with ipad and opad values */
  for (i = 0; i < key_len; i++) {
    k_ipad[i] = key[i] ^ 0x36;
    ctx->k_opad[i] = key[i] ^ 0x5c;
  }
  /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
  for ( ; i < blocksize; i++) {
    k_ipad[i] = 0x36;
    ctx->k_opad[i] = 0x5c;
  }

  /* perform inner hash */
  /* init context for 1st pass */
  return USHAReset(&ctx->shaContext, whichSha) ||
         /* and start with inner pad */
         USHAInput(&ctx->shaContext, k_ipad, blocksize);
}

/*
* hmacInput
*
* Description:
* This function accepts an array of octets as the next portion
* of the message.
*
* Parameters:
* context: [in/out]
* The HMAC context to update
* message_array: [in]
* An array of characters representing the next portion of
* the message.
* length: [in]
* The length of the message in message_array
*
* Returns:
* sha Error Code.
*
*/
int hmacInput(HMACContext *ctx, const unsigned char *text,
    int text_len)
{
  if (!ctx) return shaNull;
  /* then text of datagram */
  return USHAInput(&ctx->shaContext, text, text_len);
}

/*
* HMACFinalBits
*
* Description:
* This function will add in any final bits of the message.
*
* Parameters:
* context: [in/out]
* The HMAC context to update
* message_bits: [in]
* The final bits of the message, in the upper portion of the
* byte. (Use 0b###00000 instead of 0b00000### to input the
* three bits ###.)
* length: [in]
* The number of bits in message_bits, between 1 and 7.
*
* Returns:
* sha Error Code.
*/
int hmacFinalBits(HMACContext *ctx,
    const uint8_t bits,
    unsigned int bitcount)
{
  if (!ctx) return shaNull;
  /* then final bits of datagram */
  return USHAFinalBits(&ctx->shaContext, bits, bitcount);
}

/*
* HMACResult
*
* Description:
* This function will return the N-byte message digest into the
* Message_Digest array provided by the caller.
* NOTE: The first octet of hash is stored in the 0th element,
* the last octet of hash in the Nth element.
*
* Parameters:
* context: [in/out]
* The context to use to calculate the HMAC hash.
* digest: [out]
* Where the digest is returned.
* NOTE 2: The length of the hash is determined by the value of
* whichSha that was passed to hmacReset().
*
* Returns:
* sha Error Code.
*
*/
int hmacResult(HMACContext *ctx, uint8_t *digest)
{
  if (!ctx) return shaNull;

  /* finish up 1st pass */
  /* (Use digest here as a temporary buffer.) */
  return USHAResult(&ctx->shaContext, digest) ||

         /* perform outer SHA */
         /* init context for 2nd pass */
         USHAReset(&ctx->shaContext, ctx->whichSha) ||

         /* start with outer pad */
         USHAInput(&ctx->shaContext, ctx->k_opad, ctx->blockSize) ||

         /* then results of 1st hash */
         USHAInput(&ctx->shaContext, digest, ctx->hashSize) ||

         /* finish up 2nd pass */
         USHAResult(&ctx->shaContext, digest);
}
Something went wrong with that request. Please try again.