diff --git a/src/mesh/CryptoEngine.cpp b/src/mesh/CryptoEngine.cpp index e28df442b6..cb89899763 100644 --- a/src/mesh/CryptoEngine.cpp +++ b/src/mesh/CryptoEngine.cpp @@ -224,7 +224,11 @@ bool CryptoEngine::encryptCurve25519(uint32_t toNode, uint32_t fromNode, meshtas uint64_t packetNum, size_t numBytes, const uint8_t *bytes, uint8_t *bytesOut) { uint8_t *auth; - long extraNonceTmp = random(); + // The extra nonce must be unpredictable: use the hardware RNG, falling back to the + // seeded CSPRNG only when no hardware source is available. + uint32_t extraNonceTmp; + if (!HardwareRNG::fill((uint8_t *)&extraNonceTmp, sizeof(extraNonceTmp))) + CryptRNG.rand((uint8_t *)&extraNonceTmp, sizeof(extraNonceTmp)); auth = bytesOut + numBytes; memcpy((uint8_t *)(auth + 8), &extraNonceTmp, sizeof(uint32_t)); // do not use dereference on potential non aligned pointers : *extraNonce = extraNonceTmp; diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index 36a7d6fe97..b9cf4b03b8 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -1,6 +1,7 @@ #include "AdminModule.h" #include "Channels.h" #include "DisplayFormatters.h" +#include "HardwareRNG.h" #include "MeshService.h" #include "NodeDB.h" #include "PositionPrecision.h" @@ -49,6 +50,9 @@ #include "GPS.h" #endif +#include // CryptRNG, the seeded CSPRNG used as fallback for the session passkey +#include // rollover-safe elapsed-time checks for the session passkey + #if MESHTASTIC_EXCLUDE_GPS #include "modules/PositionModule.h" #endif @@ -1792,11 +1796,15 @@ AdminModule::AdminModule() : ProtobufModule("Admin", meshtastic_PortNum_ADMIN_AP void AdminModule::setPassKey(meshtastic_AdminMessage *res) { - if (session_time == 0 || millis() / 1000 > session_time + 150) { - for (int i = 0; i < 8; i++) { - session_passkey[i] = random(); - } - session_time = millis() / 1000; + // Regenerate once there is no session yet or the current key is older than 150s. session_time + // holds millis(); the Throttle check is rollover-safe, unlike the previous seconds comparison. + if (!sessionPasskeyValid || !Throttle::isWithinTimespanMs(session_time, 150 * 1000UL)) { + // Session passkey authenticates admin replies, so it must be unpredictable: prefer the + // hardware RNG, falling back to the seeded CSPRNG only when no hardware source exists. + if (!HardwareRNG::fill(session_passkey, sizeof(session_passkey))) + CryptRNG.rand(session_passkey, sizeof(session_passkey)); + session_time = millis(); + sessionPasskeyValid = true; } memcpy(res->session_passkey.bytes, session_passkey, 8); res->session_passkey.size = 8; @@ -1809,7 +1817,8 @@ bool AdminModule::checkPassKey(meshtastic_AdminMessage *res) { // check that the key in the packet is still valid printBytes("Incoming session key: ", res->session_passkey.bytes, 8); printBytes("Expected session key: ", session_passkey, 8); - return (session_time + 300 > millis() / 1000 && res->session_passkey.size == 8 && + // Key is valid for 300s from issue; sessionPasskeyValid guards an unissued session. + return (sessionPasskeyValid && Throttle::isWithinTimespanMs(session_time, 300 * 1000UL) && res->session_passkey.size == 8 && memcmp(res->session_passkey.bytes, session_passkey, 8) == 0); } diff --git a/src/modules/AdminModule.h b/src/modules/AdminModule.h index bfc3035b51..5c1a6ef58a 100644 --- a/src/modules/AdminModule.h +++ b/src/modules/AdminModule.h @@ -41,7 +41,8 @@ class AdminModule : public ProtobufModule, public Obser bool hasOpenEditTransaction = false; uint8_t session_passkey[8] = {0}; - uint session_time = 0; + uint32_t session_time = 0; // millis() when the current session passkey was issued + bool sessionPasskeyValid = false; // separate flag: millis() 0 at boot is a valid issue time void saveChanges(int saveWhat, bool shouldReboot = true);