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.
Fork of azure_c_shared_utility by
hmac.c
- Committer:
- AzureIoTClient
- Date:
- 2017-01-28
- Revision:
- 19:2e0811512ceb
- Parent:
- 0:fa2de1b79154
- Child:
- 25:8507bf644fdf
File content as of revision 19:2e0811512ceb:
// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. /**************************** hmac.c ****************************/ /******************** See RFC 4634 for details ******************/ /* * Description: * This file implements the HMAC algorithm (Keyed-Hashing for * Message Authentication, RFC2104), expressed in terms of the * various SHA algorithms. */ #include "azure_c_shared_utility/sha.h" /* * hmac * * Description: * This function will compute an HMAC message digest. * * Parameters: * whichSha: [in] * One of SHA1, SHA224, SHA256, SHA384, SHA512 * key: [in] * The secret shared key. * key_len: [in] * The length of the secret shared key. * message_array: [in] * An array of characters representing the message. * length: [in] * The length of the message in message_array * digest: [out] * Where the digest is returned. * NOTE: The length of the digest is determined by * the value of whichSha. * * Returns: * sha Error Code. * */ int hmac(SHAversion whichSha, const unsigned char *text, int text_len, const unsigned char *key, int key_len, uint8_t digest[USHAMaxHashSize]) { HMACContext ctx; return hmacReset(&ctx, whichSha, key, key_len) || hmacInput(&ctx, text, text_len) || hmacResult(&ctx, digest); } /* * hmacReset * * Description: * This function will initialize the hmacContext in preparation * for computing a new HMAC message digest. * * Parameters: * context: [in/out] * The context to reset. * whichSha: [in] * One of SHA1, SHA224, SHA256, SHA384, SHA512 * key: [in] * The secret shared key. * key_len: [in] * The length of the secret shared key. * * Returns: * sha Error Code. * */ int hmacReset(HMACContext *ctx, enum SHAversion whichSha, const unsigned char *key, int key_len) { int i, blocksize, hashsize; /* inner padding - key XORd with ipad */ unsigned char k_ipad[USHA_Max_Message_Block_Size]; /* temporary buffer when keylen > blocksize */ unsigned char tempkey[USHAMaxHashSize]; if (!ctx) return shaNull; blocksize = ctx->blockSize = USHABlockSize(whichSha); hashsize = ctx->hashSize = USHAHashSize(whichSha); ctx->whichSha = whichSha; /* * If key is longer than the hash blocksize, * reset it to key = HASH(key). */ if (key_len > blocksize) { USHAContext tctx; int err = USHAReset(&tctx, whichSha) || USHAInput(&tctx, key, key_len) || USHAResult(&tctx, tempkey); if (err != shaSuccess) return err; key = tempkey; key_len = hashsize; } /* * The HMAC transform looks like: * * SHA(K XOR opad, SHA(K XOR ipad, text)) * * where K is an n byte key. * ipad is the byte 0x36 repeated blocksize times * opad is the byte 0x5c repeated blocksize times * and text is the data being protected. */ /* store key into the pads, XOR'd with ipad and opad values */ for (i = 0; i < key_len; i++) { k_ipad[i] = key[i] ^ 0x36; ctx->k_opad[i] = key[i] ^ 0x5c; } /* remaining pad bytes are '\0' XOR'd with ipad and opad values */ for (; i < blocksize; i++) { k_ipad[i] = 0x36; ctx->k_opad[i] = 0x5c; } /* perform inner hash */ /* init context for 1st pass */ return USHAReset(&ctx->shaContext, whichSha) || /* and start with inner pad */ USHAInput(&ctx->shaContext, k_ipad, blocksize); } /* * hmacInput * * Description: * This function accepts an array of octets as the next portion * of the message. * * Parameters: * context: [in/out] * The HMAC context to update * message_array: [in] * An array of characters representing the next portion of * the message. * length: [in] * The length of the message in message_array * * Returns: * sha Error Code. * */ int hmacInput(HMACContext *ctx, const unsigned char *text, int text_len) { if (!ctx) return shaNull; /* then text of datagram */ return USHAInput(&ctx->shaContext, text, text_len); } /* * HMACFinalBits * * Description: * This function will add in any final bits of the message. * * Parameters: * context: [in/out] * The HMAC context to update * message_bits: [in] * The final bits of the message, in the upper portion of the * byte. (Use 0b###00000 instead of 0b00000### to input the * three bits ###.) * length: [in] * The number of bits in message_bits, between 1 and 7. * * Returns: * sha Error Code. */ int hmacFinalBits(HMACContext *ctx, const uint8_t bits, unsigned int bitcount) { if (!ctx) return shaNull; /* then final bits of datagram */ return USHAFinalBits(&ctx->shaContext, bits, bitcount); } /* * HMACResult * * Description: * This function will return the N-byte message digest into the * Message_Digest array provided by the caller. * NOTE: The first octet of hash is stored in the 0th element, * the last octet of hash in the Nth element. * * Parameters: * context: [in/out] * The context to use to calculate the HMAC hash. * digest: [out] * Where the digest is returned. * NOTE 2: The length of the hash is determined by the value of * whichSha that was passed to hmacReset(). * * Returns: * sha Error Code. * */ int hmacResult(HMACContext *ctx, uint8_t *digest) { if (!ctx) return shaNull; /* finish up 1st pass */ /* (Use digest here as a temporary buffer.) */ return USHAResult(&ctx->shaContext, digest) || /* perform outer SHA */ /* init context for 2nd pass */ USHAReset(&ctx->shaContext, ctx->whichSha) || /* start with outer pad */ USHAInput(&ctx->shaContext, ctx->k_opad, ctx->blockSize) || /* then results of 1st hash */ USHAInput(&ctx->shaContext, digest, ctx->hashSize) || /* finish up 2nd pass */ USHAResult(&ctx->shaContext, digest); }