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