diff --git a/core/MySigningAtsha204Soft.cpp b/core/MySigningAtsha204Soft.cpp index dc9645a..2a4d064 100644 --- a/core/MySigningAtsha204Soft.cpp +++ b/core/MySigningAtsha204Soft.cpp @@ -109,6 +109,10 @@ bool signerAtsha204SoftGetNonce(MyMessage &msg) } SIGN_DEBUG(PSTR("Signing backend: ATSHA204Soft\n")); +#ifdef MY_HW_HAS_GETRANDOM + // Try to get MAX_PAYLOAD random bytes + while (hwGetentropy(&_signing_verifying_nonce, MAX_PAYLOAD) != MAX_PAYLOAD); +#else // We used a basic whitening technique that XORs a random byte with the current hwMillis() counter and then the byte is // hashed (SHA256) to produce the resulting nonce _signing_sha256.init(); @@ -116,6 +120,7 @@ bool signerAtsha204SoftGetNonce(MyMessage &msg) _signing_sha256.write(random(256) ^ (hwMillis()&0xFF)); } memcpy(_signing_verifying_nonce, _signing_sha256.result(), MAX_PAYLOAD); +#endif // We set the part of the 32-byte nonce that does not fit into a message to 0xAA memset(&_signing_verifying_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_verifying_nonce)-MAX_PAYLOAD); diff --git a/examples/SecurityPersonalizer/SecurityPersonalizer.ino b/examples/SecurityPersonalizer/SecurityPersonalizer.ino index 3d9d2fb..acc47c8 100644 --- a/examples/SecurityPersonalizer/SecurityPersonalizer.ino +++ b/examples/SecurityPersonalizer/SecurityPersonalizer.ino @@ -72,7 +72,7 @@ * * @b Important
* You will need to ensure @ref MY_SIGNING_SOFT_RANDOMSEED_PIN is set to an unconnected analog pin - * in order to provide entropy to the software RNG. + * in order to provide entropy to the software RNG if your hardware has no HWRNG. * * @note The generated keys displayed in the serial log with this setting needs to be written down * and transferred to all nodes this gateway will communicate with. This is mandatory for ALL @@ -436,7 +436,7 @@ void setup() while (hwMillis() - enter < (unsigned long)500); #ifdef USE_SOFT_SIGNING // initialize pseudo-RNG - randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); + hwRandomNumberInit(); #endif Serial.begin(MY_BAUD_RATE); diff --git a/hal/architecture/MyHw.h b/hal/architecture/MyHw.h index 91bcaf6..fd78f47 100644 --- a/hal/architecture/MyHw.h +++ b/hal/architecture/MyHw.h @@ -43,6 +43,14 @@ void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); */ +/** + * @def MY_HW_HAS_GETRANDOM + * @brief Define this, if hwGetentropy is implemented + * + * ssize_t hwGetentropy(void *__buffer, size_t __length); + */ +//#define MY_HW_HAS_GETRANDOM + /** * Sleep for a defined time, using minimum power. * @param ms Time to sleep, in [ms]. @@ -138,6 +146,7 @@ void hwDebugPrint(const char *fmt, ... ); */ #ifdef DOXYGEN #define MY_CRITICAL_SECTION +#define MY_HW_HAS_GETRANDOM #endif /* DOXYGEN */ #endif // #ifdef MyHw_h diff --git a/hal/architecture/MyHwAVR.cpp b/hal/architecture/MyHwAVR.cpp index 5079a71..adef13c 100644 --- a/hal/architecture/MyHwAVR.cpp +++ b/hal/architecture/MyHwAVR.cpp @@ -202,6 +202,41 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo return ret; } +inline void hwRandomNumberInit() +{ + // This function initializes the random number generator with a seed + // of 32 bits. This method is good enough to earn FIPS 140-2 conform + // random data. This should reach to generate 32 Bit for randomSeed(). + unsigned long seed = 0; + unsigned long start = millis(); + unsigned long timeout = start + 20; + + // Trigger floating effect of an unconnected pin + pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT_PULLUP); + pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT); + delay(10); + + // Generate 32 bits of datas + for (uint8_t i=0; i<32; i++) { + int pinValue = analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN); + // Wait until the analog value has changed + while ((pinValue == analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) && (timeout>=millis())) { + seed ^= (millis() << i); + // Check of data generation is slow + if (timeout<=millis()) { + // Trigger pin again + pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT_PULLUP); + pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT); + // Pause a short while + delay(seed % 10); + timeout = millis()+20; + } + } + } + + randomSeed(seed); +} + bool hwUniqueID(unique_id_t* uniqueID) { // not implemented yet diff --git a/hal/architecture/MyHwAVR.h b/hal/architecture/MyHwAVR.h index 183db74..7eb640d 100644 --- a/hal/architecture/MyHwAVR.h +++ b/hal/architecture/MyHwAVR.h @@ -48,12 +48,12 @@ bool hwInit(void); #define hwWatchdogReset() wdt_reset() #define hwReboot() wdt_enable(WDTO_15MS); while (1) #define hwMillis() millis() -#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) #define hwReadConfig(__pos) eeprom_read_byte((uint8_t*)(__pos)) #define hwWriteConfig(__pos, __val) eeprom_update_byte((uint8_t*)(__pos), (__val)) #define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void*)(__buf), (void*)(__pos), (__length)) #define hwWriteConfigBlock(__buf, __pos, __length) eeprom_update_block((void*)(__buf), (void*)(__pos), (__length)) +inline void hwRandomNumberInit(); void hwInternalSleep(unsigned long ms); #ifndef DOXYGEN diff --git a/hal/architecture/MyHwESP8266.cpp b/hal/architecture/MyHwESP8266.cpp index 6913344..b2f053a 100644 --- a/hal/architecture/MyHwESP8266.cpp +++ b/hal/architecture/MyHwESP8266.cpp @@ -73,6 +73,21 @@ bool hwUniqueID(unique_id_t *uniqueID) return true; } +ssize_t hwGetentropy(void *__buffer, size_t __length) +{ + // cut length if > 256 + if (__length > 256) { + __length = 256; + } + uint8_t *dst = (uint8_t *)__buffer; + + // Start random number generator + for (size_t i = 0; i < __length; i++) { + dst[i] = (uint8_t)RANDOM_REG32; + } + + return __length; +} int8_t hwSleep(unsigned long ms) { diff --git a/hal/architecture/MyHwESP8266.h b/hal/architecture/MyHwESP8266.h index a713bba..2550f7a 100644 --- a/hal/architecture/MyHwESP8266.h +++ b/hal/architecture/MyHwESP8266.h @@ -41,13 +41,16 @@ #define hwWatchdogReset() wdt_reset() #define hwReboot() ESP.restart() #define hwMillis() millis() -#define hwRandomNumberInit() randomSeed(RANDOM_REG32) +// The use of randomSeed switch to pseudo random number. Keep hwRandomNumberInit empty +#define hwRandomNumberInit() bool hwInit(void); void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfig(const int addr, uint8_t value); uint8_t hwReadConfig(const int addr); +ssize_t hwGetentropy(void *__buffer, size_t __length); +//#define MY_HW_HAS_GETRANDOM /** * Restore interrupt state. diff --git a/hal/architecture/MyHwLinuxGeneric.cpp b/hal/architecture/MyHwLinuxGeneric.cpp index 09c1dbe..3c8070d 100644 --- a/hal/architecture/MyHwLinuxGeneric.cpp +++ b/hal/architecture/MyHwLinuxGeneric.cpp @@ -19,7 +19,13 @@ #include "MyHwLinuxGeneric.h" +#include +#include #include +#include +#include +#include +#include #include #include "SoftEeprom.h" #include "log.h" @@ -62,7 +68,15 @@ void hwWriteConfig(int addr, uint8_t value) void hwRandomNumberInit() { - randomSeed(time(NULL)); + unsigned long seed=0; + while (hwGetentropy(&seed, sizeof(seed)) != sizeof(seed)); + randomSeed(seed); +} + +ssize_t hwGetentropy(void *__buffer, size_t __length) +{ + // getrandom syscall + return syscall(SYS_getrandom, __buffer, __length, GRND_NONBLOCK); } unsigned long hwMillis() diff --git a/hal/architecture/MyHwLinuxGeneric.h b/hal/architecture/MyHwLinuxGeneric.h index 5074ae8..ce89572 100644 --- a/hal/architecture/MyHwLinuxGeneric.h +++ b/hal/architecture/MyHwLinuxGeneric.h @@ -54,6 +54,8 @@ inline void hwWriteConfigBlock(void* buf, void* addr, size_t length); inline uint8_t hwReadConfig(int addr); inline void hwWriteConfig(int addr, uint8_t value); inline void hwRandomNumberInit(); +ssize_t hwGetentropy(void *__buffer, size_t __length); +#define MY_HW_HAS_GETRANDOM inline unsigned long hwMillis(); #ifdef MY_RF24_IRQ_PIN diff --git a/hal/architecture/MyHwNRF5.cpp b/hal/architecture/MyHwNRF5.cpp index 18893be..889343e 100644 --- a/hal/architecture/MyHwNRF5.cpp +++ b/hal/architecture/MyHwNRF5.cpp @@ -84,6 +84,9 @@ bool hwInit() return true; } +static nrf_ecb_t hwRngData; +static int8_t hwRndDataReadPos = -1; + void hwRandomNumberInit() { // Start HWRNG @@ -106,6 +109,17 @@ void hwRandomNumberInit() } randomSeed(seed); + // Fill ESB data structure for fast random data generation + uint8_t *ecbstruct = (uint8_t *)&hwRngData; + for (uint8_t i = 0; iEVENTS_VALRDY == 0) { + yield(); + } + ecbstruct[i] = NRF_RNG->VALUE; + NRF_RNG->EVENTS_VALRDY = 0; + } + hwRndDataReadPos = 0; + // Stop HWRNG NRF_RNG->TASKS_STOP = 1; #ifdef NRF51 @@ -113,6 +127,55 @@ void hwRandomNumberInit() #endif } +ssize_t hwGetentropy(void *__buffer, size_t __length) +{ + if (hwRndDataReadPos<0) { + // Not initialized + hwRandomNumberInit(); + } + + // cut length if > 256 + if (__length > 256) { + __length = 256; + } + uint8_t *dst = (uint8_t *)__buffer; + + // Start random number generator + for (size_t i = 0; i < __length; i++) { + dst[i] = hwRngData.ciphertext[hwRndDataReadPos & 0xfu]; + MY_CRITICAL_SECTION { + if (hwRndDataReadPos >= ((int8_t)sizeof(hwRngData.ciphertext)-1)) + { + // Retry until no error + bool need_data = true; + while (need_data) { + // Stop if another task is running + NRF_ECB->TASKS_STOPECB = 1; + NRF_ECB->EVENTS_ERRORECB = 0; + NRF_ECB->EVENTS_ENDECB = 0; + uint32_t ptrbackup = NRF_ECB->ECBDATAPTR; + NRF_ECB->ECBDATAPTR = (uint32_t)&hwRngData; + NRF_ECB->TASKS_STARTECB = 1; + while (!NRF_ECB->EVENTS_ENDECB); + NRF_ECB->ECBDATAPTR = ptrbackup; + if (NRF_ECB->EVENTS_ERRORECB == 0) { + need_data = false; + } + } + hwRndDataReadPos=0; + for (uint8_t i=0; iRR[0] = WDT_RR_RR_Reload; diff --git a/hal/architecture/MyHwNRF5.h b/hal/architecture/MyHwNRF5.h index a5dbb06..2ebba32 100644 --- a/hal/architecture/MyHwNRF5.h +++ b/hal/architecture/MyHwNRF5.h @@ -59,6 +59,8 @@ void hwWriteConfigBlock(void *buf, void *adr, size_t length); void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); void hwRandomNumberInit(); +ssize_t hwGetentropy(void *__buffer, size_t __length); +#define MY_HW_HAS_GETRANDOM #ifndef MY_SERIALDEVICE #define MY_SERIALDEVICE Serial @@ -110,6 +112,20 @@ static __inline__ void __priMaskRestore(const uint32_t *priMask) #define MY_HW_RTC_IRQN RTC0_IRQn #endif +/** Datastructure for AES ECB unit + */ +typedef struct { + /** AES Key + */ + uint8_t key[16]; + /** Unencrypted data + */ + uint8_t cleartext[16]; + /** Encrypted data + */ + uint8_t ciphertext[16]; +} nrf_ecb_t; + #ifndef DOXYGEN #define MY_CRITICAL_SECTION // temp. commented, to fix "CircularBuffer.h:94:2: warning: control reaches end of non-void function" error