@@ -273,18 +273,18 @@ void markOTAvalid() {
273273}
274274
275275#if defined(ARDUINO_ARCH_ESP32) && !defined(WLED_DISABLE_OTA)
276- // Cache for bootloader SHA256 digest as hex string
277- static String bootloaderSHA256HexCache = " " ;
278-
279- // Calculate and cache the bootloader SHA256 digest as hex string
280- void calculateBootloaderSHA256 () {
281- if (!bootloaderSHA256HexCache.isEmpty ()) return ;
276+ static bool bootloaderSHA256CacheValid = false ;
277+ static uint8_t bootloaderSHA256Cache[32 ];
282278
279+ /* *
280+ * Calculate and cache the bootloader SHA256 digest
281+ * Reads the bootloader from flash at offset 0x1000 and computes SHA256 hash
282+ */
283+ static void calculateBootloaderSHA256 () {
283284 // Bootloader is at fixed offset 0x1000 (4KB) and is typically 32KB
284285 const uint32_t bootloaderSize = 0x8000 ; // 32KB, typical bootloader size
285286
286287 // Calculate SHA256
287- uint8_t sha256[32 ];
288288 mbedtls_sha256_context ctx;
289289 mbedtls_sha256_init (&ctx);
290290 mbedtls_sha256_starts (&ctx, 0 ); // 0 = SHA256 (not SHA224)
@@ -299,33 +299,50 @@ void calculateBootloaderSHA256() {
299299 }
300300 }
301301
302- mbedtls_sha256_finish (&ctx, sha256 );
302+ mbedtls_sha256_finish (&ctx, bootloaderSHA256Cache );
303303 mbedtls_sha256_free (&ctx);
304-
305- // Convert to hex string and cache it
306- char hex[65 ];
307- for (int i = 0 ; i < 32 ; i++) {
308- sprintf (hex + (i * 2 ), " %02x" , sha256[i]);
309- }
310- hex[64 ] = ' \0 ' ;
311- bootloaderSHA256HexCache = String (hex);
304+ bootloaderSHA256CacheValid = true ;
312305}
313306
314307// Get bootloader SHA256 as hex string
315308String getBootloaderSHA256Hex () {
316- calculateBootloaderSHA256 ();
317- return bootloaderSHA256HexCache;
309+ if (!bootloaderSHA256CacheValid) {
310+ calculateBootloaderSHA256 ();
311+ }
312+
313+ // Convert to hex string
314+ String result;
315+ result.reserve (65 );
316+ for (int i = 0 ; i < 32 ; i++) {
317+ char b1 = bootloaderSHA256Cache[i];
318+ char b2 = b1 >> 4 ;
319+ b1 &= 0x0F ;
320+ b1 += ' 0' ; b2 += ' 0' ;
321+ if (b1 > ' 9' ) b1 += 7 ;
322+ if (b2 > ' 9' ) b2 += 7 ;
323+ result.concat (b1);
324+ result.concat (b2);
325+ }
326+ return std::move (result);
318327}
319328
320- // Invalidate cached bootloader SHA256 (call after bootloader update)
321- void invalidateBootloaderSHA256Cache () {
322- bootloaderSHA256HexCache = " " ;
329+ /* *
330+ * Invalidate cached bootloader SHA256 (call after bootloader update)
331+ * Forces recalculation on next call to calculateBootloaderSHA256 or getBootloaderSHA256Hex
332+ */
333+ static void invalidateBootloaderSHA256Cache () {
334+ bootloaderSHA256CacheValid = false ;
323335}
324336
325- // Verify complete buffered bootloader using ESP-IDF validation approach
326- // This matches the key validation steps from esp_image_verify() in ESP-IDF
327- // Returns the actual bootloader data pointer and length via the buffer and len parameters
328- bool verifyBootloaderImage (const uint8_t * &buffer, size_t &len, String* bootloaderErrorMsg) {
337+ /* *
338+ * Verify complete buffered bootloader using ESP-IDF validation approach
339+ * This matches the key validation steps from esp_image_verify() in ESP-IDF
340+ * @param buffer Reference to pointer to bootloader binary data (will be adjusted if offset detected)
341+ * @param len Reference to length of bootloader data (will be adjusted to actual size)
342+ * @param bootloaderErrorMsg Pointer to String to store error message (must not be null)
343+ * @return true if validation passed, false otherwise
344+ */
345+ static bool verifyBootloaderImage (const uint8_t * &buffer, size_t &len, String* bootloaderErrorMsg) {
329346 size_t availableLen = len;
330347 if (!bootloaderErrorMsg) {
331348 DEBUG_PRINTLN (F (" bootloaderErrorMsg is null" ));
0 commit comments