diff --git a/platformio.ini b/platformio.ini index 4d30be322..92306b424 100644 --- a/platformio.ini +++ b/platformio.ini @@ -141,6 +141,7 @@ lib_deps = makuna/NeoPixelBus @ 2.8.0 #https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 + https://github.com/Aircoookie/arduino-crypto.git # for I2C interface ;Wire # ESP-NOW library diff --git a/wled00/crypto.cpp b/wled00/crypto.cpp new file mode 100644 index 000000000..818c0f2d2 --- /dev/null +++ b/wled00/crypto.cpp @@ -0,0 +1,52 @@ +#include +#include "wled.h" + +#define HMAC_KEY_SIZE 32 + +void print_byte_array(const byte* arr, size_t len) { + for (size_t i = 0; i < len; i++) { + Serial.print(arr[i], HEX); + } + Serial.println(); +} + +void hmac_sign(const char* message, const char* psk, byte* signature) { + SHA256HMAC hmac((const byte*)psk, strlen(psk)); + hmac.doUpdate(message, strlen(message)); + hmac.doFinal(signature); +} + +bool hmac_verify(const char* message, const char* psk, const byte* signature) { + byte sig_calculated[SHA256HMAC_SIZE]; + hmac_sign(message, psk, sig_calculated); + if (memcmp(sig_calculated, signature, SHA256HMAC_SIZE) != 0) { + DEBUG_PRINTLN(F("HMAC verification failed!")); + Serial.print(F("Expected: ")); + print_byte_array(signature, SHA256HMAC_SIZE); + Serial.print(F("Calculated: ")); + print_byte_array(sig_calculated, SHA256HMAC_SIZE); + return false; + } + Serial.println(F("HMAC verification successful!")); + return true; +} + +bool hmac_test() { + Serial.println(F("Testing HMAC...")); + unsigned long start = millis(); + char message[] = "Hello, World!"; + char psk[] = "tokyo"; + byte signature[SHA256HMAC_SIZE]; + hmac_sign(message, psk, signature); + Serial.print(F("Took ")); + Serial.print(millis() - start); + Serial.println(F("ms to sign message.")); + Serial.print(F("Signature: ")); + print_byte_array(signature, SHA256HMAC_SIZE); + start = millis(); + bool result = hmac_verify(message, psk, signature); + Serial.print(F("Took ")); + Serial.print(millis() - start); + Serial.println(F("ms to verify signature.")); + return result; +} \ No newline at end of file diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 71b00599c..78d38b85c 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -95,6 +95,11 @@ uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb); uint16_t approximateKelvinFromRGB(uint32_t rgb); void setRandomColor(byte* rgb); +//crypto.cpp +void hmac_sign(const char* message, const char* psk, byte* signature); +bool hmac_verify(const char* message, const char* psk, const byte* signature); +bool hmac_test(); + //dmx.cpp void initDMX(); void handleDMX(); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 39e0d250b..c2e4431f5 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -555,6 +555,8 @@ void WLED::setup() #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_DISABLE_BROWNOUT_DET) WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 1); //enable brownout detector #endif + + hmac_test(); } void WLED::beginStrip() diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 958b51330..4a616f9aa 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -287,18 +287,27 @@ void initServer() bool verboseResponse = false; bool isConfig = false; + Serial.println("JSON request"); + if (!requestJSONBufferLock(14)) { serveJsonError(request, 503, ERR_NOBUF); return; } DeserializationError error = deserializeJson(*pDoc, (uint8_t*)(request->_tempObject)); + + // if enabled, calculate HMAC and verify it + Serial.println("HMAC verification"); + Serial.write((const char*)request->_tempObject, request->contentLength()); + JsonObject root = pDoc->as(); if (error || root.isNull()) { releaseJSONBufferLock(); serveJsonError(request, 400, ERR_JSON); return; } + + // old 4-digit pin logic for settings authentication (no transport encryption) if (root.containsKey("pin")) checkSettingsPIN(root["pin"].as()); const String& url = request->url();