[457] | 1 | // Copyright (c) Microsoft. All rights reserved.
|
---|
| 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
---|
| 3 |
|
---|
| 4 | /**************************** hmac.c ****************************/
|
---|
| 5 | /******************** See RFC 4634 for details ******************/
|
---|
| 6 | /*
|
---|
| 7 | * Description:
|
---|
| 8 | * This file implements the HMAC algorithm (Keyed-Hashing for
|
---|
| 9 | * Message Authentication, RFC2104), expressed in terms of the
|
---|
| 10 | * various SHA algorithms.
|
---|
| 11 | */
|
---|
| 12 |
|
---|
| 13 | #include "azure_c_shared_utility/sha.h"
|
---|
| 14 |
|
---|
| 15 | /*
|
---|
| 16 | * hmac
|
---|
| 17 | *
|
---|
| 18 | * Description:
|
---|
| 19 | * This function will compute an HMAC message digest.
|
---|
| 20 | *
|
---|
| 21 | * Parameters:
|
---|
| 22 | * whichSha: [in]
|
---|
| 23 | * One of SHA1, SHA224, SHA256, SHA384, SHA512
|
---|
| 24 | * key: [in]
|
---|
| 25 | * The secret shared key.
|
---|
| 26 | * key_len: [in]
|
---|
| 27 | * The length of the secret shared key.
|
---|
| 28 | * message_array: [in]
|
---|
| 29 | * An array of characters representing the message.
|
---|
| 30 | * length: [in]
|
---|
| 31 | * The length of the message in message_array
|
---|
| 32 | * digest: [out]
|
---|
| 33 | * Where the digest is returned.
|
---|
| 34 | * NOTE: The length of the digest is determined by
|
---|
| 35 | * the value of whichSha.
|
---|
| 36 | *
|
---|
| 37 | * Returns:
|
---|
| 38 | * sha Error Code.
|
---|
| 39 | *
|
---|
| 40 | */
|
---|
| 41 | int hmac(SHAversion whichSha, const unsigned char *text, int text_len,
|
---|
| 42 | const unsigned char *key, int key_len,
|
---|
| 43 | uint8_t digest[USHAMaxHashSize])
|
---|
| 44 | {
|
---|
| 45 | HMACContext ctx;
|
---|
| 46 | return hmacReset(&ctx, whichSha, key, key_len) ||
|
---|
| 47 | hmacInput(&ctx, text, text_len) ||
|
---|
| 48 | hmacResult(&ctx, digest);
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | /*
|
---|
| 52 | * hmacReset
|
---|
| 53 | *
|
---|
| 54 | * Description:
|
---|
| 55 | * This function will initialize the hmacContext in preparation
|
---|
| 56 | * for computing a new HMAC message digest.
|
---|
| 57 | *
|
---|
| 58 | * Parameters:
|
---|
| 59 | * context: [in/out]
|
---|
| 60 | * The context to reset.
|
---|
| 61 | * whichSha: [in]
|
---|
| 62 | * One of SHA1, SHA224, SHA256, SHA384, SHA512
|
---|
| 63 | * key: [in]
|
---|
| 64 | * The secret shared key.
|
---|
| 65 | * key_len: [in]
|
---|
| 66 | * The length of the secret shared key.
|
---|
| 67 | *
|
---|
| 68 | * Returns:
|
---|
| 69 | * sha Error Code.
|
---|
| 70 | *
|
---|
| 71 | */
|
---|
| 72 | int hmacReset(HMACContext *ctx, enum SHAversion whichSha,
|
---|
| 73 | const unsigned char *key, int key_len)
|
---|
| 74 | {
|
---|
| 75 | int i, blocksize, hashsize;
|
---|
| 76 |
|
---|
| 77 | /* inner padding - key XORd with ipad */
|
---|
| 78 | unsigned char k_ipad[USHA_Max_Message_Block_Size];
|
---|
| 79 |
|
---|
| 80 | /* temporary buffer when keylen > blocksize */
|
---|
| 81 | unsigned char tempkey[USHAMaxHashSize];
|
---|
| 82 |
|
---|
| 83 | if (!ctx) return shaNull;
|
---|
| 84 |
|
---|
| 85 | blocksize = ctx->blockSize = USHABlockSize(whichSha);
|
---|
| 86 | hashsize = ctx->hashSize = USHAHashSize(whichSha);
|
---|
| 87 |
|
---|
| 88 | ctx->whichSha = whichSha;
|
---|
| 89 |
|
---|
| 90 | /*
|
---|
| 91 | * If key is longer than the hash blocksize,
|
---|
| 92 | * reset it to key = HASH(key).
|
---|
| 93 | */
|
---|
| 94 | if (key_len > blocksize) {
|
---|
| 95 | USHAContext tctx;
|
---|
| 96 | int err = USHAReset(&tctx, whichSha) ||
|
---|
| 97 | USHAInput(&tctx, key, key_len) ||
|
---|
| 98 | USHAResult(&tctx, tempkey);
|
---|
| 99 | if (err != shaSuccess) return err;
|
---|
| 100 |
|
---|
| 101 | key = tempkey;
|
---|
| 102 | key_len = hashsize;
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | /*
|
---|
| 106 | * The HMAC transform looks like:
|
---|
| 107 | *
|
---|
| 108 | * SHA(K XOR opad, SHA(K XOR ipad, text))
|
---|
| 109 | *
|
---|
| 110 | * where K is an n byte key.
|
---|
| 111 | * ipad is the byte 0x36 repeated blocksize times
|
---|
| 112 | * opad is the byte 0x5c repeated blocksize times
|
---|
| 113 | * and text is the data being protected.
|
---|
| 114 | */
|
---|
| 115 |
|
---|
| 116 | /* store key into the pads, XOR'd with ipad and opad values */
|
---|
| 117 | for (i = 0; i < key_len; i++) {
|
---|
| 118 | k_ipad[i] = key[i] ^ 0x36;
|
---|
| 119 | ctx->k_opad[i] = key[i] ^ 0x5c;
|
---|
| 120 | }
|
---|
| 121 | /* remaining pad bytes are '\0' XOR'd with ipad and opad values */
|
---|
| 122 | for (; i < blocksize; i++) {
|
---|
| 123 | k_ipad[i] = 0x36;
|
---|
| 124 | ctx->k_opad[i] = 0x5c;
|
---|
| 125 | }
|
---|
| 126 |
|
---|
| 127 | /* perform inner hash */
|
---|
| 128 | /* init context for 1st pass */
|
---|
| 129 | return USHAReset(&ctx->shaContext, whichSha) ||
|
---|
| 130 | /* and start with inner pad */
|
---|
| 131 | USHAInput(&ctx->shaContext, k_ipad, blocksize);
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | /*
|
---|
| 135 | * hmacInput
|
---|
| 136 | *
|
---|
| 137 | * Description:
|
---|
| 138 | * This function accepts an array of octets as the next portion
|
---|
| 139 | * of the message.
|
---|
| 140 | *
|
---|
| 141 | * Parameters:
|
---|
| 142 | * context: [in/out]
|
---|
| 143 | * The HMAC context to update
|
---|
| 144 | * message_array: [in]
|
---|
| 145 | * An array of characters representing the next portion of
|
---|
| 146 | * the message.
|
---|
| 147 | * length: [in]
|
---|
| 148 | * The length of the message in message_array
|
---|
| 149 | *
|
---|
| 150 | * Returns:
|
---|
| 151 | * sha Error Code.
|
---|
| 152 | *
|
---|
| 153 | */
|
---|
| 154 | int hmacInput(HMACContext *ctx, const unsigned char *text,
|
---|
| 155 | int text_len)
|
---|
| 156 | {
|
---|
| 157 | if (!ctx) return shaNull;
|
---|
| 158 | /* then text of datagram */
|
---|
| 159 | return USHAInput(&ctx->shaContext, text, text_len);
|
---|
| 160 | }
|
---|
| 161 |
|
---|
| 162 | /*
|
---|
| 163 | * HMACFinalBits
|
---|
| 164 | *
|
---|
| 165 | * Description:
|
---|
| 166 | * This function will add in any final bits of the message.
|
---|
| 167 | *
|
---|
| 168 | * Parameters:
|
---|
| 169 | * context: [in/out]
|
---|
| 170 | * The HMAC context to update
|
---|
| 171 | * message_bits: [in]
|
---|
| 172 | * The final bits of the message, in the upper portion of the
|
---|
| 173 | * byte. (Use 0b###00000 instead of 0b00000### to input the
|
---|
| 174 | * three bits ###.)
|
---|
| 175 | * length: [in]
|
---|
| 176 | * The number of bits in message_bits, between 1 and 7.
|
---|
| 177 | *
|
---|
| 178 | * Returns:
|
---|
| 179 | * sha Error Code.
|
---|
| 180 | */
|
---|
| 181 | int hmacFinalBits(HMACContext *ctx,
|
---|
| 182 | const uint8_t bits,
|
---|
| 183 | unsigned int bitcount)
|
---|
| 184 | {
|
---|
| 185 | if (!ctx) return shaNull;
|
---|
| 186 | /* then final bits of datagram */
|
---|
| 187 | return USHAFinalBits(&ctx->shaContext, bits, bitcount);
|
---|
| 188 | }
|
---|
| 189 |
|
---|
| 190 | /*
|
---|
| 191 | * HMACResult
|
---|
| 192 | *
|
---|
| 193 | * Description:
|
---|
| 194 | * This function will return the N-byte message digest into the
|
---|
| 195 | * Message_Digest array provided by the caller.
|
---|
| 196 | * NOTE: The first octet of hash is stored in the 0th element,
|
---|
| 197 | * the last octet of hash in the Nth element.
|
---|
| 198 | *
|
---|
| 199 | * Parameters:
|
---|
| 200 | * context: [in/out]
|
---|
| 201 | * The context to use to calculate the HMAC hash.
|
---|
| 202 | * digest: [out]
|
---|
| 203 | * Where the digest is returned.
|
---|
| 204 | * NOTE 2: The length of the hash is determined by the value of
|
---|
| 205 | * whichSha that was passed to hmacReset().
|
---|
| 206 | *
|
---|
| 207 | * Returns:
|
---|
| 208 | * sha Error Code.
|
---|
| 209 | *
|
---|
| 210 | */
|
---|
| 211 | int hmacResult(HMACContext *ctx, uint8_t *digest)
|
---|
| 212 | {
|
---|
| 213 | if (!ctx) return shaNull;
|
---|
| 214 |
|
---|
| 215 | /* finish up 1st pass */
|
---|
| 216 | /* (Use digest here as a temporary buffer.) */
|
---|
| 217 | return USHAResult(&ctx->shaContext, digest) ||
|
---|
| 218 |
|
---|
| 219 | /* perform outer SHA */
|
---|
| 220 | /* init context for 2nd pass */
|
---|
| 221 | USHAReset(&ctx->shaContext, (SHAversion)ctx->whichSha) ||
|
---|
| 222 |
|
---|
| 223 | /* start with outer pad */
|
---|
| 224 | USHAInput(&ctx->shaContext, ctx->k_opad, ctx->blockSize) ||
|
---|
| 225 |
|
---|
| 226 | /* then results of 1st hash */
|
---|
| 227 | USHAInput(&ctx->shaContext, digest, ctx->hashSize) ||
|
---|
| 228 |
|
---|
| 229 | /* finish up 2nd pass */
|
---|
| 230 | USHAResult(&ctx->shaContext, digest);
|
---|
| 231 | }
|
---|
| 232 |
|
---|
| 233 |
|
---|