mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-21 10:26:06 +03:00
- Replace Crypto files with CryptoInterface which uses BearSSL as a cryptographic backend.
- Move cryptographic functions from JsonTranslator to CryptoInterface. - Make AP activation separate from FloodingMesh::begin(). - Fix English bug. - Improve comments.
This commit is contained in:
parent
afc88f2652
commit
3132325bf8
@ -242,14 +242,14 @@ void setup() {
|
||||
|
||||
int32_t timeOfLastScan = -10000;
|
||||
void loop() {
|
||||
// The performEspnowMaintainance() method performs all the background operations for the EspnowMeshBackend.
|
||||
// The performEspnowMaintenance() method performs all the background operations for the EspnowMeshBackend.
|
||||
// It is recommended to place it in the beginning of the loop(), unless there is a need to put it elsewhere.
|
||||
// Among other things, the method cleans up old Espnow log entries (freeing up RAM) and sends the responses you provide to Espnow requests.
|
||||
// Note that depending on the amount of responses to send and their length, this method can take tens or even hundreds of milliseconds to complete.
|
||||
// More intense transmission activity and less frequent calls to performEspnowMaintainance will likely cause the method to take longer to complete, so plan accordingly.
|
||||
// More intense transmission activity and less frequent calls to performEspnowMaintenance will likely cause the method to take longer to complete, so plan accordingly.
|
||||
|
||||
//Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintainance() can alter the ESP-NOW state.
|
||||
EspnowMeshBackend::performEspnowMaintainance();
|
||||
//Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintenance() can alter the ESP-NOW state.
|
||||
EspnowMeshBackend::performEspnowMaintenance();
|
||||
|
||||
if (millis() - timeOfLastScan > 10000) { // Give other nodes some time to connect between data transfers.
|
||||
Serial.println("\nPerforming unencrypted ESP-NOW transmissions.");
|
||||
@ -260,8 +260,8 @@ void loop() {
|
||||
|
||||
timeOfLastScan = millis();
|
||||
|
||||
// Wait for response. espnowDelay continuously calls performEspnowMaintainance() so we will respond to ESP-NOW request while waiting.
|
||||
// Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintainance() can alter the ESP-NOW state.
|
||||
// Wait for response. espnowDelay continuously calls performEspnowMaintenance() so we will respond to ESP-NOW request while waiting.
|
||||
// Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintenance() can alter the ESP-NOW state.
|
||||
espnowDelay(100);
|
||||
|
||||
// One way to check how attemptTransmission worked out
|
||||
|
@ -1,3 +1,10 @@
|
||||
/**
|
||||
This example makes every node broadcast their AP MAC to the rest of the network during the first 28 seconds, as long as the node thinks it has the highest AP MAC in the network.
|
||||
Once 28 seconds have passed, the node that has the highest AP MAC will start broadcasting benchmark messages, which will allow you to see how many messages are lost at the other nodes.
|
||||
If you have an onboard LED on your ESP8266 it is recommended that you change the useLED variable below to true.
|
||||
That way you will get instant confirmation of the mesh communication without checking the Serial Monitor.
|
||||
*/
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <TypeConversionFunctions.h>
|
||||
#include <assert.h>
|
||||
@ -63,7 +70,7 @@ bool meshMessageHandler(String &message, FloodingMesh &meshInstance) {
|
||||
|
||||
if (useLED && !theOne) {
|
||||
bool ledState = message.charAt(1) == '1';
|
||||
digitalWrite(LED_BUILTIN, ledState); // Turn LED on/off (LED is active low)
|
||||
digitalWrite(LED_BUILTIN, ledState); // Turn LED on/off (LED_BUILTIN is active low)
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -128,13 +135,14 @@ void setup() {
|
||||
Serial.println(F("Setting up mesh node..."));
|
||||
|
||||
floodingMesh.begin();
|
||||
floodingMesh.activateAP();
|
||||
|
||||
uint8_t apMacArray[6] {0};
|
||||
theOneMac = macToString(WiFi.softAPmacAddress(apMacArray));
|
||||
|
||||
if (useLED) {
|
||||
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED on (LED is active low)
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn LED on (LED_BUILTIN is active low)
|
||||
}
|
||||
|
||||
floodingMeshDelay(5000); // Give some time for user to start the nodes
|
||||
@ -146,12 +154,12 @@ void loop() {
|
||||
static uint32_t benchmarkCount = 0;
|
||||
static uint32_t loopStart = millis();
|
||||
|
||||
// The floodingMeshDelay() method performs all the background operations for the FloodingMesh (via FloodingMesh::performMeshMaintainance()).
|
||||
// The floodingMeshDelay() method performs all the background operations for the FloodingMesh (via FloodingMesh::performMeshMaintenance()).
|
||||
// It is recommended to place one of these methods in the beginning of the loop(), unless there is a need to put them elsewhere.
|
||||
// Among other things, the method cleans up old ESP-NOW log entries (freeing up RAM) and forwards received mesh messages.
|
||||
// Note that depending on the amount of messages to forward and their length, this method can take tens or even hundreds of milliseconds to complete.
|
||||
// More intense transmission activity and less frequent calls to performMeshMaintainance will likely cause the method to take longer to complete, so plan accordingly.
|
||||
// The maintainance methods should not be used inside the meshMessageHandler callback, since they can alter the mesh node state. The framework will alert you during runtime if you make this mistake.
|
||||
// More intense transmission activity and less frequent calls to performMeshMaintenance will likely cause the method to take longer to complete, so plan accordingly.
|
||||
// The maintenance methods should not be used inside the meshMessageHandler callback, since they can alter the mesh node state. The framework will alert you during runtime if you make this mistake.
|
||||
floodingMeshDelay(1);
|
||||
|
||||
// If you wish to transmit only to a single node, try using one of the following methods (requires the node to be within range and know the MAC of the recipient):
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,254 +0,0 @@
|
||||
/**
|
||||
* An extremely minimal crypto library for Arduino devices.
|
||||
*
|
||||
* The SHA256 and AES implementations are derived from axTLS
|
||||
* (http://axtls.sourceforge.net/), Copyright (c) 2008, Cameron Rich.
|
||||
*
|
||||
* Ported and refactored by Chris Ellis 2016.
|
||||
* pkcs7 padding routines added by Mike Killewald Nov 26, 2017 (adopted from https://github.com/spaniakos/AES).
|
||||
*
|
||||
License
|
||||
=======
|
||||
Balsa SCGI
|
||||
Copyright (c) 2012, Chris Ellis
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CRYPTO_h
|
||||
#define CRYPTO_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#if defined ESP8266
|
||||
#include <osapi.h>
|
||||
#endif
|
||||
|
||||
#define SHA256_SIZE 32
|
||||
#define SHA256HMAC_SIZE 32
|
||||
#define SHA256HMAC_BLOCKSIZE 64
|
||||
#define AES_MAXROUNDS 14
|
||||
#define AES_BLOCKSIZE 16
|
||||
#define AES_IV_SIZE 16
|
||||
#define AES_IV_LENGTH 16
|
||||
#define AES_128_KEY_LENGTH 16
|
||||
#define AES_256_KEY_LENGTH 16
|
||||
|
||||
/**
|
||||
* Compute a SHA256 hash
|
||||
*/
|
||||
class SHA256
|
||||
{
|
||||
public:
|
||||
SHA256();
|
||||
/**
|
||||
* Update the hash with new data
|
||||
*/
|
||||
void doUpdate(const byte *msg, uint32_t len);
|
||||
void doUpdate(const char *msg, unsigned int len) { doUpdate((byte*) msg, len); }
|
||||
void doUpdate(const char *msg) { doUpdate((byte*) msg, strlen(msg)); }
|
||||
/**
|
||||
* Compute the final hash and store it in [digest], digest must be
|
||||
* at least 32 bytes
|
||||
*/
|
||||
void doFinal(byte *digest);
|
||||
/**
|
||||
* Compute the final hash and check it matches this given expected hash
|
||||
*/
|
||||
bool matches(const byte *expected);
|
||||
private:
|
||||
void SHA256_Process(const byte digest[64]);
|
||||
uint32_t total[2];
|
||||
uint32_t state[8];
|
||||
uint8_t buffer[64];
|
||||
};
|
||||
|
||||
#define HMAC_OPAD 0x5C
|
||||
#define HMAC_IPAD 0x36
|
||||
|
||||
/**
|
||||
* Compute a HMAC using SHA256
|
||||
*/
|
||||
class SHA256HMAC
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Compute a SHA256 HMAC with the given [key] key of [length] bytes
|
||||
* for authenticity
|
||||
*/
|
||||
SHA256HMAC(const byte *key, unsigned int keyLen);
|
||||
/**
|
||||
* Update the hash with new data
|
||||
*/
|
||||
void doUpdate(const byte *msg, unsigned int len);
|
||||
void doUpdate(const char *msg, unsigned int len) { doUpdate((byte*) msg, len); }
|
||||
void doUpdate(const char *msg) { doUpdate((byte*) msg, strlen(msg)); }
|
||||
/**
|
||||
* Compute the final hash and store it in [digest], digest must be
|
||||
* at least 32 bytes
|
||||
*/
|
||||
void doFinal(byte *digest);
|
||||
/**
|
||||
* Compute the final hash and check it matches this given expected hash
|
||||
*/
|
||||
bool matches(const byte *expected);
|
||||
private:
|
||||
void blockXor(const byte *in, byte *out, byte val, byte len);
|
||||
SHA256 _hash;
|
||||
byte _innerKey[SHA256HMAC_BLOCKSIZE];
|
||||
byte _outerKey[SHA256HMAC_BLOCKSIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
* AES 128 and 256, based on code from axTLS
|
||||
*/
|
||||
class AES
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
AES_MODE_128,
|
||||
AES_MODE_256
|
||||
} AES_MODE;
|
||||
typedef enum
|
||||
{
|
||||
CIPHER_ENCRYPT = 0x01,
|
||||
CIPHER_DECRYPT = 0x02
|
||||
} CIPHER_MODE;
|
||||
|
||||
/**
|
||||
* Create this cipher instance in either encrypt or decrypt mode
|
||||
*
|
||||
* Use the given [key] which must be 16 bytes long for AES 128 and
|
||||
* 32 bytes for AES 256
|
||||
*
|
||||
* Use the given [iv] initialistion vection which must be 16 bytes long
|
||||
*
|
||||
* Use the either AES 128 or AES 256 as specified by [mode]
|
||||
*
|
||||
* Either encrypt or decrypt as specified by [cipherMode]
|
||||
*/
|
||||
AES(const uint8_t *key, const uint8_t *iv, AES_MODE mode, CIPHER_MODE cipherMode);
|
||||
|
||||
/**
|
||||
* Either encrypt or decrypt [in] and store into [out] for [length] bytes, applying no padding
|
||||
*
|
||||
* Note: the length must be a multiple of 16 bytes
|
||||
*/
|
||||
void processNoPad(const uint8_t *in, uint8_t *out, int length);
|
||||
|
||||
/**
|
||||
* Either encrypt or decrypt [in] and store into [out] for [length] bytes, applying padding as needed
|
||||
*
|
||||
* Note: the length must be a multiple of 16 bytes
|
||||
*/
|
||||
void process(const uint8_t *in, uint8_t *out, int length);
|
||||
|
||||
/** Getter method for size
|
||||
*
|
||||
* This function returns the size
|
||||
* @return an integer, that is the size of the of the padded plaintext,
|
||||
* thus, the size of the ciphertext.
|
||||
*/
|
||||
int getSize();
|
||||
|
||||
/** Setter method for size
|
||||
*
|
||||
* This function sets the size of the plaintext+pad
|
||||
*
|
||||
*/
|
||||
void setSize(int size);
|
||||
|
||||
/** Calculates the size of the plaintext and the padding.
|
||||
*
|
||||
* Calculates the size of the plaintext with the size of the
|
||||
* padding needed. Moreover it stores them in their class variables.
|
||||
*
|
||||
* @param in_size the size of the byte array ex sizeof(plaintext)
|
||||
* @return an int the size of the plaintext plus the padding
|
||||
*/
|
||||
int calcSizeAndPad(int in_size);
|
||||
|
||||
/** Pads the plaintext
|
||||
*
|
||||
* This function pads the plaintext and returns an char array with the
|
||||
* plaintext and the padding in order for the plaintext to be compatible with
|
||||
* 16bit size blocks required by AES
|
||||
*
|
||||
* @param in the string of the plaintext in a byte array
|
||||
* @param out The string of the out array.
|
||||
* @return no return, The padded plaintext is stored in the out pointer.
|
||||
*/
|
||||
void padPlaintext(const uint8_t* in, uint8_t* out);
|
||||
|
||||
/** Check the if the padding is correct.
|
||||
*
|
||||
* This functions checks the padding of the plaintext.
|
||||
*
|
||||
* @param in the string of the plaintext in a byte array
|
||||
* @param size the size of the string
|
||||
* @return true if correct / false if not
|
||||
*/
|
||||
bool checkPad(uint8_t* in, int lsize);
|
||||
|
||||
private:
|
||||
void encryptCBC(const uint8_t *in, uint8_t *out, int length);
|
||||
void decryptCBC(const uint8_t *in, uint8_t *out, int length);
|
||||
void convertKey();
|
||||
void encrypt(uint32_t *data);
|
||||
void decrypt(uint32_t *data);
|
||||
uint16_t _rounds;
|
||||
uint16_t _key_size;
|
||||
uint32_t _ks[(AES_MAXROUNDS+1)*8];
|
||||
uint8_t _iv[AES_IV_SIZE];
|
||||
int _pad_size; // size of padding to add to plaintext
|
||||
int _size; // size of plaintext plus padding to be ciphered
|
||||
uint8_t _arr_pad[15];
|
||||
|
||||
CIPHER_MODE _cipherMode;
|
||||
};
|
||||
|
||||
#if defined ESP8266 || defined ESP32
|
||||
/**
|
||||
* ESP8266 and ESP32 specific true random number generator
|
||||
*/
|
||||
class RNG
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Fill the [dst] array with [length] random bytes
|
||||
*/
|
||||
static void fill(uint8_t *dst, unsigned int length);
|
||||
/**
|
||||
* Get a random byte
|
||||
*/
|
||||
static byte get();
|
||||
/**
|
||||
* Get a 32bit random number
|
||||
*/
|
||||
static uint32_t getLong();
|
||||
private:
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
147
libraries/ESP8266WiFiMesh/src/CryptoInterface.cpp
Normal file
147
libraries/ESP8266WiFiMesh/src/CryptoInterface.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* BearSSL Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
* 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 "TypeConversionFunctions.h"
|
||||
|
||||
#include <bearssl/bearssl.h>
|
||||
|
||||
namespace CryptoInterface
|
||||
{
|
||||
uint8_t *createBearsslHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t *resultArray, size_t resultArrayLength)
|
||||
{
|
||||
assert(1 <= resultArrayLength);
|
||||
|
||||
// Comments mainly from https://www.bearssl.org/apidoc/bearssl__hmac_8h.html
|
||||
|
||||
// HMAC is initialized with a key and an underlying hash function; it then fills a "key context". That context contains the processed key.
|
||||
// With the key context, a HMAC context can be initialized to process the input bytes and obtain the MAC output. The key context is not modified during that process, and can be reused.
|
||||
|
||||
// hashType alternatives: &br_md5_vtable; &br_sha1_vtable; &br_sha224_vtable; &br_sha256_vtable; &br_sha384_vtable; &br_sha512_vtable;
|
||||
// Use SHA256 to create the hash.
|
||||
const br_hash_class *hashType = &br_sha256_vtable;
|
||||
|
||||
br_hmac_key_context keyContext; // Holds general HMAC info
|
||||
br_hmac_context hmacContext; // Holds general HMAC info + specific info for the current message
|
||||
|
||||
// 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 resultArrayLength 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, resultArrayLength);
|
||||
|
||||
// Provide the HMAC context with the data to create a HMAC from.
|
||||
// The provided message.length() bytes are injected as extra input in the HMAC computation incarnated by the hmacContext.
|
||||
// It is acceptable that message.length() is zero, in which case data is ignored (and may be NULL) and this function does nothing.
|
||||
br_hmac_update(&hmacContext, message.c_str(), message.length());
|
||||
|
||||
// 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 String &message, const uint8_t *hashKey, uint8_t hashKeyLength, size_t hmacLength)
|
||||
{
|
||||
assert(1 <= hmacLength && hmacLength <= SHA256HMAC_NATURAL_LENGTH);
|
||||
byte hmac[hmacLength];
|
||||
createBearsslHmac(message, hashKey, hashKeyLength, hmac, hmacLength);
|
||||
return uint8ArrayToHexString(hmac, hmacLength);
|
||||
}
|
||||
|
||||
uint8_t *createBearsslHmacCT(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t *resultArray, size_t resultArrayLength)
|
||||
{
|
||||
assert(1 <= resultArrayLength);
|
||||
|
||||
// Comments mainly from https://www.bearssl.org/apidoc/bearssl__hmac_8h.html
|
||||
|
||||
// HMAC is initialized with a key and an underlying hash function; it then fills a "key context". That context contains the processed key.
|
||||
// With the key context, a HMAC context can be initialized to process the input bytes and obtain the MAC output. The key context is not modified during that process, and can be reused.
|
||||
|
||||
// hashType alternatives: &br_md5_vtable; &br_sha1_vtable; &br_sha224_vtable; &br_sha256_vtable; &br_sha384_vtable; &br_sha512_vtable;
|
||||
// Use SHA256 to create the hash.
|
||||
const br_hash_class *hashType = &br_sha256_vtable;
|
||||
|
||||
br_hmac_key_context keyContext; // Holds general HMAC info
|
||||
br_hmac_context hmacContext; // Holds general HMAC info + specific info for the current message
|
||||
|
||||
// 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 resultArrayLength 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, resultArrayLength);
|
||||
|
||||
// Provide the HMAC context with the data to create a HMAC from.
|
||||
// The provided message.length() bytes are injected as extra input in the HMAC computation incarnated by the hmacContext.
|
||||
// It is acceptable that message.length() is zero, in which case data is ignored (and may be NULL) and this function does nothing.
|
||||
// No need for br_hmac_update when using constant-time version it seems. If it is used, the data provided to br_hmac_outCT will just be appended.
|
||||
// br_hmac_update(&hmacContext, message.c_str(), message.length());
|
||||
|
||||
// Compute the HMAC output. Assumes message is minimum 0 bytes and maximum 1000 bytes.
|
||||
// As long as this is true, the correct HMAC output is calculated in constant-time. More constant-time info here: https://www.bearssl.org/constanttime.html
|
||||
// Some extra input bytes are processed, then the output is computed.
|
||||
// The extra input consists in the message.length() bytes pointed to by message.c_str(). The message.length() parameter must lie between min_len and max_len (inclusive);
|
||||
// max_len bytes are actually read from data (indicating each data byte can be read multiple times, if message.length() < max_len).
|
||||
// Computing time (and memory access pattern) will not depend upon the data byte contents or the value of len.
|
||||
// The output is written in the resultArray buffer, that MUST be large enough to receive it.
|
||||
// The difference max_len - min_len MUST be less than 2^30 (i.e. about one gigabyte).
|
||||
// This function computes the output properly only if the underlying hash function uses MD padding (i.e. MD5, SHA-1, SHA-224, SHA-256, SHA-384 or SHA-512).
|
||||
// The provided context is NOT modified.
|
||||
size_t min_len = 0;
|
||||
size_t max_len = 1000;
|
||||
assert(min_len <= message.length() && message.length() <= max_len);
|
||||
br_hmac_outCT(&hmacContext, message.c_str(), message.length(), min_len, max_len, resultArray); // returns size_t outputLength
|
||||
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
String createBearsslHmacCT(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, size_t hmacLength)
|
||||
{
|
||||
assert(1 <= hmacLength && hmacLength <= SHA256HMAC_NATURAL_LENGTH);
|
||||
byte hmac[hmacLength];
|
||||
createBearsslHmacCT(message, hashKey, hashKeyLength, hmac, hmacLength);
|
||||
return uint8ArrayToHexString(hmac, hmacLength);
|
||||
}
|
||||
|
||||
bool verifyBearsslHmac(const String &message, const String &messageHmac, const uint8_t *hashKey, uint8_t hashKeyLength)
|
||||
{
|
||||
String generatedHmac = createBearsslHmac(message, hashKey, hashKeyLength, messageHmac.length()/2); // We know that each HMAC byte should become 2 String characters due to uint8ArrayToHexString.
|
||||
if(generatedHmac == messageHmac)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
120
libraries/ESP8266WiFiMesh/src/CryptoInterface.h
Normal file
120
libraries/ESP8266WiFiMesh/src/CryptoInterface.h
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* BearSSL Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
* 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 <Arduino.h>
|
||||
|
||||
#ifndef __MESHCRYPTOINTERFACE_H__
|
||||
#define __MESHCRYPTOINTERFACE_H__
|
||||
|
||||
namespace CryptoInterface
|
||||
{
|
||||
const uint8_t SHA256HMAC_NATURAL_LENGTH = 32;
|
||||
|
||||
/**
|
||||
* Create a SHA256 HMAC from the message, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param message The string from which to create the HMAC.
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param resultArray The array wherein to store the resulting HMAC.
|
||||
* @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA256HMAC_NATURAL_LENGTH,
|
||||
* the first (lowest index) SHA256HMAC_NATURAL_LENGTH bytes of resultArray will be used for the HMAC.
|
||||
*
|
||||
* @return A pointer to resultArray.
|
||||
*/
|
||||
uint8_t *createBearsslHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t *resultArray, size_t resultArrayLength);
|
||||
|
||||
/**
|
||||
* Create a SHA256 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param message The string from which to create the HMAC.
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to 32. Defaults to SHA256HMAC_NATURAL_LENGTH.
|
||||
*
|
||||
* @return A String with the generated HMAC in HEX format.
|
||||
*/
|
||||
String createBearsslHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, size_t hmacLength = SHA256HMAC_NATURAL_LENGTH);
|
||||
|
||||
/**
|
||||
* Create a SHA256 HMAC from the message, using the provided hashKey. The result will be resultArrayLength bytes long and stored in resultArray.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* Constant-time version of createBearsslHmac(). More constant-time info here: https://www.bearssl.org/constanttime.html
|
||||
* For small messages, it takes substantially longer time to complete than a normal HMAC (5 ms vs 2 ms in a quick benchmark,
|
||||
* determined by the difference between min and max allowed message length), and it also sets a maximum length that messages can be (set to 1000 bytes here).
|
||||
* Making the fixed max length variable would defeat the whole purpose of using constant-time, and not making it variable would create the wrong HMAC if message size exceeds the maximum.
|
||||
*
|
||||
* Also, HMAC is already partially constant-time. Quoting the link above:
|
||||
* "Hash functions implemented by BearSSL (MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512) consist in bitwise logical operations and additions on 32-bit or 64-bit words,
|
||||
* naturally yielding constant-time operations. HMAC is naturally as constant-time as the underlying hash function. The size of the MACed data, and the size of the key,
|
||||
* may leak, though; only the contents are protected."
|
||||
*
|
||||
* Thus the non constant-time version is used within the mesh framework instead.
|
||||
*
|
||||
* @param message The string from which to create the HMAC. Min size 0 bytes. Max size 1000 bytes.
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param resultArray The array wherein to store the resulting HMAC.
|
||||
* @param resultArrayLength The length of resultArray in bytes. Determines the HMAC length. If resultArrayLength is greater than SHA256HMAC_NATURAL_LENGTH,
|
||||
* the first (lowest index) SHA256HMAC_NATURAL_LENGTH bytes of resultArray will be used for the HMAC.
|
||||
*
|
||||
* @return A pointer to resultArray.
|
||||
*/
|
||||
uint8_t *createBearsslHmacCT(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t *resultArray, size_t resultArrayLength);
|
||||
|
||||
/**
|
||||
* Create a SHA256 HMAC from the message, using the provided hashKey. The result will be hmacLength bytes long and returned as a String in HEX format.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* Constant-time version of createBearsslHmac(). More constant-time info here: https://www.bearssl.org/constanttime.html
|
||||
* Not used within the mesh framework for reasons outlined in the uint8_t *createBearsslHmacCT() description.
|
||||
*
|
||||
* @param message The string from which to create the HMAC. Min size 0 bytes. Max size 1000 bytes.
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
* @param hmacLength The desired length of the generated HMAC, in bytes. Valid values are 1 to 32. Defaults to SHA256HMAC_NATURAL_LENGTH.
|
||||
*
|
||||
* @return A String with the generated HMAC in HEX format.
|
||||
*/
|
||||
String createBearsslHmacCT(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, size_t hmacLength = SHA256HMAC_NATURAL_LENGTH);
|
||||
|
||||
/**
|
||||
* Verify a SHA256 HMAC which was created from the message using the provided hashKey.
|
||||
* Uses the BearSSL cryptographic library.
|
||||
*
|
||||
* @param message The string from which the HMAC was created.
|
||||
* @param messageHmac A string with the generated HMAC in HEX format. Valid messageHmac.length() is 2 to 64.
|
||||
* @param hashKey The hash key to use when creating the HMAC.
|
||||
* @param hashKeyLength The length of the hash key in bytes.
|
||||
*
|
||||
* @return True if the HMAC is correct. False otherwise.
|
||||
*/
|
||||
bool verifyBearsslHmac(const String &message, const String &messageHmac, const uint8_t *hashKey, uint8_t hashKeyLength);
|
||||
}
|
||||
|
||||
#endif
|
@ -26,6 +26,7 @@
|
||||
#include "UtilityFunctions.h"
|
||||
#include "TypeConversionFunctions.h"
|
||||
#include "JsonTranslator.h"
|
||||
#include "CryptoInterface.h"
|
||||
|
||||
using EspnowProtocolInterpreter::espnowHashKeyLength;
|
||||
|
||||
@ -127,7 +128,7 @@ uint64_t EncryptedConnectionData::getOwnSessionKey() const { return _ownSessionK
|
||||
|
||||
uint64_t EncryptedConnectionData::incrementSessionKey(uint64_t sessionKey, const uint8_t *hashKey, uint8_t hashKeyLength)
|
||||
{
|
||||
String hmac = JsonTranslator::createHmac(uint64ToString(sessionKey), hashKey, hashKeyLength);
|
||||
String hmac = CryptoInterface::createBearsslHmac(uint64ToString(sessionKey), hashKey, hashKeyLength);
|
||||
|
||||
/* HMAC truncation should be OK since hmac sha256 is a PRF and we are truncating to the leftmost (MSB) bits.
|
||||
PRF: https://crypto.stackexchange.com/questions/26410/whats-the-gcm-sha-256-of-a-tls-protocol/26434#26434
|
||||
|
@ -55,7 +55,7 @@ void EncryptedConnectionLog::removeDuration()
|
||||
|
||||
void EncryptedConnectionLog::scheduleForRemoval()
|
||||
{
|
||||
// When we give the connection 0 remaining duration it will be removed during the next performEspnowMaintainance() call.
|
||||
// When we give the connection 0 remaining duration it will be removed during the next performEspnowMaintenance() call.
|
||||
// Duration must be changed before setting the scheduledForRemoval flag to true, since the flag is otherwise cleared.
|
||||
setRemainingDuration(0);
|
||||
setScheduledForRemoval(true);
|
||||
|
@ -26,7 +26,6 @@ extern "C" {
|
||||
#include "UtilityFunctions.h"
|
||||
#include "MutexTracker.h"
|
||||
#include "JsonTranslator.h"
|
||||
#include "Crypto.h"
|
||||
|
||||
using EspnowProtocolInterpreter::espnowEncryptionKeyLength;
|
||||
using EspnowProtocolInterpreter::espnowHashKeyLength;
|
||||
@ -99,7 +98,7 @@ void espnowDelay(uint32_t durationMs)
|
||||
while(millis() - startingTime < durationMs)
|
||||
{
|
||||
delay(1);
|
||||
EspnowMeshBackend::performEspnowMaintainance();
|
||||
EspnowMeshBackend::performEspnowMaintenance();
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,7 +223,7 @@ bool EspnowMeshBackend::latestTransmissionSuccessful()
|
||||
return latestTransmissionSuccessfulBase(latestTransmissionOutcomes());
|
||||
}
|
||||
|
||||
void EspnowMeshBackend::performEspnowMaintainance(uint32_t estimatedMaxDuration)
|
||||
void EspnowMeshBackend::performEspnowMaintenance(uint32_t estimatedMaxDuration)
|
||||
{
|
||||
ExpiringTimeTracker estimatedMaxDurationTracker = ExpiringTimeTracker(estimatedMaxDuration);
|
||||
|
||||
@ -232,7 +231,7 @@ void EspnowMeshBackend::performEspnowMaintainance(uint32_t estimatedMaxDuration)
|
||||
MutexTracker mutexTracker(_espnowTransmissionMutex, handlePostponedRemovals);
|
||||
if(!mutexTracker.mutexCaptured())
|
||||
{
|
||||
assert(false && "ERROR! Transmission in progress. Don't call performEspnowMaintainance from callbacks as this may corrupt program state! Aborting.");
|
||||
assert(false && "ERROR! Transmission in progress. Don't call performEspnowMaintenance from callbacks as this may corrupt program state! Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,6 @@
|
||||
#include "MessageData.h"
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include "Crypto.h"
|
||||
#include "EspnowNetworkInfo.h"
|
||||
|
||||
typedef enum
|
||||
@ -111,11 +110,11 @@ typedef enum
|
||||
|
||||
|
||||
/**
|
||||
* An alternative to standard delay(). Will continuously call performEspnowMaintainance() during the waiting time, so that the ESP-NOW node remains responsive.
|
||||
* An alternative to standard delay(). Will continuously call performEspnowMaintenance() during the waiting time, so that the ESP-NOW node remains responsive.
|
||||
* Note that if there is a lot of ESP-NOW transmission activity to the node during the espnowDelay, the desired duration may be overshot by several ms.
|
||||
* Thus, if precise timing is required, use standard delay() instead.
|
||||
*
|
||||
* Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintainance() can alter the ESP-NOW state.
|
||||
* Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintenance() can alter the ESP-NOW state.
|
||||
*
|
||||
* @param durationMs The shortest allowed delay duration, in milliseconds.
|
||||
*/
|
||||
@ -202,15 +201,15 @@ public:
|
||||
* It is recommended to place it in the beginning of the loop(), unless there is a need to put it elsewhere.
|
||||
* Among other things, the method cleans up old Espnow log entries (freeing up RAM) and sends the responses you provide to Espnow requests.
|
||||
* Note that depending on the amount of responses to send and their length, this method can take tens or even hundreds of milliseconds to complete.
|
||||
* More intense transmission activity and less frequent calls to performEspnowMaintainance will likely cause the method to take longer to complete, so plan accordingly.
|
||||
* More intense transmission activity and less frequent calls to performEspnowMaintenance will likely cause the method to take longer to complete, so plan accordingly.
|
||||
*
|
||||
* Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintainance() can alter the ESP-NOW state.
|
||||
* Should not be used inside responseHandler, requestHandler, networkFilter or broadcastFilter callbacks since performEspnowMaintenance() can alter the ESP-NOW state.
|
||||
*
|
||||
* @param estimatedMaxDuration The desired max duration for the method. If set to 0 there is no duration limit.
|
||||
* Note that setting the estimatedMaxDuration too low may result in missed ESP-NOW transmissions because of too little time for maintainance.
|
||||
* Note that setting the estimatedMaxDuration too low may result in missed ESP-NOW transmissions because of too little time for maintenance.
|
||||
* Also note that although the method will try to respect the max duration limit, there is no guarantee. Overshoots by tens of milliseconds are possible.
|
||||
*/
|
||||
static void performEspnowMaintainance(uint32_t estimatedMaxDuration = 0);
|
||||
static void performEspnowMaintenance(uint32_t estimatedMaxDuration = 0);
|
||||
|
||||
/**
|
||||
* At critical heap level no more incoming requests are accepted.
|
||||
@ -703,19 +702,19 @@ protected:
|
||||
* For example, response order will be mixed up if some responses fail to transmit while others transmit successfully.
|
||||
*
|
||||
* @param estimatedMaxDurationTracker A pointer to an ExpiringTimeTracker initialized with the desired max duration for the method. If set to nullptr there is no duration limit.
|
||||
* Note that setting the estimatedMaxDuration too low may result in missed ESP-NOW transmissions because of too little time for maintainance.
|
||||
* Note that setting the estimatedMaxDuration too low may result in missed ESP-NOW transmissions because of too little time for maintenance.
|
||||
* Also note that although the method will try to respect the max duration limit, there is no guarantee. Overshoots by tens of milliseconds are possible.
|
||||
*/
|
||||
static void sendStoredEspnowMessages(const ExpiringTimeTracker *estimatedMaxDurationTracker = nullptr);
|
||||
/*
|
||||
* @param estimatedMaxDurationTracker A pointer to an ExpiringTimeTracker initialized with the desired max duration for the method. If set to nullptr there is no duration limit.
|
||||
* Note that setting the estimatedMaxDuration too low may result in missed ESP-NOW transmissions because of too little time for maintainance.
|
||||
* Note that setting the estimatedMaxDuration too low may result in missed ESP-NOW transmissions because of too little time for maintenance.
|
||||
* Also note that although the method will try to respect the max duration limit, there is no guarantee. Overshoots by tens of milliseconds are possible.
|
||||
*/
|
||||
static void sendPeerRequestConfirmations(const ExpiringTimeTracker *estimatedMaxDurationTracker = nullptr);
|
||||
/*
|
||||
* @param estimatedMaxDurationTracker A pointer to an ExpiringTimeTracker initialized with the desired max duration for the method. If set to nullptr there is no duration limit.
|
||||
* Note that setting the estimatedMaxDuration too low may result in missed ESP-NOW transmissions because of too little time for maintainance.
|
||||
* Note that setting the estimatedMaxDuration too low may result in missed ESP-NOW transmissions because of too little time for maintenance.
|
||||
* Also note that although the method will try to respect the max duration limit, there is no guarantee. Overshoots by tens of milliseconds are possible.
|
||||
*/
|
||||
static void sendEspnowResponses(const ExpiringTimeTracker *estimatedMaxDurationTracker = nullptr);
|
||||
|
@ -37,7 +37,7 @@ void floodingMeshDelay(uint32_t durationMs)
|
||||
while(millis() - startingTime < durationMs)
|
||||
{
|
||||
delay(1);
|
||||
FloodingMesh::performMeshMaintainance();
|
||||
FloodingMesh::performMeshMaintenance();
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,25 +74,25 @@ void FloodingMesh::begin()
|
||||
// Initialise the mesh node
|
||||
getEspnowMeshBackend().begin();
|
||||
|
||||
// Makes it possible to find the node through scans, and also makes it possible to recover from an encrypted ESP-NOW connection where only the other node is encrypted.
|
||||
// Note that only one AP can be active at a time in total, and this will always be the one which was last activated.
|
||||
// Thus the AP is shared by all backends.
|
||||
getEspnowMeshBackend().activateAP();
|
||||
|
||||
availableFloodingMeshes.insert(this); // Returns std::pair<iterator,bool>
|
||||
}
|
||||
|
||||
void FloodingMesh::performMeshMaintainance()
|
||||
void FloodingMesh::activateAP()
|
||||
{
|
||||
getEspnowMeshBackend().activateAP();
|
||||
}
|
||||
|
||||
void FloodingMesh::performMeshMaintenance()
|
||||
{
|
||||
for(FloodingMesh *meshInstance : availableFloodingMeshes)
|
||||
{
|
||||
meshInstance->performMeshInstanceMaintainance();
|
||||
meshInstance->performMeshInstanceMaintenance();
|
||||
}
|
||||
}
|
||||
|
||||
void FloodingMesh::performMeshInstanceMaintainance()
|
||||
void FloodingMesh::performMeshInstanceMaintenance()
|
||||
{
|
||||
EspnowMeshBackend::performEspnowMaintainance();
|
||||
EspnowMeshBackend::performEspnowMaintenance();
|
||||
|
||||
for(std::list<std::pair<String, bool>>::iterator backlogIterator = _forwardingBacklog.begin(); backlogIterator != _forwardingBacklog.end(); )
|
||||
{
|
||||
@ -110,7 +110,7 @@ void FloodingMesh::performMeshInstanceMaintainance()
|
||||
|
||||
backlogIterator = _forwardingBacklog.erase(backlogIterator);
|
||||
|
||||
EspnowMeshBackend::performEspnowMaintainance(); // It is best to performEspnowMaintainance frequently to keep the Espnow backend responsive. Especially if each encryptedBroadcast takes a lot of time.
|
||||
EspnowMeshBackend::performEspnowMaintenance(); // It is best to performEspnowMaintenance frequently to keep the Espnow backend responsive. Especially if each encryptedBroadcast takes a lot of time.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,11 +31,11 @@
|
||||
#include <queue>
|
||||
|
||||
/**
|
||||
* An alternative to standard delay(). Will continuously call performMeshMaintainance() during the waiting time, so that the FloodingMesh node remains responsive.
|
||||
* An alternative to standard delay(). Will continuously call performMeshMaintenance() during the waiting time, so that the FloodingMesh node remains responsive.
|
||||
* Note that if there is a lot of FloodingMesh transmission activity to the node during the floodingMeshDelay, the desired duration may be overshot by several ms.
|
||||
* Thus, if precise timing is required, use standard delay() instead.
|
||||
*
|
||||
* Should not be used inside callbacks since performMeshMaintainance() can alter the ESP-NOW state.
|
||||
* Should not be used inside callbacks since performMeshMaintenance() can alter the ESP-NOW state.
|
||||
*
|
||||
* @param durationMs The shortest allowed delay duration, in milliseconds.
|
||||
*/
|
||||
@ -94,14 +94,23 @@ public:
|
||||
void begin();
|
||||
|
||||
/**
|
||||
* Performs maintainance for all available Flooding Mesh instances
|
||||
* Makes it possible to find the node through scans, and also makes it possible to recover from an encrypted ESP-NOW connection where only the other node is encrypted.
|
||||
* Required for encryptedBroadcast() usage, but also slows down the start-up of the node.
|
||||
*
|
||||
* Note that only one AP can be active at a time in total, and this will always be the one which was last activated.
|
||||
* Thus the AP is shared by all backends.
|
||||
*/
|
||||
static void performMeshMaintainance();
|
||||
void activateAP();
|
||||
|
||||
/**
|
||||
* Performs maintainance for this particular Flooding Mesh instance
|
||||
* Performs maintenance for all available Flooding Mesh instances
|
||||
*/
|
||||
void performMeshInstanceMaintainance();
|
||||
static void performMeshMaintenance();
|
||||
|
||||
/**
|
||||
* Performs maintenance for this particular Flooding Mesh instance
|
||||
*/
|
||||
void performMeshInstanceMaintenance();
|
||||
|
||||
/**
|
||||
* Serialize the current mesh node state. Useful to save a state before the node goes to sleep.
|
||||
|
@ -23,9 +23,9 @@
|
||||
*/
|
||||
|
||||
#include "JsonTranslator.h"
|
||||
#include "Crypto.h"
|
||||
#include "EspnowProtocolInterpreter.h"
|
||||
#include "TypeConversionFunctions.h"
|
||||
#include "CryptoInterface.h"
|
||||
|
||||
namespace JsonTranslator
|
||||
{
|
||||
@ -39,59 +39,6 @@ namespace JsonTranslator
|
||||
return valueIdentifier + "\"" + value + "\"}}";
|
||||
}
|
||||
|
||||
uint8_t *createHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t resultArray[SHA256HMAC_SIZE])
|
||||
{
|
||||
// Create the HMAC instance with our key
|
||||
SHA256HMAC hmac(hashKey, hashKeyLength);
|
||||
|
||||
// Update the HMAC with our message
|
||||
hmac.doUpdate(message.c_str());
|
||||
|
||||
// Finish the HMAC calculation and return the authentication code
|
||||
hmac.doFinal(resultArray);
|
||||
|
||||
// resultArray now contains our SHA256HMAC_SIZE byte authentication code
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
String createHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength)
|
||||
{
|
||||
byte hmac[SHA256HMAC_SIZE];
|
||||
createHmac(message, hashKey, hashKeyLength, hmac);
|
||||
return uint8ArrayToHexString(hmac, SHA256HMAC_SIZE);
|
||||
}
|
||||
|
||||
bool verifyHmac(const String &message, const String &messageHmac, const uint8_t *hashKey, uint8_t hashKeyLength)
|
||||
{
|
||||
if(messageHmac.length() != 2*SHA256HMAC_SIZE) // We know that each HMAC byte should become 2 String characters due to uint8ArrayToHexString.
|
||||
return false;
|
||||
|
||||
String generatedHmac = createHmac(message, hashKey, hashKeyLength);
|
||||
if(generatedHmac == messageHmac)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool verifyEncryptionRequestHmac(const String &encryptionRequestHmacMessage, const uint8_t *requesterStaMac, const uint8_t *requesterApMac,
|
||||
const uint8_t *hashKey, uint8_t hashKeyLength)
|
||||
{
|
||||
String hmac = "";
|
||||
if(getHmac(encryptionRequestHmacMessage, hmac))
|
||||
{
|
||||
int32_t hmacStartIndex = encryptionRequestHmacMessage.indexOf(jsonHmac);
|
||||
if(hmacStartIndex < 0)
|
||||
return false;
|
||||
|
||||
if(verifyHmac(macToString(requesterStaMac) + macToString(requesterApMac) + encryptionRequestHmacMessage.substring(0, hmacStartIndex), hmac, hashKey, hashKeyLength))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
String createEncryptedConnectionInfo(const String &infoHeader, const String &requestNonce, const String &authenticationPassword, uint64_t ownSessionKey, uint64_t peerSessionKey)
|
||||
{
|
||||
// Returns: Encrypted connection info:{"arguments":{"nonce":"1F2","password":"abc","ownSK":"3B4","peerSK":"1A2"}}
|
||||
@ -122,10 +69,32 @@ namespace JsonTranslator
|
||||
uint8_t staMac[6] {0};
|
||||
uint8_t apMac[6] {0};
|
||||
String requesterStaApMac = macToString(WiFi.macAddress(staMac)) + macToString(WiFi.softAPmacAddress(apMac));
|
||||
String hmac = createHmac(requesterStaApMac + mainMessage, hashKey, hashKeyLength);
|
||||
String hmac = CryptoInterface::createBearsslHmac(requesterStaApMac + mainMessage, hashKey, hashKeyLength);
|
||||
return mainMessage + createJsonEndPair(jsonHmac, hmac);
|
||||
}
|
||||
|
||||
bool verifyEncryptionRequestHmac(const String &encryptionRequestHmacMessage, const uint8_t *requesterStaMac, const uint8_t *requesterApMac,
|
||||
const uint8_t *hashKey, uint8_t hashKeyLength)
|
||||
{
|
||||
using namespace CryptoInterface;
|
||||
|
||||
String hmac = "";
|
||||
if(getHmac(encryptionRequestHmacMessage, hmac))
|
||||
{
|
||||
int32_t hmacStartIndex = encryptionRequestHmacMessage.indexOf(jsonHmac);
|
||||
if(hmacStartIndex < 0)
|
||||
return false;
|
||||
|
||||
if(hmac.length() == 2*SHA256HMAC_NATURAL_LENGTH // We know that each HMAC byte should become 2 String characters due to uint8ArrayToHexString.
|
||||
&& verifyBearsslHmac(macToString(requesterStaMac) + macToString(requesterApMac) + encryptionRequestHmacMessage.substring(0, hmacStartIndex), hmac, hashKey, hashKeyLength))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t getStartIndex(const String &jsonString, const String &valueIdentifier, int32_t searchStartIndex)
|
||||
{
|
||||
int32_t startIndex = jsonString.indexOf(valueIdentifier, searchStartIndex);
|
||||
|
@ -26,7 +26,6 @@
|
||||
#define __ESPNOWJSONTRANSLATOR_H__
|
||||
|
||||
#include <WString.h>
|
||||
#include "Crypto.h"
|
||||
|
||||
namespace JsonTranslator
|
||||
{
|
||||
@ -46,17 +45,13 @@ namespace JsonTranslator
|
||||
String createJsonPair(const String &valueIdentifier, const String &value);
|
||||
String createJsonEndPair(const String &valueIdentifier, const String &value);
|
||||
|
||||
uint8_t *createHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength, uint8_t resultArray[SHA256HMAC_SIZE]);
|
||||
String createHmac(const String &message, const uint8_t *hashKey, uint8_t hashKeyLength);
|
||||
|
||||
bool verifyHmac(const String &message, const String &messageHmac, const uint8_t *hashKey, uint8_t hashKeyLength);
|
||||
bool verifyEncryptionRequestHmac(const String &encryptionRequestHmacMessage, const uint8_t *requesterStaMac, const uint8_t *requesterApMac, const uint8_t *hashKey, uint8_t hashKeyLength);
|
||||
|
||||
String createEncryptedConnectionInfo(const String &infoHeader, const String &requestNonce, const String &authenticationPassword, uint64_t ownSessionKey, uint64_t peerSessionKey);
|
||||
String createEncryptionRequestIntro(const String &requestHeader, uint32_t duration = 0);
|
||||
String createEncryptionRequestEnding(const String &requestNonce);
|
||||
String createEncryptionRequestHmacMessage(const String &requestHeader, const String &requestNonce, const uint8_t *hashKey, uint8_t hashKeyLength, uint32_t duration = 0);
|
||||
|
||||
bool verifyEncryptionRequestHmac(const String &encryptionRequestHmacMessage, const uint8_t *requesterStaMac, const uint8_t *requesterApMac, const uint8_t *hashKey, uint8_t hashKeyLength);
|
||||
|
||||
/**
|
||||
* Provides the index within jsonString where the value of valueIdentifier starts.
|
||||
*
|
||||
|
@ -24,7 +24,6 @@
|
||||
*/
|
||||
|
||||
#include "TypeConversionFunctions.h"
|
||||
#include "Crypto.h"
|
||||
|
||||
String uint64ToString(uint64_t number, byte base)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user