diff --git a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino index 785c17583..d9f138ca2 100644 --- a/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino +++ b/libraries/ESP8266WiFiMesh/examples/HelloMesh/HelloMesh.ino @@ -55,7 +55,7 @@ bool useLED = false; // Change this to true if you wish the onboard LED to mark @return True if this node should forward the received message to other nodes. False otherwise. */ bool meshMessageHandler(String &message, FloodingMesh &meshInstance) { - int32_t delimiterIndex = message.indexOf(meshInstance.broadcastMetadataDelimiter()); + int32_t delimiterIndex = message.indexOf(meshInstance.metadataDelimiter()); if (delimiterIndex == 0) { Serial.print("Message received from STA MAC " + meshInstance.getEspnowMeshBackend().getSenderMac() + ": "); Serial.println(message.substring(2, 102)); @@ -172,7 +172,7 @@ void loop() { ledState = ledState ^ bool(benchmarkCount); // Make other nodes' LEDs alternate between on and off once benchmarking begins. // Note: The maximum length of an unencrypted broadcast message is given by floodingMesh.maxUnencryptedMessageSize(). It is around 670 bytes by default. - floodingMesh.broadcast(String(floodingMesh.broadcastMetadataDelimiter()) + String(ledState) + theOneMac + " is The One."); + floodingMesh.broadcast(String(floodingMesh.metadataDelimiter()) + String(ledState) + theOneMac + " is The One."); Serial.println("Proclamation broadcast done in " + String(millis() - startTime) + " ms."); timeOfLastProclamation = millis(); @@ -181,7 +181,7 @@ void loop() { if (millis() - loopStart > 23000) { // Start benchmarking the mesh once three proclamations have been made uint32_t startTime = millis(); - floodingMesh.broadcast(String(benchmarkCount++) + String(floodingMesh.broadcastMetadataDelimiter()) + ": Not a spoon in sight."); + floodingMesh.broadcast(String(benchmarkCount++) + String(floodingMesh.metadataDelimiter()) + ": Not a spoon in sight."); Serial.println("Benchmark broadcast done in " + String(millis() - startTime) + " ms."); floodingMeshDelay(20); } diff --git a/libraries/ESP8266WiFiMesh/src/CryptoInterface.cpp b/libraries/ESP8266WiFiMesh/src/CryptoInterface.cpp index 8ed81823f..9499bf656 100644 --- a/libraries/ESP8266WiFiMesh/src/CryptoInterface.cpp +++ b/libraries/ESP8266WiFiMesh/src/CryptoInterface.cpp @@ -28,9 +28,14 @@ #include -namespace CryptoInterface +namespace { - uint8_t *createBearsslHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t *resultArray, size_t resultArrayLength) + size_t _ctMinDataLength = 0; + size_t _ctMaxDataLength = 1024; + + bool _warningsEnabled = true; + + void *createBearsslHmac(const br_hash_class *hashType, const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) { assert(1 <= resultArrayLength); @@ -38,13 +43,9 @@ namespace CryptoInterface // HMAC is initialized with a key and an underlying hash function; it then fills a "key context". That context contains the processed key. // With the key context, a HMAC context can be initialized to process the input bytes and obtain the MAC output. The key context is not modified during that process, and can be reused. - - // hashType alternatives: &br_md5_vtable; &br_sha1_vtable; &br_sha224_vtable; &br_sha256_vtable; &br_sha384_vtable; &br_sha512_vtable; - // Use SHA256 to create the hash. - const br_hash_class *hashType = &br_sha256_vtable; br_hmac_key_context keyContext; // Holds general HMAC info - br_hmac_context hmacContext; // Holds general HMAC info + specific info for the current message + br_hmac_context hmacContext; // Holds general HMAC info + specific info for the current operation // HMAC key context initialisation. // Initialise the key context with the provided hash key, using the hash function identified by hashType. This supports arbitrary key lengths. @@ -57,9 +58,9 @@ namespace CryptoInterface br_hmac_init(&hmacContext, &keyContext, resultArrayLength); // Provide the HMAC context with the data to create a HMAC from. - // The provided message.length() bytes are injected as extra input in the HMAC computation incarnated by the hmacContext. - // It is acceptable that message.length() is zero, in which case data is ignored (and may be NULL) and this function does nothing. - br_hmac_update(&hmacContext, message.c_str(), message.length()); + // The provided dataLength bytes are injected as extra input in the HMAC computation incarnated by the hmacContext. + // It is acceptable that dataLength is zero, in which case data is ignored (and may be NULL) and this function does nothing. + br_hmac_update(&hmacContext, data, dataLength); // Compute the HMAC output. // The destination buffer MUST be large enough to accommodate the result; its length is at most the "natural length" of HMAC (i.e. the output length of the underlying hash function). @@ -70,29 +71,27 @@ namespace CryptoInterface return resultArray; } - String createBearsslHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, size_t hmacLength) + String createBearsslHmac(const br_hash_class *hashType, const uint8_t hashTypeNaturalLength, const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) { - assert(1 <= hmacLength && hmacLength <= SHA256HMAC_NATURAL_LENGTH); - byte hmac[hmacLength]; - createBearsslHmac(message, hashKey, hashKeyLength, hmac, hmacLength); + assert(1 <= hmacLength && hmacLength <= hashTypeNaturalLength); + + uint8_t hmac[hmacLength]; + createBearsslHmac(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); return uint8ArrayToHexString(hmac, hmacLength); } - uint8_t *createBearsslHmacCT(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t *resultArray, size_t resultArrayLength) + void *createBearsslHmacCT(const br_hash_class *hashType, const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) { assert(1 <= resultArrayLength); + assert(_ctMinDataLength <= dataLength && dataLength <= _ctMaxDataLength); // Comments mainly from https://www.bearssl.org/apidoc/bearssl__hmac_8h.html // HMAC is initialized with a key and an underlying hash function; it then fills a "key context". That context contains the processed key. // With the key context, a HMAC context can be initialized to process the input bytes and obtain the MAC output. The key context is not modified during that process, and can be reused. - - // hashType alternatives: &br_md5_vtable; &br_sha1_vtable; &br_sha224_vtable; &br_sha256_vtable; &br_sha384_vtable; &br_sha512_vtable; - // Use SHA256 to create the hash. - const br_hash_class *hashType = &br_sha256_vtable; br_hmac_key_context keyContext; // Holds general HMAC info - br_hmac_context hmacContext; // Holds general HMAC info + specific info for the current message + br_hmac_context hmacContext; // Holds general HMAC info + specific info for the current operation // HMAC key context initialisation. // Initialise the key context with the provided hash key, using the hash function identified by hashType. This supports arbitrary key lengths. @@ -105,43 +104,323 @@ namespace CryptoInterface br_hmac_init(&hmacContext, &keyContext, resultArrayLength); // Provide the HMAC context with the data to create a HMAC from. - // The provided message.length() bytes are injected as extra input in the HMAC computation incarnated by the hmacContext. - // It is acceptable that message.length() is zero, in which case data is ignored (and may be NULL) and this function does nothing. + // The provided dataLength bytes are injected as extra input in the HMAC computation incarnated by the hmacContext. + // It is acceptable that dataLength is zero, in which case data is ignored (and may be NULL) and this function does nothing. // No need for br_hmac_update when using constant-time version it seems. If it is used, the data provided to br_hmac_outCT will just be appended. - // br_hmac_update(&hmacContext, message.c_str(), message.length()); + // br_hmac_update(&hmacContext, data, dataLength); - // Compute the HMAC output. Assumes message is minimum 0 bytes and maximum 1000 bytes. + // Compute the HMAC output. Assumes message is minimum _ctMinDataLength bytes and maximum _ctMaxDataLength bytes. // As long as this is true, the correct HMAC output is calculated in constant-time. More constant-time info here: https://www.bearssl.org/constanttime.html // Some extra input bytes are processed, then the output is computed. - // The extra input consists in the message.length() bytes pointed to by message.c_str(). The message.length() parameter must lie between min_len and max_len (inclusive); - // max_len bytes are actually read from data (indicating each data byte can be read multiple times, if message.length() < max_len). - // Computing time (and memory access pattern) will not depend upon the data byte contents or the value of len. + // The extra input consists in the dataLength bytes pointed to by data. The dataLength parameter must lie between _ctMinDataLength and _ctMaxDataLength (inclusive); + // _ctMaxDataLength bytes are actually read from data (indicating each data byte can be read multiple times, if dataLength < _ctMaxDataLength). + // Computing time (and memory access pattern) will not depend upon the data byte contents or the value of dataLength. // The output is written in the resultArray buffer, that MUST be large enough to receive it. - // The difference max_len - min_len MUST be less than 2^30 (i.e. about one gigabyte). + // The difference _ctMaxDataLength - _ctMinDataLength MUST be less than 2^30 (i.e. about one gigabyte). // This function computes the output properly only if the underlying hash function uses MD padding (i.e. MD5, SHA-1, SHA-224, SHA-256, SHA-384 or SHA-512). // The provided context is NOT modified. - size_t min_len = 0; - size_t max_len = 1000; - assert(min_len <= message.length() && message.length() <= max_len); - br_hmac_outCT(&hmacContext, message.c_str(), message.length(), min_len, max_len, resultArray); // returns size_t outputLength + br_hmac_outCT(&hmacContext, data, dataLength, _ctMinDataLength, _ctMaxDataLength, resultArray); // returns size_t outputLength return resultArray; } - String createBearsslHmacCT(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, size_t hmacLength) + String createBearsslHmacCT(const br_hash_class *hashType, const uint8_t hashTypeNaturalLength, const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) { - assert(1 <= hmacLength && hmacLength <= SHA256HMAC_NATURAL_LENGTH); - byte hmac[hmacLength]; - createBearsslHmacCT(message, hashKey, hashKeyLength, hmac, hmacLength); + assert(1 <= hmacLength && hmacLength <= hashTypeNaturalLength); + + uint8_t hmac[hmacLength]; + createBearsslHmacCT(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); return uint8ArrayToHexString(hmac, hmacLength); } - - bool verifyBearsslHmac(const String &message, const String &messageHmac, const uint8_t *hashKey, uint8_t hashKeyLength) - { - String generatedHmac = createBearsslHmac(message, hashKey, hashKeyLength, messageHmac.length()/2); // We know that each HMAC byte should become 2 String characters due to uint8ArrayToHexString. - if(generatedHmac == messageHmac) - return true; - else - return false; - } +} + +namespace CryptoInterface +{ + void setCtMinDataLength(const size_t ctMinDataLength) + { + assert(ctMaxDataLength() - ctMinDataLength <= ctMaxDiff); + _ctMinDataLength = ctMinDataLength; + } + size_t ctMinDataLength() {return _ctMinDataLength;} + + void setCtMaxDataLength(const size_t ctMaxDataLength) + { + assert(ctMaxDataLength - ctMinDataLength() <= ctMaxDiff); + _ctMaxDataLength = ctMaxDataLength; + } + size_t ctMaxDataLength() {return _ctMaxDataLength;} + + void setWarningsEnabled(bool warningsEnabled) { _warningsEnabled = warningsEnabled; } + bool warningsEnabled() { return _warningsEnabled; } + + + // #################### MD5 #################### + + // resultArray must have size MD5_NATURAL_LENGTH or greater + void *md5Hash(const void *data, const size_t dataLength, void *resultArray) + { + if(warningsEnabled()) + Serial.println(F("\nWARNING! The MD5 hash is broken in terms of attacker resistance.\n" + "Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise.\n" + "Use CryptoInterface::setWarningsEnabled(false) to turn off this warning.\n")); + + br_md5_context context; + br_md5_init(&context); + br_md5_update(&context, data, dataLength); + br_md5_out(&context, resultArray); + return resultArray; + } + + String md5Hash(const String &message) + { + uint8_t hash[MD5_NATURAL_LENGTH]; + md5Hash(message.c_str(), message.length(), hash); + return uint8ArrayToHexString(hash, MD5_NATURAL_LENGTH); + } + + void *md5Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmac(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String md5Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmac(&br_md5_vtable, MD5_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + void *md5HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmacCT(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String md5HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmacCT(&br_md5_vtable, MD5_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + + // #################### SHA-1 #################### + + // resultArray must have size SHA1_NATURAL_LENGTH or greater + void *sha1Hash(const void *data, const size_t dataLength, void *resultArray) + { + if(warningsEnabled()) + Serial.println(F("\nWARNING! The SHA-1 hash is broken in terms of attacker resistance.\n" + "Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise.\n" + "Use CryptoInterface::setWarningsEnabled(false) to turn off this warning.\n")); + + br_sha1_context context; + br_sha1_init(&context); + br_sha1_update(&context, data, dataLength); + br_sha1_out(&context, resultArray); + return resultArray; + } + + String sha1Hash(const String &message) + { + uint8_t hash[SHA1_NATURAL_LENGTH]; + sha1Hash(message.c_str(), message.length(), hash); + return uint8ArrayToHexString(hash, SHA1_NATURAL_LENGTH); + } + + void *sha1Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmac(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha1Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmac(&br_sha1_vtable, SHA1_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + void *sha1HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmacCT(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha1HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmacCT(&br_sha1_vtable, SHA1_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + + // #################### SHA-224 #################### + + // resultArray must have size SHA224_NATURAL_LENGTH or greater + void *sha224Hash(const void *data, const size_t dataLength, void *resultArray) + { + br_sha224_context context; + br_sha224_init(&context); + br_sha224_update(&context, data, dataLength); + br_sha224_out(&context, resultArray); + return resultArray; + } + + String sha224Hash(const String &message) + { + uint8_t hash[SHA224_NATURAL_LENGTH]; + sha224Hash(message.c_str(), message.length(), hash); + return uint8ArrayToHexString(hash, SHA224_NATURAL_LENGTH); + } + + void *sha224Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmac(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha224Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmac(&br_sha224_vtable, SHA224_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + void *sha224HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmacCT(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha224HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmacCT(&br_sha224_vtable, SHA224_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + + // #################### SHA-256 #################### + + // resultArray must have size SHA256_NATURAL_LENGTH or greater + void *sha256Hash(const void *data, const size_t dataLength, void *resultArray) + { + br_sha256_context context; + br_sha256_init(&context); + br_sha256_update(&context, data, dataLength); + br_sha256_out(&context, resultArray); + return resultArray; + } + + String sha256Hash(const String &message) + { + uint8_t hash[SHA256_NATURAL_LENGTH]; + sha256Hash(message.c_str(), message.length(), hash); + return uint8ArrayToHexString(hash, SHA256_NATURAL_LENGTH); + } + + void *sha256Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmac(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha256Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmac(&br_sha256_vtable, SHA256_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + void *sha256HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmacCT(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha256HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmacCT(&br_sha256_vtable, SHA256_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + + // #################### SHA-384 #################### + + // resultArray must have size SHA384_NATURAL_LENGTH or greater + void *sha384Hash(const void *data, const size_t dataLength, void *resultArray) + { + br_sha384_context context; + br_sha384_init(&context); + br_sha384_update(&context, data, dataLength); + br_sha384_out(&context, resultArray); + return resultArray; + } + + String sha384Hash(const String &message) + { + uint8_t hash[SHA384_NATURAL_LENGTH]; + sha384Hash(message.c_str(), message.length(), hash); + return uint8ArrayToHexString(hash, SHA384_NATURAL_LENGTH); + } + + void *sha384Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmac(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha384Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmac(&br_sha384_vtable, SHA384_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + void *sha384HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmacCT(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha384HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmacCT(&br_sha384_vtable, SHA384_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + + // #################### SHA-512 #################### + + // resultArray must have size SHA512_NATURAL_LENGTH or greater + void *sha512Hash(const void *data, const size_t dataLength, void *resultArray) + { + br_sha512_context context; + br_sha512_init(&context); + br_sha512_update(&context, data, dataLength); + br_sha512_out(&context, resultArray); + return resultArray; + } + + String sha512Hash(const String &message) + { + uint8_t hash[SHA512_NATURAL_LENGTH]; + sha512Hash(message.c_str(), message.length(), hash); + return uint8ArrayToHexString(hash, SHA512_NATURAL_LENGTH); + } + + void *sha512Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmac(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha512Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmac(&br_sha512_vtable, SHA512_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + void *sha512HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength) + { + return createBearsslHmacCT(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, resultArrayLength); + } + + String sha512HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return createBearsslHmacCT(&br_sha512_vtable, SHA512_NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); + } + + + // #################### MD5+SHA-1 #################### + + // resultArray must have size MD5SHA1_NATURAL_LENGTH or greater + void *md5sha1Hash(const void *data, const size_t dataLength, void *resultArray) + { + br_md5sha1_context context; + br_md5sha1_init(&context); + br_md5sha1_update(&context, data, dataLength); + br_md5sha1_out(&context, resultArray); + return resultArray; + } + + String md5sha1Hash(const String &message) + { + uint8_t hash[MD5SHA1_NATURAL_LENGTH]; + md5sha1Hash(message.c_str(), message.length(), hash); + return uint8ArrayToHexString(hash, MD5SHA1_NATURAL_LENGTH); + } + } diff --git a/libraries/ESP8266WiFiMesh/src/CryptoInterface.h b/libraries/ESP8266WiFiMesh/src/CryptoInterface.h index 5a348a069..2b87c44fd 100644 --- a/libraries/ESP8266WiFiMesh/src/CryptoInterface.h +++ b/libraries/ESP8266WiFiMesh/src/CryptoInterface.h @@ -23,98 +23,622 @@ * THE SOFTWARE. */ -#include +#ifndef __ESP8266ARDUINOCRYPTOINTERFACE_H__ +#define __ESP8266ARDUINOCRYPTOINTERFACE_H__ -#ifndef __MESHCRYPTOINTERFACE_H__ -#define __MESHCRYPTOINTERFACE_H__ +#include namespace CryptoInterface { - const uint8_t SHA256HMAC_NATURAL_LENGTH = 32; - /** - * Create a SHA256 HMAC from the message, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. - * Uses the BearSSL cryptographic library. + * Regarding constant-time (CT) HMAC: * - * @param message The string from which to create the HMAC. - * @param hashKey The hash key to use when creating the HMAC. - * @param hashKeyLength The length of the hash key in bytes. - * @param resultArray The array wherein to store the resulting HMAC. - * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA256HMAC_NATURAL_LENGTH, - * the first (lowest index) SHA256HMAC_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * Basically, constant-time algorithms makes it harder for attackers to learn things about your system based on the execution time of code. + * Good intro here: https://www.bearssl.org/constanttime.html * - * @return A pointer to resultArray. - */ - uint8_t *createBearsslHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t *resultArray, size_t resultArrayLength); - - /** - * Create a SHA256 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. - * Uses the BearSSL cryptographic library. - * - * @param message The string from which to create the HMAC. - * @param hashKey The hash key to use when creating the HMAC. - * @param hashKeyLength The length of the hash key in bytes. - * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to 32. Defaults to SHA256HMAC_NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - String createBearsslHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, size_t hmacLength = SHA256HMAC_NATURAL_LENGTH); - - /** - * Create a SHA256 HMAC from the message, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. - * Uses the BearSSL cryptographic library. - * - * Constant-time version of createBearsslHmac(). More constant-time info here: https://www.bearssl.org/constanttime.html - * For small messages, it takes substantially longer time to complete than a normal HMAC (5 ms vs 2 ms in a quick benchmark, - * determined by the difference between min and max allowed message length), and it also sets a maximum length that messages can be (set to 1000 bytes here). - * Making the fixed max length variable would defeat the whole purpose of using constant-time, and not making it variable would create the wrong HMAC if message size exceeds the maximum. - * - * Also, HMAC is already partially constant-time. Quoting the link above: + * It should be noted that every HMAC is already partially constant-time. Quoting the link above: * "Hash functions implemented by BearSSL (MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512) consist in bitwise logical operations and additions on 32-bit or 64-bit words, * naturally yielding constant-time operations. HMAC is naturally as constant-time as the underlying hash function. The size of the MACed data, and the size of the key, * may leak, though; only the contents are protected." + * + * For messages much smaller than ctMaxDataLength(), constant-time processing takes substantially longer time to complete than a normal HMAC, + * determined by the size of (ctMaxDataLength() - ctMinDataLength()). + * Constant-time processing also sets limits on the data length. * - * Thus the non constant-time version is used within the mesh framework instead. + * Making the fixed data length limits variable will generally defeat the purpose of using constant-time. + * Using data that exceeds the fixed data length limits will create the wrong HMAC. + */ + + + constexpr uint8_t MD5_NATURAL_LENGTH = 16; + constexpr uint8_t SHA1_NATURAL_LENGTH = 20; + constexpr uint8_t SHA224_NATURAL_LENGTH = 28; + constexpr uint8_t SHA256_NATURAL_LENGTH = 32; + constexpr uint8_t SHA384_NATURAL_LENGTH = 48; + constexpr uint8_t SHA512_NATURAL_LENGTH = 64; + + /** + * MD5+SHA-1 is the concatenation of MD5 and SHA-1 computed over the same input; in the implementation, the internal data buffer is shared, + * thus making it more memory-efficient than separate MD5 and SHA-1. It can be useful in implementing SSL 3.0, TLS 1.0 and TLS 1.1. + */ + constexpr uint8_t MD5SHA1_NATURAL_LENGTH = 36; + + constexpr uint32_t ctMaxDiff = 1073741823; // 2^30 - 1 + + /** + * This function allows for fine-tuning of the specifications for the constant time calculations. + * It should not be changed once a constant time function has been used at least once. + * Otherwise the constant time will not be constant for the used functions. * - * @param message The string from which to create the HMAC. Min size 0 bytes. Max size 1000 bytes. - * @param hashKey The hash key to use when creating the HMAC. - * @param hashKeyLength The length of the hash key in bytes. - * @param resultArray The array wherein to store the resulting HMAC. - * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA256HMAC_NATURAL_LENGTH, - * the first (lowest index) SHA256HMAC_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * The difference ctMaxDataLength() - ctMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte). + */ + void setCtMinDataLength(const size_t ctMinDataLength); + /** + * 0 by default. + */ + size_t ctMinDataLength(); + + /** + * This function allows for fine-tuning of the specifications for the constant time calculations. + * It should not be changed once a constant time function has been used at least once. + * Otherwise the constant time will not be constant for the used functions. + * + * The difference ctMaxDataLength() - ctMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte). + */ + void setCtMaxDataLength(const size_t ctMaxDataLength); + /** + * 1024 by default. + */ + size_t ctMaxDataLength(); + + /** + * Turn on or off warning Serial prints from the CryptoInterface functions. + * + * @param warningsEnabled If true, warnings will be printed to Serial. + */ + void setWarningsEnabled(bool warningsEnabled); + bool warningsEnabled(); + + + // #################### MD5 #################### + + /** + * Create a MD5 hash of the data. The result will be MD5_NATURAL_LENGTH bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the hash. + * @param dataLength The length of the data array in bytes. + * @param resultArray The array wherein to store the resulting hash. MUST be be able to contain MD5_NATURAL_LENGTH bytes or more. * * @return A pointer to resultArray. */ - uint8_t *createBearsslHmacCT(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t *resultArray, size_t resultArrayLength); + void *md5Hash(const void *data, const size_t dataLength, void *resultArray); + /** + * Create a MD5 hash of the data. The result will be MD5_NATURAL_LENGTH bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the hash. + * + * @return A String with the generated hash in HEX format. + */ + String md5Hash(const String &message); + + /** + * Create a MD5 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than MD5_NATURAL_LENGTH, + * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *md5Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a MD5 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to MD5_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String md5Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + /** + * Create a MD5 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than MD5_NATURAL_LENGTH, + * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *md5HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a MD5 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to MD5_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String md5HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + + // #################### SHA-1 #################### + + /** + * Create a SHA1 hash of the data. The result will be SHA1_NATURAL_LENGTH bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the hash. + * @param dataLength The length of the data array in bytes. + * @param resultArray The array wherein to store the resulting hash. MUST be be able to contain SHA1_NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + void *sha1Hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a SHA1 hash of the data. The result will be SHA1_NATURAL_LENGTH bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the hash. + * + * @return A String with the generated hash in HEX format. + */ + String sha1Hash(const String &message); + + /** + * Create a SHA1 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA1_NATURAL_LENGTH, + * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *sha1Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a SHA1 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA1_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha1Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + /** + * Create a SHA1 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA1_NATURAL_LENGTH, + * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *sha1HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a SHA1 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA1_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha1HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + + // #################### SHA-224 #################### + + /** + * Create a SHA224 hash of the data. The result will be SHA224_NATURAL_LENGTH bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the hash. + * @param dataLength The length of the data array in bytes. + * @param resultArray The array wherein to store the resulting hash. MUST be be able to contain SHA224_NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + void *sha224Hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a SHA224 hash of the data. The result will be SHA224_NATURAL_LENGTH bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the hash. + * + * @return A String with the generated hash in HEX format. + */ + String sha224Hash(const String &message); + + /** + * Create a SHA224 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA224_NATURAL_LENGTH, + * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *sha224Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a SHA224 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA224_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha224Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + /** + * Create a SHA224 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA224_NATURAL_LENGTH, + * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *sha224HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a SHA224 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA224_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha224HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + + // #################### SHA-256 #################### + + /** + * Create a SHA256 hash of the data. The result will be SHA256_NATURAL_LENGTH bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the hash. + * @param dataLength The length of the data array in bytes. + * @param resultArray The array wherein to store the resulting hash. MUST be be able to contain SHA256_NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + void *sha256Hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a SHA256 hash of the data. The result will be SHA256_NATURAL_LENGTH bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the hash. + * + * @return A String with the generated hash in HEX format. + */ + String sha256Hash(const String &message); + + /** + * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA256_NATURAL_LENGTH, + * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *sha256Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + /** * Create a SHA256 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. * Uses the BearSSL cryptographic library. * - * Constant-time version of createBearsslHmac(). More constant-time info here: https://www.bearssl.org/constanttime.html - * Not used within the mesh framework for reasons outlined in the uint8_t *createBearsslHmacCT() description. - * - * @param message The string from which to create the HMAC. Min size 0 bytes. Max size 1000 bytes. + * @param message The string from which to create the HMAC. * @param hashKey The hash key to use when creating the HMAC. * @param hashKeyLength The length of the hash key in bytes. - * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to 32. Defaults to SHA256HMAC_NATURAL_LENGTH. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA256_NATURAL_LENGTH. * * @return A String with the generated HMAC in HEX format. */ - String createBearsslHmacCT(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, size_t hmacLength = SHA256HMAC_NATURAL_LENGTH); + String sha256Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); /** - * Verify a SHA256 HMAC which was created from the message using the provided hashKey. + * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Constant-time version. * Uses the BearSSL cryptographic library. * - * @param message The string from which the HMAC was created. - * @param messageHmac A string with the generated HMAC in HEX format. Valid messageHmac.length() is 2 to 64. + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()]. * @param hashKey The hash key to use when creating the HMAC. * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA256_NATURAL_LENGTH, + * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. * - * @return True if the HMAC is correct. False otherwise. + * @return A pointer to resultArray. */ - bool verifyBearsslHmac(const String &message, const String &messageHmac, const uint8_t *hashKey, uint8_t hashKeyLength); + void *sha256HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a SHA256 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA256_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha256HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + + // #################### SHA-384 #################### + + /** + * Create a SHA384 hash of the data. The result will be SHA384_NATURAL_LENGTH bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the hash. + * @param dataLength The length of the data array in bytes. + * @param resultArray The array wherein to store the resulting hash. MUST be be able to contain SHA384_NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + void *sha384Hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a SHA384 hash of the data. The result will be SHA384_NATURAL_LENGTH bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the hash. + * + * @return A String with the generated hash in HEX format. + */ + String sha384Hash(const String &message); + + /** + * Create a SHA384 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA384_NATURAL_LENGTH, + * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *sha384Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a SHA384 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA384_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha384Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + /** + * Create a SHA384 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA384_NATURAL_LENGTH, + * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *sha384HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a SHA384 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA384_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha384HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + + // #################### SHA-512 #################### + + /** + * Create a SHA512 hash of the data. The result will be SHA512_NATURAL_LENGTH bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the hash. + * @param dataLength The length of the data array in bytes. + * @param resultArray The array wherein to store the resulting hash. MUST be be able to contain SHA512_NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + void *sha512Hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a SHA512 hash of the data. The result will be SHA512_NATURAL_LENGTH bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the hash. + * + * @return A String with the generated hash in HEX format. + */ + String sha512Hash(const String &message); + + /** + * Create a SHA512 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA512_NATURAL_LENGTH, + * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *sha512Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a SHA512 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA512_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha512Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + /** + * Create a SHA512 HMAC from the data, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param data The data array from which to create the HMAC. + * @param dataLength The length of the data array in bytes. Valid values are in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param resultArray The array wherein to store the resulting HMAC. + * @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA512_NATURAL_LENGTH, + * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * + * @return A pointer to resultArray. + */ + void *sha512HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t resultArrayLength); + + /** + * Create a SHA512 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * Constant-time version. + * Uses the BearSSL cryptographic library. + * + * @param message The string from which to create the HMAC. Must have a length in the range [ctMinDataLength(), ctMaxDataLength()]. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to SHA512_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha512HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + + // #################### MD5+SHA-1 #################### + + /** + * Create a MD5+SHA-1 hash of the data. The result will be MD5SHA1_NATURAL_LENGTH bytes long and stored in resultArray. + * Uses the BearSSL cryptographic library. + * + * MD5+SHA-1 is the concatenation of MD5 and SHA-1 computed over the same input; in the implementation, the internal data buffer is shared, + * thus making it more memory-efficient than separate MD5 and SHA-1. It can be useful in implementing SSL 3.0, TLS 1.0 and TLS 1.1. + * + * @param data The data array from which to create the hash. + * @param dataLength The length of the data array in bytes. + * @param resultArray The array wherein to store the resulting hash. MUST be be able to contain MD5SHA1_NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + void *md5sha1Hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a MD5+SHA-1 hash of the data. The result will be MD5SHA1_NATURAL_LENGTH bytes long and returned as a String in HEX format. + * Uses the BearSSL cryptographic library. + * + * MD5+SHA-1 is the concatenation of MD5 and SHA-1 computed over the same input; in the implementation, the internal data buffer is shared, + * thus making it more memory-efficient than separate MD5 and SHA-1. It can be useful in implementing SSL 3.0, TLS 1.0 and TLS 1.1. + * + * @param message The string from which to create the hash. + * + * @return A String with the generated hash in HEX format. + */ + String md5sha1Hash(const String &message); } #endif diff --git a/libraries/ESP8266WiFiMesh/src/EncryptedConnectionData.cpp b/libraries/ESP8266WiFiMesh/src/EncryptedConnectionData.cpp index d83ece4d2..c4992a7ae 100644 --- a/libraries/ESP8266WiFiMesh/src/EncryptedConnectionData.cpp +++ b/libraries/ESP8266WiFiMesh/src/EncryptedConnectionData.cpp @@ -26,7 +26,7 @@ #include "UtilityFunctions.h" #include "TypeConversionFunctions.h" #include "JsonTranslator.h" -#include "CryptoInterface.h" +#include "MeshCryptoInterface.h" using EspnowProtocolInterpreter::espnowHashKeyLength; @@ -128,7 +128,7 @@ uint64_t EncryptedConnectionData::getOwnSessionKey() const { return _ownSessionK uint64_t EncryptedConnectionData::incrementSessionKey(uint64_t sessionKey, const uint8_t *hashKey, uint8_t hashKeyLength) { - String hmac = CryptoInterface::createBearsslHmac(uint64ToString(sessionKey), hashKey, hashKeyLength); + String hmac = MeshCryptoInterface::createMeshHmac(uint64ToString(sessionKey), hashKey, hashKeyLength); /* HMAC truncation should be OK since hmac sha256 is a PRF and we are truncating to the leftmost (MSB) bits. PRF: https://crypto.stackexchange.com/questions/26410/whats-the-gcm-sha-256-of-a-tls-protocol/26434#26434 diff --git a/libraries/ESP8266WiFiMesh/src/FloodingMesh.cpp b/libraries/ESP8266WiFiMesh/src/FloodingMesh.cpp index 021a2bfe0..ab4dd4e10 100644 --- a/libraries/ESP8266WiFiMesh/src/FloodingMesh.cpp +++ b/libraries/ESP8266WiFiMesh/src/FloodingMesh.cpp @@ -28,7 +28,7 @@ std::set FloodingMesh::availableFloodingMeshes = {}; -char FloodingMesh::_broadcastMetadataDelimiter = 23; +char FloodingMesh::_metadataDelimiter = 23; void floodingMeshDelay(uint32_t durationMs) { @@ -156,10 +156,10 @@ void FloodingMesh::broadcast(const String &message) String messageID = generateMessageID(); - // Remove getEspnowMeshBackend().getMeshName() from the broadcastMetadata below to broadcast to all ESP-NOW nodes regardless of MeshName. + // Remove getEspnowMeshBackend().getMeshName() from the metadata below to broadcast to all ESP-NOW nodes regardless of MeshName. String targetMeshName = getEspnowMeshBackend().getMeshName(); - broadcastKernel(targetMeshName + String(broadcastMetadataDelimiter()) + messageID + String(broadcastMetadataDelimiter()) + message); + broadcastKernel(targetMeshName + String(metadataDelimiter()) + messageID + String(metadataDelimiter()) + message); } void FloodingMesh::broadcastKernel(const String &message) @@ -180,7 +180,7 @@ void FloodingMesh::encryptedBroadcast(const String &message) String messageID = generateMessageID(); - encryptedBroadcastKernel(messageID + String(broadcastMetadataDelimiter()) + message); + encryptedBroadcastKernel(messageID + String(metadataDelimiter()) + message); } void FloodingMesh::encryptedBroadcastKernel(const String &message) @@ -232,15 +232,15 @@ void FloodingMesh::setMessageLogSize(uint16_t messageLogSize) } uint16_t FloodingMesh::messageLogSize() { return _messageLogSize; } -void FloodingMesh::setBroadcastMetadataDelimiter(char broadcastMetadataDelimiter) +void FloodingMesh::setMetadataDelimiter(char metadataDelimiter) { // Using HEX number characters as a delimiter is a bad idea regardless of broadcast type, since they are always in the broadcast metadata - assert(broadcastMetadataDelimiter < 48 || 57 < broadcastMetadataDelimiter); - assert(broadcastMetadataDelimiter < 65 || 70 < broadcastMetadataDelimiter); + assert(metadataDelimiter < 48 || 57 < metadataDelimiter); + assert(metadataDelimiter < 65 || 70 < metadataDelimiter); - _broadcastMetadataDelimiter = broadcastMetadataDelimiter; + _metadataDelimiter = metadataDelimiter; } -char FloodingMesh::broadcastMetadataDelimiter() { return _broadcastMetadataDelimiter; } +char FloodingMesh::metadataDelimiter() { return _metadataDelimiter; } EspnowMeshBackend &FloodingMesh::getEspnowMeshBackend() { @@ -342,12 +342,12 @@ String FloodingMesh::_defaultRequestHandler(const String &request, MeshBackendBa String broadcastTarget = ""; String remainingRequest = ""; - if(request.charAt(0) == broadcastMetadataDelimiter()) + if(request.charAt(0) == metadataDelimiter()) { - int32_t broadcastTargetEndIndex = request.indexOf(broadcastMetadataDelimiter(), 1); + int32_t broadcastTargetEndIndex = request.indexOf(metadataDelimiter(), 1); if(broadcastTargetEndIndex == -1) - return ""; // broadcastMetadataDelimiter not found + return ""; // metadataDelimiter not found broadcastTarget = request.substring(1, broadcastTargetEndIndex + 1); // Include delimiter remainingRequest = request.substring(broadcastTargetEndIndex + 1); @@ -357,10 +357,10 @@ String FloodingMesh::_defaultRequestHandler(const String &request, MeshBackendBa remainingRequest = request; } - int32_t messageIDEndIndex = remainingRequest.indexOf(broadcastMetadataDelimiter()); + int32_t messageIDEndIndex = remainingRequest.indexOf(metadataDelimiter()); if(messageIDEndIndex == -1) - return ""; // broadcastMetadataDelimiter not found + return ""; // metadataDelimiter not found uint64_t messageID = stringToUint64(remainingRequest.substring(0, messageIDEndIndex)); @@ -447,16 +447,16 @@ void FloodingMesh::_defaultNetworkFilter(int numberOfNetworks, MeshBackendBase & */ bool FloodingMesh::_defaultBroadcastFilter(String &firstTransmission, EspnowMeshBackend &meshInstance) { - // This broadcastFilter will accept a transmission if it contains the broadcastMetadataDelimiter + // This broadcastFilter will accept a transmission if it contains the metadataDelimiter // and as metaData either no targetMeshName or a targetMeshName that matches the MeshName of meshInstance // and insertPreliminaryMessageID(messageID) returns true. // Broadcast firstTransmission String structure: targetMeshName+messageID+message. - int32_t metadataEndIndex = firstTransmission.indexOf(broadcastMetadataDelimiter()); + int32_t metadataEndIndex = firstTransmission.indexOf(metadataDelimiter()); if(metadataEndIndex == -1) - return false; // broadcastMetadataDelimiter not found + return false; // metadataDelimiter not found String targetMeshName = firstTransmission.substring(0, metadataEndIndex); @@ -466,17 +466,17 @@ bool FloodingMesh::_defaultBroadcastFilter(String &firstTransmission, EspnowMesh } else { - int32_t messageIDEndIndex = firstTransmission.indexOf(broadcastMetadataDelimiter(), metadataEndIndex + 1); + int32_t messageIDEndIndex = firstTransmission.indexOf(metadataDelimiter(), metadataEndIndex + 1); if(messageIDEndIndex == -1) - return false; // broadcastMetadataDelimiter not found + return false; // metadataDelimiter not found uint64_t messageID = stringToUint64(firstTransmission.substring(metadataEndIndex + 1, messageIDEndIndex)); if(insertPreliminaryMessageID(messageID)) { // Add broadcast identifier to stored message and mark as accepted broadcast. - firstTransmission = String(broadcastMetadataDelimiter()) + firstTransmission; + firstTransmission = String(metadataDelimiter()) + firstTransmission; return true; } else diff --git a/libraries/ESP8266WiFiMesh/src/FloodingMesh.h b/libraries/ESP8266WiFiMesh/src/FloodingMesh.h index cc4176841..6bd7f0afb 100644 --- a/libraries/ESP8266WiFiMesh/src/FloodingMesh.h +++ b/libraries/ESP8266WiFiMesh/src/FloodingMesh.h @@ -217,11 +217,11 @@ public: * Set the delimiter character used for metadata by every FloodingMesh instance. * Using characters found in the mesh name or in HEX numbers is unwise, as is using ','. * - * @param broadcastMetadataDelimiter The metadata delimiter character to use. + * @param metadataDelimiter The metadata delimiter character to use. * Defaults to 23 = End-of-Transmission-Block (ETB) control character in ASCII */ - static void setBroadcastMetadataDelimiter(char broadcastMetadataDelimiter); - static char broadcastMetadataDelimiter(); + static void setMetadataDelimiter(char metadataDelimiter); + static char metadataDelimiter(); /* * Gives you access to the EspnowMeshBackend used by the mesh node. @@ -274,7 +274,7 @@ private: uint8_t _broadcastReceptionRedundancy = 2; - static char _broadcastMetadataDelimiter; // Defaults to 23 = End-of-Transmission-Block (ETB) control character in ASCII + static char _metadataDelimiter; // Defaults to 23 = End-of-Transmission-Block (ETB) control character in ASCII uint8_t _originMac[6] = {0}; diff --git a/libraries/ESP8266WiFiMesh/src/JsonTranslator.cpp b/libraries/ESP8266WiFiMesh/src/JsonTranslator.cpp index b78b1babe..f953b9933 100644 --- a/libraries/ESP8266WiFiMesh/src/JsonTranslator.cpp +++ b/libraries/ESP8266WiFiMesh/src/JsonTranslator.cpp @@ -25,7 +25,7 @@ #include "JsonTranslator.h" #include "EspnowProtocolInterpreter.h" #include "TypeConversionFunctions.h" -#include "CryptoInterface.h" +#include "MeshCryptoInterface.h" namespace JsonTranslator { @@ -69,14 +69,14 @@ namespace JsonTranslator uint8_t staMac[6] {0}; uint8_t apMac[6] {0}; String requesterStaApMac = macToString(WiFi.macAddress(staMac)) + macToString(WiFi.softAPmacAddress(apMac)); - String hmac = CryptoInterface::createBearsslHmac(requesterStaApMac + mainMessage, hashKey, hashKeyLength); + String hmac = MeshCryptoInterface::createMeshHmac(requesterStaApMac + mainMessage, hashKey, hashKeyLength); return mainMessage + createJsonEndPair(jsonHmac, hmac); } bool verifyEncryptionRequestHmac(const String &encryptionRequestHmacMessage, const uint8_t *requesterStaMac, const uint8_t *requesterApMac, const uint8_t *hashKey, uint8_t hashKeyLength) { - using namespace CryptoInterface; + using MeshCryptoInterface::verifyMeshHmac; String hmac = ""; if(getHmac(encryptionRequestHmacMessage, hmac)) @@ -85,8 +85,8 @@ namespace JsonTranslator if(hmacStartIndex < 0) return false; - if(hmac.length() == 2*SHA256HMAC_NATURAL_LENGTH // We know that each HMAC byte should become 2 String characters due to uint8ArrayToHexString. - && verifyBearsslHmac(macToString(requesterStaMac) + macToString(requesterApMac) + encryptionRequestHmacMessage.substring(0, hmacStartIndex), hmac, hashKey, hashKeyLength)) + if(hmac.length() == 2*CryptoInterface::SHA256_NATURAL_LENGTH // We know that each HMAC byte should become 2 String characters due to uint8ArrayToHexString. + && verifyMeshHmac(macToString(requesterStaMac) + macToString(requesterApMac) + encryptionRequestHmacMessage.substring(0, hmacStartIndex), hmac, hashKey, hashKeyLength)) { return true; } diff --git a/libraries/ESP8266WiFiMesh/src/MeshCryptoInterface.cpp b/libraries/ESP8266WiFiMesh/src/MeshCryptoInterface.cpp new file mode 100644 index 000000000..607f6cbf0 --- /dev/null +++ b/libraries/ESP8266WiFiMesh/src/MeshCryptoInterface.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 Anders Löfgren + * + * License (MIT license): + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "MeshCryptoInterface.h" + +namespace MeshCryptoInterface +{ + String createMeshHmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + { + return CryptoInterface::sha256Hmac(message, hashKey, hashKeyLength, hmacLength); + } + + bool verifyMeshHmac(const String &message, const String &messageHmac, const uint8_t *hashKey, uint8_t hashKeyLength) + { + String generatedHmac = createMeshHmac(message, hashKey, hashKeyLength, messageHmac.length()/2); // We know that each HMAC byte should become 2 String characters due to uint8ArrayToHexString. + if(generatedHmac == messageHmac) + return true; + else + return false; + } +} diff --git a/libraries/ESP8266WiFiMesh/src/MeshCryptoInterface.h b/libraries/ESP8266WiFiMesh/src/MeshCryptoInterface.h new file mode 100644 index 000000000..25f90eb49 --- /dev/null +++ b/libraries/ESP8266WiFiMesh/src/MeshCryptoInterface.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2019 Anders Löfgren + * + * License (MIT license): + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef __MESHCRYPTOINTERFACE_H__ +#define __MESHCRYPTOINTERFACE_H__ + +#include +#include "CryptoInterface.h" + +namespace MeshCryptoInterface +{ + /** + * There is a constant-time HMAC version available. More constant-time info here: https://www.bearssl.org/constanttime.html + * For small messages, it takes substantially longer time to complete than a normal HMAC (5 ms vs 2 ms in a quick benchmark, + * determined by the difference between min and max allowed message length), and it also sets a maximum length that messages can be (1024 bytes by default). + * Making the fixed max length variable would defeat the whole purpose of using constant-time, and not making it variable would create the wrong HMAC if message size exceeds the maximum. + * + * Also, HMAC is already partially constant-time. Quoting the link above: + * "Hash functions implemented by BearSSL (MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512) consist in bitwise logical operations and additions on 32-bit or 64-bit words, + * naturally yielding constant-time operations. HMAC is naturally as constant-time as the underlying hash function. The size of the MACed data, and the size of the key, + * may leak, though; only the contents are protected." + * + * Thus the non constant-time version is used within the mesh framework instead. + */ + + /** + * Create a SHA256 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format. + * + * @param message The string from which to create the HMAC. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to 32. Defaults to CryptoInterface::SHA256_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String createMeshHmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength = CryptoInterface::SHA256_NATURAL_LENGTH); + + /** + * Verify a SHA256 HMAC which was created from the message using the provided hashKey. + * + * @param message The string from which the HMAC was created. + * @param messageHmac A string with the generated HMAC in HEX format. Valid messageHmac.length() is 2 to 64. + * @param hashKey The hash key to use when creating the HMAC. + * @param hashKeyLength The length of the hash key in bytes. + * + * @return True if the HMAC is correct. False otherwise. + */ + bool verifyMeshHmac(const String &message, const String &messageHmac, const uint8_t *hashKey, uint8_t hashKeyLength); +} + +#endif