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