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