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