diff --git a/wled00/crypto.cpp b/wled00/crypto.cpp index 94c5c069f..002e0d53c 100644 --- a/wled00/crypto.cpp +++ b/wled00/crypto.cpp @@ -34,12 +34,12 @@ void hmacSign(const byte* message, size_t msgLen, const char* pskHex, byte* sign bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const byte* signature) { byte sigCalculated[SHA256HMAC_SIZE]; hmacSign(message, msgLen, pskHex, sigCalculated); + Serial.print(F("Calculated: ")); + printByteArray(sigCalculated, SHA256HMAC_SIZE); if (memcmp(sigCalculated, signature, SHA256HMAC_SIZE) != 0) { - DEBUG_PRINTLN(F("HMAC verification failed!")); + Serial.println(F("HMAC verification failed!")); Serial.print(F("Expected: ")); printByteArray(signature, SHA256HMAC_SIZE); - Serial.print(F("Calculated: ")); - printByteArray(sigCalculated, SHA256HMAC_SIZE); return false; } Serial.println(F("HMAC verification successful!")); @@ -49,71 +49,89 @@ bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const by #define WLED_HMAC_TEST_PW "guessihadthekeyafterall" #define WLED_HMAC_TEST_PSK "a6f8488da62c5888d7f640276676e78da8639faf0495110b43e226b35ac37a4c" +bool verifyHmacFromJsonString0Term(byte* jsonStr, size_t len) { + // Zero-terminate the JSON string (replace the last character, usually '}', with a null terminator temporarily) + char lastChar = jsonStr[len-1]; + jsonStr[len-1] = '\0'; + bool result = verifyHmacFromJsonStr((const char*)jsonStr, len); + jsonStr[len-1] = lastChar; + return result; +} + bool verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen) { // Extract the signature from the JSON string size_t jsonLen = strlen(jsonStr); + Serial.print(F("Length: ")); + Serial.println(jsonLen); if (jsonLen > maxLen) { // memory safety - Serial.println(F("JSON string too long!")); - Serial.print(F("Length: ")); - Serial.print(jsonLen); + Serial.print(F("JSON string too long!")); Serial.print(F(", max: ")); Serial.println(maxLen); return false; } Serial.print(F("Received JSON: ")); Serial.println(jsonStr); - char* sigPos = strstr(jsonStr, PSTR("\"sig\":\"")); - if (sigPos == nullptr) { - Serial.println(F("No signature found in JSON.")); + + char* macPos = strstr(jsonStr, "\"mac\":\""); + if (macPos == nullptr) { + Serial.println(F("No MAC found in JSON.")); return false; } StaticJsonDocument<256> doc; - DeserializationError error = deserializeJson(doc, jsonStr +7); + DeserializationError error = deserializeJson(doc, macPos +6); if (error) { Serial.print(F("deserializeJson() failed: ")); Serial.println(error.c_str()); return false; } - const char* sig = doc.as(); - if (sig == nullptr) { - Serial.println(F("Failed signature JSON.")); + const char* mac = doc.as(); + if (mac == nullptr) { + Serial.println(F("Failed MAC JSON.")); return false; } - Serial.print(F("Received signature: ")); - Serial.println(sig); + Serial.print(F("Received MAC: ")); + Serial.println(mac); // extract the message object from the JSON string - char* msgPos = strstr(jsonStr, PSTR("\"msg\":\"")); - char* objStart = strchr(msgPos + 7, '{'); + char* msgPos = strstr(jsonStr, "\"msg\":"); + char* objStart = strchr(msgPos + 6, '{'); + if (objStart == nullptr) { + Serial.println(F("Couldn't find msg object start.")); + return false; + } size_t maxObjLen = jsonLen - (objStart - jsonStr); - uint32_t objDepth = 0; + Serial.print(F("Max object length: ")); Serial.println(maxObjLen); + int32_t objDepth = 0; char* objEnd = nullptr; for (size_t i = 0; i < maxObjLen; i++) { + Serial.write(objStart[i]); if (objStart[i] == '{') objDepth++; - if (objStart [i] == '}') objDepth--; + if (objStart[i] == '}') objDepth--; if (objDepth == 0) { + Serial.print(F("Found msg object end: ")); + Serial.println(i); objEnd = objStart + i; break; } - i++; + //i++; } if (objEnd == nullptr) { Serial.println(F("Couldn't find msg object end.")); return false; } - // Convert the signature from hex string to byte array - size_t len = strlen(sig) / 2; // This will drop the last character if the string has an odd length + // Convert the MAC from hex string to byte array + size_t len = strlen(mac) / 2; // This will drop the last character if the string has an odd length if (len != SHA256HMAC_SIZE) { - Serial.println(F("Received sig not expected size!")); + Serial.println(F("Received MAC not expected size!")); return false; } - unsigned char sigByteArray[len]; - hexStringToByteArray(sig, sigByteArray, len); + unsigned char macByteArray[len]; + hexStringToByteArray(mac, macByteArray, len); // Calculate the HMAC of the message object - return hmacVerify((const byte*)objStart, objEnd - objStart + 1, WLED_HMAC_TEST_PSK, sigByteArray); + return hmacVerify((const byte*)objStart, objEnd - objStart + 1, WLED_HMAC_TEST_PSK, macByteArray); } bool hmacTest() { @@ -121,17 +139,17 @@ bool hmacTest() { unsigned long start = millis(); const char message[] = "Hello, World!"; const char psk[] = "d0c0ffeedeadbeef"; - byte signature[SHA256HMAC_SIZE]; - hmacSign((const byte*)message, strlen(message), psk, signature); + byte mac[SHA256HMAC_SIZE]; + hmacSign((const byte*)message, strlen(message), psk, mac); Serial.print(F("Took ")); Serial.print(millis() - start); Serial.println(F("ms to sign message.")); - Serial.print(F("Signature: ")); - printByteArray(signature, SHA256HMAC_SIZE); + Serial.print(F("MAC: ")); + printByteArray(mac, SHA256HMAC_SIZE); start = millis(); - bool result = hmacVerify((const byte*)message, strlen(message), psk, signature); + bool result = hmacVerify((const byte*)message, strlen(message), psk, mac); Serial.print(F("Took ")); Serial.print(millis() - start); - Serial.println(F("ms to verify signature.")); + Serial.println(F("ms to verify MAC.")); return result; } \ No newline at end of file diff --git a/wled00/data/index.js b/wled00/data/index.js index cc078d23b..22561a2e3 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -326,7 +326,7 @@ function handleWindowMessageEvent(event) { sraWindow = event.source; sraOrigin = event.origin; } else if (json['wled-rc'] === 'hmac') { - console.log(`Received HMAC: ${json['sig']}`); + console.log(`Received HMAC: ${json['mac']}`); requestJson(json); } } @@ -1743,8 +1743,8 @@ function requestJson(command=null) if (req.length > 500 && lastinfo && lastinfo.arch == "esp8266") useWs = false; // esp8266 can only handle 500 bytes }; - if (command && useSRA && !command['sig']) { // secure remote access integration, need to get HMAC from rc.wled.me - // if we already have a command including a signature, we are good to go + if (command && useSRA && !command['mac']) { // secure remote access integration, need to get HMAC from rc.wled.me + // if we already have a command including a MAC, we are good to go sraWindow.postMessage(JSON.stringify({"wled-ui":"hmac-req", "msg":command}), sraOrigin); return; // TODO need a sort of pending indicator } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 13a0cd3ad..2b47a4d83 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -99,6 +99,7 @@ void setRandomColor(byte* rgb); void hmacSign(const byte* message, size_t msgLen, const char* pskHex, byte* signature); bool hmacVerify(const byte* message, size_t msgLen, const char* pskHex, const byte* signature); bool verifyHmacFromJsonStr(const char* jsonStr, uint32_t maxLen); +bool verifyHmacFromJsonString0Term(byte* jsonStr, size_t len); bool hmacTest(); //dmx.cpp diff --git a/wled00/wled_server.cpp b/wled00/wled_server.cpp index 407bfb9d0..dbfe905ff 100644 --- a/wled00/wled_server.cpp +++ b/wled00/wled_server.cpp @@ -289,7 +289,7 @@ void initServer() Serial.println("JSON request"); Serial.println((const char*)request->_tempObject); - if (!verifyHmacFromJsonStr((const char*)request->_tempObject, request->contentLength())) { + if (!verifyHmacFromJsonString0Term((byte*)request->_tempObject, request->contentLength())) { //releaseJSONBufferLock(); serveJsonError(request, 401, ERR_DENIED); return; diff --git a/wled00/ws.cpp b/wled00/ws.cpp index 41d0615ad..401cd47fd 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -43,8 +43,10 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp Serial.print(F("WS message: ")); Serial.println((const char*)data); + verifyHmacFromJsonString0Term(data, len); DeserializationError error = deserializeJson(*pDoc, data, len); + verifyHmacFromJsonString0Term(data, len); JsonObject root = pDoc->as(); if (error || root.isNull()) { releaseJSONBufferLock(); @@ -56,11 +58,11 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp } else if (root.containsKey("lv")) { wsLiveClientId = root["lv"] ? client->id() : 0; } else { - if (!verifyHmacFromJsonStr((const char*)data, len)) { - releaseJSONBufferLock(); - client->text(F("{\"error\":1}")); // ERR_DENIED - return; - } + // if (!verifyHmacFromJsonString0Term(data, len)) { + // releaseJSONBufferLock(); + // client->text(F("{\"error\":1}")); // ERR_DENIED + // return; + // } verboseResponse = deserializeState(root["msg"]); } releaseJSONBufferLock();