diff --git a/cores/esp32/Esp.cpp b/cores/esp32/Esp.cpp
index 9e5dbc25254..60e4490d72e 100644
--- a/cores/esp32/Esp.cpp
+++ b/cores/esp32/Esp.cpp
@@ -30,6 +30,7 @@
 extern "C" {
 #include <esp_image_format.h>
 }
+#include <MD5Builder.h>
 
 /**
  * User-defined Literals
@@ -158,9 +159,9 @@ static uint32_t sketchSize(sketchSize_t response) {
     data.start_addr = running_pos.offset;
     esp_image_verify(ESP_IMAGE_VERIFY, &running_pos, &data);
     if (response) {
-    return running_pos.size - data.image_len;
+        return running_pos.size - data.image_len;
     } else {
-    return data.image_len;
+        return data.image_len;
     }
 }
     
@@ -168,6 +169,38 @@ uint32_t EspClass::getSketchSize () {
     return sketchSize(SKETCH_SIZE_TOTAL);
 }
 
+String EspClass::getSketchMD5()
+{
+    static String result;
+    if (result.length()) {
+        return result;
+    }
+    uint32_t lengthLeft = getSketchSize();
+
+    const esp_partition_t *running = esp_ota_get_running_partition();
+    if (!running) return String();
+    const size_t bufSize = SPI_FLASH_SEC_SIZE;
+    std::unique_ptr<uint8_t[]> buf(new uint8_t[bufSize]);
+    uint32_t offset = 0;
+    if(!buf.get()) {
+        return String();
+    }
+    MD5Builder md5;
+    md5.begin();
+    while( lengthLeft > 0) {
+        size_t readBytes = (lengthLeft < bufSize) ? lengthLeft : bufSize;
+        if (!ESP.flashRead(running->address + offset, reinterpret_cast<uint32_t*>(buf.get()), (readBytes + 3) & ~3)) {
+            return String();
+        }
+        md5.add(buf.get(), readBytes);
+        lengthLeft -= readBytes;
+        offset += readBytes;
+    }
+    md5.calculate();
+    result = md5.toString();
+    return result;
+}
+
 uint32_t EspClass::getFreeSketchSpace () {
     const esp_partition_t* _partition = esp_ota_get_next_update_partition(NULL);
     if(!_partition){
diff --git a/cores/esp32/Esp.h b/cores/esp32/Esp.h
index 385bcbb4b1f..f8e7b9cfe70 100644
--- a/cores/esp32/Esp.h
+++ b/cores/esp32/Esp.h
@@ -90,6 +90,7 @@ class EspClass
     FlashMode_t magicFlashChipMode(uint8_t byte);
 
     uint32_t getSketchSize();
+    String getSketchMD5();
     uint32_t getFreeSketchSpace();
 
     bool flashEraseSector(uint32_t sector);
diff --git a/libraries/HTTPUpdate/src/HTTPUpdate.cpp b/libraries/HTTPUpdate/src/HTTPUpdate.cpp
index dd4f8623689..0163c768ec7 100644
--- a/libraries/HTTPUpdate/src/HTTPUpdate.cpp
+++ b/libraries/HTTPUpdate/src/HTTPUpdate.cpp
@@ -181,8 +181,8 @@ HTTPUpdateResult HTTPUpdate::handleUpdate(HTTPClient& http, const String& curren
     http.addHeader("x-ESP32-AP-MAC", WiFi.softAPmacAddress());
     http.addHeader("x-ESP32-free-space", String(ESP.getFreeSketchSpace()));
     http.addHeader("x-ESP32-sketch-size", String(ESP.getSketchSize()));
-// To do    http.addHeader("x-ESP32-sketch-md5", String(ESP.getSketchMD5()));
-    // Sketch MD5 is not supported by the core, but SHA256 is, so add a SHA256 instead
+    http.addHeader("x-ESP32-sketch-md5", String(ESP.getSketchMD5()));
+    // Add also a SHA256
     String sketchSHA256 = getSketchSHA256();
     if(sketchSHA256.length() != 0) {
       http.addHeader("x-ESP32-sketch-sha256", sketchSHA256);