From b3362a04badb2355d33f6ddfce3edc97ec509760 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 24 Dec 2019 11:28:08 +0100 Subject: [PATCH 1/9] - Add CryptoInterface library. - Add TypeConversion core files. --- cores/esp8266/TypeConversion.cpp | 82 ++ cores/esp8266/TypeConversion.h | 78 ++ libraries/CryptoInterface/README.md | 9 + .../examples/HelloCrypto/HelloCrypto.ino | 101 +++ libraries/CryptoInterface/keywords.txt | 65 ++ libraries/CryptoInterface/library.properties | 10 + .../CryptoInterface/src/CryptoInterface.cpp | 565 +++++++++++++ .../CryptoInterface/src/CryptoInterface.h | 799 ++++++++++++++++++ 8 files changed, 1709 insertions(+) create mode 100644 cores/esp8266/TypeConversion.cpp create mode 100644 cores/esp8266/TypeConversion.h create mode 100644 libraries/CryptoInterface/README.md create mode 100644 libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino create mode 100644 libraries/CryptoInterface/keywords.txt create mode 100644 libraries/CryptoInterface/library.properties create mode 100644 libraries/CryptoInterface/src/CryptoInterface.cpp create mode 100644 libraries/CryptoInterface/src/CryptoInterface.h diff --git a/cores/esp8266/TypeConversion.cpp b/cores/esp8266/TypeConversion.cpp new file mode 100644 index 0000000000..e71d810d95 --- /dev/null +++ b/cores/esp8266/TypeConversion.cpp @@ -0,0 +1,82 @@ +/* + TypeConversion functionality + 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 +#include "TypeConversion.h" + +namespace esp8266 { + namespace TypeConversion { + const char base36Chars[36] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; + const uint8_t base36CharValues[75] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, // 0 to 10 + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 0, 0, 0, 0, 0, // Upper case letters + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 + }; // Lower case letters + + + String uint8ArrayToHexString(const uint8_t *uint8Array, const uint32_t arrayLength) { + String hexString; + if (!hexString.reserve(2 * arrayLength)) { // Each uint8_t will become two characters (00 to FF) + return emptyString; + } + + for (uint32_t i = 0; i < arrayLength; ++i) { + hexString += base36Chars[ uint8Array[i] >> 4 ]; + hexString += base36Chars[ uint8Array[i] % 16 ]; + } + + return hexString; + } + + uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, const uint32_t arrayLength) { + assert(hexString.length() >= arrayLength * 2); // Each array element can hold two hexString characters + + for (uint32_t i = 0; i < arrayLength; ++i) { + uint8Array[i] = (base36CharValues[hexString.charAt(i * 2) - '0'] << 4) + base36CharValues[hexString.charAt(i * 2 + 1) - '0']; + } + + return uint8Array; + } + + uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray) { + resultArray[7] = value; + resultArray[6] = value >> 8; + resultArray[5] = value >> 16; + resultArray[4] = value >> 24; + resultArray[3] = value >> 32; + resultArray[2] = value >> 40; + resultArray[1] = value >> 48; + resultArray[0] = value >> 56; + + return resultArray; + } + + uint64_t uint8ArrayToUint64(const uint8_t *inputArray) { + uint64_t result = (uint64_t)inputArray[0] << 56 | (uint64_t)inputArray[1] << 48 | (uint64_t)inputArray[2] << 40 | (uint64_t)inputArray[3] << 32 + | (uint64_t)inputArray[4] << 24 | (uint64_t)inputArray[5] << 16 | (uint64_t)inputArray[6] << 8 | (uint64_t)inputArray[7]; + + return result; + } + } +} diff --git a/cores/esp8266/TypeConversion.h b/cores/esp8266/TypeConversion.h new file mode 100644 index 0000000000..ecce9cf55e --- /dev/null +++ b/cores/esp8266/TypeConversion.h @@ -0,0 +1,78 @@ +/* + TypeConversion functionality + 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 __ESP8266_TYPECONVERSION_H__ +#define __ESP8266_TYPECONVERSION_H__ + +#include + +namespace esp8266 { + namespace TypeConversion { + extern const char base36Chars[36]; + + // Subtract '0' to normalize the char before lookup. + extern const uint8_t base36CharValues[75]; + + /** + Convert the contents of a uint8_t array to a String in HEX format. The resulting String starts from index 0 of the array. + All array elements will be padded with zeroes to ensure they are converted to 2 String characters each. + + @param uint8Array The array to make into a HEX String. + @param arrayLength The size of uint8Array, in bytes. + @return Normally a String containing the HEX representation of the uint8Array. An empty String if the memory allocation for the String failed. + */ + String uint8ArrayToHexString(const uint8_t *uint8Array, const uint32_t arrayLength); + + /** + Convert the contents of a String in HEX format to a uint8_t array. Index 0 of the array will represent the start of the String. + There must be 2 String characters for each array element. Use padding with zeroes where required. + + @param hexString The HEX String to convert to a uint8_t array. Must contain at least 2*arrayLength characters. + @param uint8Array The array to fill with the contents of the hexString. + @param arrayLength The number of bytes to fill in uint8Array. + @return A pointer to the uint8Array. + */ + uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, const uint32_t arrayLength); + + /** + Takes a uint64_t value and stores the bits in a uint8_t array. Assumes index 0 of the array should contain MSB. + + @param value The uint64_t value to convert to a uint8_t array. + @param resultArray A uint8_t array that will hold the result once the function returns. Should have a size of at least 8 bytes. + @return The resultArray. + */ + uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray); + + /** + Takes a uint8_t array and converts the first 8 (lowest index) elements to a uint64_t. Assumes index 0 of the array contains MSB. + + @param inputArray A uint8_t array containing the data to convert to a uint64_t. Should have a size of at least 8 bytes. + @return A uint64_t representation of the first 8 bytes of the array. + */ + uint64_t uint8ArrayToUint64(const uint8_t *inputArray); + } +} + +#endif diff --git a/libraries/CryptoInterface/README.md b/libraries/CryptoInterface/README.md new file mode 100644 index 0000000000..d32c33ca3d --- /dev/null +++ b/libraries/CryptoInterface/README.md @@ -0,0 +1,9 @@ +ESP8266 CryptoInterface +================= + +A library containing easy-to-use cryptographic functions. Primarily a frontend for the cryptographic library BearSSL which is used by `BearSSL::WiFiClientSecure` and `BearSSL::WiFiServerSecure` in the ESP8266 Arduino Core. + +Usage +----- + +There are a number of cryptographic functions in the library. See the included example for a guide on how to use some of them. Extensive documentation can be found in the library source code files and on the [BearSSL homepage](https://www.bearssl.org). \ No newline at end of file diff --git a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino new file mode 100644 index 0000000000..b16b97675e --- /dev/null +++ b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino @@ -0,0 +1,101 @@ +/** + This example shows the functionality of the CryptoInterface library. +*/ + +#include +#include +#include + +namespace TypeCast = esp8266::TypeConversion; + +/** + NOTE: Although we could define the strings below as normal String variables, + here we are using PROGMEM combined with the FPSTR() macro (and also just the F() macro further down in the file). + The reason is that this approach will place the strings in flash memory which will help save RAM during program execution. + Reading strings from flash will be slower than reading them from RAM, + but this will be a negligible difference when printing them to Serial. + + More on F(), FPSTR() and PROGMEM: + https://github.com/esp8266/Arduino/issues/1143 + https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html +*/ +constexpr char masterKey[] PROGMEM = "w86vn@rpfA O+S"; // Use 8 random characters or more + +void setup() { + // Prevents the flash memory from being worn out, see: https://github.com/esp8266/Arduino/issues/1054 . + // This will however delay node WiFi start-up by about 700 ms. The delay is 900 ms if we otherwise would have stored the WiFi network we want to connect to. + WiFi.persistent(false); + + Serial.begin(115200); + delay(50); // Wait for Serial. + + //yield(); // Use this if you don't want to wait for Serial. + + // The WiFi.disconnect() ensures that the WiFi is working correctly. If this is not done before receiving WiFi connections, + // those WiFi connections will take a long time to make or sometimes will not work at all. + WiFi.disconnect(); + + Serial.println(); + Serial.println(); +} + +void loop() +{ + // This serves only to demonstrate the library use. See the header file for a full list of functions. + + String exampleData = F("Hello Crypto World!"); + Serial.println(String(F("This is our example data: ")) + exampleData); + + uint8_t resultArray[CryptoInterface::SHA256_NATURAL_LENGTH] { 0 }; + uint8_t derivedKey[CryptoInterface::ENCRYPTION_KEY_LENGTH] { 0 }; + + static uint32_t encryptionCounter = 0; + + + // Generate the salt to use for HKDF + uint8_t hkdfSalt[16] { 0 }; + CryptoInterface::getNonceGenerator()(hkdfSalt, sizeof hkdfSalt); + + // Generate the key to use for HMAC and encryption + CryptoInterface::hkdfInit(FPSTR(masterKey), (sizeof masterKey) - 1, hkdfSalt, sizeof hkdfSalt); // (sizeof masterKey) - 1 removes the terminating null value of the c-string + CryptoInterface::hkdfProduce(derivedKey, sizeof derivedKey); + + // Hash + CryptoInterface::sha256Hash(exampleData.c_str(), exampleData.length(), resultArray); + Serial.println(String(F("\nThis is the SHA256 hash of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); + Serial.println(String(F("This is the SHA256 hash of our example data, in HEX format, using String output:\n")) + CryptoInterface::sha256Hash(exampleData)); + + + // HMAC + // Note that HMAC output length is limited + CryptoInterface::sha256Hmac(exampleData.c_str(), exampleData.length(), derivedKey, sizeof derivedKey, resultArray, sizeof resultArray); + Serial.println(String(F("\nThis is the SHA256 HMAC of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); + Serial.println(String(F("This is the SHA256 HMAC of our example data, in HEX format, using String output:\n")) + CryptoInterface::sha256Hmac(exampleData, derivedKey, sizeof derivedKey, CryptoInterface::SHA256_NATURAL_LENGTH)); + + + // Authenticated Encryption with Associated Data (AEAD) + String dataToEncrypt = F("This data is not encrypted."); + uint8_t resultingNonce[12] { 0 }; // The nonce is always 12 bytes + uint8_t resultingTag[16] { 0 }; // The tag is always 16 bytes + + Serial.println(String(F("\nThis is the data to encrypt: ")) + dataToEncrypt); + + // Note that the key must be ENCRYPTION_KEY_LENGTH long. + CryptoInterface::chacha20Poly1305Encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + Serial.println(String(F("Encrypted data: ")) + dataToEncrypt); + + bool decryptionSucceeded = CryptoInterface::chacha20Poly1305Decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + encryptionCounter++; + + if(decryptionSucceeded) + Serial.print(F("Decryption succeeded. Result: ")); + else + Serial.print(F("Decryption failed. Result: ")); + + Serial.println(dataToEncrypt); + + + Serial.println(F("\n##########################################################################################################\n")); + + delay(10000); +} diff --git a/libraries/CryptoInterface/keywords.txt b/libraries/CryptoInterface/keywords.txt new file mode 100644 index 0000000000..0b984df26c --- /dev/null +++ b/libraries/CryptoInterface/keywords.txt @@ -0,0 +1,65 @@ +####################################### +# Syntax Coloring Map For ESP8266WiFiMesh +####################################### + +####################################### +# Library (KEYWORD3) +####################################### + +CryptoInterface KEYWORD3 + +####################################### +# Datatypes (KEYWORD1) +####################################### + +nonceGeneratorType KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +setCtMinDataLength KEYWORD2 +ctMinDataLength KEYWORD2 +setCtMaxDataLength KEYWORD2 +ctMaxDataLength KEYWORD2 +setWarningsEnabled KEYWORD2 +warningsEnabled KEYWORD2 +setNonceGenerator KEYWORD2 +getNonceGenerator KEYWORD2 +md5Hash KEYWORD2 +md5Hmac KEYWORD2 +md5HmacCT KEYWORD2 +sha1Hash KEYWORD2 +sha1Hmac KEYWORD2 +sha1HmacCT KEYWORD2 +sha224Hash KEYWORD2 +sha224Hmac KEYWORD2 +sha224HmacCT KEYWORD2 +sha256Hash KEYWORD2 +sha256Hmac KEYWORD2 +sha256HmacCT KEYWORD2 +sha384Hash KEYWORD2 +sha384Hmac KEYWORD2 +sha384HmacCT KEYWORD2 +sha512Hash->KEYWORD2 +sha512Hmac KEYWORD2 +sha512HmacCT KEYWORD2 +md5sha1Hash KEYWORD2 +hkdfInit KEYWORD2 +hkdfProduce KEYWORD2 +chacha20Poly1305Encrypt KEYWORD2 +chacha20Poly1305Decrypt KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### + +MD5_NATURAL_LENGTH LITERAL1 +SHA1_NATURAL_LENGTH LITERAL1 +SHA224_NATURAL_LENGTH LITERAL1 +SHA256_NATURAL_LENGTH LITERAL1 +SHA384_NATURAL_LENGTH LITERAL1 +SHA512_NATURAL_LENGTH LITERAL1 +MD5SHA1_NATURAL_LENGTH LITERAL1 +ENCRYPTION_KEY_LENGTH LITERAL1 +CT_MAX_DIFF LITERAL1 diff --git a/libraries/CryptoInterface/library.properties b/libraries/CryptoInterface/library.properties new file mode 100644 index 0000000000..3a1ebe6bf4 --- /dev/null +++ b/libraries/CryptoInterface/library.properties @@ -0,0 +1,10 @@ +name=CryptoInterface +version=1.0 +author=Anders Löfgren +maintainer=Anders Löfgren +sentence=Interface to the cryptographic library +paragraph=The library acts as a frontend to the cryptographic backend library in ESP8266 Arduino Core. +category=Cryptography +url= +architectures=esp8266 +dot_a_linkage=true diff --git a/libraries/CryptoInterface/src/CryptoInterface.cpp b/libraries/CryptoInterface/src/CryptoInterface.cpp new file mode 100644 index 0000000000..a998f759e7 --- /dev/null +++ b/libraries/CryptoInterface/src/CryptoInterface.cpp @@ -0,0 +1,565 @@ +/* + * BearSSL Copyright (c) 2016 Thomas Pornin + * Rest of this file 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 "CryptoInterface.h" +#include + +#include + +namespace TypeCast = esp8266::TypeConversion; + +namespace +{ + size_t _ctMinDataLength = 0; + size_t _ctMaxDataLength = 1024; + + bool _warningsEnabled = true; + + br_hkdf_context _storedHkdfContext; + bool _hkdfContextStored = false; + + uint8_t *defaultNonceGenerator(uint8_t *nonceArray, const size_t nonceLength) + { + /** + * The ESP32 Technical Reference Manual v4.1 chapter 24 has the following to say about random number generation (no information found for ESP8266): + * + * "When used correctly, every 32-bit value the system reads from the RNG_DATA_REG register of the random number generator is a true random number. + * These true random numbers are generated based on the noise in the Wi-Fi/BT RF system. + * When Wi-Fi and BT are disabled, the random number generator will give out pseudo-random numbers. + * + * When Wi-Fi or BT is enabled, the random number generator is fed two bits of entropy every APB clock cycle (normally 80 MHz). + * Thus, for the maximum amount of entropy, it is advisable to read the random register at a maximum rate of 5 MHz. + * A data sample of 2 GB, read from the random number generator with Wi-Fi enabled and the random register read at 5 MHz, + * has been tested using the Dieharder Random Number Testsuite (version 3.31.1). + * The sample passed all tests." + * + * Since ESP32 is the sequal to ESP8266 it is unlikely that the ESP8266 is able to generate random numbers more quickly than 5 MHz when run at a 80 MHz frequency. + * A maximum random number frequency of 0.5 MHz is used here to leave some margin for possibly inferior components in the ESP8266. + * It should be noted that the ESP8266 has no Bluetooth functionality, so turning the WiFi off is likely to cause RANDOM_REG32 to use pseudo-random numbers. + * + * It is possible that yield() must be called on the ESP8266 to properly feed the hardware random number generator new bits, since there is only one processor core available. + * However, no feeding requirements are mentioned in the ESP32 documentation, and using yield() could possibly cause extended delays during nonce generation. + * Thus only delayMicroseconds() is used below. + */ + + constexpr uint8_t cooldownMicros = 2; + static uint32_t lastCalledMicros = micros() - cooldownMicros; + + uint32_t randomNumber = 0; + + for(size_t byteIndex = 0; byteIndex < nonceLength; ++byteIndex) + { + if(byteIndex % 4 == 0) + { + // Old random number has been used up (random number could be exactly 0, so we can't check for that) + + uint32_t timeSinceLastCall = micros() - lastCalledMicros; + if(timeSinceLastCall < cooldownMicros) + delayMicroseconds(cooldownMicros - timeSinceLastCall); + + randomNumber = RANDOM_REG32; + lastCalledMicros = micros(); + } + + nonceArray[byteIndex] = randomNumber; + randomNumber >>= 8; + } + + return nonceArray; + } + + CryptoInterface::nonceGeneratorType _nonceGenerator = defaultNonceGenerator; + + 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 outputLength) + { + // 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. + + br_hmac_key_context keyContext; // Holds general HMAC info + 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. + br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); + + // Initialise a HMAC context with a key context. The key context is unmodified. + // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. + // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. + // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. + br_hmac_init(&hmacContext, &keyContext, outputLength); + + // Provide the HMAC context with the data to create a HMAC from. + // 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). + // The context is NOT modified; further bytes may be processed. Thus, "partial HMAC" values can be efficiently obtained. + // Optionally the constant-time version br_hmac_outCT() can be used. More info here: https://www.bearssl.org/constanttime.html . + br_hmac_out(&hmacContext, resultArray); // returns size_t outputLength + + return resultArray; + } + + 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 <= hashTypeNaturalLength); + + uint8_t hmac[hmacLength]; + createBearsslHmac(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); + return TypeCast::uint8ArrayToHexString(hmac, hmacLength); + } + + 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 outputLength) + { + 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. + + br_hmac_key_context keyContext; // Holds general HMAC info + 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. + br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); + + // Initialise a HMAC context with a key context. The key context is unmodified. + // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. + // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. + // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. + br_hmac_init(&hmacContext, &keyContext, outputLength); + + // Provide the HMAC context with the data to create a HMAC from. + // 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, data, dataLength); + + // 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 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 _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. + br_hmac_outCT(&hmacContext, data, dataLength, _ctMinDataLength, _ctMaxDataLength, resultArray); // returns size_t outputLength + + return resultArray; + } + + 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 <= hashTypeNaturalLength); + + uint8_t hmac[hmacLength]; + createBearsslHmacCT(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); + return TypeCast::uint8ArrayToHexString(hmac, hmacLength); + } +} + +namespace CryptoInterface +{ + void setCtMinDataLength(const size_t ctMinDataLength) + { + assert(ctMaxDataLength() - ctMinDataLength <= CT_MAX_DIFF); + _ctMinDataLength = ctMinDataLength; + } + size_t ctMinDataLength() {return _ctMinDataLength;} + + void setCtMaxDataLength(const size_t ctMaxDataLength) + { + assert(ctMaxDataLength - ctMinDataLength() <= CT_MAX_DIFF); + _ctMaxDataLength = ctMaxDataLength; + } + size_t ctMaxDataLength() {return _ctMaxDataLength;} + + void setWarningsEnabled(bool warningsEnabled) { _warningsEnabled = warningsEnabled; } + bool warningsEnabled() { return _warningsEnabled; } + + void setNonceGenerator(nonceGeneratorType nonceGenerator) { _nonceGenerator = nonceGenerator; } + nonceGeneratorType getNonceGenerator() { return _nonceGenerator; } + + + // #################### 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 TypeCast::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 outputLength) + { + return createBearsslHmac(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 outputLength) + { + return createBearsslHmacCT(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 TypeCast::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 outputLength) + { + return createBearsslHmac(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 outputLength) + { + return createBearsslHmacCT(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 TypeCast::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 outputLength) + { + return createBearsslHmac(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 outputLength) + { + return createBearsslHmacCT(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 TypeCast::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 outputLength) + { + return createBearsslHmac(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 outputLength) + { + return createBearsslHmacCT(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 TypeCast::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 outputLength) + { + return createBearsslHmac(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 outputLength) + { + return createBearsslHmacCT(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 TypeCast::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 outputLength) + { + return createBearsslHmac(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 outputLength) + { + return createBearsslHmacCT(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 TypeCast::uint8ArrayToHexString(hash, MD5SHA1_NATURAL_LENGTH); + } + + + // #################### HKDF #################### + + void hkdfInit(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) + { + // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html + + br_hkdf_context context; + + // Initialize an HKDF context, with a hash function, and the salt. This starts the HKDF-Extract process. + br_hkdf_init(&context, &br_sha256_vtable, salt, saltLength); + + // Inject more input bytes. This function may be called repeatedly if the input data is provided by chunks, after br_hkdf_init() but before br_hkdf_flip(). + br_hkdf_inject(&context, keyMaterial, keyMaterialLength); + + // End the HKDF-Extract process, and start the HKDF-Expand process. + br_hkdf_flip(&context); + + _storedHkdfContext = context; + _hkdfContextStored = true; + } + + size_t hkdfProduce(void *resultArray, const size_t outputLength, const void *info, const size_t infoLength) + { + // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html + + if(!_hkdfContextStored) // hkdfInit has not yet been executed + return 0; + + // HKDF output production (HKDF-Expand). + // Produces more output bytes from the current state. This function may be called several times, but only after br_hkdf_flip(). + // Returned value is the number of actually produced bytes. The total output length is limited to 255 times the output length of the underlying hash function. + return br_hkdf_produce(&_storedHkdfContext, info, infoLength, resultArray, outputLength); + } + + + // #################### Authenticated Encryption with Associated Data (AEAD) #################### + + + // #################### ChaCha20+Poly1305 AEAD #################### + + void chacha20Poly1305Kernel(const int encrypt, void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + const void *nonce, void *tag, const void *aad, const size_t aadLength) + { + if(keySalt == nullptr) + { + br_poly1305_ctmul32_run(key, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); + } + else + { + hkdfInit(key, ENCRYPTION_KEY_LENGTH, keySalt, keySaltLength); + uint8_t derivedEncryptionKey[ENCRYPTION_KEY_LENGTH] {0}; + hkdfProduce(derivedEncryptionKey, ENCRYPTION_KEY_LENGTH); + br_poly1305_ctmul32_run(derivedEncryptionKey, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); + } + } + + void chacha20Poly1305Encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + void *resultingNonce, void *resultingTag, const void *aad, const size_t aadLength) + { + uint8_t *nonce = (uint8_t *)resultingNonce; + getNonceGenerator()(nonce, 12); + + chacha20Poly1305Kernel(1, data, dataLength, key, keySalt, keySaltLength, nonce, resultingTag, aad, aadLength); + } + + bool chacha20Poly1305Decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + const void *encryptionNonce, const void *encryptionTag, const void *aad, const size_t aadLength) + { + const uint8_t *oldTag = (const uint8_t *)encryptionTag; + uint8_t newTag[16] {0}; + + chacha20Poly1305Kernel(0, data, dataLength, key, keySalt, keySaltLength, encryptionNonce, newTag, aad, aadLength); + + for(uint32_t i = 0; i < sizeof newTag; ++i) + { + if(newTag[i] != oldTag[i]) + return false; + } + + return true; + } +} diff --git a/libraries/CryptoInterface/src/CryptoInterface.h b/libraries/CryptoInterface/src/CryptoInterface.h new file mode 100644 index 0000000000..b29d93abdc --- /dev/null +++ b/libraries/CryptoInterface/src/CryptoInterface.h @@ -0,0 +1,799 @@ +/* + * BearSSL Copyright (c) 2016 Thomas Pornin + * Rest of this file 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 __ESP8266ARDUINOCRYPTOINTERFACE_H__ +#define __ESP8266ARDUINOCRYPTOINTERFACE_H__ + +#include + +namespace CryptoInterface +{ + /** + * Regarding constant-time (CT) 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 + * + * 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. + * + * 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. + */ + + + /** + * The nonce generator should take an uint8_t array with a given size in bytes and fill it with the nonce. + * The uint8_t array should then be returned by the nonce generator. + */ + using nonceGeneratorType = std::function; + + 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 uint8_t ENCRYPTION_KEY_LENGTH = 32; + + constexpr uint32_t CT_MAX_DIFF = 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. + * + * 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(); + + /** + * Set the nonce generator used by the CryptoInterface functions. + * + * @param nonceGenerator The nonce generator to use. + */ + void setNonceGenerator(nonceGeneratorType nonceGenerator); + nonceGeneratorType getNonceGenerator(); + + + // #################### 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. + */ + 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than MD5_NATURAL_LENGTH, + * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than MD5_NATURAL_LENGTH, + * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA1_NATURAL_LENGTH, + * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA1_NATURAL_LENGTH, + * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA224_NATURAL_LENGTH, + * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA224_NATURAL_LENGTH, + * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA256_NATURAL_LENGTH, + * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 SHA256_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha256Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + /** + * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA256_NATURAL_LENGTH, + * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + void *sha256HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA384_NATURAL_LENGTH, + * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA384_NATURAL_LENGTH, + * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA512_NATURAL_LENGTH, + * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA512_NATURAL_LENGTH, + * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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); + + + // #################### HKDF #################### + + /** + * KDFs (key derivation functions) are functions that takes a variable length input, and provide a variable length output, meant to be used to derive subkeys from a master key. + * HKDF is a KDF defined by RFC 5869. It is based on HMAC. The provided implementation uses SHA-256 as the underlying hash function. + * + * This function initializes the HKDF implementation with the input data to use for HKDF processing. + * Uses the BearSSL cryptographic library. + * + * Must be called at least once before hkdfProduce() can be used. + * + * @param keyMaterial An array containing the key material to use when deriving subkeys. Typically this would be the master key. + * @param keyMaterialLength The length of keyMaterial in bytes. + * @param salt An array containing the salt to use when ingesting key material. Salt is non-secret and can be empty. + * Its role is normally to bind the input to a conventional identifier that qualify it within the used protocol or application. + * @param saltLength The length of the salt array, in bytes. + */ + void hkdfInit(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); + + /** + * Produce more output bytes from the current HKDF state. This function may be called several times to obtain the full output by chunks. + * The total output size is limited to 255 * SHA256_NATURAL_LENGTH bytes per unique hkdfInit() call. + * Uses the BearSSL cryptographic library. + * + * Should only be used when hkdfInit() has been called at least once. + * + * @param resultArray The array wherein to store the resulting HKDF. + * @param outputLength The requested number of bytes to fill with HKDF output in resultArray. + * @param info NOTE: For correct HKDF processing, the same "info" string must be provided for every call until there's a new unique hkdfInit(). + * An array containing the information string to use when producing output. Info is non-secret and can be empty. + * Its role is normally to bind the output to a conventional identifier that qualify it within the used protocol or application. + * @param infoLength The length of the info array, in bytes. + * + * @return The number of HKDF bytes actually produced. + */ + size_t hkdfProduce(void *resultArray, const size_t outputLength, const void *info = nullptr, size_t infoLength = 0); + + + // #################### Authenticated Encryption with Associated Data (AEAD) #################### + + /** + * From https://www.bearssl.org/apidoc/bearssl__aead_8h.html + * + * An AEAD algorithm processes messages and provides confidentiality (encryption) and checked integrity (MAC). It uses the following parameters: + * + * - A symmetric key. Exact size depends on the AEAD algorithm. + * - A nonce (IV). Size depends on the AEAD algorithm; for most algorithms, it is crucial for security that any given nonce value is never used twice for the same key and distinct messages. + * - Data to encrypt and protect. + * - Additional authenticated data, which is covered by the MAC but otherwise left untouched (i.e. not encrypted). + * + * The AEAD algorithm encrypts the data, and produces an authentication tag. + * It is assumed that the encrypted data, the tag, the additional authenticated data and the nonce are sent to the receiver; + * the additional data and the nonce may be implicit (e.g. using elements of the underlying transport protocol, such as record sequence numbers). + * The receiver will recompute the tag value and compare it with the one received; + * if they match, then the data is correct, and can be decrypted and used; + * otherwise, at least one of the elements was altered in transit, normally leading to wholesale rejection of the complete message. + */ + + + // #################### ChaCha20+Poly1305 AEAD #################### + + /** + * Encrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. + * The function generates in place an equal-length ChaCha20 encrypted version of the data array. + * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 + * Uses the BearSSL cryptographic library. + * + * Encryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms with the default nonceGenerator, half of this without keySalt. + * + * The output values of chacha20Poly1305Encrypt should be passed as input values to chacha20Poly1305Decrypt. + * + * Note that a 12 byte nonce is generated via getNonceGenerator() every time chacha20Poly1305Encrypt is called. + * If the same key and nonce combination is used more than once for distinct messages, the encryption will be broken, so keep the following in mind: + * + * By default the nonce is generated via the hardware random number generator of the ESP8266. + * The entropy of this source may not be sufficient to avoid nonce collisions, so to further reduce the risk of encryption failure + * it is recommended that a keySalt is always provided when using the default nonceGenerator. Using a keySalt will create a + * pseudorandom subkey from the original key via HKDF, and use that for the encryption/decryption. + * The same key + keySalt will always generate the same subkey. + * + * An alternative to using a keySalt is to change the nonceGenerator so that it does not rely on random numbers. + * One way to do this would be to use a counter that guarantees the same key + nonce combination is never used. + * This may not be easily achievable in all scenarios, however. + * + * @param data An array containing the data to encrypt. The encrypted data is generated in place, so when the function returns the data array will contain the encrypted data. + * @param dataLength The length of the data array in bytes. + * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. + * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. + * @param keySaltLength The length of keySalt in bytes. + * @param resultingNonce The array that will store the nonce generated during encryption. Must be able to contain at least 12 bytes. The nonce is not secret and must be passed to the decryption function. + * @param resultingTag The array that will store the message authentication tag generated during encryption. Must be able to contain at least 16 bytes. The tag is not secret and must be passed to the decryption function. + * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not encrypted. + * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot + * be re-sent with replaced unencrypted data by an attacker. + * Defaults to nullptr. + * @param aadLength The length of the aad array in bytes. Defaults to 0. + */ + void chacha20Poly1305Encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, void *resultingNonce, void *resultingTag, const void *aad = nullptr, const size_t aadLength = 0); + + /** + * Decrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. + * The function generates in place an equal-length ChaCha20 decrypted version of the data array. + * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 + * Uses the BearSSL cryptographic library. + * + * Decryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms, half of this without keySalt. + * + * The output values of chacha20Poly1305Encrypt should be passed as input values to chacha20Poly1305Decrypt. + * + * @param data An array containing the data to decrypt. The decrypted data is generated in place, so when the function returns the data array will contain the decrypted data. + * @param dataLength The length of the data array in bytes. + * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. + * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. + * @param keySaltLength The length of keySalt in bytes. + * @param encryptionNonce An array containing the nonce that was generated during encryption. The nonce should be 12 bytes. + * @param encryptionTag An array containing the message authentication tag that was generated during encryption. The tag should be 16 bytes. + * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not decrypted. + * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot + * be re-sent with replaced unencrypted data by an attacker. + * Defaults to nullptr. + * @param aadLength The length of the aad array in bytes. Defaults to 0. + * + * @return True if the decryption was successful (the generated tag matches encryptionTag). False otherwise. Note that the data array is modified regardless of this outcome. + */ + bool chacha20Poly1305Decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, const void *encryptionNonce, const void *encryptionTag, const void *aad = nullptr, const size_t aadLength = 0); +} + +#endif From 6a448bc6175c97e5342206379a64421422fafab6 Mon Sep 17 00:00:00 2001 From: Anders Date: Sun, 29 Dec 2019 19:03:08 +0100 Subject: [PATCH 2/9] Fix compiler errors. - Make HelloCrypto.ino stylish. - Include assert.h in CryptoInterface.cpp. --- .../examples/HelloCrypto/HelloCrypto.ino | 16 ++++++++-------- .../CryptoInterface/src/CryptoInterface.cpp | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino index b16b97675e..3b2e9182e2 100644 --- a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino +++ b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino @@ -39,8 +39,7 @@ void setup() { Serial.println(); } -void loop() -{ +void loop() { // This serves only to demonstrate the library use. See the header file for a full list of functions. String exampleData = F("Hello Crypto World!"); @@ -79,23 +78,24 @@ void loop() uint8_t resultingTag[16] { 0 }; // The tag is always 16 bytes Serial.println(String(F("\nThis is the data to encrypt: ")) + dataToEncrypt); - + // Note that the key must be ENCRYPTION_KEY_LENGTH long. CryptoInterface::chacha20Poly1305Encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); Serial.println(String(F("Encrypted data: ")) + dataToEncrypt); - + bool decryptionSucceeded = CryptoInterface::chacha20Poly1305Decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); encryptionCounter++; - - if(decryptionSucceeded) + + if (decryptionSucceeded) { Serial.print(F("Decryption succeeded. Result: ")); - else + } else { Serial.print(F("Decryption failed. Result: ")); + } Serial.println(dataToEncrypt); Serial.println(F("\n##########################################################################################################\n")); - + delay(10000); } diff --git a/libraries/CryptoInterface/src/CryptoInterface.cpp b/libraries/CryptoInterface/src/CryptoInterface.cpp index a998f759e7..ccd7108da8 100644 --- a/libraries/CryptoInterface/src/CryptoInterface.cpp +++ b/libraries/CryptoInterface/src/CryptoInterface.cpp @@ -27,6 +27,7 @@ #include #include +#include namespace TypeCast = esp8266::TypeConversion; From b1fc47ab4e130e35bc53dda8f42d472eb50ec7e2 Mon Sep 17 00:00:00 2001 From: Anders Date: Sun, 5 Jan 2020 22:27:49 +0100 Subject: [PATCH 3/9] - Move base36 arrays to PROGMEM in TypeConversionFunctions.cpp. - Add deprecated attribute to SHA1 and MD5 hashes. - Remove _warningsEnabled since this has been replaced by the deprecated attribute. - Prefix all getters with "get". - Move all CryptoInterface functionality to the experimental namespace. - Change formatting of core files. - Improve comments. --- cores/esp8266/TypeConversion.cpp | 139 +- cores/esp8266/TypeConversion.h | 136 +- .../examples/HelloCrypto/HelloCrypto.ino | 1 + libraries/CryptoInterface/library.properties | 2 +- .../CryptoInterface/src/CryptoInterface.cpp | 941 +++++----- .../CryptoInterface/src/CryptoInterface.h | 1537 +++++++++-------- 6 files changed, 1388 insertions(+), 1368 deletions(-) diff --git a/cores/esp8266/TypeConversion.cpp b/cores/esp8266/TypeConversion.cpp index e71d810d95..1772378823 100644 --- a/cores/esp8266/TypeConversion.cpp +++ b/cores/esp8266/TypeConversion.cpp @@ -1,82 +1,91 @@ /* - TypeConversion functionality - 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. + TypeConversion functionality + 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 #include "TypeConversion.h" -namespace esp8266 { - namespace TypeConversion { - const char base36Chars[36] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; - const uint8_t base36CharValues[75] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, // 0 to 10 - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 0, 0, 0, 0, 0, // Upper case letters - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 - }; // Lower case letters - - - String uint8ArrayToHexString(const uint8_t *uint8Array, const uint32_t arrayLength) { - String hexString; - if (!hexString.reserve(2 * arrayLength)) { // Each uint8_t will become two characters (00 to FF) +namespace esp8266 +{ +namespace TypeConversion +{ +const char base36Chars[36] PROGMEM = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}; +const uint8_t base36CharValues[75] PROGMEM {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, // 0 to 9 + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 0, 0, 0, 0, 0, 0, // Upper case letters + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 // Lower case letters +}; + + +String uint8ArrayToHexString(const uint8_t *uint8Array, const uint32_t arrayLength) +{ + String hexString; + if (!hexString.reserve(2 * arrayLength)) // Each uint8_t will become two characters (00 to FF) + { return emptyString; - } - - for (uint32_t i = 0; i < arrayLength; ++i) { - hexString += base36Chars[ uint8Array[i] >> 4 ]; - hexString += base36Chars[ uint8Array[i] % 16 ]; - } + } - return hexString; + for (uint32_t i = 0; i < arrayLength; ++i) + { + hexString += (char)pgm_read_byte(base36Chars + (uint8Array[i] >> 4)); + hexString += (char)pgm_read_byte(base36Chars + uint8Array[i] % 16); } - uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, const uint32_t arrayLength) { - assert(hexString.length() >= arrayLength * 2); // Each array element can hold two hexString characters + return hexString; +} - for (uint32_t i = 0; i < arrayLength; ++i) { - uint8Array[i] = (base36CharValues[hexString.charAt(i * 2) - '0'] << 4) + base36CharValues[hexString.charAt(i * 2 + 1) - '0']; - } +uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, const uint32_t arrayLength) +{ + assert(hexString.length() >= arrayLength * 2); // Each array element can hold two hexString characters - return uint8Array; + for (uint32_t i = 0; i < arrayLength; ++i) + { + uint8Array[i] = (pgm_read_byte(base36CharValues + hexString.charAt(i * 2) - '0') << 4) + pgm_read_byte(base36CharValues + hexString.charAt(i * 2 + 1) - '0'); } - uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray) { - resultArray[7] = value; - resultArray[6] = value >> 8; - resultArray[5] = value >> 16; - resultArray[4] = value >> 24; - resultArray[3] = value >> 32; - resultArray[2] = value >> 40; - resultArray[1] = value >> 48; - resultArray[0] = value >> 56; - - return resultArray; - } + return uint8Array; +} - uint64_t uint8ArrayToUint64(const uint8_t *inputArray) { - uint64_t result = (uint64_t)inputArray[0] << 56 | (uint64_t)inputArray[1] << 48 | (uint64_t)inputArray[2] << 40 | (uint64_t)inputArray[3] << 32 - | (uint64_t)inputArray[4] << 24 | (uint64_t)inputArray[5] << 16 | (uint64_t)inputArray[6] << 8 | (uint64_t)inputArray[7]; +uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray) +{ + resultArray[7] = value; + resultArray[6] = value >> 8; + resultArray[5] = value >> 16; + resultArray[4] = value >> 24; + resultArray[3] = value >> 32; + resultArray[2] = value >> 40; + resultArray[1] = value >> 48; + resultArray[0] = value >> 56; + + return resultArray; +} - return result; - } - } +uint64_t uint8ArrayToUint64(const uint8_t *inputArray) +{ + uint64_t result = (uint64_t)inputArray[0] << 56 | (uint64_t)inputArray[1] << 48 | (uint64_t)inputArray[2] << 40 | (uint64_t)inputArray[3] << 32 + | (uint64_t)inputArray[4] << 24 | (uint64_t)inputArray[5] << 16 | (uint64_t)inputArray[6] << 8 | (uint64_t)inputArray[7]; + + return result; +} +} } diff --git a/cores/esp8266/TypeConversion.h b/cores/esp8266/TypeConversion.h index ecce9cf55e..f63a7a2129 100644 --- a/cores/esp8266/TypeConversion.h +++ b/cores/esp8266/TypeConversion.h @@ -1,26 +1,26 @@ /* - TypeConversion functionality - 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. + TypeConversion functionality + 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 __ESP8266_TYPECONVERSION_H__ @@ -28,51 +28,53 @@ #include -namespace esp8266 { - namespace TypeConversion { - extern const char base36Chars[36]; - - // Subtract '0' to normalize the char before lookup. - extern const uint8_t base36CharValues[75]; - - /** - Convert the contents of a uint8_t array to a String in HEX format. The resulting String starts from index 0 of the array. - All array elements will be padded with zeroes to ensure they are converted to 2 String characters each. - - @param uint8Array The array to make into a HEX String. - @param arrayLength The size of uint8Array, in bytes. - @return Normally a String containing the HEX representation of the uint8Array. An empty String if the memory allocation for the String failed. - */ - String uint8ArrayToHexString(const uint8_t *uint8Array, const uint32_t arrayLength); - - /** - Convert the contents of a String in HEX format to a uint8_t array. Index 0 of the array will represent the start of the String. - There must be 2 String characters for each array element. Use padding with zeroes where required. - - @param hexString The HEX String to convert to a uint8_t array. Must contain at least 2*arrayLength characters. - @param uint8Array The array to fill with the contents of the hexString. - @param arrayLength The number of bytes to fill in uint8Array. - @return A pointer to the uint8Array. - */ - uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, const uint32_t arrayLength); - - /** - Takes a uint64_t value and stores the bits in a uint8_t array. Assumes index 0 of the array should contain MSB. - - @param value The uint64_t value to convert to a uint8_t array. - @param resultArray A uint8_t array that will hold the result once the function returns. Should have a size of at least 8 bytes. - @return The resultArray. - */ - uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray); - - /** - Takes a uint8_t array and converts the first 8 (lowest index) elements to a uint64_t. Assumes index 0 of the array contains MSB. - - @param inputArray A uint8_t array containing the data to convert to a uint64_t. Should have a size of at least 8 bytes. - @return A uint64_t representation of the first 8 bytes of the array. - */ - uint64_t uint8ArrayToUint64(const uint8_t *inputArray); - } +namespace esp8266 +{ +namespace TypeConversion +{ +extern const char base36Chars[36]; + +// Subtract '0' to normalize the char before lookup. +extern const uint8_t base36CharValues[75]; + +/** + Convert the contents of a uint8_t array to a String in HEX format. The resulting String starts from index 0 of the array. + All array elements will be padded with zeroes to ensure they are converted to 2 String characters each. + + @param uint8Array The array to make into a HEX String. + @param arrayLength The size of uint8Array, in bytes. + @return Normally a String containing the HEX representation of the uint8Array. An empty String if the memory allocation for the String failed. +*/ +String uint8ArrayToHexString(const uint8_t *uint8Array, const uint32_t arrayLength); + +/** + Convert the contents of a String in HEX format to a uint8_t array. Index 0 of the array will represent the start of the String. + There must be 2 String characters for each array element. Use padding with zeroes where required. + + @param hexString The HEX String to convert to a uint8_t array. Must contain at least 2*arrayLength characters. + @param uint8Array The array to fill with the contents of the hexString. + @param arrayLength The number of bytes to fill in uint8Array. + @return A pointer to the uint8Array. +*/ +uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, const uint32_t arrayLength); + +/** + Takes a uint64_t value and stores the bits in a uint8_t array. Assumes index 0 of the array should contain MSB. + + @param value The uint64_t value to convert to a uint8_t array. + @param resultArray A uint8_t array that will hold the result once the function returns. Should have a size of at least 8 bytes. + @return The resultArray. +*/ +uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray); + +/** + Takes a uint8_t array and converts the first 8 (lowest index) elements to a uint64_t. Assumes index 0 of the array contains MSB. + + @param inputArray A uint8_t array containing the data to convert to a uint64_t. Should have a size of at least 8 bytes. + @return A uint64_t representation of the first 8 bytes of the array. +*/ +uint64_t uint8ArrayToUint64(const uint8_t *inputArray); +} } #endif diff --git a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino index 3b2e9182e2..c3eabe3765 100644 --- a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino +++ b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino @@ -7,6 +7,7 @@ #include namespace TypeCast = esp8266::TypeConversion; +using namespace experimental; /** NOTE: Although we could define the strings below as normal String variables, diff --git a/libraries/CryptoInterface/library.properties b/libraries/CryptoInterface/library.properties index 3a1ebe6bf4..455161a091 100644 --- a/libraries/CryptoInterface/library.properties +++ b/libraries/CryptoInterface/library.properties @@ -4,7 +4,7 @@ author=Anders Löfgren maintainer=Anders Löfgren sentence=Interface to the cryptographic library paragraph=The library acts as a frontend to the cryptographic backend library in ESP8266 Arduino Core. -category=Cryptography +category=Other url= architectures=esp8266 dot_a_linkage=true diff --git a/libraries/CryptoInterface/src/CryptoInterface.cpp b/libraries/CryptoInterface/src/CryptoInterface.cpp index ccd7108da8..d9c270626d 100644 --- a/libraries/CryptoInterface/src/CryptoInterface.cpp +++ b/libraries/CryptoInterface/src/CryptoInterface.cpp @@ -31,536 +31,537 @@ namespace TypeCast = esp8266::TypeConversion; -namespace +namespace experimental { - size_t _ctMinDataLength = 0; - size_t _ctMaxDataLength = 1024; - - bool _warningsEnabled = true; - - br_hkdf_context _storedHkdfContext; - bool _hkdfContextStored = false; - - uint8_t *defaultNonceGenerator(uint8_t *nonceArray, const size_t nonceLength) + namespace { - /** - * The ESP32 Technical Reference Manual v4.1 chapter 24 has the following to say about random number generation (no information found for ESP8266): - * - * "When used correctly, every 32-bit value the system reads from the RNG_DATA_REG register of the random number generator is a true random number. - * These true random numbers are generated based on the noise in the Wi-Fi/BT RF system. - * When Wi-Fi and BT are disabled, the random number generator will give out pseudo-random numbers. - * - * When Wi-Fi or BT is enabled, the random number generator is fed two bits of entropy every APB clock cycle (normally 80 MHz). - * Thus, for the maximum amount of entropy, it is advisable to read the random register at a maximum rate of 5 MHz. - * A data sample of 2 GB, read from the random number generator with Wi-Fi enabled and the random register read at 5 MHz, - * has been tested using the Dieharder Random Number Testsuite (version 3.31.1). - * The sample passed all tests." - * - * Since ESP32 is the sequal to ESP8266 it is unlikely that the ESP8266 is able to generate random numbers more quickly than 5 MHz when run at a 80 MHz frequency. - * A maximum random number frequency of 0.5 MHz is used here to leave some margin for possibly inferior components in the ESP8266. - * It should be noted that the ESP8266 has no Bluetooth functionality, so turning the WiFi off is likely to cause RANDOM_REG32 to use pseudo-random numbers. - * - * It is possible that yield() must be called on the ESP8266 to properly feed the hardware random number generator new bits, since there is only one processor core available. - * However, no feeding requirements are mentioned in the ESP32 documentation, and using yield() could possibly cause extended delays during nonce generation. - * Thus only delayMicroseconds() is used below. - */ - - constexpr uint8_t cooldownMicros = 2; - static uint32_t lastCalledMicros = micros() - cooldownMicros; - - uint32_t randomNumber = 0; - - for(size_t byteIndex = 0; byteIndex < nonceLength; ++byteIndex) - { - if(byteIndex % 4 == 0) + size_t _ctMinDataLength = 0; + size_t _ctMaxDataLength = 1024; + + br_hkdf_context _storedHkdfContext; + bool _hkdfContextStored = false; + + uint8_t *defaultNonceGenerator(uint8_t *nonceArray, const size_t nonceLength) + { + /** + * The ESP32 Technical Reference Manual v4.1 chapter 24 has the following to say about random number generation (no information found for ESP8266): + * + * "When used correctly, every 32-bit value the system reads from the RNG_DATA_REG register of the random number generator is a true random number. + * These true random numbers are generated based on the noise in the Wi-Fi/BT RF system. + * When Wi-Fi and BT are disabled, the random number generator will give out pseudo-random numbers. + * + * When Wi-Fi or BT is enabled, the random number generator is fed two bits of entropy every APB clock cycle (normally 80 MHz). + * Thus, for the maximum amount of entropy, it is advisable to read the random register at a maximum rate of 5 MHz. + * A data sample of 2 GB, read from the random number generator with Wi-Fi enabled and the random register read at 5 MHz, + * has been tested using the Dieharder Random Number Testsuite (version 3.31.1). + * The sample passed all tests." + * + * Since ESP32 is the sequal to ESP8266 it is unlikely that the ESP8266 is able to generate random numbers more quickly than 5 MHz when run at a 80 MHz frequency. + * A maximum random number frequency of 0.5 MHz is used here to leave some margin for possibly inferior components in the ESP8266. + * It should be noted that the ESP8266 has no Bluetooth functionality, so turning the WiFi off is likely to cause RANDOM_REG32 to use pseudo-random numbers. + * + * It is possible that yield() must be called on the ESP8266 to properly feed the hardware random number generator new bits, since there is only one processor core available. + * However, no feeding requirements are mentioned in the ESP32 documentation, and using yield() could possibly cause extended delays during nonce generation. + * Thus only delayMicroseconds() is used below. + */ + + constexpr uint8_t cooldownMicros = 2; + static uint32_t lastCalledMicros = micros() - cooldownMicros; + + uint32_t randomNumber = 0; + + for(size_t byteIndex = 0; byteIndex < nonceLength; ++byteIndex) { - // Old random number has been used up (random number could be exactly 0, so we can't check for that) - - uint32_t timeSinceLastCall = micros() - lastCalledMicros; - if(timeSinceLastCall < cooldownMicros) - delayMicroseconds(cooldownMicros - timeSinceLastCall); + if(byteIndex % 4 == 0) + { + // Old random number has been used up (random number could be exactly 0, so we can't check for that) + + uint32_t timeSinceLastCall = micros() - lastCalledMicros; + if(timeSinceLastCall < cooldownMicros) + delayMicroseconds(cooldownMicros - timeSinceLastCall); + + randomNumber = RANDOM_REG32; + lastCalledMicros = micros(); + } - randomNumber = RANDOM_REG32; - lastCalledMicros = micros(); + nonceArray[byteIndex] = randomNumber; + randomNumber >>= 8; } - - nonceArray[byteIndex] = randomNumber; - randomNumber >>= 8; - } - return nonceArray; - } - - CryptoInterface::nonceGeneratorType _nonceGenerator = defaultNonceGenerator; + return nonceArray; + } + + CryptoInterface::nonceGeneratorType _nonceGenerator = defaultNonceGenerator; - 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 outputLength) - { - // 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. - - br_hmac_key_context keyContext; // Holds general HMAC info - 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. - br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); - - // Initialise a HMAC context with a key context. The key context is unmodified. - // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. - // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. - // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. - br_hmac_init(&hmacContext, &keyContext, outputLength); - - // Provide the HMAC context with the data to create a HMAC from. - // 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). - // The context is NOT modified; further bytes may be processed. Thus, "partial HMAC" values can be efficiently obtained. - // Optionally the constant-time version br_hmac_outCT() can be used. More info here: https://www.bearssl.org/constanttime.html . - br_hmac_out(&hmacContext, resultArray); // returns size_t outputLength - - return resultArray; - } - - 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 <= hashTypeNaturalLength); + 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 outputLength) + { + // 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. + + br_hmac_key_context keyContext; // Holds general HMAC info + br_hmac_context hmacContext; // Holds general HMAC info + specific info for the current operation - uint8_t hmac[hmacLength]; - createBearsslHmac(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); - return TypeCast::uint8ArrayToHexString(hmac, hmacLength); - } - - 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 outputLength) - { - 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. - - br_hmac_key_context keyContext; // Holds general HMAC info - 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. - br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); - - // Initialise a HMAC context with a key context. The key context is unmodified. - // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. - // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. - // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. - br_hmac_init(&hmacContext, &keyContext, outputLength); - - // Provide the HMAC context with the data to create a HMAC from. - // 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, data, dataLength); - - // 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 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 _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. - br_hmac_outCT(&hmacContext, data, dataLength, _ctMinDataLength, _ctMaxDataLength, resultArray); // returns size_t outputLength - - return resultArray; - } - - 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 <= hashTypeNaturalLength); + // 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. + br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); + + // Initialise a HMAC context with a key context. The key context is unmodified. + // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. + // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. + // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. + br_hmac_init(&hmacContext, &keyContext, outputLength); + + // Provide the HMAC context with the data to create a HMAC from. + // 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). + // The context is NOT modified; further bytes may be processed. Thus, "partial HMAC" values can be efficiently obtained. + // Optionally the constant-time version br_hmac_outCT() can be used. More info here: https://www.bearssl.org/constanttime.html . + br_hmac_out(&hmacContext, resultArray); // returns size_t outputLength + + return resultArray; + } + + 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 <= hashTypeNaturalLength); + + uint8_t hmac[hmacLength]; + createBearsslHmac(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); + return TypeCast::uint8ArrayToHexString(hmac, hmacLength); + } - uint8_t hmac[hmacLength]; - createBearsslHmacCT(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); - return TypeCast::uint8ArrayToHexString(hmac, hmacLength); + 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 outputLength) + { + 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. + + br_hmac_key_context keyContext; // Holds general HMAC info + 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. + br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); + + // Initialise a HMAC context with a key context. The key context is unmodified. + // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. + // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. + // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. + br_hmac_init(&hmacContext, &keyContext, outputLength); + + // Provide the HMAC context with the data to create a HMAC from. + // 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, data, dataLength); + + // 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 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 _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. + br_hmac_outCT(&hmacContext, data, dataLength, _ctMinDataLength, _ctMaxDataLength, resultArray); // returns size_t outputLength + + return resultArray; + } + + 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 <= hashTypeNaturalLength); + + uint8_t hmac[hmacLength]; + createBearsslHmacCT(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); + return TypeCast::uint8ArrayToHexString(hmac, hmacLength); + } + + + // Helper function to avoid deprecated warnings. + void *md5HashHelper(const void *data, const size_t dataLength, void *resultArray) + { + br_md5_context context; + br_md5_init(&context); + br_md5_update(&context, data, dataLength); + br_md5_out(&context, resultArray); + return resultArray; + } + + // Helper function to avoid deprecated warnings. + void *sha1HashHelper(const void *data, const size_t dataLength, void *resultArray) + { + br_sha1_context context; + br_sha1_init(&context); + br_sha1_update(&context, data, dataLength); + br_sha1_out(&context, resultArray); + return resultArray; + } } -} -namespace CryptoInterface -{ - void setCtMinDataLength(const size_t ctMinDataLength) + namespace CryptoInterface { - assert(ctMaxDataLength() - ctMinDataLength <= CT_MAX_DIFF); - _ctMinDataLength = ctMinDataLength; - } - size_t ctMinDataLength() {return _ctMinDataLength;} + void setCtMinDataLength(const size_t ctMinDataLength) + { + assert(getCtMaxDataLength() - ctMinDataLength <= CT_MAX_DIFF); + _ctMinDataLength = ctMinDataLength; + } + size_t getCtMinDataLength() {return _ctMinDataLength;} - void setCtMaxDataLength(const size_t ctMaxDataLength) - { - assert(ctMaxDataLength - ctMinDataLength() <= CT_MAX_DIFF); - _ctMaxDataLength = ctMaxDataLength; - } - size_t ctMaxDataLength() {return _ctMaxDataLength;} + void setCtMaxDataLength(const size_t ctMaxDataLength) + { + assert(ctMaxDataLength - getCtMinDataLength() <= CT_MAX_DIFF); + _ctMaxDataLength = ctMaxDataLength; + } + size_t getCtMaxDataLength() {return _ctMaxDataLength;} - void setWarningsEnabled(bool warningsEnabled) { _warningsEnabled = warningsEnabled; } - bool warningsEnabled() { return _warningsEnabled; } + void setNonceGenerator(nonceGeneratorType nonceGenerator) { _nonceGenerator = nonceGenerator; } + nonceGeneratorType getNonceGenerator() { return _nonceGenerator; } - void setNonceGenerator(nonceGeneratorType nonceGenerator) { _nonceGenerator = nonceGenerator; } - nonceGeneratorType getNonceGenerator() { return _nonceGenerator; } + // #################### MD5 #################### + + // resultArray must have size MD5_NATURAL_LENGTH or greater + void *md5Hash(const void *data, const size_t dataLength, void *resultArray) + { + return md5HashHelper(data, dataLength, resultArray); + } + + String md5Hash(const String &message) + { + uint8_t hash[MD5_NATURAL_LENGTH]; + md5HashHelper(message.c_str(), message.length(), hash); + return TypeCast::uint8ArrayToHexString(hash, MD5_NATURAL_LENGTH); + } - // #################### MD5 #################### + void *md5Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + { + return createBearsslHmac(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } - // 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 TypeCast::uint8ArrayToHexString(hash, MD5_NATURAL_LENGTH); - } + 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 *md5Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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 outputLength) + { + return createBearsslHmacCT(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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); + } - void *md5HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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 #################### - // #################### SHA-1 #################### + // resultArray must have size SHA1_NATURAL_LENGTH or greater + void *sha1Hash(const void *data, const size_t dataLength, void *resultArray) + { + return sha1HashHelper(data, dataLength, resultArray); + } + + String sha1Hash(const String &message) + { + uint8_t hash[SHA1_NATURAL_LENGTH]; + sha1HashHelper(message.c_str(), message.length(), hash); + return TypeCast::uint8ArrayToHexString(hash, SHA1_NATURAL_LENGTH); + } - // 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 TypeCast::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 outputLength) + { + return createBearsslHmac(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 *sha1Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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 outputLength) + { + return createBearsslHmacCT(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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); + } - void *sha1HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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 #################### - // #################### 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 TypeCast::uint8ArrayToHexString(hash, SHA224_NATURAL_LENGTH); + } - // 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 TypeCast::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 outputLength) + { + return createBearsslHmac(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 *sha224Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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 outputLength) + { + return createBearsslHmacCT(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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); + } + - void *sha224HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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 TypeCast::uint8ArrayToHexString(hash, SHA256_NATURAL_LENGTH); - } + // #################### SHA-256 #################### - void *sha256Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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); - } + // 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 TypeCast::uint8ArrayToHexString(hash, SHA256_NATURAL_LENGTH); + } - void *sha256HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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); - } + void *sha256Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + { + return createBearsslHmac(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 outputLength) + { + return createBearsslHmacCT(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 TypeCast::uint8ArrayToHexString(hash, SHA384_NATURAL_LENGTH); - } + // #################### SHA-384 #################### - void *sha384Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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); - } + // 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 TypeCast::uint8ArrayToHexString(hash, SHA384_NATURAL_LENGTH); + } - void *sha384HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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); - } + void *sha384Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + { + return createBearsslHmac(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 outputLength) + { + return createBearsslHmacCT(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 TypeCast::uint8ArrayToHexString(hash, SHA512_NATURAL_LENGTH); - } + // #################### SHA-512 #################### - void *sha512Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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); - } + // 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 TypeCast::uint8ArrayToHexString(hash, SHA512_NATURAL_LENGTH); + } - void *sha512HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - 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 TypeCast::uint8ArrayToHexString(hash, MD5SHA1_NATURAL_LENGTH); - } + void *sha512Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + { + return createBearsslHmac(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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 outputLength) + { + return createBearsslHmacCT(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); + } + + 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); + } + - // #################### HKDF #################### + // #################### MD5+SHA-1 #################### - void hkdfInit(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) - { - // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html + // 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; + } - br_hkdf_context context; - - // Initialize an HKDF context, with a hash function, and the salt. This starts the HKDF-Extract process. - br_hkdf_init(&context, &br_sha256_vtable, salt, saltLength); + String md5sha1Hash(const String &message) + { + uint8_t hash[MD5SHA1_NATURAL_LENGTH]; + md5sha1Hash(message.c_str(), message.length(), hash); + return TypeCast::uint8ArrayToHexString(hash, MD5SHA1_NATURAL_LENGTH); + } - // Inject more input bytes. This function may be called repeatedly if the input data is provided by chunks, after br_hkdf_init() but before br_hkdf_flip(). - br_hkdf_inject(&context, keyMaterial, keyMaterialLength); - // End the HKDF-Extract process, and start the HKDF-Expand process. - br_hkdf_flip(&context); + // #################### HKDF #################### - _storedHkdfContext = context; - _hkdfContextStored = true; - } - - size_t hkdfProduce(void *resultArray, const size_t outputLength, const void *info, const size_t infoLength) - { - // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html - - if(!_hkdfContextStored) // hkdfInit has not yet been executed - return 0; - - // HKDF output production (HKDF-Expand). - // Produces more output bytes from the current state. This function may be called several times, but only after br_hkdf_flip(). - // Returned value is the number of actually produced bytes. The total output length is limited to 255 times the output length of the underlying hash function. - return br_hkdf_produce(&_storedHkdfContext, info, infoLength, resultArray, outputLength); - } + void hkdfInit(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) + { + // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html + + br_hkdf_context context; + // Initialize an HKDF context, with a hash function, and the salt. This starts the HKDF-Extract process. + br_hkdf_init(&context, &br_sha256_vtable, salt, saltLength); - // #################### Authenticated Encryption with Associated Data (AEAD) #################### + // Inject more input bytes. This function may be called repeatedly if the input data is provided by chunks, after br_hkdf_init() but before br_hkdf_flip(). + br_hkdf_inject(&context, keyMaterial, keyMaterialLength); - - // #################### ChaCha20+Poly1305 AEAD #################### + // End the HKDF-Extract process, and start the HKDF-Expand process. + br_hkdf_flip(&context); - void chacha20Poly1305Kernel(const int encrypt, void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, - const void *nonce, void *tag, const void *aad, const size_t aadLength) - { - if(keySalt == nullptr) - { - br_poly1305_ctmul32_run(key, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); + _storedHkdfContext = context; + _hkdfContextStored = true; } - else + + size_t hkdfProduce(void *resultArray, const size_t outputLength, const void *info, const size_t infoLength) { - hkdfInit(key, ENCRYPTION_KEY_LENGTH, keySalt, keySaltLength); - uint8_t derivedEncryptionKey[ENCRYPTION_KEY_LENGTH] {0}; - hkdfProduce(derivedEncryptionKey, ENCRYPTION_KEY_LENGTH); - br_poly1305_ctmul32_run(derivedEncryptionKey, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); - } - } + // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html + + if(!_hkdfContextStored) // hkdfInit has not yet been executed + return 0; + + // HKDF output production (HKDF-Expand). + // Produces more output bytes from the current state. This function may be called several times, but only after br_hkdf_flip(). + // Returned value is the number of actually produced bytes. The total output length is limited to 255 times the output length of the underlying hash function. + return br_hkdf_produce(&_storedHkdfContext, info, infoLength, resultArray, outputLength); + } + + + // #################### Authenticated Encryption with Associated Data (AEAD) #################### - void chacha20Poly1305Encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, - void *resultingNonce, void *resultingTag, const void *aad, const size_t aadLength) - { - uint8_t *nonce = (uint8_t *)resultingNonce; - getNonceGenerator()(nonce, 12); - chacha20Poly1305Kernel(1, data, dataLength, key, keySalt, keySaltLength, nonce, resultingTag, aad, aadLength); - } - - bool chacha20Poly1305Decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, - const void *encryptionNonce, const void *encryptionTag, const void *aad, const size_t aadLength) - { - const uint8_t *oldTag = (const uint8_t *)encryptionTag; - uint8_t newTag[16] {0}; + // #################### ChaCha20+Poly1305 AEAD #################### - chacha20Poly1305Kernel(0, data, dataLength, key, keySalt, keySaltLength, encryptionNonce, newTag, aad, aadLength); + void chacha20Poly1305Kernel(const int encrypt, void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + const void *nonce, void *tag, const void *aad, const size_t aadLength) + { + if(keySalt == nullptr) + { + br_poly1305_ctmul32_run(key, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); + } + else + { + hkdfInit(key, ENCRYPTION_KEY_LENGTH, keySalt, keySaltLength); + uint8_t derivedEncryptionKey[ENCRYPTION_KEY_LENGTH] {0}; + hkdfProduce(derivedEncryptionKey, ENCRYPTION_KEY_LENGTH); + br_poly1305_ctmul32_run(derivedEncryptionKey, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); + } + } - for(uint32_t i = 0; i < sizeof newTag; ++i) + void chacha20Poly1305Encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + void *resultingNonce, void *resultingTag, const void *aad, const size_t aadLength) { - if(newTag[i] != oldTag[i]) - return false; + uint8_t *nonce = (uint8_t *)resultingNonce; + getNonceGenerator()(nonce, 12); + + chacha20Poly1305Kernel(1, data, dataLength, key, keySalt, keySaltLength, nonce, resultingTag, aad, aadLength); } + + bool chacha20Poly1305Decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + const void *encryptionNonce, const void *encryptionTag, const void *aad, const size_t aadLength) + { + const uint8_t *oldTag = (const uint8_t *)encryptionTag; + uint8_t newTag[16] {0}; - return true; + chacha20Poly1305Kernel(0, data, dataLength, key, keySalt, keySaltLength, encryptionNonce, newTag, aad, aadLength); + + for(uint32_t i = 0; i < sizeof newTag; ++i) + { + if(newTag[i] != oldTag[i]) + return false; + } + + return true; + } } -} +} \ No newline at end of file diff --git a/libraries/CryptoInterface/src/CryptoInterface.h b/libraries/CryptoInterface/src/CryptoInterface.h index b29d93abdc..9c8f193ef0 100644 --- a/libraries/CryptoInterface/src/CryptoInterface.h +++ b/libraries/CryptoInterface/src/CryptoInterface.h @@ -28,772 +28,779 @@ #include -namespace CryptoInterface +namespace experimental { - /** - * Regarding constant-time (CT) 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 - * - * 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. - * - * 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. - */ - - - /** - * The nonce generator should take an uint8_t array with a given size in bytes and fill it with the nonce. - * The uint8_t array should then be returned by the nonce generator. - */ - using nonceGeneratorType = std::function; - - 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 uint8_t ENCRYPTION_KEY_LENGTH = 32; - - constexpr uint32_t CT_MAX_DIFF = 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. - * - * 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(); - - /** - * Set the nonce generator used by the CryptoInterface functions. - * - * @param nonceGenerator The nonce generator to use. - */ - void setNonceGenerator(nonceGeneratorType nonceGenerator); - nonceGeneratorType getNonceGenerator(); - - - // #################### 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. - */ - 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than MD5_NATURAL_LENGTH, - * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than MD5_NATURAL_LENGTH, - * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA1_NATURAL_LENGTH, - * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA1_NATURAL_LENGTH, - * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA224_NATURAL_LENGTH, - * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA224_NATURAL_LENGTH, - * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA256_NATURAL_LENGTH, - * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 SHA256_NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - String sha256Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); - - /** - * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA256_NATURAL_LENGTH, - * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - void *sha256HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA384_NATURAL_LENGTH, - * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA384_NATURAL_LENGTH, - * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA512_NATURAL_LENGTH, - * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA512_NATURAL_LENGTH, - * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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); - - - // #################### HKDF #################### - - /** - * KDFs (key derivation functions) are functions that takes a variable length input, and provide a variable length output, meant to be used to derive subkeys from a master key. - * HKDF is a KDF defined by RFC 5869. It is based on HMAC. The provided implementation uses SHA-256 as the underlying hash function. - * - * This function initializes the HKDF implementation with the input data to use for HKDF processing. - * Uses the BearSSL cryptographic library. - * - * Must be called at least once before hkdfProduce() can be used. - * - * @param keyMaterial An array containing the key material to use when deriving subkeys. Typically this would be the master key. - * @param keyMaterialLength The length of keyMaterial in bytes. - * @param salt An array containing the salt to use when ingesting key material. Salt is non-secret and can be empty. - * Its role is normally to bind the input to a conventional identifier that qualify it within the used protocol or application. - * @param saltLength The length of the salt array, in bytes. - */ - void hkdfInit(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); - - /** - * Produce more output bytes from the current HKDF state. This function may be called several times to obtain the full output by chunks. - * The total output size is limited to 255 * SHA256_NATURAL_LENGTH bytes per unique hkdfInit() call. - * Uses the BearSSL cryptographic library. - * - * Should only be used when hkdfInit() has been called at least once. - * - * @param resultArray The array wherein to store the resulting HKDF. - * @param outputLength The requested number of bytes to fill with HKDF output in resultArray. - * @param info NOTE: For correct HKDF processing, the same "info" string must be provided for every call until there's a new unique hkdfInit(). - * An array containing the information string to use when producing output. Info is non-secret and can be empty. - * Its role is normally to bind the output to a conventional identifier that qualify it within the used protocol or application. - * @param infoLength The length of the info array, in bytes. - * - * @return The number of HKDF bytes actually produced. - */ - size_t hkdfProduce(void *resultArray, const size_t outputLength, const void *info = nullptr, size_t infoLength = 0); - - - // #################### Authenticated Encryption with Associated Data (AEAD) #################### - - /** - * From https://www.bearssl.org/apidoc/bearssl__aead_8h.html - * - * An AEAD algorithm processes messages and provides confidentiality (encryption) and checked integrity (MAC). It uses the following parameters: - * - * - A symmetric key. Exact size depends on the AEAD algorithm. - * - A nonce (IV). Size depends on the AEAD algorithm; for most algorithms, it is crucial for security that any given nonce value is never used twice for the same key and distinct messages. - * - Data to encrypt and protect. - * - Additional authenticated data, which is covered by the MAC but otherwise left untouched (i.e. not encrypted). - * - * The AEAD algorithm encrypts the data, and produces an authentication tag. - * It is assumed that the encrypted data, the tag, the additional authenticated data and the nonce are sent to the receiver; - * the additional data and the nonce may be implicit (e.g. using elements of the underlying transport protocol, such as record sequence numbers). - * The receiver will recompute the tag value and compare it with the one received; - * if they match, then the data is correct, and can be decrypted and used; - * otherwise, at least one of the elements was altered in transit, normally leading to wholesale rejection of the complete message. - */ - - - // #################### ChaCha20+Poly1305 AEAD #################### - - /** - * Encrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. - * The function generates in place an equal-length ChaCha20 encrypted version of the data array. - * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 - * Uses the BearSSL cryptographic library. - * - * Encryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms with the default nonceGenerator, half of this without keySalt. - * - * The output values of chacha20Poly1305Encrypt should be passed as input values to chacha20Poly1305Decrypt. - * - * Note that a 12 byte nonce is generated via getNonceGenerator() every time chacha20Poly1305Encrypt is called. - * If the same key and nonce combination is used more than once for distinct messages, the encryption will be broken, so keep the following in mind: - * - * By default the nonce is generated via the hardware random number generator of the ESP8266. - * The entropy of this source may not be sufficient to avoid nonce collisions, so to further reduce the risk of encryption failure - * it is recommended that a keySalt is always provided when using the default nonceGenerator. Using a keySalt will create a - * pseudorandom subkey from the original key via HKDF, and use that for the encryption/decryption. - * The same key + keySalt will always generate the same subkey. - * - * An alternative to using a keySalt is to change the nonceGenerator so that it does not rely on random numbers. - * One way to do this would be to use a counter that guarantees the same key + nonce combination is never used. - * This may not be easily achievable in all scenarios, however. - * - * @param data An array containing the data to encrypt. The encrypted data is generated in place, so when the function returns the data array will contain the encrypted data. - * @param dataLength The length of the data array in bytes. - * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. - * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. - * @param keySaltLength The length of keySalt in bytes. - * @param resultingNonce The array that will store the nonce generated during encryption. Must be able to contain at least 12 bytes. The nonce is not secret and must be passed to the decryption function. - * @param resultingTag The array that will store the message authentication tag generated during encryption. Must be able to contain at least 16 bytes. The tag is not secret and must be passed to the decryption function. - * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not encrypted. - * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot - * be re-sent with replaced unencrypted data by an attacker. - * Defaults to nullptr. - * @param aadLength The length of the aad array in bytes. Defaults to 0. - */ - void chacha20Poly1305Encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, void *resultingNonce, void *resultingTag, const void *aad = nullptr, const size_t aadLength = 0); - - /** - * Decrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. - * The function generates in place an equal-length ChaCha20 decrypted version of the data array. - * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 - * Uses the BearSSL cryptographic library. - * - * Decryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms, half of this without keySalt. - * - * The output values of chacha20Poly1305Encrypt should be passed as input values to chacha20Poly1305Decrypt. - * - * @param data An array containing the data to decrypt. The decrypted data is generated in place, so when the function returns the data array will contain the decrypted data. - * @param dataLength The length of the data array in bytes. - * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. - * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. - * @param keySaltLength The length of keySalt in bytes. - * @param encryptionNonce An array containing the nonce that was generated during encryption. The nonce should be 12 bytes. - * @param encryptionTag An array containing the message authentication tag that was generated during encryption. The tag should be 16 bytes. - * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not decrypted. - * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot - * be re-sent with replaced unencrypted data by an attacker. - * Defaults to nullptr. - * @param aadLength The length of the aad array in bytes. Defaults to 0. - * - * @return True if the decryption was successful (the generated tag matches encryptionTag). False otherwise. Note that the data array is modified regardless of this outcome. - */ - bool chacha20Poly1305Decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, const void *encryptionNonce, const void *encryptionTag, const void *aad = nullptr, const size_t aadLength = 0); + namespace CryptoInterface + { + /** + * Regarding constant-time (CT) 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 + * + * 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 getCtMaxDataLength(), constant-time processing takes substantially longer time to complete than a normal HMAC, + * determined by the size of (getCtMaxDataLength() - getCtMinDataLength()). + * Constant-time processing also sets limits on the data length. + * + * 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. + */ + + + /** + * The nonce generator should take an uint8_t array with a given size in bytes and fill it with the nonce. + * The uint8_t array should then be returned by the nonce generator. + */ + using nonceGeneratorType = std::function; + + 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 uint8_t ENCRYPTION_KEY_LENGTH = 32; + + constexpr uint32_t CT_MAX_DIFF = 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. + * + * The difference getCtMaxDataLength() - getCtMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte). + */ + void setCtMinDataLength(const size_t ctMinDataLength); + /** + * 0 by default. + */ + size_t getCtMinDataLength(); + + /** + * 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 getCtMaxDataLength() - getCtMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte). + */ + void setCtMaxDataLength(const size_t ctMaxDataLength); + /** + * 1024 by default. + */ + size_t getCtMaxDataLength(); + + /** + * Set the nonce generator used by the CryptoInterface functions. + * + * @param nonceGenerator The nonce generator to use. + */ + void setNonceGenerator(nonceGeneratorType nonceGenerator); + nonceGeneratorType getNonceGenerator(); + + + // #################### MD5 #################### + + /** + * WARNING! The MD5 hash is broken in terms of attacker resistance. + * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + * + * 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. + */ + void *md5Hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated)); + + /** + * WARNING! The MD5 hash is broken in terms of attacker resistance. + * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + * + * 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) __attribute__((deprecated)); + + /** + * Create a MD5 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than MD5_NATURAL_LENGTH, + * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than MD5_NATURAL_LENGTH, + * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 #################### + + /** + * WARNING! The SHA-1 hash is broken in terms of attacker resistance. + * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + * + * 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) __attribute__((deprecated)); + + /** + * WARNING! The SHA-1 hash is broken in terms of attacker resistance. + * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + * + * 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) __attribute__((deprecated)); + + /** + * Create a SHA1 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA1_NATURAL_LENGTH, + * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA1_NATURAL_LENGTH, + * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA224_NATURAL_LENGTH, + * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA224_NATURAL_LENGTH, + * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA256_NATURAL_LENGTH, + * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 SHA256_NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + String sha256Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + /** + * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA256_NATURAL_LENGTH, + * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + void *sha256HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA384_NATURAL_LENGTH, + * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA384_NATURAL_LENGTH, + * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA512_NATURAL_LENGTH, + * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA512_NATURAL_LENGTH, + * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @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 outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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); + + + // #################### HKDF #################### + + /** + * KDFs (key derivation functions) are functions that takes a variable length input, and provide a variable length output, meant to be used to derive subkeys from a master key. + * HKDF is a KDF defined by RFC 5869. It is based on HMAC. The provided implementation uses SHA-256 as the underlying hash function. + * + * This function initializes the HKDF implementation with the input data to use for HKDF processing. + * Uses the BearSSL cryptographic library. + * + * Must be called at least once before hkdfProduce() can be used. + * + * @param keyMaterial An array containing the key material to use when deriving subkeys. Typically this would be the master key. + * @param keyMaterialLength The length of keyMaterial in bytes. + * @param salt An array containing the salt to use when ingesting key material. Salt is non-secret and can be empty. + * Its role is normally to bind the input to a conventional identifier that qualify it within the used protocol or application. + * @param saltLength The length of the salt array, in bytes. + */ + void hkdfInit(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); + + /** + * Produce more output bytes from the current HKDF state. This function may be called several times to obtain the full output by chunks. + * The total output size is limited to 255 * SHA256_NATURAL_LENGTH bytes per unique hkdfInit() call. + * Uses the BearSSL cryptographic library. + * + * Should only be used when hkdfInit() has been called at least once. + * + * @param resultArray The array wherein to store the resulting HKDF. + * @param outputLength The requested number of bytes to fill with HKDF output in resultArray. + * @param info NOTE: For correct HKDF processing, the same "info" string must be provided for every call until there's a new unique hkdfInit(). + * An array containing the information string to use when producing output. Info is non-secret and can be empty. + * Its role is normally to bind the output to a conventional identifier that qualify it within the used protocol or application. + * @param infoLength The length of the info array, in bytes. + * + * @return The number of HKDF bytes actually produced. + */ + size_t hkdfProduce(void *resultArray, const size_t outputLength, const void *info = nullptr, size_t infoLength = 0); + + + // #################### Authenticated Encryption with Associated Data (AEAD) #################### + + /** + * From https://www.bearssl.org/apidoc/bearssl__aead_8h.html + * + * An AEAD algorithm processes messages and provides confidentiality (encryption) and checked integrity (MAC). It uses the following parameters: + * + * - A symmetric key. Exact size depends on the AEAD algorithm. + * - A nonce (IV). Size depends on the AEAD algorithm; for most algorithms, it is crucial for security that any given nonce value is never used twice for the same key and distinct messages. + * - Data to encrypt and protect. + * - Additional authenticated data, which is covered by the MAC but otherwise left untouched (i.e. not encrypted). + * + * The AEAD algorithm encrypts the data, and produces an authentication tag. + * It is assumed that the encrypted data, the tag, the additional authenticated data and the nonce are sent to the receiver; + * the additional data and the nonce may be implicit (e.g. using elements of the underlying transport protocol, such as record sequence numbers). + * The receiver will recompute the tag value and compare it with the one received; + * if they match, then the data is correct, and can be decrypted and used; + * otherwise, at least one of the elements was altered in transit, normally leading to wholesale rejection of the complete message. + */ + + + // #################### ChaCha20+Poly1305 AEAD #################### + + /** + * Encrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. + * The function generates in place an equal-length ChaCha20 encrypted version of the data array. + * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 + * Uses the BearSSL cryptographic library. + * + * Encryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms with the default nonceGenerator, half of this without keySalt. + * + * The output values of chacha20Poly1305Encrypt should be passed as input values to chacha20Poly1305Decrypt. + * + * Note that a 12 byte nonce is generated via getNonceGenerator() every time chacha20Poly1305Encrypt is called. + * If the same key and nonce combination is used more than once for distinct messages, the encryption will be broken, so keep the following in mind: + * + * By default the nonce is generated via the hardware random number generator of the ESP8266. + * The entropy of this source may not be sufficient to avoid nonce collisions, so to further reduce the risk of encryption failure + * it is recommended that a keySalt is always provided when using the default nonceGenerator. Using a keySalt will create a + * pseudorandom subkey from the original key via HKDF, and use that for the encryption/decryption. + * The same key + keySalt will always generate the same subkey. + * + * An alternative to using a keySalt is to change the nonceGenerator so that it does not rely on random numbers. + * One way to do this would be to use a counter that guarantees the same key + nonce combination is never used. + * This may not be easily achievable in all scenarios, however. + * + * @param data An array containing the data to encrypt. The encrypted data is generated in place, so when the function returns the data array will contain the encrypted data. + * @param dataLength The length of the data array in bytes. + * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. + * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. + * @param keySaltLength The length of keySalt in bytes. + * @param resultingNonce The array that will store the nonce generated during encryption. Must be able to contain at least 12 bytes. The nonce is not secret and must be passed to the decryption function. + * @param resultingTag The array that will store the message authentication tag generated during encryption. Must be able to contain at least 16 bytes. The tag is not secret and must be passed to the decryption function. + * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not encrypted. + * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot + * be re-sent with replaced unencrypted data by an attacker. + * Defaults to nullptr. + * @param aadLength The length of the aad array in bytes. Defaults to 0. + */ + void chacha20Poly1305Encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, void *resultingNonce, void *resultingTag, const void *aad = nullptr, const size_t aadLength = 0); + + /** + * Decrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. + * The function generates in place an equal-length ChaCha20 decrypted version of the data array. + * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 + * Uses the BearSSL cryptographic library. + * + * Decryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms, half of this without keySalt. + * + * The output values of chacha20Poly1305Encrypt should be passed as input values to chacha20Poly1305Decrypt. + * + * @param data An array containing the data to decrypt. The decrypted data is generated in place, so when the function returns the data array will contain the decrypted data. + * @param dataLength The length of the data array in bytes. + * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. + * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. + * @param keySaltLength The length of keySalt in bytes. + * @param encryptionNonce An array containing the nonce that was generated during encryption. The nonce should be 12 bytes. + * @param encryptionTag An array containing the message authentication tag that was generated during encryption. The tag should be 16 bytes. + * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not decrypted. + * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot + * be re-sent with replaced unencrypted data by an attacker. + * Defaults to nullptr. + * @param aadLength The length of the aad array in bytes. Defaults to 0. + * + * @return True if the decryption was successful (the generated tag matches encryptionTag). False otherwise. Note that the data array is modified regardless of this outcome. + */ + bool chacha20Poly1305Decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, const void *encryptionNonce, const void *encryptionTag, const void *aad = nullptr, const size_t aadLength = 0); + } } #endif From 9e5b63fbfda02fd660ac35ef79abeaee43610e06 Mon Sep 17 00:00:00 2001 From: Anders Date: Mon, 6 Jan 2020 18:07:02 +0100 Subject: [PATCH 4/9] - Update keywords.txt. --- libraries/CryptoInterface/keywords.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/libraries/CryptoInterface/keywords.txt b/libraries/CryptoInterface/keywords.txt index 0b984df26c..a4649c4a6a 100644 --- a/libraries/CryptoInterface/keywords.txt +++ b/libraries/CryptoInterface/keywords.txt @@ -1,5 +1,5 @@ ####################################### -# Syntax Coloring Map For ESP8266WiFiMesh +# Syntax Coloring Map For CryptoInterface ####################################### ####################################### @@ -19,11 +19,9 @@ nonceGeneratorType KEYWORD1 ####################################### setCtMinDataLength KEYWORD2 -ctMinDataLength KEYWORD2 +getCtMinDataLength KEYWORD2 setCtMaxDataLength KEYWORD2 -ctMaxDataLength KEYWORD2 -setWarningsEnabled KEYWORD2 -warningsEnabled KEYWORD2 +getCtMaxDataLength KEYWORD2 setNonceGenerator KEYWORD2 getNonceGenerator KEYWORD2 md5Hash KEYWORD2 From efb11c17ea4d4d1fcb2476c02f026e4ab7fcaeee Mon Sep 17 00:00:00 2001 From: Anders Date: Sun, 26 Apr 2020 22:01:37 +0200 Subject: [PATCH 5/9] - Remove WiFi.disconnect() from setup() in HelloCrypto example since it no longer seems to be required. --- .../CryptoInterface/examples/HelloCrypto/HelloCrypto.ino | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino index c3eabe3765..96fdf16e4c 100644 --- a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino +++ b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino @@ -32,10 +32,6 @@ void setup() { //yield(); // Use this if you don't want to wait for Serial. - // The WiFi.disconnect() ensures that the WiFi is working correctly. If this is not done before receiving WiFi connections, - // those WiFi connections will take a long time to make or sometimes will not work at all. - WiFi.disconnect(); - Serial.println(); Serial.println(); } From 884113bd308dfc44183dd9da32760467df8f2509 Mon Sep 17 00:00:00 2001 From: Anders Date: Mon, 27 Apr 2020 22:24:34 +0200 Subject: [PATCH 6/9] - Classify everything. - Remove delay in setup() from HelloCrypto example since it does not seem to be required to prevent missing initial Serial prints. - Mark type conversion functions as big endian. - Update keywords.txt. --- cores/esp8266/TypeConversion.cpp | 4 +- cores/esp8266/TypeConversion.h | 8 +- .../examples/HelloCrypto/HelloCrypto.ino | 21 +- libraries/CryptoInterface/keywords.txt | 47 +- .../CryptoInterface/src/CryptoInterface.cpp | 196 ++- .../CryptoInterface/src/CryptoInterface.h | 1333 +++++++++-------- 6 files changed, 811 insertions(+), 798 deletions(-) diff --git a/cores/esp8266/TypeConversion.cpp b/cores/esp8266/TypeConversion.cpp index 1772378823..61a47858d4 100644 --- a/cores/esp8266/TypeConversion.cpp +++ b/cores/esp8266/TypeConversion.cpp @@ -66,7 +66,7 @@ uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, con return uint8Array; } -uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray) +uint8_t *uint64ToUint8ArrayBE(const uint64_t value, uint8_t *resultArray) { resultArray[7] = value; resultArray[6] = value >> 8; @@ -80,7 +80,7 @@ uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray) return resultArray; } -uint64_t uint8ArrayToUint64(const uint8_t *inputArray) +uint64_t uint8ArrayToUint64BE(const uint8_t *inputArray) { uint64_t result = (uint64_t)inputArray[0] << 56 | (uint64_t)inputArray[1] << 48 | (uint64_t)inputArray[2] << 40 | (uint64_t)inputArray[3] << 32 | (uint64_t)inputArray[4] << 24 | (uint64_t)inputArray[5] << 16 | (uint64_t)inputArray[6] << 8 | (uint64_t)inputArray[7]; diff --git a/cores/esp8266/TypeConversion.h b/cores/esp8266/TypeConversion.h index f63a7a2129..6360eb9cbc 100644 --- a/cores/esp8266/TypeConversion.h +++ b/cores/esp8266/TypeConversion.h @@ -59,21 +59,21 @@ String uint8ArrayToHexString(const uint8_t *uint8Array, const uint32_t arrayLeng uint8_t *hexStringToUint8Array(const String &hexString, uint8_t *uint8Array, const uint32_t arrayLength); /** - Takes a uint64_t value and stores the bits in a uint8_t array. Assumes index 0 of the array should contain MSB. + Takes a uint64_t value and stores the bits in a uint8_t array. Assumes index 0 of the array should contain MSB (big endian). @param value The uint64_t value to convert to a uint8_t array. @param resultArray A uint8_t array that will hold the result once the function returns. Should have a size of at least 8 bytes. @return The resultArray. */ -uint8_t *uint64ToUint8Array(const uint64_t value, uint8_t *resultArray); +uint8_t *uint64ToUint8ArrayBE(const uint64_t value, uint8_t *resultArray); /** - Takes a uint8_t array and converts the first 8 (lowest index) elements to a uint64_t. Assumes index 0 of the array contains MSB. + Takes a uint8_t array and converts the first 8 (lowest index) elements to a uint64_t. Assumes index 0 of the array contains MSB (big endian). @param inputArray A uint8_t array containing the data to convert to a uint64_t. Should have a size of at least 8 bytes. @return A uint64_t representation of the first 8 bytes of the array. */ -uint64_t uint8ArrayToUint64(const uint8_t *inputArray); +uint64_t uint8ArrayToUint64BE(const uint8_t *inputArray); } } diff --git a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino index 96fdf16e4c..d15cdf8c70 100644 --- a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino +++ b/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino @@ -28,9 +28,6 @@ void setup() { WiFi.persistent(false); Serial.begin(115200); - delay(50); // Wait for Serial. - - //yield(); // Use this if you don't want to wait for Serial. Serial.println(); Serial.println(); @@ -42,7 +39,7 @@ void loop() { String exampleData = F("Hello Crypto World!"); Serial.println(String(F("This is our example data: ")) + exampleData); - uint8_t resultArray[CryptoInterface::SHA256_NATURAL_LENGTH] { 0 }; + uint8_t resultArray[CryptoInterface::SHA256::NATURAL_LENGTH] { 0 }; uint8_t derivedKey[CryptoInterface::ENCRYPTION_KEY_LENGTH] { 0 }; static uint32_t encryptionCounter = 0; @@ -53,20 +50,20 @@ void loop() { CryptoInterface::getNonceGenerator()(hkdfSalt, sizeof hkdfSalt); // Generate the key to use for HMAC and encryption - CryptoInterface::hkdfInit(FPSTR(masterKey), (sizeof masterKey) - 1, hkdfSalt, sizeof hkdfSalt); // (sizeof masterKey) - 1 removes the terminating null value of the c-string - CryptoInterface::hkdfProduce(derivedKey, sizeof derivedKey); + CryptoInterface::HKDF hkdfInstance(FPSTR(masterKey), (sizeof masterKey) - 1, hkdfSalt, sizeof hkdfSalt); // (sizeof masterKey) - 1 removes the terminating null value of the c-string + hkdfInstance.produce(derivedKey, sizeof derivedKey); // Hash - CryptoInterface::sha256Hash(exampleData.c_str(), exampleData.length(), resultArray); + CryptoInterface::SHA256::hash(exampleData.c_str(), exampleData.length(), resultArray); Serial.println(String(F("\nThis is the SHA256 hash of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); - Serial.println(String(F("This is the SHA256 hash of our example data, in HEX format, using String output:\n")) + CryptoInterface::sha256Hash(exampleData)); + Serial.println(String(F("This is the SHA256 hash of our example data, in HEX format, using String output:\n")) + CryptoInterface::SHA256::hash(exampleData)); // HMAC // Note that HMAC output length is limited - CryptoInterface::sha256Hmac(exampleData.c_str(), exampleData.length(), derivedKey, sizeof derivedKey, resultArray, sizeof resultArray); + CryptoInterface::SHA256::hmac(exampleData.c_str(), exampleData.length(), derivedKey, sizeof derivedKey, resultArray, sizeof resultArray); Serial.println(String(F("\nThis is the SHA256 HMAC of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); - Serial.println(String(F("This is the SHA256 HMAC of our example data, in HEX format, using String output:\n")) + CryptoInterface::sha256Hmac(exampleData, derivedKey, sizeof derivedKey, CryptoInterface::SHA256_NATURAL_LENGTH)); + Serial.println(String(F("This is the SHA256 HMAC of our example data, in HEX format, using String output:\n")) + CryptoInterface::SHA256::hmac(exampleData, derivedKey, sizeof derivedKey, CryptoInterface::SHA256::NATURAL_LENGTH)); // Authenticated Encryption with Associated Data (AEAD) @@ -77,10 +74,10 @@ void loop() { Serial.println(String(F("\nThis is the data to encrypt: ")) + dataToEncrypt); // Note that the key must be ENCRYPTION_KEY_LENGTH long. - CryptoInterface::chacha20Poly1305Encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + CryptoInterface::ChaCha20Poly1305::encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); Serial.println(String(F("Encrypted data: ")) + dataToEncrypt); - bool decryptionSucceeded = CryptoInterface::chacha20Poly1305Decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + bool decryptionSucceeded = CryptoInterface::ChaCha20Poly1305::decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); encryptionCounter++; if (decryptionSucceeded) { diff --git a/libraries/CryptoInterface/keywords.txt b/libraries/CryptoInterface/keywords.txt index a4649c4a6a..c2ea133c24 100644 --- a/libraries/CryptoInterface/keywords.txt +++ b/libraries/CryptoInterface/keywords.txt @@ -13,6 +13,15 @@ CryptoInterface KEYWORD3 ####################################### nonceGeneratorType KEYWORD1 +MD5 KEYWORD1 +SHA1 KEYWORD1 +SHA224 KEYWORD1 +SHA256 KEYWORD1 +SHA384 KEYWORD1 +SHA512 KEYWORD1 +MD5SHA1 KEYWORD1 +HKDF KEYWORD1 +ChaCha20Poly1305 KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -24,40 +33,18 @@ setCtMaxDataLength KEYWORD2 getCtMaxDataLength KEYWORD2 setNonceGenerator KEYWORD2 getNonceGenerator KEYWORD2 -md5Hash KEYWORD2 -md5Hmac KEYWORD2 -md5HmacCT KEYWORD2 -sha1Hash KEYWORD2 -sha1Hmac KEYWORD2 -sha1HmacCT KEYWORD2 -sha224Hash KEYWORD2 -sha224Hmac KEYWORD2 -sha224HmacCT KEYWORD2 -sha256Hash KEYWORD2 -sha256Hmac KEYWORD2 -sha256HmacCT KEYWORD2 -sha384Hash KEYWORD2 -sha384Hmac KEYWORD2 -sha384HmacCT KEYWORD2 -sha512Hash->KEYWORD2 -sha512Hmac KEYWORD2 -sha512HmacCT KEYWORD2 -md5sha1Hash KEYWORD2 -hkdfInit KEYWORD2 -hkdfProduce KEYWORD2 -chacha20Poly1305Encrypt KEYWORD2 -chacha20Poly1305Decrypt KEYWORD2 +hash KEYWORD2 +hmac KEYWORD2 +hmacCT KEYWORD2 +init KEYWORD2 +produce KEYWORD2 +encrypt KEYWORD2 +decrypt KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### -MD5_NATURAL_LENGTH LITERAL1 -SHA1_NATURAL_LENGTH LITERAL1 -SHA224_NATURAL_LENGTH LITERAL1 -SHA256_NATURAL_LENGTH LITERAL1 -SHA384_NATURAL_LENGTH LITERAL1 -SHA512_NATURAL_LENGTH LITERAL1 -MD5SHA1_NATURAL_LENGTH LITERAL1 +NATURAL_LENGTH LITERAL1 ENCRYPTION_KEY_LENGTH LITERAL1 CT_MAX_DIFF LITERAL1 diff --git a/libraries/CryptoInterface/src/CryptoInterface.cpp b/libraries/CryptoInterface/src/CryptoInterface.cpp index d9c270626d..fc8d0de8b5 100644 --- a/libraries/CryptoInterface/src/CryptoInterface.cpp +++ b/libraries/CryptoInterface/src/CryptoInterface.cpp @@ -23,10 +23,10 @@ * THE SOFTWARE. */ +#include #include "CryptoInterface.h" #include -#include #include namespace TypeCast = esp8266::TypeConversion; @@ -37,9 +37,6 @@ namespace experimental { size_t _ctMinDataLength = 0; size_t _ctMaxDataLength = 1024; - - br_hkdf_context _storedHkdfContext; - bool _hkdfContextStored = false; uint8_t *defaultNonceGenerator(uint8_t *nonceArray, const size_t nonceLength) { @@ -232,80 +229,80 @@ namespace experimental // #################### MD5 #################### - // resultArray must have size MD5_NATURAL_LENGTH or greater - void *md5Hash(const void *data, const size_t dataLength, void *resultArray) + // resultArray must have size MD5::NATURAL_LENGTH or greater + void *MD5::hash(const void *data, const size_t dataLength, void *resultArray) { return md5HashHelper(data, dataLength, resultArray); } - String md5Hash(const String &message) + String MD5::hash(const String &message) { - uint8_t hash[MD5_NATURAL_LENGTH]; - md5HashHelper(message.c_str(), message.length(), hash); - return TypeCast::uint8ArrayToHexString(hash, MD5_NATURAL_LENGTH); + uint8_t hashArray[NATURAL_LENGTH]; + md5HashHelper(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); } - void *md5Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + void *MD5::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmac(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String md5Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String MD5::hmac(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); + return createBearsslHmac(&br_md5_vtable, 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 outputLength) + void *MD5::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmacCT(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String md5HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String MD5::hmacCT(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); + return createBearsslHmacCT(&br_md5_vtable, 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) + // resultArray must have size SHA1::NATURAL_LENGTH or greater + void *SHA1::hash(const void *data, const size_t dataLength, void *resultArray) { return sha1HashHelper(data, dataLength, resultArray); } - String sha1Hash(const String &message) + String SHA1::hash(const String &message) { - uint8_t hash[SHA1_NATURAL_LENGTH]; - sha1HashHelper(message.c_str(), message.length(), hash); - return TypeCast::uint8ArrayToHexString(hash, SHA1_NATURAL_LENGTH); + uint8_t hashArray[NATURAL_LENGTH]; + sha1HashHelper(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); } - void *sha1Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + void *SHA1::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmac(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha1Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA1::hmac(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); + return createBearsslHmac(&br_sha1_vtable, 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 outputLength) + void *SHA1::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmacCT(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha1HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA1::hmacCT(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); + return createBearsslHmacCT(&br_sha1_vtable, 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) + // resultArray must have size SHA224::NATURAL_LENGTH or greater + void *SHA224::hash(const void *data, const size_t dataLength, void *resultArray) { br_sha224_context context; br_sha224_init(&context); @@ -314,38 +311,38 @@ namespace experimental return resultArray; } - String sha224Hash(const String &message) + String SHA224::hash(const String &message) { - uint8_t hash[SHA224_NATURAL_LENGTH]; - sha224Hash(message.c_str(), message.length(), hash); - return TypeCast::uint8ArrayToHexString(hash, SHA224_NATURAL_LENGTH); + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); } - void *sha224Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + void *SHA224::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmac(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha224Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA224::hmac(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); + return createBearsslHmac(&br_sha224_vtable, 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 outputLength) + void *SHA224::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmacCT(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha224HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA224::hmacCT(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); + return createBearsslHmacCT(&br_sha224_vtable, 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) + // resultArray must have size SHA256::NATURAL_LENGTH or greater + void *SHA256::hash(const void *data, const size_t dataLength, void *resultArray) { br_sha256_context context; br_sha256_init(&context); @@ -354,38 +351,38 @@ namespace experimental return resultArray; } - String sha256Hash(const String &message) + String SHA256::hash(const String &message) { - uint8_t hash[SHA256_NATURAL_LENGTH]; - sha256Hash(message.c_str(), message.length(), hash); - return TypeCast::uint8ArrayToHexString(hash, SHA256_NATURAL_LENGTH); + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); } - void *sha256Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + void *SHA256::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmac(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha256Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA256::hmac(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); + return createBearsslHmac(&br_sha256_vtable, 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 outputLength) + void *SHA256::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmacCT(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha256HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA256::hmacCT(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); + return createBearsslHmacCT(&br_sha256_vtable, 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) + // resultArray must have size SHA384::NATURAL_LENGTH or greater + void *SHA384::hash(const void *data, const size_t dataLength, void *resultArray) { br_sha384_context context; br_sha384_init(&context); @@ -394,38 +391,38 @@ namespace experimental return resultArray; } - String sha384Hash(const String &message) + String SHA384::hash(const String &message) { - uint8_t hash[SHA384_NATURAL_LENGTH]; - sha384Hash(message.c_str(), message.length(), hash); - return TypeCast::uint8ArrayToHexString(hash, SHA384_NATURAL_LENGTH); + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); } - void *sha384Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + void *SHA384::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmac(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha384Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA384::hmac(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); + return createBearsslHmac(&br_sha384_vtable, 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 outputLength) + void *SHA384::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmacCT(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha384HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA384::hmacCT(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); + return createBearsslHmacCT(&br_sha384_vtable, 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) + // resultArray must have size SHA512::NATURAL_LENGTH or greater + void *SHA512::hash(const void *data, const size_t dataLength, void *resultArray) { br_sha512_context context; br_sha512_init(&context); @@ -434,38 +431,38 @@ namespace experimental return resultArray; } - String sha512Hash(const String &message) + String SHA512::hash(const String &message) { - uint8_t hash[SHA512_NATURAL_LENGTH]; - sha512Hash(message.c_str(), message.length(), hash); - return TypeCast::uint8ArrayToHexString(hash, SHA512_NATURAL_LENGTH); + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); } - void *sha512Hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) + void *SHA512::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmac(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha512Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA512::hmac(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); + return createBearsslHmac(&br_sha512_vtable, 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 outputLength) + void *SHA512::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) { return createBearsslHmacCT(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); } - String sha512HmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) + String SHA512::hmacCT(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); + return createBearsslHmacCT(&br_sha512_vtable, 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) + // resultArray must have size MD5SHA1::NATURAL_LENGTH or greater + void *MD5SHA1::hash(const void *data, const size_t dataLength, void *resultArray) { br_md5sha1_context context; br_md5sha1_init(&context); @@ -474,46 +471,43 @@ namespace experimental return resultArray; } - String md5sha1Hash(const String &message) + String MD5SHA1::hash(const String &message) { - uint8_t hash[MD5SHA1_NATURAL_LENGTH]; - md5sha1Hash(message.c_str(), message.length(), hash); - return TypeCast::uint8ArrayToHexString(hash, MD5SHA1_NATURAL_LENGTH); + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); } // #################### HKDF #################### - void hkdfInit(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) + HKDF::HKDF(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) + { + init(keyMaterial, keyMaterialLength, salt, saltLength); + } + + void HKDF::init(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) { // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html - - br_hkdf_context context; // Initialize an HKDF context, with a hash function, and the salt. This starts the HKDF-Extract process. - br_hkdf_init(&context, &br_sha256_vtable, salt, saltLength); + br_hkdf_init(&hkdfContext, &br_sha256_vtable, salt, saltLength); // Inject more input bytes. This function may be called repeatedly if the input data is provided by chunks, after br_hkdf_init() but before br_hkdf_flip(). - br_hkdf_inject(&context, keyMaterial, keyMaterialLength); + br_hkdf_inject(&hkdfContext, keyMaterial, keyMaterialLength); // End the HKDF-Extract process, and start the HKDF-Expand process. - br_hkdf_flip(&context); - - _storedHkdfContext = context; - _hkdfContextStored = true; + br_hkdf_flip(&hkdfContext); } - size_t hkdfProduce(void *resultArray, const size_t outputLength, const void *info, const size_t infoLength) + size_t HKDF::produce(void *resultArray, const size_t outputLength, const void *info, const size_t infoLength) { // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html - if(!_hkdfContextStored) // hkdfInit has not yet been executed - return 0; - // HKDF output production (HKDF-Expand). // Produces more output bytes from the current state. This function may be called several times, but only after br_hkdf_flip(). // Returned value is the number of actually produced bytes. The total output length is limited to 255 times the output length of the underlying hash function. - return br_hkdf_produce(&_storedHkdfContext, info, infoLength, resultArray, outputLength); + return br_hkdf_produce(&hkdfContext, info, infoLength, resultArray, outputLength); } @@ -531,14 +525,14 @@ namespace experimental } else { - hkdfInit(key, ENCRYPTION_KEY_LENGTH, keySalt, keySaltLength); + HKDF hkdfInstance(key, ENCRYPTION_KEY_LENGTH, keySalt, keySaltLength); uint8_t derivedEncryptionKey[ENCRYPTION_KEY_LENGTH] {0}; - hkdfProduce(derivedEncryptionKey, ENCRYPTION_KEY_LENGTH); + hkdfInstance.produce(derivedEncryptionKey, ENCRYPTION_KEY_LENGTH); br_poly1305_ctmul32_run(derivedEncryptionKey, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); } } - void chacha20Poly1305Encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + void ChaCha20Poly1305::encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, void *resultingNonce, void *resultingTag, const void *aad, const size_t aadLength) { uint8_t *nonce = (uint8_t *)resultingNonce; @@ -547,7 +541,7 @@ namespace experimental chacha20Poly1305Kernel(1, data, dataLength, key, keySalt, keySaltLength, nonce, resultingTag, aad, aadLength); } - bool chacha20Poly1305Decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + bool ChaCha20Poly1305::decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, const void *encryptionNonce, const void *encryptionTag, const void *aad, const size_t aadLength) { const uint8_t *oldTag = (const uint8_t *)encryptionTag; @@ -564,4 +558,4 @@ namespace experimental return true; } } -} \ No newline at end of file +} diff --git a/libraries/CryptoInterface/src/CryptoInterface.h b/libraries/CryptoInterface/src/CryptoInterface.h index 9c8f193ef0..d572d30180 100644 --- a/libraries/CryptoInterface/src/CryptoInterface.h +++ b/libraries/CryptoInterface/src/CryptoInterface.h @@ -32,6 +32,8 @@ namespace experimental { namespace CryptoInterface { + #include + /** * Regarding constant-time (CT) HMAC: * @@ -57,19 +59,6 @@ namespace experimental * The uint8_t array should then be returned by the nonce generator. */ using nonceGeneratorType = std::function; - - 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 uint8_t ENCRYPTION_KEY_LENGTH = 32; @@ -112,605 +101,648 @@ namespace experimental // #################### MD5 #################### - /** - * WARNING! The MD5 hash is broken in terms of attacker resistance. - * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. - * - * 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. - */ - void *md5Hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated)); - - /** - * WARNING! The MD5 hash is broken in terms of attacker resistance. - * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. - * - * 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) __attribute__((deprecated)); - - /** - * Create a MD5 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than MD5_NATURAL_LENGTH, - * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than MD5_NATURAL_LENGTH, - * the first (lowest index) MD5_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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); + struct MD5 + { + static constexpr uint8_t NATURAL_LENGTH = 16; + + /** + * WARNING! The MD5 hash is broken in terms of attacker resistance. + * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + * + * Create a MD5 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated)); + + /** + * WARNING! The MD5 hash is broken in terms of attacker resistance. + * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + * + * Create a MD5 hash of the data. The result will be 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. + */ + static String hash(const String &message) __attribute__((deprecated)); + + /** + * Create a MD5 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + }; // #################### SHA-1 #################### - - /** - * WARNING! The SHA-1 hash is broken in terms of attacker resistance. - * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. - * - * 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) __attribute__((deprecated)); - /** - * WARNING! The SHA-1 hash is broken in terms of attacker resistance. - * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. - * - * 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) __attribute__((deprecated)); - - /** - * Create a SHA1 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA1_NATURAL_LENGTH, - * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA1_NATURAL_LENGTH, - * the first (lowest index) SHA1_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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); + struct SHA1 + { + static constexpr uint8_t NATURAL_LENGTH = 20; + + /** + * WARNING! The SHA-1 hash is broken in terms of attacker resistance. + * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + * + * Create a SHA1 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated)); + + /** + * WARNING! The SHA-1 hash is broken in terms of attacker resistance. + * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + * + * Create a SHA1 hash of the data. The result will be 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. + */ + static String hash(const String &message) __attribute__((deprecated)); + + /** + * Create a SHA1 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA224_NATURAL_LENGTH, - * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA224_NATURAL_LENGTH, - * the first (lowest index) SHA224_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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); + struct SHA224 + { + static constexpr uint8_t NATURAL_LENGTH = 28; + + /** + * Create a SHA224 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a SHA224 hash of the data. The result will be 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. + */ + static String hash(const String &message); + + /** + * Create a SHA224 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA256_NATURAL_LENGTH, - * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 SHA256_NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - String sha256Hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); - - /** - * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA256_NATURAL_LENGTH, - * the first (lowest index) SHA256_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - void *sha256HmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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); + struct SHA256 + { + static constexpr uint8_t NATURAL_LENGTH = 32; + + /** + * Create a SHA256 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a SHA256 hash of the data. The result will be 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. + */ + static String hash(const String &message); + + /** + * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + /** + * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA384_NATURAL_LENGTH, - * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA384_NATURAL_LENGTH, - * the first (lowest index) SHA384_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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); + struct SHA384 + { + static constexpr uint8_t NATURAL_LENGTH = 48; + + /** + * Create a SHA384 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a SHA384 hash of the data. The result will be 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. + */ + static String hash(const String &message); + + /** + * Create a SHA384 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(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 up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA512_NATURAL_LENGTH, - * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than SHA512_NATURAL_LENGTH, - * the first (lowest index) SHA512_NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @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 outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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); + struct SHA512 + { + static constexpr uint8_t NATURAL_LENGTH = 64; + + /** + * Create a SHA512 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a SHA512 hash of the data. The result will be 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. + */ + static String hash(const String &message); + + /** + * Create a SHA512 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + * If outputLength is 0, then the natural HMAC output length is selected. + * + * @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + * 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 [getCtMinDataLength(), getCtMaxDataLength()]. + * @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 NATURAL_LENGTH. + * + * @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(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); + struct MD5SHA1 + { + static constexpr uint8_t NATURAL_LENGTH = 36; + + /** + * Create a MD5+SHA-1 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + * + * @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + * Create a MD5+SHA-1 hash of the data. The result will be 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. + */ + static String hash(const String &message); + }; - // #################### HKDF #################### - /** - * KDFs (key derivation functions) are functions that takes a variable length input, and provide a variable length output, meant to be used to derive subkeys from a master key. - * HKDF is a KDF defined by RFC 5869. It is based on HMAC. The provided implementation uses SHA-256 as the underlying hash function. - * - * This function initializes the HKDF implementation with the input data to use for HKDF processing. - * Uses the BearSSL cryptographic library. - * - * Must be called at least once before hkdfProduce() can be used. - * - * @param keyMaterial An array containing the key material to use when deriving subkeys. Typically this would be the master key. - * @param keyMaterialLength The length of keyMaterial in bytes. - * @param salt An array containing the salt to use when ingesting key material. Salt is non-secret and can be empty. - * Its role is normally to bind the input to a conventional identifier that qualify it within the used protocol or application. - * @param saltLength The length of the salt array, in bytes. - */ - void hkdfInit(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); + // #################### HKDF #################### - /** - * Produce more output bytes from the current HKDF state. This function may be called several times to obtain the full output by chunks. - * The total output size is limited to 255 * SHA256_NATURAL_LENGTH bytes per unique hkdfInit() call. - * Uses the BearSSL cryptographic library. - * - * Should only be used when hkdfInit() has been called at least once. - * - * @param resultArray The array wherein to store the resulting HKDF. - * @param outputLength The requested number of bytes to fill with HKDF output in resultArray. - * @param info NOTE: For correct HKDF processing, the same "info" string must be provided for every call until there's a new unique hkdfInit(). - * An array containing the information string to use when producing output. Info is non-secret and can be empty. - * Its role is normally to bind the output to a conventional identifier that qualify it within the used protocol or application. - * @param infoLength The length of the info array, in bytes. - * - * @return The number of HKDF bytes actually produced. - */ - size_t hkdfProduce(void *resultArray, const size_t outputLength, const void *info = nullptr, size_t infoLength = 0); + struct HKDF + { + /** + * KDFs (key derivation functions) are functions that takes a variable length input, and provide a variable length output, meant to be used to derive subkeys from a master key. + * HKDF is a KDF defined by RFC 5869. It is based on HMAC. The provided implementation uses SHA-256 as the underlying hash function. + * + * This method initializes the HKDF implementation with the input data to use for HKDF processing. (calls HKDF::Init()) + */ + HKDF(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); + + /** + * This method initializes the HKDF implementation with the input data to use for HKDF processing. + * Uses the BearSSL cryptographic library. + * + * @param keyMaterial An array containing the key material to use when deriving subkeys. Typically this would be the master key. + * @param keyMaterialLength The length of keyMaterial in bytes. + * @param salt An array containing the salt to use when ingesting key material. Salt is non-secret and can be empty. + * Its role is normally to bind the input to a conventional identifier that qualify it within the used protocol or application. + * @param saltLength The length of the salt array, in bytes. + */ + void init(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); + + /** + * Produce more output bytes from the current HKDF state. This method may be called several times to obtain the full output by chunks. + * The total output size is limited to 255 * SHA256::NATURAL_LENGTH bytes per unique HKDF::Init()/constructor call. + * Uses the BearSSL cryptographic library. + * + * @param resultArray The array wherein to store the resulting HKDF. + * @param outputLength The requested number of bytes to fill with HKDF output in resultArray. + * @param info NOTE: For correct HKDF processing, the same "info" string must be provided for every call until there's a new unique HKDF::Init(). + * An array containing the information string to use when producing output. Info is non-secret and can be empty. + * Its role is normally to bind the output to a conventional identifier that qualify it within the used protocol or application. + * @param infoLength The length of the info array, in bytes. + * + * @return The number of HKDF bytes actually produced. + */ + size_t produce(void *resultArray, const size_t outputLength, const void *info = nullptr, size_t infoLength = 0); + + private: + + br_hkdf_context hkdfContext; + }; // #################### Authenticated Encryption with Associated Data (AEAD) #################### @@ -736,70 +768,73 @@ namespace experimental // #################### ChaCha20+Poly1305 AEAD #################### - /** - * Encrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. - * The function generates in place an equal-length ChaCha20 encrypted version of the data array. - * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 - * Uses the BearSSL cryptographic library. - * - * Encryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms with the default nonceGenerator, half of this without keySalt. - * - * The output values of chacha20Poly1305Encrypt should be passed as input values to chacha20Poly1305Decrypt. - * - * Note that a 12 byte nonce is generated via getNonceGenerator() every time chacha20Poly1305Encrypt is called. - * If the same key and nonce combination is used more than once for distinct messages, the encryption will be broken, so keep the following in mind: - * - * By default the nonce is generated via the hardware random number generator of the ESP8266. - * The entropy of this source may not be sufficient to avoid nonce collisions, so to further reduce the risk of encryption failure - * it is recommended that a keySalt is always provided when using the default nonceGenerator. Using a keySalt will create a - * pseudorandom subkey from the original key via HKDF, and use that for the encryption/decryption. - * The same key + keySalt will always generate the same subkey. - * - * An alternative to using a keySalt is to change the nonceGenerator so that it does not rely on random numbers. - * One way to do this would be to use a counter that guarantees the same key + nonce combination is never used. - * This may not be easily achievable in all scenarios, however. - * - * @param data An array containing the data to encrypt. The encrypted data is generated in place, so when the function returns the data array will contain the encrypted data. - * @param dataLength The length of the data array in bytes. - * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. - * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. - * @param keySaltLength The length of keySalt in bytes. - * @param resultingNonce The array that will store the nonce generated during encryption. Must be able to contain at least 12 bytes. The nonce is not secret and must be passed to the decryption function. - * @param resultingTag The array that will store the message authentication tag generated during encryption. Must be able to contain at least 16 bytes. The tag is not secret and must be passed to the decryption function. - * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not encrypted. - * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot - * be re-sent with replaced unencrypted data by an attacker. - * Defaults to nullptr. - * @param aadLength The length of the aad array in bytes. Defaults to 0. - */ - void chacha20Poly1305Encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, void *resultingNonce, void *resultingTag, const void *aad = nullptr, const size_t aadLength = 0); - - /** - * Decrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. - * The function generates in place an equal-length ChaCha20 decrypted version of the data array. - * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 - * Uses the BearSSL cryptographic library. - * - * Decryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms, half of this without keySalt. - * - * The output values of chacha20Poly1305Encrypt should be passed as input values to chacha20Poly1305Decrypt. - * - * @param data An array containing the data to decrypt. The decrypted data is generated in place, so when the function returns the data array will contain the decrypted data. - * @param dataLength The length of the data array in bytes. - * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. - * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. - * @param keySaltLength The length of keySalt in bytes. - * @param encryptionNonce An array containing the nonce that was generated during encryption. The nonce should be 12 bytes. - * @param encryptionTag An array containing the message authentication tag that was generated during encryption. The tag should be 16 bytes. - * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not decrypted. - * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot - * be re-sent with replaced unencrypted data by an attacker. - * Defaults to nullptr. - * @param aadLength The length of the aad array in bytes. Defaults to 0. - * - * @return True if the decryption was successful (the generated tag matches encryptionTag). False otherwise. Note that the data array is modified regardless of this outcome. - */ - bool chacha20Poly1305Decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, const void *encryptionNonce, const void *encryptionTag, const void *aad = nullptr, const size_t aadLength = 0); + struct ChaCha20Poly1305 + { + /** + * Encrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. + * The function generates in place an equal-length ChaCha20 encrypted version of the data array. + * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 + * Uses the BearSSL cryptographic library. + * + * Encryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms with the default nonceGenerator, half of this without keySalt. + * + * The output values of ChaCha20Poly1305::encrypt should be passed as input values to ChaCha20Poly1305::decrypt. + * + * Note that a 12 byte nonce is generated via getNonceGenerator() every time ChaCha20Poly1305::encrypt is called. + * If the same key and nonce combination is used more than once for distinct messages, the encryption will be broken, so keep the following in mind: + * + * By default the nonce is generated via the hardware random number generator of the ESP8266. + * The entropy of this source may not be sufficient to avoid nonce collisions, so to further reduce the risk of encryption failure + * it is recommended that a keySalt is always provided when using the default nonceGenerator. Using a keySalt will create a + * pseudorandom subkey from the original key via HKDF, and use that for the encryption/decryption. + * The same key + keySalt will always generate the same subkey. + * + * An alternative to using a keySalt is to change the nonceGenerator so that it does not rely on random numbers. + * One way to do this would be to use a counter that guarantees the same key + nonce combination is never used. + * This may not be easily achievable in all scenarios, however. + * + * @param data An array containing the data to encrypt. The encrypted data is generated in place, so when the function returns the data array will contain the encrypted data. + * @param dataLength The length of the data array in bytes. + * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. + * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. + * @param keySaltLength The length of keySalt in bytes. + * @param resultingNonce The array that will store the nonce generated during encryption. Must be able to contain at least 12 bytes. The nonce is not secret and must be passed to the decryption function. + * @param resultingTag The array that will store the message authentication tag generated during encryption. Must be able to contain at least 16 bytes. The tag is not secret and must be passed to the decryption function. + * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not encrypted. + * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot + * be re-sent with replaced unencrypted data by an attacker. + * Defaults to nullptr. + * @param aadLength The length of the aad array in bytes. Defaults to 0. + */ + static void encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, void *resultingNonce, void *resultingTag, const void *aad = nullptr, const size_t aadLength = 0); + + /** + * Decrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. + * The function generates in place an equal-length ChaCha20 decrypted version of the data array. + * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 + * Uses the BearSSL cryptographic library. + * + * Decryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms, half of this without keySalt. + * + * The output values of ChaCha20Poly1305::encrypt should be passed as input values to ChaCha20Poly1305::decrypt. + * + * @param data An array containing the data to decrypt. The decrypted data is generated in place, so when the function returns the data array will contain the decrypted data. + * @param dataLength The length of the data array in bytes. + * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. + * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. + * @param keySaltLength The length of keySalt in bytes. + * @param encryptionNonce An array containing the nonce that was generated during encryption. The nonce should be 12 bytes. + * @param encryptionTag An array containing the message authentication tag that was generated during encryption. The tag should be 16 bytes. + * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not decrypted. + * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot + * be re-sent with replaced unencrypted data by an attacker. + * Defaults to nullptr. + * @param aadLength The length of the aad array in bytes. Defaults to 0. + * + * @return True if the decryption was successful (the generated tag matches encryptionTag). False otherwise. Note that the data array is modified regardless of this outcome. + */ + static bool decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, const void *encryptionNonce, const void *encryptionTag, const void *aad = nullptr, const size_t aadLength = 0); + }; } } From ef86d201651bf13344a972f217d3878c1ce8a9ce Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 28 Apr 2020 20:38:06 +0200 Subject: [PATCH 7/9] - Remove namespace experimental. - Create ESP.random functions in the core based on the defaultNonceGenerator code, and use these in defaultNonceGenerator. - Rename CryptoInterface to esp8266::Crypto and move all functionality to the core. - Remove need to #include in the Crypto header file by changing br_hkdf_context to ::br_hkdf_context. - Restyle code files for core usage. --- cores/esp8266/Crypto.cpp | 552 ++++++++++++ cores/esp8266/Crypto.h | 844 ++++++++++++++++++ cores/esp8266/Esp.cpp | 57 ++ cores/esp8266/Esp.h | 3 + libraries/CryptoInterface/README.md | 9 - libraries/CryptoInterface/keywords.txt | 50 -- libraries/CryptoInterface/library.properties | 10 - .../CryptoInterface/src/CryptoInterface.cpp | 561 ------------ .../CryptoInterface/src/CryptoInterface.h | 841 ----------------- .../examples/HelloCrypto/HelloCrypto.ino | 27 +- libraries/esp8266/keywords.txt | 31 + libraries/esp8266/library.properties | 2 +- 12 files changed, 1502 insertions(+), 1485 deletions(-) create mode 100644 cores/esp8266/Crypto.cpp create mode 100644 cores/esp8266/Crypto.h delete mode 100644 libraries/CryptoInterface/README.md delete mode 100644 libraries/CryptoInterface/keywords.txt delete mode 100644 libraries/CryptoInterface/library.properties delete mode 100644 libraries/CryptoInterface/src/CryptoInterface.cpp delete mode 100644 libraries/CryptoInterface/src/CryptoInterface.h rename libraries/{CryptoInterface => esp8266}/examples/HelloCrypto/HelloCrypto.ino (73%) diff --git a/cores/esp8266/Crypto.cpp b/cores/esp8266/Crypto.cpp new file mode 100644 index 0000000000..e4feb22890 --- /dev/null +++ b/cores/esp8266/Crypto.cpp @@ -0,0 +1,552 @@ +/* + BearSSL Copyright (c) 2016 Thomas Pornin + Rest of this file 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 +#include "Crypto.h" +#include + +#include + +namespace TypeCast = esp8266::TypeConversion; + +namespace +{ +size_t _ctMinDataLength = 0; +size_t _ctMaxDataLength = 1024; + +uint8_t *defaultNonceGenerator(uint8_t *nonceArray, const size_t nonceLength) +{ + /** + The ESP32 Technical Reference Manual v4.1 chapter 24 has the following to say about random number generation (no information found for ESP8266): + + "When used correctly, every 32-bit value the system reads from the RNG_DATA_REG register of the random number generator is a true random number. + These true random numbers are generated based on the noise in the Wi-Fi/BT RF system. + When Wi-Fi and BT are disabled, the random number generator will give out pseudo-random numbers. + + When Wi-Fi or BT is enabled, the random number generator is fed two bits of entropy every APB clock cycle (normally 80 MHz). + Thus, for the maximum amount of entropy, it is advisable to read the random register at a maximum rate of 5 MHz. + A data sample of 2 GB, read from the random number generator with Wi-Fi enabled and the random register read at 5 MHz, + has been tested using the Dieharder Random Number Testsuite (version 3.31.1). + The sample passed all tests." + + Since ESP32 is the sequal to ESP8266 it is unlikely that the ESP8266 is able to generate random numbers more quickly than 5 MHz when run at a 80 MHz frequency. + A maximum random number frequency of 0.5 MHz is used here to leave some margin for possibly inferior components in the ESP8266. + It should be noted that the ESP8266 has no Bluetooth functionality, so turning the WiFi off is likely to cause RANDOM_REG32 to use pseudo-random numbers. + + It is possible that yield() must be called on the ESP8266 to properly feed the hardware random number generator new bits, since there is only one processor core available. + However, no feeding requirements are mentioned in the ESP32 documentation, and using yield() could possibly cause extended delays during nonce generation. + Thus only delayMicroseconds() is used below. + */ + + return ESP.random(nonceArray, nonceLength); +} + +esp8266::Crypto::nonceGeneratorType _nonceGenerator = defaultNonceGenerator; + +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 outputLength) +{ + // 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. + + br_hmac_key_context keyContext; // Holds general HMAC info + 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. + br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); + + // Initialise a HMAC context with a key context. The key context is unmodified. + // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. + // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. + // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. + br_hmac_init(&hmacContext, &keyContext, outputLength); + + // Provide the HMAC context with the data to create a HMAC from. + // 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). + // The context is NOT modified; further bytes may be processed. Thus, "partial HMAC" values can be efficiently obtained. + // Optionally the constant-time version br_hmac_outCT() can be used. More info here: https://www.bearssl.org/constanttime.html . + br_hmac_out(&hmacContext, resultArray); // returns size_t outputLength + + return resultArray; +} + +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 <= hashTypeNaturalLength); + + uint8_t hmac[hmacLength]; + createBearsslHmac(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); + return TypeCast::uint8ArrayToHexString(hmac, hmacLength); +} + +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 outputLength) +{ + 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. + + br_hmac_key_context keyContext; // Holds general HMAC info + 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. + br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); + + // Initialise a HMAC context with a key context. The key context is unmodified. + // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. + // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. + // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. + br_hmac_init(&hmacContext, &keyContext, outputLength); + + // Provide the HMAC context with the data to create a HMAC from. + // 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, data, dataLength); + + // 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 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 _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. + br_hmac_outCT(&hmacContext, data, dataLength, _ctMinDataLength, _ctMaxDataLength, resultArray); // returns size_t outputLength + + return resultArray; +} + +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 <= hashTypeNaturalLength); + + uint8_t hmac[hmacLength]; + createBearsslHmacCT(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); + return TypeCast::uint8ArrayToHexString(hmac, hmacLength); +} + + +// Helper function to avoid deprecated warnings. +void *md5HashHelper(const void *data, const size_t dataLength, void *resultArray) +{ + br_md5_context context; + br_md5_init(&context); + br_md5_update(&context, data, dataLength); + br_md5_out(&context, resultArray); + return resultArray; +} + +// Helper function to avoid deprecated warnings. +void *sha1HashHelper(const void *data, const size_t dataLength, void *resultArray) +{ + br_sha1_context context; + br_sha1_init(&context); + br_sha1_update(&context, data, dataLength); + br_sha1_out(&context, resultArray); + return resultArray; +} +} + +namespace esp8266 +{ +namespace Crypto +{ +void setCtMinDataLength(const size_t ctMinDataLength) +{ + assert(getCtMaxDataLength() - ctMinDataLength <= CT_MAX_DIFF); + _ctMinDataLength = ctMinDataLength; +} +size_t getCtMinDataLength() +{ + return _ctMinDataLength; +} + +void setCtMaxDataLength(const size_t ctMaxDataLength) +{ + assert(ctMaxDataLength - getCtMinDataLength() <= CT_MAX_DIFF); + _ctMaxDataLength = ctMaxDataLength; +} +size_t getCtMaxDataLength() +{ + return _ctMaxDataLength; +} + +void setNonceGenerator(nonceGeneratorType nonceGenerator) +{ + _nonceGenerator = nonceGenerator; +} +nonceGeneratorType getNonceGenerator() +{ + return _nonceGenerator; +} + + +// #################### MD5 #################### + +// resultArray must have size MD5::NATURAL_LENGTH or greater +void *MD5::hash(const void *data, const size_t dataLength, void *resultArray) +{ + return md5HashHelper(data, dataLength, resultArray); +} + +String MD5::hash(const String &message) +{ + uint8_t hashArray[NATURAL_LENGTH]; + md5HashHelper(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); +} + +void *MD5::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmac(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String MD5::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmac(&br_md5_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + +void *MD5::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmacCT(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String MD5::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmacCT(&br_md5_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + + +// #################### SHA-1 #################### + +// resultArray must have size SHA1::NATURAL_LENGTH or greater +void *SHA1::hash(const void *data, const size_t dataLength, void *resultArray) +{ + return sha1HashHelper(data, dataLength, resultArray); +} + +String SHA1::hash(const String &message) +{ + uint8_t hashArray[NATURAL_LENGTH]; + sha1HashHelper(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); +} + +void *SHA1::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmac(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA1::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmac(&br_sha1_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + +void *SHA1::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmacCT(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA1::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmacCT(&br_sha1_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + + +// #################### SHA-224 #################### + +// resultArray must have size SHA224::NATURAL_LENGTH or greater +void *SHA224::hash(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 SHA224::hash(const String &message) +{ + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); +} + +void *SHA224::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmac(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA224::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmac(&br_sha224_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + +void *SHA224::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmacCT(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA224::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmacCT(&br_sha224_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + + +// #################### SHA-256 #################### + +// resultArray must have size SHA256::NATURAL_LENGTH or greater +void *SHA256::hash(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 SHA256::hash(const String &message) +{ + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); +} + +void *SHA256::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmac(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA256::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmac(&br_sha256_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + +void *SHA256::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmacCT(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA256::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmacCT(&br_sha256_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + + +// #################### SHA-384 #################### + +// resultArray must have size SHA384::NATURAL_LENGTH or greater +void *SHA384::hash(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 SHA384::hash(const String &message) +{ + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); +} + +void *SHA384::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmac(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA384::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmac(&br_sha384_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + +void *SHA384::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmacCT(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA384::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmacCT(&br_sha384_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + + +// #################### SHA-512 #################### + +// resultArray must have size SHA512::NATURAL_LENGTH or greater +void *SHA512::hash(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 SHA512::hash(const String &message) +{ + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); +} + +void *SHA512::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmac(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA512::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmac(&br_sha512_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + +void *SHA512::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) +{ + return createBearsslHmacCT(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); +} + +String SHA512::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) +{ + return createBearsslHmacCT(&br_sha512_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); +} + + +// #################### MD5+SHA-1 #################### + +// resultArray must have size MD5SHA1::NATURAL_LENGTH or greater +void *MD5SHA1::hash(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 MD5SHA1::hash(const String &message) +{ + uint8_t hashArray[NATURAL_LENGTH]; + hash(message.c_str(), message.length(), hashArray); + return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); +} + + +// #################### HKDF #################### + +HKDF::HKDF(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) +{ + init(keyMaterial, keyMaterialLength, salt, saltLength); +} + +void HKDF::init(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) +{ + // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html + + // Initialize an HKDF context, with a hash function, and the salt. This starts the HKDF-Extract process. + br_hkdf_init(&hkdfContext, &br_sha256_vtable, salt, saltLength); + + // Inject more input bytes. This function may be called repeatedly if the input data is provided by chunks, after br_hkdf_init() but before br_hkdf_flip(). + br_hkdf_inject(&hkdfContext, keyMaterial, keyMaterialLength); + + // End the HKDF-Extract process, and start the HKDF-Expand process. + br_hkdf_flip(&hkdfContext); +} + +size_t HKDF::produce(void *resultArray, const size_t outputLength, const void *info, const size_t infoLength) +{ + // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html + + // HKDF output production (HKDF-Expand). + // Produces more output bytes from the current state. This function may be called several times, but only after br_hkdf_flip(). + // Returned value is the number of actually produced bytes. The total output length is limited to 255 times the output length of the underlying hash function. + return br_hkdf_produce(&hkdfContext, info, infoLength, resultArray, outputLength); +} + + +// #################### Authenticated Encryption with Associated Data (AEAD) #################### + + +// #################### ChaCha20+Poly1305 AEAD #################### + +void chacha20Poly1305Kernel(const int encrypt, void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + const void *nonce, void *tag, const void *aad, const size_t aadLength) +{ + if (keySalt == nullptr) + { + br_poly1305_ctmul32_run(key, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); + } + else + { + HKDF hkdfInstance(key, ENCRYPTION_KEY_LENGTH, keySalt, keySaltLength); + uint8_t derivedEncryptionKey[ENCRYPTION_KEY_LENGTH] {0}; + hkdfInstance.produce(derivedEncryptionKey, ENCRYPTION_KEY_LENGTH); + br_poly1305_ctmul32_run(derivedEncryptionKey, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); + } +} + +void ChaCha20Poly1305::encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + void *resultingNonce, void *resultingTag, const void *aad, const size_t aadLength) +{ + uint8_t *nonce = (uint8_t *)resultingNonce; + getNonceGenerator()(nonce, 12); + + chacha20Poly1305Kernel(1, data, dataLength, key, keySalt, keySaltLength, nonce, resultingTag, aad, aadLength); +} + +bool ChaCha20Poly1305::decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, + const void *encryptionNonce, const void *encryptionTag, const void *aad, const size_t aadLength) +{ + const uint8_t *oldTag = (const uint8_t *)encryptionTag; + uint8_t newTag[16] {0}; + + chacha20Poly1305Kernel(0, data, dataLength, key, keySalt, keySaltLength, encryptionNonce, newTag, aad, aadLength); + + for (uint32_t i = 0; i < sizeof newTag; ++i) + { + if (newTag[i] != oldTag[i]) + { + return false; + } + } + + return true; +} +} +} diff --git a/cores/esp8266/Crypto.h b/cores/esp8266/Crypto.h new file mode 100644 index 0000000000..37477cf04f --- /dev/null +++ b/cores/esp8266/Crypto.h @@ -0,0 +1,844 @@ +/* + BearSSL Copyright (c) 2016 Thomas Pornin + Rest of this file 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 __ESP8266_ARDUINO_CRYPTO_H__ +#define __ESP8266_ARDUINO_CRYPTO_H__ + +#include + +namespace esp8266 +{ +namespace Crypto +{ +/** + Regarding constant-time (CT) 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 + + 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 getCtMaxDataLength(), constant-time processing takes substantially longer time to complete than a normal HMAC, + determined by the size of (getCtMaxDataLength() - getCtMinDataLength()). + Constant-time processing also sets limits on the data length. + + 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. +*/ + + +/** + The nonce generator should take an uint8_t array with a given size in bytes and fill it with the nonce. + The uint8_t array should then be returned by the nonce generator. +*/ +using nonceGeneratorType = std::function; + +constexpr uint8_t ENCRYPTION_KEY_LENGTH = 32; + +constexpr uint32_t CT_MAX_DIFF = 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. + + The difference getCtMaxDataLength() - getCtMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte). +*/ +void setCtMinDataLength(const size_t ctMinDataLength); +/** + 0 by default. +*/ +size_t getCtMinDataLength(); + +/** + 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 getCtMaxDataLength() - getCtMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte). +*/ +void setCtMaxDataLength(const size_t ctMaxDataLength); +/** + 1024 by default. +*/ +size_t getCtMaxDataLength(); + +/** + Set the nonce generator used by the Crypto functions. + + @param nonceGenerator The nonce generator to use. +*/ +void setNonceGenerator(nonceGeneratorType nonceGenerator); +nonceGeneratorType getNonceGenerator(); + + +// #################### MD5 #################### + +struct MD5 +{ + static constexpr uint8_t NATURAL_LENGTH = 16; + + /** + WARNING! The MD5 hash is broken in terms of attacker resistance. + Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + + Create a MD5 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + + @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated)); + + /** + WARNING! The MD5 hash is broken in terms of attacker resistance. + Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + + Create a MD5 hash of the data. The result will be 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. + */ + static String hash(const String &message) __attribute__((deprecated)); + + /** + Create a MD5 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); +}; + + +// #################### SHA-1 #################### + +struct SHA1 +{ + static constexpr uint8_t NATURAL_LENGTH = 20; + + /** + WARNING! The SHA-1 hash is broken in terms of attacker resistance. + Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + + Create a SHA1 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + + @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated)); + + /** + WARNING! The SHA-1 hash is broken in terms of attacker resistance. + Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. + + Create a SHA1 hash of the data. The result will be 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. + */ + static String hash(const String &message) __attribute__((deprecated)); + + /** + Create a SHA1 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); +}; + + +// #################### SHA-224 #################### + +struct SHA224 +{ + static constexpr uint8_t NATURAL_LENGTH = 28; + + /** + Create a SHA224 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + + @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + Create a SHA224 hash of the data. The result will be 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. + */ + static String hash(const String &message); + + /** + Create a SHA224 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); +}; + + +// #################### SHA-256 #################### + +struct SHA256 +{ + static constexpr uint8_t NATURAL_LENGTH = 32; + + /** + Create a SHA256 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + + @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + Create a SHA256 hash of the data. The result will be 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. + */ + static String hash(const String &message); + + /** + Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); + + /** + Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); +}; + + +// #################### SHA-384 #################### + +struct SHA384 +{ + static constexpr uint8_t NATURAL_LENGTH = 48; + + /** + Create a SHA384 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + + @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + Create a SHA384 hash of the data. The result will be 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. + */ + static String hash(const String &message); + + /** + Create a SHA384 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); +}; + + +// #################### SHA-512 #################### + +struct SHA512 +{ + static constexpr uint8_t NATURAL_LENGTH = 64; + + /** + Create a SHA512 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + + @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + Create a SHA512 hash of the data. The result will be 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. + */ + static String hash(const String &message); + + /** + Create a SHA512 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, + the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. + If outputLength is 0, then the natural HMAC output length is selected. + + @return A pointer to resultArray. + */ + static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); + + /** + 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 [getCtMinDataLength(), getCtMaxDataLength()]. + @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 NATURAL_LENGTH. + + @return A String with the generated HMAC in HEX format. + */ + static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); +}; + + +// #################### MD5+SHA-1 #################### + +struct MD5SHA1 +{ + static constexpr uint8_t NATURAL_LENGTH = 36; + + /** + Create a MD5+SHA-1 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. + + @return A pointer to resultArray. + */ + static void *hash(const void *data, const size_t dataLength, void *resultArray); + + /** + Create a MD5+SHA-1 hash of the data. The result will be 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. + */ + static String hash(const String &message); +}; + + +// #################### HKDF #################### + +struct HKDF +{ + /** + KDFs (key derivation functions) are functions that takes a variable length input, and provide a variable length output, meant to be used to derive subkeys from a master key. + HKDF is a KDF defined by RFC 5869. It is based on HMAC. The provided implementation uses SHA-256 as the underlying hash function. + + The constructor initializes the HKDF implementation with the input data to use for HKDF processing. (calls HKDF::init()) + + @param keyMaterial An array containing the key material to use when deriving subkeys. Typically this would be the master key. + @param keyMaterialLength The length of keyMaterial in bytes. + @param salt An array containing the salt to use when ingesting key material. Salt is non-secret and can be empty. + Its role is normally to bind the input to a conventional identifier that qualify it within the used protocol or application. + @param saltLength The length of the salt array, in bytes. + */ + HKDF(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); + + /** + This method initializes the HKDF implementation with the input data to use for HKDF processing. + Uses the BearSSL cryptographic library. + + @param keyMaterial An array containing the key material to use when deriving subkeys. Typically this would be the master key. + @param keyMaterialLength The length of keyMaterial in bytes. + @param salt An array containing the salt to use when ingesting key material. Salt is non-secret and can be empty. + Its role is normally to bind the input to a conventional identifier that qualify it within the used protocol or application. + @param saltLength The length of the salt array, in bytes. + */ + void init(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); + + /** + Produce more output bytes from the current HKDF state. This method may be called several times to obtain the full output by chunks. + The total output size is limited to 255 * SHA256::NATURAL_LENGTH bytes per unique HKDF::init()/constructor call. + Uses the BearSSL cryptographic library. + + @param resultArray The array wherein to store the resulting HKDF. + @param outputLength The requested number of bytes to fill with HKDF output in resultArray. + @param info NOTE: For correct HKDF processing, the same "info" string must be provided for every call until there's a new unique HKDF::init(). + An array containing the information string to use when producing output. Info is non-secret and can be empty. + Its role is normally to bind the output to a conventional identifier that qualify it within the used protocol or application. + @param infoLength The length of the info array, in bytes. + + @return The number of HKDF bytes actually produced. + */ + size_t produce(void *resultArray, const size_t outputLength, const void *info = nullptr, size_t infoLength = 0); + +private: + + ::br_hkdf_context hkdfContext; +}; + + +// #################### Authenticated Encryption with Associated Data (AEAD) #################### + +/** + From https://www.bearssl.org/apidoc/bearssl__aead_8h.html + + An AEAD algorithm processes messages and provides confidentiality (encryption) and checked integrity (MAC). It uses the following parameters: + + - A symmetric key. Exact size depends on the AEAD algorithm. + - A nonce (IV). Size depends on the AEAD algorithm; for most algorithms, it is crucial for security that any given nonce value is never used twice for the same key and distinct messages. + - Data to encrypt and protect. + - Additional authenticated data, which is covered by the MAC but otherwise left untouched (i.e. not encrypted). + + The AEAD algorithm encrypts the data, and produces an authentication tag. + It is assumed that the encrypted data, the tag, the additional authenticated data and the nonce are sent to the receiver; + the additional data and the nonce may be implicit (e.g. using elements of the underlying transport protocol, such as record sequence numbers). + The receiver will recompute the tag value and compare it with the one received; + if they match, then the data is correct, and can be decrypted and used; + otherwise, at least one of the elements was altered in transit, normally leading to wholesale rejection of the complete message. +*/ + + +// #################### ChaCha20+Poly1305 AEAD #################### + +struct ChaCha20Poly1305 +{ + /** + Encrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. + The function generates in place an equal-length ChaCha20 encrypted version of the data array. + More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 + Uses the BearSSL cryptographic library. + + Encryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms with the default nonceGenerator, half of this without keySalt. + + The output values of ChaCha20Poly1305::encrypt should be passed as input values to ChaCha20Poly1305::decrypt. + + Note that a 12 byte nonce is generated via getNonceGenerator() every time ChaCha20Poly1305::encrypt is called. + If the same key and nonce combination is used more than once for distinct messages, the encryption will be broken, so keep the following in mind: + + By default the nonce is generated via the hardware random number generator of the ESP8266. + The entropy of this source may not be sufficient to avoid nonce collisions, so to further reduce the risk of encryption failure + it is recommended that a keySalt is always provided when using the default nonceGenerator. Using a keySalt will create a + pseudorandom subkey from the original key via HKDF, and use that for the encryption/decryption. + The same key + keySalt will always generate the same subkey. + + An alternative to using a keySalt is to change the nonceGenerator so that it does not rely on random numbers. + One way to do this would be to use a counter that guarantees the same key + nonce combination is never used. + This may not be easily achievable in all scenarios, however. + + @param data An array containing the data to encrypt. The encrypted data is generated in place, so when the function returns the data array will contain the encrypted data. + @param dataLength The length of the data array in bytes. + @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. + @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. + @param keySaltLength The length of keySalt in bytes. + @param resultingNonce The array that will store the nonce generated during encryption. Must be able to contain at least 12 bytes. The nonce is not secret and must be passed to the decryption function. + @param resultingTag The array that will store the message authentication tag generated during encryption. Must be able to contain at least 16 bytes. The tag is not secret and must be passed to the decryption function. + @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not encrypted. + You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot + be re-sent with replaced unencrypted data by an attacker. + Defaults to nullptr. + @param aadLength The length of the aad array in bytes. Defaults to 0. + */ + static void encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, void *resultingNonce, void *resultingTag, const void *aad = nullptr, const size_t aadLength = 0); + + /** + Decrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. + The function generates in place an equal-length ChaCha20 decrypted version of the data array. + More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 + Uses the BearSSL cryptographic library. + + Decryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms, half of this without keySalt. + + The output values of ChaCha20Poly1305::encrypt should be passed as input values to ChaCha20Poly1305::decrypt. + + @param data An array containing the data to decrypt. The decrypted data is generated in place, so when the function returns the data array will contain the decrypted data. + @param dataLength The length of the data array in bytes. + @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. + @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. + @param keySaltLength The length of keySalt in bytes. + @param encryptionNonce An array containing the nonce that was generated during encryption. The nonce should be 12 bytes. + @param encryptionTag An array containing the message authentication tag that was generated during encryption. The tag should be 16 bytes. + @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not decrypted. + You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot + be re-sent with replaced unencrypted data by an attacker. + Defaults to nullptr. + @param aadLength The length of the aad array in bytes. Defaults to 0. + + @return True if the decryption was successful (the generated tag matches encryptionTag). False otherwise. Note that the data array is modified regardless of this outcome. + */ + static bool decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, const void *encryptionNonce, const void *encryptionTag, const void *aad = nullptr, const size_t aadLength = 0); +}; +} +} +#endif diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index dc9e069d9d..f385220eed 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -522,6 +522,63 @@ bool EspClass::eraseConfig(void) { return true; } +uint8_t *EspClass::random(uint8_t *resultArray, const size_t outputSizeBytes) const +{ + /** + * The ESP32 Technical Reference Manual v4.1 chapter 24 has the following to say about random number generation (no information found for ESP8266): + * + * "When used correctly, every 32-bit value the system reads from the RNG_DATA_REG register of the random number generator is a true random number. + * These true random numbers are generated based on the noise in the Wi-Fi/BT RF system. + * When Wi-Fi and BT are disabled, the random number generator will give out pseudo-random numbers. + * + * When Wi-Fi or BT is enabled, the random number generator is fed two bits of entropy every APB clock cycle (normally 80 MHz). + * Thus, for the maximum amount of entropy, it is advisable to read the random register at a maximum rate of 5 MHz. + * A data sample of 2 GB, read from the random number generator with Wi-Fi enabled and the random register read at 5 MHz, + * has been tested using the Dieharder Random Number Testsuite (version 3.31.1). + * The sample passed all tests." + * + * Since ESP32 is the sequal to ESP8266 it is unlikely that the ESP8266 is able to generate random numbers more quickly than 5 MHz when run at a 80 MHz frequency. + * A maximum random number frequency of 0.5 MHz is used here to leave some margin for possibly inferior components in the ESP8266. + * It should be noted that the ESP8266 has no Bluetooth functionality, so turning the WiFi off is likely to cause RANDOM_REG32 to use pseudo-random numbers. + * + * It is possible that yield() must be called on the ESP8266 to properly feed the hardware random number generator new bits, since there is only one processor core available. + * However, no feeding requirements are mentioned in the ESP32 documentation, and using yield() could possibly cause extended delays during nonce generation. + * Thus only delayMicroseconds() is used below. + */ + + constexpr uint8_t cooldownMicros = 2; + static uint32_t lastCalledMicros = micros() - cooldownMicros; + + uint32_t randomNumber = 0; + + for(size_t byteIndex = 0; byteIndex < outputSizeBytes; ++byteIndex) + { + if(byteIndex % 4 == 0) + { + // Old random number has been used up (random number could be exactly 0, so we can't check for that) + + uint32_t timeSinceLastCall = micros() - lastCalledMicros; + if(timeSinceLastCall < cooldownMicros) + delayMicroseconds(cooldownMicros - timeSinceLastCall); + + randomNumber = RANDOM_REG32; + lastCalledMicros = micros(); + } + + resultArray[byteIndex] = randomNumber; + randomNumber >>= 8; + } + + return resultArray; +} + +uint32_t EspClass::random() const +{ + union { uint32_t b32; uint8_t b8[4]; } result; + random(result.b8, 4); + return result.b32; +} + uint32_t EspClass::getSketchSize() { static uint32_t result = 0; if (result) diff --git a/cores/esp8266/Esp.h b/cores/esp8266/Esp.h index a8fff36515..4ad59e2237 100644 --- a/cores/esp8266/Esp.h +++ b/cores/esp8266/Esp.h @@ -164,6 +164,9 @@ class EspClass { bool eraseConfig(); + uint8_t *random(uint8_t *resultArray, const size_t outputSizeBytes) const; + uint32_t random() const; + #ifndef CORE_MOCK inline uint32_t getCycleCount() __attribute__((always_inline)); #else diff --git a/libraries/CryptoInterface/README.md b/libraries/CryptoInterface/README.md deleted file mode 100644 index d32c33ca3d..0000000000 --- a/libraries/CryptoInterface/README.md +++ /dev/null @@ -1,9 +0,0 @@ -ESP8266 CryptoInterface -================= - -A library containing easy-to-use cryptographic functions. Primarily a frontend for the cryptographic library BearSSL which is used by `BearSSL::WiFiClientSecure` and `BearSSL::WiFiServerSecure` in the ESP8266 Arduino Core. - -Usage ------ - -There are a number of cryptographic functions in the library. See the included example for a guide on how to use some of them. Extensive documentation can be found in the library source code files and on the [BearSSL homepage](https://www.bearssl.org). \ No newline at end of file diff --git a/libraries/CryptoInterface/keywords.txt b/libraries/CryptoInterface/keywords.txt deleted file mode 100644 index c2ea133c24..0000000000 --- a/libraries/CryptoInterface/keywords.txt +++ /dev/null @@ -1,50 +0,0 @@ -####################################### -# Syntax Coloring Map For CryptoInterface -####################################### - -####################################### -# Library (KEYWORD3) -####################################### - -CryptoInterface KEYWORD3 - -####################################### -# Datatypes (KEYWORD1) -####################################### - -nonceGeneratorType KEYWORD1 -MD5 KEYWORD1 -SHA1 KEYWORD1 -SHA224 KEYWORD1 -SHA256 KEYWORD1 -SHA384 KEYWORD1 -SHA512 KEYWORD1 -MD5SHA1 KEYWORD1 -HKDF KEYWORD1 -ChaCha20Poly1305 KEYWORD1 - -####################################### -# Methods and Functions (KEYWORD2) -####################################### - -setCtMinDataLength KEYWORD2 -getCtMinDataLength KEYWORD2 -setCtMaxDataLength KEYWORD2 -getCtMaxDataLength KEYWORD2 -setNonceGenerator KEYWORD2 -getNonceGenerator KEYWORD2 -hash KEYWORD2 -hmac KEYWORD2 -hmacCT KEYWORD2 -init KEYWORD2 -produce KEYWORD2 -encrypt KEYWORD2 -decrypt KEYWORD2 - -####################################### -# Constants (LITERAL1) -####################################### - -NATURAL_LENGTH LITERAL1 -ENCRYPTION_KEY_LENGTH LITERAL1 -CT_MAX_DIFF LITERAL1 diff --git a/libraries/CryptoInterface/library.properties b/libraries/CryptoInterface/library.properties deleted file mode 100644 index 455161a091..0000000000 --- a/libraries/CryptoInterface/library.properties +++ /dev/null @@ -1,10 +0,0 @@ -name=CryptoInterface -version=1.0 -author=Anders Löfgren -maintainer=Anders Löfgren -sentence=Interface to the cryptographic library -paragraph=The library acts as a frontend to the cryptographic backend library in ESP8266 Arduino Core. -category=Other -url= -architectures=esp8266 -dot_a_linkage=true diff --git a/libraries/CryptoInterface/src/CryptoInterface.cpp b/libraries/CryptoInterface/src/CryptoInterface.cpp deleted file mode 100644 index fc8d0de8b5..0000000000 --- a/libraries/CryptoInterface/src/CryptoInterface.cpp +++ /dev/null @@ -1,561 +0,0 @@ -/* - * BearSSL Copyright (c) 2016 Thomas Pornin - * Rest of this file 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 -#include "CryptoInterface.h" -#include - -#include - -namespace TypeCast = esp8266::TypeConversion; - -namespace experimental -{ - namespace - { - size_t _ctMinDataLength = 0; - size_t _ctMaxDataLength = 1024; - - uint8_t *defaultNonceGenerator(uint8_t *nonceArray, const size_t nonceLength) - { - /** - * The ESP32 Technical Reference Manual v4.1 chapter 24 has the following to say about random number generation (no information found for ESP8266): - * - * "When used correctly, every 32-bit value the system reads from the RNG_DATA_REG register of the random number generator is a true random number. - * These true random numbers are generated based on the noise in the Wi-Fi/BT RF system. - * When Wi-Fi and BT are disabled, the random number generator will give out pseudo-random numbers. - * - * When Wi-Fi or BT is enabled, the random number generator is fed two bits of entropy every APB clock cycle (normally 80 MHz). - * Thus, for the maximum amount of entropy, it is advisable to read the random register at a maximum rate of 5 MHz. - * A data sample of 2 GB, read from the random number generator with Wi-Fi enabled and the random register read at 5 MHz, - * has been tested using the Dieharder Random Number Testsuite (version 3.31.1). - * The sample passed all tests." - * - * Since ESP32 is the sequal to ESP8266 it is unlikely that the ESP8266 is able to generate random numbers more quickly than 5 MHz when run at a 80 MHz frequency. - * A maximum random number frequency of 0.5 MHz is used here to leave some margin for possibly inferior components in the ESP8266. - * It should be noted that the ESP8266 has no Bluetooth functionality, so turning the WiFi off is likely to cause RANDOM_REG32 to use pseudo-random numbers. - * - * It is possible that yield() must be called on the ESP8266 to properly feed the hardware random number generator new bits, since there is only one processor core available. - * However, no feeding requirements are mentioned in the ESP32 documentation, and using yield() could possibly cause extended delays during nonce generation. - * Thus only delayMicroseconds() is used below. - */ - - constexpr uint8_t cooldownMicros = 2; - static uint32_t lastCalledMicros = micros() - cooldownMicros; - - uint32_t randomNumber = 0; - - for(size_t byteIndex = 0; byteIndex < nonceLength; ++byteIndex) - { - if(byteIndex % 4 == 0) - { - // Old random number has been used up (random number could be exactly 0, so we can't check for that) - - uint32_t timeSinceLastCall = micros() - lastCalledMicros; - if(timeSinceLastCall < cooldownMicros) - delayMicroseconds(cooldownMicros - timeSinceLastCall); - - randomNumber = RANDOM_REG32; - lastCalledMicros = micros(); - } - - nonceArray[byteIndex] = randomNumber; - randomNumber >>= 8; - } - - return nonceArray; - } - - CryptoInterface::nonceGeneratorType _nonceGenerator = defaultNonceGenerator; - - 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 outputLength) - { - // 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. - - br_hmac_key_context keyContext; // Holds general HMAC info - 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. - br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); - - // Initialise a HMAC context with a key context. The key context is unmodified. - // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. - // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. - // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. - br_hmac_init(&hmacContext, &keyContext, outputLength); - - // Provide the HMAC context with the data to create a HMAC from. - // 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). - // The context is NOT modified; further bytes may be processed. Thus, "partial HMAC" values can be efficiently obtained. - // Optionally the constant-time version br_hmac_outCT() can be used. More info here: https://www.bearssl.org/constanttime.html . - br_hmac_out(&hmacContext, resultArray); // returns size_t outputLength - - return resultArray; - } - - 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 <= hashTypeNaturalLength); - - uint8_t hmac[hmacLength]; - createBearsslHmac(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); - return TypeCast::uint8ArrayToHexString(hmac, hmacLength); - } - - 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 outputLength) - { - 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. - - br_hmac_key_context keyContext; // Holds general HMAC info - 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. - br_hmac_key_init(&keyContext, hashType, hashKey, hashKeyLength); - - // Initialise a HMAC context with a key context. The key context is unmodified. - // Relevant data from the key context is immediately copied; the key context can thus be independently reused, modified or released without impacting this HMAC computation. - // An explicit output length can be specified; the actual output length will be the minimum of that value and the natural HMAC output length. - // If outputLength is 0, then the natural HMAC output length is selected. The "natural output length" is the output length of the underlying hash function. - br_hmac_init(&hmacContext, &keyContext, outputLength); - - // Provide the HMAC context with the data to create a HMAC from. - // 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, data, dataLength); - - // 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 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 _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. - br_hmac_outCT(&hmacContext, data, dataLength, _ctMinDataLength, _ctMaxDataLength, resultArray); // returns size_t outputLength - - return resultArray; - } - - 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 <= hashTypeNaturalLength); - - uint8_t hmac[hmacLength]; - createBearsslHmacCT(hashType, message.c_str(), message.length(), hashKey, hashKeyLength, hmac, hmacLength); - return TypeCast::uint8ArrayToHexString(hmac, hmacLength); - } - - - // Helper function to avoid deprecated warnings. - void *md5HashHelper(const void *data, const size_t dataLength, void *resultArray) - { - br_md5_context context; - br_md5_init(&context); - br_md5_update(&context, data, dataLength); - br_md5_out(&context, resultArray); - return resultArray; - } - - // Helper function to avoid deprecated warnings. - void *sha1HashHelper(const void *data, const size_t dataLength, void *resultArray) - { - br_sha1_context context; - br_sha1_init(&context); - br_sha1_update(&context, data, dataLength); - br_sha1_out(&context, resultArray); - return resultArray; - } - } - - namespace CryptoInterface - { - void setCtMinDataLength(const size_t ctMinDataLength) - { - assert(getCtMaxDataLength() - ctMinDataLength <= CT_MAX_DIFF); - _ctMinDataLength = ctMinDataLength; - } - size_t getCtMinDataLength() {return _ctMinDataLength;} - - void setCtMaxDataLength(const size_t ctMaxDataLength) - { - assert(ctMaxDataLength - getCtMinDataLength() <= CT_MAX_DIFF); - _ctMaxDataLength = ctMaxDataLength; - } - size_t getCtMaxDataLength() {return _ctMaxDataLength;} - - void setNonceGenerator(nonceGeneratorType nonceGenerator) { _nonceGenerator = nonceGenerator; } - nonceGeneratorType getNonceGenerator() { return _nonceGenerator; } - - - // #################### MD5 #################### - - // resultArray must have size MD5::NATURAL_LENGTH or greater - void *MD5::hash(const void *data, const size_t dataLength, void *resultArray) - { - return md5HashHelper(data, dataLength, resultArray); - } - - String MD5::hash(const String &message) - { - uint8_t hashArray[NATURAL_LENGTH]; - md5HashHelper(message.c_str(), message.length(), hashArray); - return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); - } - - void *MD5::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String MD5::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmac(&br_md5_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - void *MD5::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_md5_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String MD5::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmacCT(&br_md5_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - - // #################### SHA-1 #################### - - // resultArray must have size SHA1::NATURAL_LENGTH or greater - void *SHA1::hash(const void *data, const size_t dataLength, void *resultArray) - { - return sha1HashHelper(data, dataLength, resultArray); - } - - String SHA1::hash(const String &message) - { - uint8_t hashArray[NATURAL_LENGTH]; - sha1HashHelper(message.c_str(), message.length(), hashArray); - return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); - } - - void *SHA1::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA1::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmac(&br_sha1_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - void *SHA1::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha1_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA1::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmacCT(&br_sha1_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - - // #################### SHA-224 #################### - - // resultArray must have size SHA224::NATURAL_LENGTH or greater - void *SHA224::hash(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 SHA224::hash(const String &message) - { - uint8_t hashArray[NATURAL_LENGTH]; - hash(message.c_str(), message.length(), hashArray); - return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); - } - - void *SHA224::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA224::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmac(&br_sha224_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - void *SHA224::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha224_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA224::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmacCT(&br_sha224_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - - // #################### SHA-256 #################### - - // resultArray must have size SHA256::NATURAL_LENGTH or greater - void *SHA256::hash(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 SHA256::hash(const String &message) - { - uint8_t hashArray[NATURAL_LENGTH]; - hash(message.c_str(), message.length(), hashArray); - return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); - } - - void *SHA256::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA256::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmac(&br_sha256_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - void *SHA256::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha256_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA256::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmacCT(&br_sha256_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - - // #################### SHA-384 #################### - - // resultArray must have size SHA384::NATURAL_LENGTH or greater - void *SHA384::hash(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 SHA384::hash(const String &message) - { - uint8_t hashArray[NATURAL_LENGTH]; - hash(message.c_str(), message.length(), hashArray); - return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); - } - - void *SHA384::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA384::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmac(&br_sha384_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - void *SHA384::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha384_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA384::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmacCT(&br_sha384_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - - // #################### SHA-512 #################### - - // resultArray must have size SHA512::NATURAL_LENGTH or greater - void *SHA512::hash(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 SHA512::hash(const String &message) - { - uint8_t hashArray[NATURAL_LENGTH]; - hash(message.c_str(), message.length(), hashArray); - return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); - } - - void *SHA512::hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmac(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA512::hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmac(&br_sha512_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - void *SHA512::hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength) - { - return createBearsslHmacCT(&br_sha512_vtable, data, dataLength, hashKey, hashKeyLength, resultArray, outputLength); - } - - String SHA512::hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength) - { - return createBearsslHmacCT(&br_sha512_vtable, NATURAL_LENGTH, message, hashKey, hashKeyLength, hmacLength); - } - - - // #################### MD5+SHA-1 #################### - - // resultArray must have size MD5SHA1::NATURAL_LENGTH or greater - void *MD5SHA1::hash(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 MD5SHA1::hash(const String &message) - { - uint8_t hashArray[NATURAL_LENGTH]; - hash(message.c_str(), message.length(), hashArray); - return TypeCast::uint8ArrayToHexString(hashArray, NATURAL_LENGTH); - } - - - // #################### HKDF #################### - - HKDF::HKDF(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) - { - init(keyMaterial, keyMaterialLength, salt, saltLength); - } - - void HKDF::init(const void *keyMaterial, const size_t keyMaterialLength, const void *salt, const size_t saltLength) - { - // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html - - // Initialize an HKDF context, with a hash function, and the salt. This starts the HKDF-Extract process. - br_hkdf_init(&hkdfContext, &br_sha256_vtable, salt, saltLength); - - // Inject more input bytes. This function may be called repeatedly if the input data is provided by chunks, after br_hkdf_init() but before br_hkdf_flip(). - br_hkdf_inject(&hkdfContext, keyMaterial, keyMaterialLength); - - // End the HKDF-Extract process, and start the HKDF-Expand process. - br_hkdf_flip(&hkdfContext); - } - - size_t HKDF::produce(void *resultArray, const size_t outputLength, const void *info, const size_t infoLength) - { - // Comments mainly from https://www.bearssl.org/apidoc/bearssl__kdf_8h.html - - // HKDF output production (HKDF-Expand). - // Produces more output bytes from the current state. This function may be called several times, but only after br_hkdf_flip(). - // Returned value is the number of actually produced bytes. The total output length is limited to 255 times the output length of the underlying hash function. - return br_hkdf_produce(&hkdfContext, info, infoLength, resultArray, outputLength); - } - - - // #################### Authenticated Encryption with Associated Data (AEAD) #################### - - - // #################### ChaCha20+Poly1305 AEAD #################### - - void chacha20Poly1305Kernel(const int encrypt, void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, - const void *nonce, void *tag, const void *aad, const size_t aadLength) - { - if(keySalt == nullptr) - { - br_poly1305_ctmul32_run(key, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); - } - else - { - HKDF hkdfInstance(key, ENCRYPTION_KEY_LENGTH, keySalt, keySaltLength); - uint8_t derivedEncryptionKey[ENCRYPTION_KEY_LENGTH] {0}; - hkdfInstance.produce(derivedEncryptionKey, ENCRYPTION_KEY_LENGTH); - br_poly1305_ctmul32_run(derivedEncryptionKey, nonce, data, dataLength, aad, aadLength, tag, br_chacha20_ct_run, encrypt); - } - } - - void ChaCha20Poly1305::encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, - void *resultingNonce, void *resultingTag, const void *aad, const size_t aadLength) - { - uint8_t *nonce = (uint8_t *)resultingNonce; - getNonceGenerator()(nonce, 12); - - chacha20Poly1305Kernel(1, data, dataLength, key, keySalt, keySaltLength, nonce, resultingTag, aad, aadLength); - } - - bool ChaCha20Poly1305::decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, - const void *encryptionNonce, const void *encryptionTag, const void *aad, const size_t aadLength) - { - const uint8_t *oldTag = (const uint8_t *)encryptionTag; - uint8_t newTag[16] {0}; - - chacha20Poly1305Kernel(0, data, dataLength, key, keySalt, keySaltLength, encryptionNonce, newTag, aad, aadLength); - - for(uint32_t i = 0; i < sizeof newTag; ++i) - { - if(newTag[i] != oldTag[i]) - return false; - } - - return true; - } - } -} diff --git a/libraries/CryptoInterface/src/CryptoInterface.h b/libraries/CryptoInterface/src/CryptoInterface.h deleted file mode 100644 index d572d30180..0000000000 --- a/libraries/CryptoInterface/src/CryptoInterface.h +++ /dev/null @@ -1,841 +0,0 @@ -/* - * BearSSL Copyright (c) 2016 Thomas Pornin - * Rest of this file 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 __ESP8266ARDUINOCRYPTOINTERFACE_H__ -#define __ESP8266ARDUINOCRYPTOINTERFACE_H__ - -#include - -namespace experimental -{ - namespace CryptoInterface - { - #include - - /** - * Regarding constant-time (CT) 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 - * - * 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 getCtMaxDataLength(), constant-time processing takes substantially longer time to complete than a normal HMAC, - * determined by the size of (getCtMaxDataLength() - getCtMinDataLength()). - * Constant-time processing also sets limits on the data length. - * - * 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. - */ - - - /** - * The nonce generator should take an uint8_t array with a given size in bytes and fill it with the nonce. - * The uint8_t array should then be returned by the nonce generator. - */ - using nonceGeneratorType = std::function; - - constexpr uint8_t ENCRYPTION_KEY_LENGTH = 32; - - constexpr uint32_t CT_MAX_DIFF = 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. - * - * The difference getCtMaxDataLength() - getCtMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte). - */ - void setCtMinDataLength(const size_t ctMinDataLength); - /** - * 0 by default. - */ - size_t getCtMinDataLength(); - - /** - * 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 getCtMaxDataLength() - getCtMinDataLength() MUST be less than 2^30 (i.e. about one gigabyte). - */ - void setCtMaxDataLength(const size_t ctMaxDataLength); - /** - * 1024 by default. - */ - size_t getCtMaxDataLength(); - - /** - * Set the nonce generator used by the CryptoInterface functions. - * - * @param nonceGenerator The nonce generator to use. - */ - void setNonceGenerator(nonceGeneratorType nonceGenerator); - nonceGeneratorType getNonceGenerator(); - - - // #################### MD5 #################### - - struct MD5 - { - static constexpr uint8_t NATURAL_LENGTH = 16; - - /** - * WARNING! The MD5 hash is broken in terms of attacker resistance. - * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. - * - * Create a MD5 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. - * - * @return A pointer to resultArray. - */ - static void *hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated)); - - /** - * WARNING! The MD5 hash is broken in terms of attacker resistance. - * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. - * - * Create a MD5 hash of the data. The result will be 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. - */ - static String hash(const String &message) __attribute__((deprecated)); - - /** - * Create a MD5 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); - }; - - - // #################### SHA-1 #################### - - struct SHA1 - { - static constexpr uint8_t NATURAL_LENGTH = 20; - - /** - * WARNING! The SHA-1 hash is broken in terms of attacker resistance. - * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. - * - * Create a SHA1 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. - * - * @return A pointer to resultArray. - */ - static void *hash(const void *data, const size_t dataLength, void *resultArray) __attribute__((deprecated)); - - /** - * WARNING! The SHA-1 hash is broken in terms of attacker resistance. - * Only use it in those cases where attacker resistance is not important. Prefer SHA-256 or higher otherwise. - * - * Create a SHA1 hash of the data. The result will be 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. - */ - static String hash(const String &message) __attribute__((deprecated)); - - /** - * Create a SHA1 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); - }; - - - // #################### SHA-224 #################### - - struct SHA224 - { - static constexpr uint8_t NATURAL_LENGTH = 28; - - /** - * Create a SHA224 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. - * - * @return A pointer to resultArray. - */ - static void *hash(const void *data, const size_t dataLength, void *resultArray); - - /** - * Create a SHA224 hash of the data. The result will be 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. - */ - static String hash(const String &message); - - /** - * Create a SHA224 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); - }; - - - // #################### SHA-256 #################### - - struct SHA256 - { - static constexpr uint8_t NATURAL_LENGTH = 32; - - /** - * Create a SHA256 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. - * - * @return A pointer to resultArray. - */ - static void *hash(const void *data, const size_t dataLength, void *resultArray); - - /** - * Create a SHA256 hash of the data. The result will be 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. - */ - static String hash(const String &message); - - /** - * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmac(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); - - /** - * Create a SHA256 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); - }; - - - // #################### SHA-384 #################### - - struct SHA384 - { - static constexpr uint8_t NATURAL_LENGTH = 48; - - /** - * Create a SHA384 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. - * - * @return A pointer to resultArray. - */ - static void *hash(const void *data, const size_t dataLength, void *resultArray); - - /** - * Create a SHA384 hash of the data. The result will be 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. - */ - static String hash(const String &message); - - /** - * Create a SHA384 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); - }; - - - // #################### SHA-512 #################### - - struct SHA512 - { - static constexpr uint8_t NATURAL_LENGTH = 64; - - /** - * Create a SHA512 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. - * - * @return A pointer to resultArray. - */ - static void *hash(const void *data, const size_t dataLength, void *resultArray); - - /** - * Create a SHA512 hash of the data. The result will be 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. - */ - static String hash(const String &message); - - /** - * Create a SHA512 HMAC from the data, using the provided hashKey. The result will be up to outputLength 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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmac(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmac(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 up to outputLength 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 outputLength The desired length of the generated HMAC, in bytes. Must fit within resultArray. If outputLength is greater than NATURAL_LENGTH, - * the first (lowest index) NATURAL_LENGTH bytes of resultArray will be used for the HMAC. - * If outputLength is 0, then the natural HMAC output length is selected. - * - * @return A pointer to resultArray. - */ - static void *hmacCT(const void *data, const size_t dataLength, const void *hashKey, const size_t hashKeyLength, void *resultArray, const size_t outputLength); - - /** - * 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 [getCtMinDataLength(), getCtMaxDataLength()]. - * @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 NATURAL_LENGTH. - * - * @return A String with the generated HMAC in HEX format. - */ - static String hmacCT(const String &message, const void *hashKey, const size_t hashKeyLength, const size_t hmacLength); - }; - - - // #################### MD5+SHA-1 #################### - - struct MD5SHA1 - { - static constexpr uint8_t NATURAL_LENGTH = 36; - - /** - * Create a MD5+SHA-1 hash of the data. The result will be 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 NATURAL_LENGTH bytes or more. - * - * @return A pointer to resultArray. - */ - static void *hash(const void *data, const size_t dataLength, void *resultArray); - - /** - * Create a MD5+SHA-1 hash of the data. The result will be 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. - */ - static String hash(const String &message); - }; - - - // #################### HKDF #################### - - struct HKDF - { - /** - * KDFs (key derivation functions) are functions that takes a variable length input, and provide a variable length output, meant to be used to derive subkeys from a master key. - * HKDF is a KDF defined by RFC 5869. It is based on HMAC. The provided implementation uses SHA-256 as the underlying hash function. - * - * This method initializes the HKDF implementation with the input data to use for HKDF processing. (calls HKDF::Init()) - */ - HKDF(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); - - /** - * This method initializes the HKDF implementation with the input data to use for HKDF processing. - * Uses the BearSSL cryptographic library. - * - * @param keyMaterial An array containing the key material to use when deriving subkeys. Typically this would be the master key. - * @param keyMaterialLength The length of keyMaterial in bytes. - * @param salt An array containing the salt to use when ingesting key material. Salt is non-secret and can be empty. - * Its role is normally to bind the input to a conventional identifier that qualify it within the used protocol or application. - * @param saltLength The length of the salt array, in bytes. - */ - void init(const void *keyMaterial, const size_t keyMaterialLength, const void *salt = nullptr, const size_t saltLength = 0); - - /** - * Produce more output bytes from the current HKDF state. This method may be called several times to obtain the full output by chunks. - * The total output size is limited to 255 * SHA256::NATURAL_LENGTH bytes per unique HKDF::Init()/constructor call. - * Uses the BearSSL cryptographic library. - * - * @param resultArray The array wherein to store the resulting HKDF. - * @param outputLength The requested number of bytes to fill with HKDF output in resultArray. - * @param info NOTE: For correct HKDF processing, the same "info" string must be provided for every call until there's a new unique HKDF::Init(). - * An array containing the information string to use when producing output. Info is non-secret and can be empty. - * Its role is normally to bind the output to a conventional identifier that qualify it within the used protocol or application. - * @param infoLength The length of the info array, in bytes. - * - * @return The number of HKDF bytes actually produced. - */ - size_t produce(void *resultArray, const size_t outputLength, const void *info = nullptr, size_t infoLength = 0); - - private: - - br_hkdf_context hkdfContext; - }; - - - // #################### Authenticated Encryption with Associated Data (AEAD) #################### - - /** - * From https://www.bearssl.org/apidoc/bearssl__aead_8h.html - * - * An AEAD algorithm processes messages and provides confidentiality (encryption) and checked integrity (MAC). It uses the following parameters: - * - * - A symmetric key. Exact size depends on the AEAD algorithm. - * - A nonce (IV). Size depends on the AEAD algorithm; for most algorithms, it is crucial for security that any given nonce value is never used twice for the same key and distinct messages. - * - Data to encrypt and protect. - * - Additional authenticated data, which is covered by the MAC but otherwise left untouched (i.e. not encrypted). - * - * The AEAD algorithm encrypts the data, and produces an authentication tag. - * It is assumed that the encrypted data, the tag, the additional authenticated data and the nonce are sent to the receiver; - * the additional data and the nonce may be implicit (e.g. using elements of the underlying transport protocol, such as record sequence numbers). - * The receiver will recompute the tag value and compare it with the one received; - * if they match, then the data is correct, and can be decrypted and used; - * otherwise, at least one of the elements was altered in transit, normally leading to wholesale rejection of the complete message. - */ - - - // #################### ChaCha20+Poly1305 AEAD #################### - - struct ChaCha20Poly1305 - { - /** - * Encrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. - * The function generates in place an equal-length ChaCha20 encrypted version of the data array. - * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 - * Uses the BearSSL cryptographic library. - * - * Encryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms with the default nonceGenerator, half of this without keySalt. - * - * The output values of ChaCha20Poly1305::encrypt should be passed as input values to ChaCha20Poly1305::decrypt. - * - * Note that a 12 byte nonce is generated via getNonceGenerator() every time ChaCha20Poly1305::encrypt is called. - * If the same key and nonce combination is used more than once for distinct messages, the encryption will be broken, so keep the following in mind: - * - * By default the nonce is generated via the hardware random number generator of the ESP8266. - * The entropy of this source may not be sufficient to avoid nonce collisions, so to further reduce the risk of encryption failure - * it is recommended that a keySalt is always provided when using the default nonceGenerator. Using a keySalt will create a - * pseudorandom subkey from the original key via HKDF, and use that for the encryption/decryption. - * The same key + keySalt will always generate the same subkey. - * - * An alternative to using a keySalt is to change the nonceGenerator so that it does not rely on random numbers. - * One way to do this would be to use a counter that guarantees the same key + nonce combination is never used. - * This may not be easily achievable in all scenarios, however. - * - * @param data An array containing the data to encrypt. The encrypted data is generated in place, so when the function returns the data array will contain the encrypted data. - * @param dataLength The length of the data array in bytes. - * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. - * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. - * @param keySaltLength The length of keySalt in bytes. - * @param resultingNonce The array that will store the nonce generated during encryption. Must be able to contain at least 12 bytes. The nonce is not secret and must be passed to the decryption function. - * @param resultingTag The array that will store the message authentication tag generated during encryption. Must be able to contain at least 16 bytes. The tag is not secret and must be passed to the decryption function. - * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not encrypted. - * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot - * be re-sent with replaced unencrypted data by an attacker. - * Defaults to nullptr. - * @param aadLength The length of the aad array in bytes. Defaults to 0. - */ - static void encrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, void *resultingNonce, void *resultingTag, const void *aad = nullptr, const size_t aadLength = 0); - - /** - * Decrypt the data array using the ChaCha20 stream cipher and use Poly1305 for message authentication. - * The function generates in place an equal-length ChaCha20 decrypted version of the data array. - * More information about this encryption standard can be found here: https://tools.ietf.org/html/rfc7539 , https://tools.ietf.org/html/rfc8439 - * Uses the BearSSL cryptographic library. - * - * Decryption of small messages (up to a few hundred data bytes) takes around 0.5-1 ms, half of this without keySalt. - * - * The output values of ChaCha20Poly1305::encrypt should be passed as input values to ChaCha20Poly1305::decrypt. - * - * @param data An array containing the data to decrypt. The decrypted data is generated in place, so when the function returns the data array will contain the decrypted data. - * @param dataLength The length of the data array in bytes. - * @param key The secret encryption key to use. Must be 32 bytes (ENCRYPTION_KEY_LENGTH) long. - * @param keySalt The salt to use when generating a subkey from key. Note that the same salt must be used during decryption as during encryption. Set to nullptr to prevent subkey generation. - * @param keySaltLength The length of keySalt in bytes. - * @param encryptionNonce An array containing the nonce that was generated during encryption. The nonce should be 12 bytes. - * @param encryptionTag An array containing the message authentication tag that was generated during encryption. The tag should be 16 bytes. - * @param aad Additional authenticated data. This data will be covered by the Poly1305 MAC, but not decrypted. - * You can include the unencrypted parts of your message as AAD to ensure that the encrypted content cannot - * be re-sent with replaced unencrypted data by an attacker. - * Defaults to nullptr. - * @param aadLength The length of the aad array in bytes. Defaults to 0. - * - * @return True if the decryption was successful (the generated tag matches encryptionTag). False otherwise. Note that the data array is modified regardless of this outcome. - */ - static bool decrypt(void *data, const size_t dataLength, const void *key, const void *keySalt, const size_t keySaltLength, const void *encryptionNonce, const void *encryptionTag, const void *aad = nullptr, const size_t aadLength = 0); - }; - } -} - -#endif diff --git a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino b/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino similarity index 73% rename from libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino rename to libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino index d15cdf8c70..566afd5ad4 100644 --- a/libraries/CryptoInterface/examples/HelloCrypto/HelloCrypto.ino +++ b/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino @@ -1,13 +1,14 @@ /** - This example shows the functionality of the CryptoInterface library. + This example demonstrates the usage of the ESP8266 Crypto implementation, which aims to contain easy-to-use cryptographic functions. + Crypto is currently primarily a frontend for the cryptographic library BearSSL which is used by `BearSSL::WiFiClientSecure` and `BearSSL::WiFiServerSecure` in the ESP8266 Arduino Core. + Extensive documentation can be found in the Crypto source code files and on the [BearSSL homepage](https://www.bearssl.org). */ #include #include -#include +#include namespace TypeCast = esp8266::TypeConversion; -using namespace experimental; /** NOTE: Although we could define the strings below as normal String variables, @@ -39,31 +40,31 @@ void loop() { String exampleData = F("Hello Crypto World!"); Serial.println(String(F("This is our example data: ")) + exampleData); - uint8_t resultArray[CryptoInterface::SHA256::NATURAL_LENGTH] { 0 }; - uint8_t derivedKey[CryptoInterface::ENCRYPTION_KEY_LENGTH] { 0 }; + uint8_t resultArray[esp8266::Crypto::SHA256::NATURAL_LENGTH] { 0 }; + uint8_t derivedKey[esp8266::Crypto::ENCRYPTION_KEY_LENGTH] { 0 }; static uint32_t encryptionCounter = 0; // Generate the salt to use for HKDF uint8_t hkdfSalt[16] { 0 }; - CryptoInterface::getNonceGenerator()(hkdfSalt, sizeof hkdfSalt); + esp8266::Crypto::getNonceGenerator()(hkdfSalt, sizeof hkdfSalt); // Generate the key to use for HMAC and encryption - CryptoInterface::HKDF hkdfInstance(FPSTR(masterKey), (sizeof masterKey) - 1, hkdfSalt, sizeof hkdfSalt); // (sizeof masterKey) - 1 removes the terminating null value of the c-string + esp8266::Crypto::HKDF hkdfInstance(FPSTR(masterKey), (sizeof masterKey) - 1, hkdfSalt, sizeof hkdfSalt); // (sizeof masterKey) - 1 removes the terminating null value of the c-string hkdfInstance.produce(derivedKey, sizeof derivedKey); // Hash - CryptoInterface::SHA256::hash(exampleData.c_str(), exampleData.length(), resultArray); + esp8266::Crypto::SHA256::hash(exampleData.c_str(), exampleData.length(), resultArray); Serial.println(String(F("\nThis is the SHA256 hash of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); - Serial.println(String(F("This is the SHA256 hash of our example data, in HEX format, using String output:\n")) + CryptoInterface::SHA256::hash(exampleData)); + Serial.println(String(F("This is the SHA256 hash of our example data, in HEX format, using String output:\n")) + esp8266::Crypto::SHA256::hash(exampleData)); // HMAC // Note that HMAC output length is limited - CryptoInterface::SHA256::hmac(exampleData.c_str(), exampleData.length(), derivedKey, sizeof derivedKey, resultArray, sizeof resultArray); + esp8266::Crypto::SHA256::hmac(exampleData.c_str(), exampleData.length(), derivedKey, sizeof derivedKey, resultArray, sizeof resultArray); Serial.println(String(F("\nThis is the SHA256 HMAC of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); - Serial.println(String(F("This is the SHA256 HMAC of our example data, in HEX format, using String output:\n")) + CryptoInterface::SHA256::hmac(exampleData, derivedKey, sizeof derivedKey, CryptoInterface::SHA256::NATURAL_LENGTH)); + Serial.println(String(F("This is the SHA256 HMAC of our example data, in HEX format, using String output:\n")) + esp8266::Crypto::SHA256::hmac(exampleData, derivedKey, sizeof derivedKey, esp8266::Crypto::SHA256::NATURAL_LENGTH)); // Authenticated Encryption with Associated Data (AEAD) @@ -74,10 +75,10 @@ void loop() { Serial.println(String(F("\nThis is the data to encrypt: ")) + dataToEncrypt); // Note that the key must be ENCRYPTION_KEY_LENGTH long. - CryptoInterface::ChaCha20Poly1305::encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + esp8266::Crypto::ChaCha20Poly1305::encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); Serial.println(String(F("Encrypted data: ")) + dataToEncrypt); - bool decryptionSucceeded = CryptoInterface::ChaCha20Poly1305::decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + bool decryptionSucceeded = esp8266::Crypto::ChaCha20Poly1305::decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); encryptionCounter++; if (decryptionSucceeded) { diff --git a/libraries/esp8266/keywords.txt b/libraries/esp8266/keywords.txt index 902db205c9..a80c2e3ed3 100644 --- a/libraries/esp8266/keywords.txt +++ b/libraries/esp8266/keywords.txt @@ -12,6 +12,18 @@ ESP KEYWORD1 +Crypto KEYWORD1 +nonceGeneratorType KEYWORD1 +MD5 KEYWORD1 +SHA1 KEYWORD1 +SHA224 KEYWORD1 +SHA256 KEYWORD1 +SHA384 KEYWORD1 +SHA512 KEYWORD1 +MD5SHA1 KEYWORD1 +HKDF KEYWORD1 +ChaCha20Poly1305 KEYWORD1 + ####################################### # Methods and Functions (KEYWORD2) ####################################### @@ -60,6 +72,21 @@ getResetInfo KEYWORD2 getResetInfoPtr KEYWORD2 eraseConfig KEYWORD2 getCycleCount KEYWORD2 +random->KEYWORD2 + +setCtMinDataLength KEYWORD2 +getCtMinDataLength KEYWORD2 +setCtMaxDataLength KEYWORD2 +getCtMaxDataLength KEYWORD2 +setNonceGenerator KEYWORD2 +getNonceGenerator KEYWORD2 +hash KEYWORD2 +hmac KEYWORD2 +hmacCT KEYWORD2 +init KEYWORD2 +produce KEYWORD2 +encrypt KEYWORD2 +decrypt KEYWORD2 ####################################### # Constants (LITERAL1) @@ -79,6 +106,10 @@ WAKE_RF_DISABLED LITERAL1 ADC_VCC LITERAL1 ADC_TOUT LITERAL1 +NATURAL_LENGTH LITERAL1 +ENCRYPTION_KEY_LENGTH LITERAL1 +CT_MAX_DIFF LITERAL1 + ####################################### # namespace esp8266 ####################################### diff --git a/libraries/esp8266/library.properties b/libraries/esp8266/library.properties index 4c879f66ad..2fc43d7e0b 100644 --- a/libraries/esp8266/library.properties +++ b/libraries/esp8266/library.properties @@ -1,6 +1,6 @@ name=ESP8266 version=1.0 -author=Simon Peter,Markus Sattler,Ivan Grokhotkov +author=Anders Löfgren,Simon Peter,Markus Sattler,Ivan Grokhotkov maintainer=Ivan Grokhtkov sentence=ESP8266 sketches examples paragraph= From f1783e02a44a8956ab5cd0883926dd581c1aa291 Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 28 Apr 2020 21:54:42 +0200 Subject: [PATCH 8/9] - Re-add namespace experimental. - Improve comments. --- cores/esp8266/Crypto.cpp | 5 ++++- cores/esp8266/Crypto.h | 4 ++++ .../examples/HelloCrypto/HelloCrypto.ino | 20 +++++++++---------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/cores/esp8266/Crypto.cpp b/cores/esp8266/Crypto.cpp index e4feb22890..44359832e1 100644 --- a/cores/esp8266/Crypto.cpp +++ b/cores/esp8266/Crypto.cpp @@ -63,7 +63,7 @@ uint8_t *defaultNonceGenerator(uint8_t *nonceArray, const size_t nonceLength) return ESP.random(nonceArray, nonceLength); } -esp8266::Crypto::nonceGeneratorType _nonceGenerator = defaultNonceGenerator; +esp8266::experimental::Crypto::nonceGeneratorType _nonceGenerator = defaultNonceGenerator; 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 outputLength) { @@ -184,6 +184,8 @@ void *sha1HashHelper(const void *data, const size_t dataLength, void *resultArra namespace esp8266 { +namespace experimental +{ namespace Crypto { void setCtMinDataLength(const size_t ctMinDataLength) @@ -550,3 +552,4 @@ bool ChaCha20Poly1305::decrypt(void *data, const size_t dataLength, const void * } } } +} diff --git a/cores/esp8266/Crypto.h b/cores/esp8266/Crypto.h index 37477cf04f..58d8877d90 100644 --- a/cores/esp8266/Crypto.h +++ b/cores/esp8266/Crypto.h @@ -30,6 +30,8 @@ namespace esp8266 { +namespace experimental +{ namespace Crypto { /** @@ -745,6 +747,7 @@ struct HKDF private: + // Use an opaque type to avoid #include which drags the lib declarations into userland. The global scope prefix is required for compilation to succeed, it seems. ::br_hkdf_context hkdfContext; }; @@ -841,4 +844,5 @@ struct ChaCha20Poly1305 }; } } +} #endif diff --git a/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino b/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino index 566afd5ad4..d0fdd9bd87 100644 --- a/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino +++ b/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino @@ -40,31 +40,31 @@ void loop() { String exampleData = F("Hello Crypto World!"); Serial.println(String(F("This is our example data: ")) + exampleData); - uint8_t resultArray[esp8266::Crypto::SHA256::NATURAL_LENGTH] { 0 }; - uint8_t derivedKey[esp8266::Crypto::ENCRYPTION_KEY_LENGTH] { 0 }; + uint8_t resultArray[esp8266::experimental::Crypto::SHA256::NATURAL_LENGTH] { 0 }; + uint8_t derivedKey[esp8266::experimental::Crypto::ENCRYPTION_KEY_LENGTH] { 0 }; static uint32_t encryptionCounter = 0; // Generate the salt to use for HKDF uint8_t hkdfSalt[16] { 0 }; - esp8266::Crypto::getNonceGenerator()(hkdfSalt, sizeof hkdfSalt); + esp8266::experimental::Crypto::getNonceGenerator()(hkdfSalt, sizeof hkdfSalt); // Generate the key to use for HMAC and encryption - esp8266::Crypto::HKDF hkdfInstance(FPSTR(masterKey), (sizeof masterKey) - 1, hkdfSalt, sizeof hkdfSalt); // (sizeof masterKey) - 1 removes the terminating null value of the c-string + esp8266::experimental::Crypto::HKDF hkdfInstance(FPSTR(masterKey), (sizeof masterKey) - 1, hkdfSalt, sizeof hkdfSalt); // (sizeof masterKey) - 1 removes the terminating null value of the c-string hkdfInstance.produce(derivedKey, sizeof derivedKey); // Hash - esp8266::Crypto::SHA256::hash(exampleData.c_str(), exampleData.length(), resultArray); + esp8266::experimental::Crypto::SHA256::hash(exampleData.c_str(), exampleData.length(), resultArray); Serial.println(String(F("\nThis is the SHA256 hash of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); - Serial.println(String(F("This is the SHA256 hash of our example data, in HEX format, using String output:\n")) + esp8266::Crypto::SHA256::hash(exampleData)); + Serial.println(String(F("This is the SHA256 hash of our example data, in HEX format, using String output:\n")) + esp8266::experimental::Crypto::SHA256::hash(exampleData)); // HMAC // Note that HMAC output length is limited - esp8266::Crypto::SHA256::hmac(exampleData.c_str(), exampleData.length(), derivedKey, sizeof derivedKey, resultArray, sizeof resultArray); + esp8266::experimental::Crypto::SHA256::hmac(exampleData.c_str(), exampleData.length(), derivedKey, sizeof derivedKey, resultArray, sizeof resultArray); Serial.println(String(F("\nThis is the SHA256 HMAC of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); - Serial.println(String(F("This is the SHA256 HMAC of our example data, in HEX format, using String output:\n")) + esp8266::Crypto::SHA256::hmac(exampleData, derivedKey, sizeof derivedKey, esp8266::Crypto::SHA256::NATURAL_LENGTH)); + Serial.println(String(F("This is the SHA256 HMAC of our example data, in HEX format, using String output:\n")) + esp8266::experimental::Crypto::SHA256::hmac(exampleData, derivedKey, sizeof derivedKey, esp8266::experimental::Crypto::SHA256::NATURAL_LENGTH)); // Authenticated Encryption with Associated Data (AEAD) @@ -75,10 +75,10 @@ void loop() { Serial.println(String(F("\nThis is the data to encrypt: ")) + dataToEncrypt); // Note that the key must be ENCRYPTION_KEY_LENGTH long. - esp8266::Crypto::ChaCha20Poly1305::encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + esp8266::experimental::Crypto::ChaCha20Poly1305::encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); Serial.println(String(F("Encrypted data: ")) + dataToEncrypt); - bool decryptionSucceeded = esp8266::Crypto::ChaCha20Poly1305::decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + bool decryptionSucceeded = esp8266::experimental::Crypto::ChaCha20Poly1305::decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); encryptionCounter++; if (decryptionSucceeded) { From 7f0324c1ee51b6ddd76e3671f96c08e1366d871c Mon Sep 17 00:00:00 2001 From: Anders Date: Tue, 28 Apr 2020 22:29:25 +0200 Subject: [PATCH 9/9] - Remove namespace esp8266. - Rename namespace Crypto to namespace crypto. --- cores/esp8266/Crypto.cpp | 7 ++----- cores/esp8266/Crypto.h | 5 +---- .../examples/HelloCrypto/HelloCrypto.ino | 21 ++++++++++--------- libraries/esp8266/keywords.txt | 2 +- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/cores/esp8266/Crypto.cpp b/cores/esp8266/Crypto.cpp index 44359832e1..b2b40b3c06 100644 --- a/cores/esp8266/Crypto.cpp +++ b/cores/esp8266/Crypto.cpp @@ -63,7 +63,7 @@ uint8_t *defaultNonceGenerator(uint8_t *nonceArray, const size_t nonceLength) return ESP.random(nonceArray, nonceLength); } -esp8266::experimental::Crypto::nonceGeneratorType _nonceGenerator = defaultNonceGenerator; +experimental::crypto::nonceGeneratorType _nonceGenerator = defaultNonceGenerator; 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 outputLength) { @@ -182,11 +182,9 @@ void *sha1HashHelper(const void *data, const size_t dataLength, void *resultArra } } -namespace esp8266 -{ namespace experimental { -namespace Crypto +namespace crypto { void setCtMinDataLength(const size_t ctMinDataLength) { @@ -552,4 +550,3 @@ bool ChaCha20Poly1305::decrypt(void *data, const size_t dataLength, const void * } } } -} diff --git a/cores/esp8266/Crypto.h b/cores/esp8266/Crypto.h index 58d8877d90..435b4836a3 100644 --- a/cores/esp8266/Crypto.h +++ b/cores/esp8266/Crypto.h @@ -28,11 +28,9 @@ #include -namespace esp8266 -{ namespace experimental { -namespace Crypto +namespace crypto { /** Regarding constant-time (CT) HMAC: @@ -844,5 +842,4 @@ struct ChaCha20Poly1305 }; } } -} #endif diff --git a/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino b/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino index d0fdd9bd87..e6c4c493ab 100644 --- a/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino +++ b/libraries/esp8266/examples/HelloCrypto/HelloCrypto.ino @@ -9,6 +9,7 @@ #include namespace TypeCast = esp8266::TypeConversion; +using namespace experimental; /** NOTE: Although we could define the strings below as normal String variables, @@ -40,31 +41,31 @@ void loop() { String exampleData = F("Hello Crypto World!"); Serial.println(String(F("This is our example data: ")) + exampleData); - uint8_t resultArray[esp8266::experimental::Crypto::SHA256::NATURAL_LENGTH] { 0 }; - uint8_t derivedKey[esp8266::experimental::Crypto::ENCRYPTION_KEY_LENGTH] { 0 }; + uint8_t resultArray[crypto::SHA256::NATURAL_LENGTH] { 0 }; + uint8_t derivedKey[crypto::ENCRYPTION_KEY_LENGTH] { 0 }; static uint32_t encryptionCounter = 0; // Generate the salt to use for HKDF uint8_t hkdfSalt[16] { 0 }; - esp8266::experimental::Crypto::getNonceGenerator()(hkdfSalt, sizeof hkdfSalt); + crypto::getNonceGenerator()(hkdfSalt, sizeof hkdfSalt); // Generate the key to use for HMAC and encryption - esp8266::experimental::Crypto::HKDF hkdfInstance(FPSTR(masterKey), (sizeof masterKey) - 1, hkdfSalt, sizeof hkdfSalt); // (sizeof masterKey) - 1 removes the terminating null value of the c-string + crypto::HKDF hkdfInstance(FPSTR(masterKey), (sizeof masterKey) - 1, hkdfSalt, sizeof hkdfSalt); // (sizeof masterKey) - 1 removes the terminating null value of the c-string hkdfInstance.produce(derivedKey, sizeof derivedKey); // Hash - esp8266::experimental::Crypto::SHA256::hash(exampleData.c_str(), exampleData.length(), resultArray); + crypto::SHA256::hash(exampleData.c_str(), exampleData.length(), resultArray); Serial.println(String(F("\nThis is the SHA256 hash of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); - Serial.println(String(F("This is the SHA256 hash of our example data, in HEX format, using String output:\n")) + esp8266::experimental::Crypto::SHA256::hash(exampleData)); + Serial.println(String(F("This is the SHA256 hash of our example data, in HEX format, using String output:\n")) + crypto::SHA256::hash(exampleData)); // HMAC // Note that HMAC output length is limited - esp8266::experimental::Crypto::SHA256::hmac(exampleData.c_str(), exampleData.length(), derivedKey, sizeof derivedKey, resultArray, sizeof resultArray); + crypto::SHA256::hmac(exampleData.c_str(), exampleData.length(), derivedKey, sizeof derivedKey, resultArray, sizeof resultArray); Serial.println(String(F("\nThis is the SHA256 HMAC of our example data, in HEX format:\n")) + TypeCast::uint8ArrayToHexString(resultArray, sizeof resultArray)); - Serial.println(String(F("This is the SHA256 HMAC of our example data, in HEX format, using String output:\n")) + esp8266::experimental::Crypto::SHA256::hmac(exampleData, derivedKey, sizeof derivedKey, esp8266::experimental::Crypto::SHA256::NATURAL_LENGTH)); + Serial.println(String(F("This is the SHA256 HMAC of our example data, in HEX format, using String output:\n")) + crypto::SHA256::hmac(exampleData, derivedKey, sizeof derivedKey, crypto::SHA256::NATURAL_LENGTH)); // Authenticated Encryption with Associated Data (AEAD) @@ -75,10 +76,10 @@ void loop() { Serial.println(String(F("\nThis is the data to encrypt: ")) + dataToEncrypt); // Note that the key must be ENCRYPTION_KEY_LENGTH long. - esp8266::experimental::Crypto::ChaCha20Poly1305::encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + crypto::ChaCha20Poly1305::encrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); Serial.println(String(F("Encrypted data: ")) + dataToEncrypt); - bool decryptionSucceeded = esp8266::experimental::Crypto::ChaCha20Poly1305::decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); + bool decryptionSucceeded = crypto::ChaCha20Poly1305::decrypt(dataToEncrypt.begin(), dataToEncrypt.length(), derivedKey, &encryptionCounter, sizeof encryptionCounter, resultingNonce, resultingTag); encryptionCounter++; if (decryptionSucceeded) { diff --git a/libraries/esp8266/keywords.txt b/libraries/esp8266/keywords.txt index a80c2e3ed3..6d4587bb82 100644 --- a/libraries/esp8266/keywords.txt +++ b/libraries/esp8266/keywords.txt @@ -12,7 +12,7 @@ ESP KEYWORD1 -Crypto KEYWORD1 +crypto KEYWORD1 nonceGeneratorType KEYWORD1 MD5 KEYWORD1 SHA1 KEYWORD1