Skip to content

Update using encrypted firmware binary does not appear to work #10205

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
victorfleischauer opened this issue Aug 19, 2024 · 2 comments
Closed
1 task done
Labels
Status: Awaiting triage Issue is waiting for triage

Comments

@victorfleischauer
Copy link

victorfleischauer commented Aug 19, 2024

Board

ESP32-S3-DevKitC-1

Device Description

ESP32-S3-DevKitC-1 v1.0

Hardware Configuration

No other hardware attached.

Version

3.0.4

IDE Name

PlatformIO

Operating System

Windows 11

Flash frequency

40Mhz

PSRAM enabled

no

Upload speed

460800

Description

Update using an encrypted firmware does not appear to work correctly as it seems to try to decrypt incorrectly.
When using a slightly modified version of the example sketch "OTAWebUpdater" to include

const uint8_t key[32] = {/* PUT YOUR KEY HERE */};
Update.setupCrypt(key, 0, 0, U_AES_DECRYPT_ON);

in void handleUpdate(), the update does not work and during it the error "Wrong Magic Byte" is printed repeatedly.

Proposed solution

By changing MBEDTLS_AES_ENCRYPT to MBEDTLS_AES_DECRYPT in line 331 of Updater.cpp the code works as expected.

Sketch

#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
#include <Ticker.h>
#include "html.h"

#define SSID_FORMAT "ESP32-%06lX"  // 12 chars total
//#define PASSWORD "test123456"    // generate if remarked

WebServer server(80);
Ticker tkSecond;
uint8_t otaDone = 0;

const char *alphanum = "0123456789!@#$%^&*abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String generatePass(uint8_t str_len) {
  String buff;
  for (int i = 0; i < str_len; i++) {
    buff += alphanum[random(strlen(alphanum) - 1)];
  }
  return buff;
}

void apMode() {
  char ssid[13];
  char passwd[11];
  long unsigned int espmac = ESP.getEfuseMac() >> 24;
  snprintf(ssid, 13, SSID_FORMAT, espmac);
#ifdef PASSWORD
  snprintf(passwd, 11, PASSWORD);
#else
  snprintf(passwd, 11, generatePass(10).c_str());
#endif
  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, passwd);  // Set up the SoftAP
  MDNS.begin("esp32");
  Serial.printf("AP: %s, PASS: %s\n", ssid, passwd);
}

void handleUpdateEnd() {
  server.sendHeader("Connection", "close");
  if (Update.hasError()) {
    server.send(502, "text/plain", Update.errorString());
  } else {
    server.sendHeader("Refresh", "10");
    server.sendHeader("Location", "/");
    server.send(307);
    ESP.restart();
  }
}

void handleUpdate() {
  size_t fsize = UPDATE_SIZE_UNKNOWN;
  if (server.hasArg("size")) {
    fsize = server.arg("size").toInt();
  }
  HTTPUpload &upload = server.upload();
  if (upload.status == UPLOAD_FILE_START) {
    Serial.printf("Receiving Update: %s, Size: %d\n", upload.filename.c_str(), fsize);
    if (!Update.begin(fsize)) {
      otaDone = 0;
      Update.printError(Serial);
    }

  const uint8_t key[32] = {/* PUT YOUR KEY HERE */};
  Update.setupCrypt(key, 0, 0, U_AES_DECRYPT_ON);


  } else if (upload.status == UPLOAD_FILE_WRITE) {
    if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
      Update.printError(Serial);
    } else {
      otaDone = 100 * Update.progress() / Update.size();
    }
  } else if (upload.status == UPLOAD_FILE_END) {
    if (Update.end(true)) {
      Serial.printf("Update Success: %u bytes\nRebooting...\n", upload.totalSize);
    } else {
      Serial.printf("%s\n", Update.errorString());
      otaDone = 0;
    }
  }
}

void webServerInit() {
  server.on(
    "/update", HTTP_POST,
    []() {
      handleUpdateEnd();
    },
    []() {
      handleUpdate();
    }
  );
  server.on("/favicon.ico", HTTP_GET, []() {
    server.sendHeader("Content-Encoding", "gzip");
    server.send_P(200, "image/x-icon", favicon_ico_gz, favicon_ico_gz_len);
  });
  server.onNotFound([]() {
    server.send(200, "text/html", indexHtml);
  });
  server.begin();
  Serial.printf("Web Server ready at http://esp32.local or http://%s\n", WiFi.localIP().toString().c_str());
}

void everySecond() {
  if (otaDone > 1) {
    Serial.printf("ota: %d%%\n", otaDone);
  }
}

void setup() {
  Serial.begin(115200);
  // apMode();
  // Either or
  WiFi.begin("SSID", "PASS");
  while(WiFi.status() != WL_CONNECTED)
  {
    Serial.println("Waiting for connection");
    delay(1000);
  }

  webServerInit();
  tkSecond.attach(1, everySecond);
}

void loop() {
  delay(150);
  server.handleClient();
}

Debug Message

Wrong Magic Byte
Wrong Magic Byte
Wrong Magic Byte
...

Other Steps to Reproduce

Having an encrypted binary along with its key is of course necessary.

platformio.ini:

[env:esp32-s3-devkitc-1]
platform = https://github.com/pioarduino/platform-espressif32/releases/download/51.03.04/platform-espressif32.zip
framework = arduino
board = esp32-s3-devkitc-1
monitor_speed = 115200

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.
@victorfleischauer
Copy link
Author

I have opened a pull request that implements the change I proposed, in case this is indeed not the intended behavior

@lucasssvaz
Copy link
Collaborator

AES algorithm is used inverted in flash encryption, so the flash encryption "encrypt" operation is AES decrypt and the "decrypt" operation is AES encrypt. This is for performance reasons and does not alter the effeciency of the algorithm.

This is intended. You can read more about it here:
https://docs.espressif.com/projects/esp-idf/en/release-v5.1/esp32/security/flash-encryption.html#flash-encryption-algorithm

I would suggest trying this example as I tested it when it was added and everything was working as intended:
https://github.com/espressif/arduino-esp32/blob/master/libraries/Update/examples/HTTP_Client_AES_OTA_Update/HTTP_Client_AES_OTA_Update.ino

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Awaiting triage Issue is waiting for triage
Projects
None yet
Development

No branches or pull requests

2 participants