Azure IoT common library

Dependents:   STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more

Revision:
0:fa2de1b79154
Child:
19:2e0811512ceb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hmac.c	Fri Apr 08 12:01:36 2016 -0700
@@ -0,0 +1,239 @@
+// 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 <stdlib.h>
+#ifdef _CRTDBG_MAP_ALLOC
+#include <crtdbg.h>
+#endif
+#include "azure_c_shared_utility/gballoc.h"
+
+#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);
+}
+
+