From d6cd65e1089d96a3c22ac5805bb99a170224a6bf Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 27 Nov 2025 20:31:41 -0500 Subject: [PATCH 1/3] ota_update: Clean up SHA API Many of these functions are internal, and we can reduce RAM by caching the binary value instead. --- wled00/ota_update.cpp | 67 +++++++++++++++++++++++++++---------------- wled00/ota_update.h | 21 -------------- 2 files changed, 42 insertions(+), 46 deletions(-) diff --git a/wled00/ota_update.cpp b/wled00/ota_update.cpp index 4a93312d3a..5fa8dba4e5 100644 --- a/wled00/ota_update.cpp +++ b/wled00/ota_update.cpp @@ -273,18 +273,18 @@ void markOTAvalid() { } #if defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DISABLE_OTA) -// Cache for bootloader SHA256 digest as hex string -static String bootloaderSHA256HexCache = ""; - -// Calculate and cache the bootloader SHA256 digest as hex string -void calculateBootloaderSHA256() { - if (!bootloaderSHA256HexCache.isEmpty()) return; +static bool bootloaderSHA256CacheValid = false; +static uint8_t bootloaderSHA256Cache[32]; +/** + * Calculate and cache the bootloader SHA256 digest + * Reads the bootloader from flash at offset 0x1000 and computes SHA256 hash + */ +static void calculateBootloaderSHA256() { // Bootloader is at fixed offset 0x1000 (4KB) and is typically 32KB const uint32_t bootloaderSize = 0x8000; // 32KB, typical bootloader size // Calculate SHA256 - uint8_t sha256[32]; mbedtls_sha256_context ctx; mbedtls_sha256_init(&ctx); mbedtls_sha256_starts(&ctx, 0); // 0 = SHA256 (not SHA224) @@ -299,33 +299,50 @@ void calculateBootloaderSHA256() { } } - mbedtls_sha256_finish(&ctx, sha256); + mbedtls_sha256_finish(&ctx, bootloaderSHA256Cache); mbedtls_sha256_free(&ctx); - - // Convert to hex string and cache it - char hex[65]; - for (int i = 0; i < 32; i++) { - sprintf(hex + (i * 2), "%02x", sha256[i]); - } - hex[64] = '\0'; - bootloaderSHA256HexCache = String(hex); + bootloaderSHA256CacheValid = true; } // Get bootloader SHA256 as hex string String getBootloaderSHA256Hex() { - calculateBootloaderSHA256(); - return bootloaderSHA256HexCache; + if (!bootloaderSHA256CacheValid) { + calculateBootloaderSHA256(); + } + + // Convert to hex string + String result; + result.reserve(65); + for (int i = 0; i < 32; i++) { + char b1 = bootloaderSHA256Cache[i]; + char b2 = b1 >> 4; + b1 &= 0x0F; + b1 += '0'; b2 += '0'; + if (b1 > '9') b1 += 7; + if (b2 > '9') b2 += 7; + result.concat(b1); + result.concat(b2); + } + return std::move(result); } -// Invalidate cached bootloader SHA256 (call after bootloader update) -void invalidateBootloaderSHA256Cache() { - bootloaderSHA256HexCache = ""; +/** + * Invalidate cached bootloader SHA256 (call after bootloader update) + * Forces recalculation on next call to calculateBootloaderSHA256 or getBootloaderSHA256Hex + */ +static void invalidateBootloaderSHA256Cache() { + bootloaderSHA256CacheValid = false; } -// Verify complete buffered bootloader using ESP-IDF validation approach -// This matches the key validation steps from esp_image_verify() in ESP-IDF -// Returns the actual bootloader data pointer and length via the buffer and len parameters -bool verifyBootloaderImage(const uint8_t* &buffer, size_t &len, String* bootloaderErrorMsg) { +/** + * Verify complete buffered bootloader using ESP-IDF validation approach + * This matches the key validation steps from esp_image_verify() in ESP-IDF + * @param buffer Reference to pointer to bootloader binary data (will be adjusted if offset detected) + * @param len Reference to length of bootloader data (will be adjusted to actual size) + * @param bootloaderErrorMsg Pointer to String to store error message (must not be null) + * @return true if validation passed, false otherwise + */ +static bool verifyBootloaderImage(const uint8_t* &buffer, size_t &len, String* bootloaderErrorMsg) { size_t availableLen = len; if (!bootloaderErrorMsg) { DEBUG_PRINTLN(F("bootloaderErrorMsg is null")); diff --git a/wled00/ota_update.h b/wled00/ota_update.h index 691429b305..d2fa887d30 100644 --- a/wled00/ota_update.h +++ b/wled00/ota_update.h @@ -58,11 +58,6 @@ void handleOTAData(AsyncWebServerRequest *request, size_t index, uint8_t *data, void markOTAvalid(); #if defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DISABLE_OTA) -/** - * Calculate and cache the bootloader SHA256 digest - * Reads the bootloader from flash at offset 0x1000 and computes SHA256 hash - */ -void calculateBootloaderSHA256(); /** * Get bootloader SHA256 as hex string @@ -70,22 +65,6 @@ void calculateBootloaderSHA256(); */ String getBootloaderSHA256Hex(); -/** - * Invalidate cached bootloader SHA256 (call after bootloader update) - * Forces recalculation on next call to calculateBootloaderSHA256 or getBootloaderSHA256Hex - */ -void invalidateBootloaderSHA256Cache(); - -/** - * Verify complete buffered bootloader using ESP-IDF validation approach - * This matches the key validation steps from esp_image_verify() in ESP-IDF - * @param buffer Reference to pointer to bootloader binary data (will be adjusted if offset detected) - * @param len Reference to length of bootloader data (will be adjusted to actual size) - * @param bootloaderErrorMsg Pointer to String to store error message (must not be null) - * @return true if validation passed, false otherwise - */ -bool verifyBootloaderImage(const uint8_t* &buffer, size_t &len, String* bootloaderErrorMsg); - /** * Create a bootloader OTA context object on an AsyncWebServerRequest * @param request Pointer to web request object From 0b965ea4312490a6940a6f89207469aec3297dc5 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 27 Nov 2025 21:42:57 -0500 Subject: [PATCH 2/3] ota_update: Fix hex print --- wled00/ota_update.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/ota_update.cpp b/wled00/ota_update.cpp index 5fa8dba4e5..0f7a65c012 100644 --- a/wled00/ota_update.cpp +++ b/wled00/ota_update.cpp @@ -318,10 +318,10 @@ String getBootloaderSHA256Hex() { char b2 = b1 >> 4; b1 &= 0x0F; b1 += '0'; b2 += '0'; - if (b1 > '9') b1 += 7; - if (b2 > '9') b2 += 7; - result.concat(b1); + if (b1 > '9') b1 += 39; + if (b2 > '9') b2 += 39; result.concat(b2); + result.concat(b1); } return std::move(result); } From 379343278d7f7ac639f9aecc12d22d9fe2c36ad5 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 27 Nov 2025 21:46:06 -0500 Subject: [PATCH 3/3] ota_update: Fix NRVO in getBootloaderSHA256Hex h/t @coderabbitai --- wled00/ota_update.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/ota_update.cpp b/wled00/ota_update.cpp index 0f7a65c012..ac4f83acb2 100644 --- a/wled00/ota_update.cpp +++ b/wled00/ota_update.cpp @@ -323,7 +323,7 @@ String getBootloaderSHA256Hex() { result.concat(b2); result.concat(b1); } - return std::move(result); + return result; } /**