Skip to content
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

Encryption #28

Merged
merged 10 commits into from
Apr 11, 2024
7 changes: 2 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
**/[Ss]ecrets*
**/[Ss]ecret*
**/[Cc]erts.h
**/[Cc]ert.h

noisemeter-device/config.h
noisemeter-device/secret.h
noisemeter-device/certs.h
hardware/pcb-*/noisemeter-backups
hardware/pcb-*/production
hardware/pcb-*/fp-info-cache
Expand Down
21 changes: 21 additions & 0 deletions noisemeter-device/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,33 @@ const char* API_TOKEN = "Your API token here";

## Code compiling and upload

### PlatformIO

1. [Install PlatformIO](https://platformio.org/install).

2. Run `pio run` to compile for the PCB. A breadboard target is available too: `pio run -e esp32-breadboard`.

3. Run `pio run -t upload` to upload to the device (this also compiles the code if there have been any changes).

### Arduino

1. Install the Arduino IDE and [follow these instructions](https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html) to add support for ESP32 microcontrollers.

2. Under "Tools" > "Board: " > "ESP32 Arduino", select either "ESP32C3 Dev Module" for the PCB boards or "ESP32-WROOM-DA Module" for the ESP32 breadboard prototype.

3. Compile the sketch and upload it to the device.

## HMAC encryption key

Data stored on the device (e.g. WiFi credentials) are encrypted with an "eFuse" key. This key can only be written once, and is not be read or written after that.

Using PlatformIO:

```bash
dd if=/dev/urandom of=hmac_key bs=1 count=32
pio pkg exec -- espefuse.py --port /dev/ttyACM0 burn_key BLOCK4 hmac_key HMAC_UP
```

# Operating Instructions:

- Power on the device by connecting it to power. The device should start in Hotspot mode.
Expand Down
31 changes: 17 additions & 14 deletions noisemeter-device/noisemeter-device.ino
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <WiFiClientSecure.h>
#include <dummy.h> // ESP32 core
#include <driver/i2s.h> // ESP32 core
#include <mbedtls/aes.h>
#include <esp_efuse.h>
#include <esp_efuse_table.h>

Expand All @@ -25,6 +26,7 @@
#include "sos-iir-filter.h"
#include "certs.h"
#include "secret.h"
#include "secret-store.h"
#include "storage.h"
#include "ota-update.h"
#include "UUID/UUID.h"
Expand Down Expand Up @@ -281,21 +283,17 @@ void printReadingToConsole(double reading) {
void saveNetworkCreds(WebServer& httpServer) {
// Confirm that the form was actually submitted.
if (httpServer.hasArg("ssid") && httpServer.hasArg("psk")) {
const auto ssid = httpServer.arg("ssid");
const auto psk = httpServer.arg("psk");
const auto id = String(buildDeviceId());
const auto ssid = Secret::encrypt(id, httpServer.arg("ssid"));
const auto psk = Secret::encrypt(id, httpServer.arg("psk"));

// Confirm that the given credentials will fit in the allocated EEPROM space.
if (!ssid.isEmpty() && Creds.canStore(ssid) && Creds.canStore(psk)) {
Creds.set(Storage::Entry::SSID, ssid);
Creds.set(Storage::Entry::Passkey, psk);
Creds.commit();

SERIAL.print("Saving ");
SERIAL.println(Creds);

SERIAL.println("Saved network credentials. Restarting...");
delay(2000);
ESP.restart(); // Software reset.
ESP.restart(); // Software reset.
}
}

Expand All @@ -312,16 +310,21 @@ UUID buildDeviceId()

int tryWifiConnection()
{
const auto ssid = Creds.get(Storage::Entry::SSID);
//const auto ssid = Creds.get(Storage::Entry::SSID);

if (ssid.isEmpty())
return -1;
//if (ssid.isEmpty())
// return -1;

SERIAL.print("Ready to connect to ");
SERIAL.println(ssid);
//SERIAL.print("Ready to connect to ");
//SERIAL.println(ssid);

const auto ssid = Creds.get(Storage::Entry::SSID);
const auto psk = Creds.get(Storage::Entry::Passkey);

WiFi.mode(WIFI_STA);
if (WiFi.begin(ssid.c_str(), Creds.get(Storage::Entry::Passkey).c_str()) == WL_CONNECT_FAILED)
const auto id = String(buildDeviceId());
const auto stat = WiFi.begin(Secret::decrypt(id, ssid).c_str(), Secret::decrypt(id, psk).c_str());
if (stat == WL_CONNECT_FAILED)
return -1;

// wait for WiFi connection
Expand Down
72 changes: 72 additions & 0 deletions noisemeter-device/secret-store.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "board.h"
#include "secret-store.h"

#if defined(BOARD_ESP32_PCB)

#include <esp_hmac.h>
#include <mbedtls/aes.h>

constexpr static unsigned BITS = 256; // do not change

namespace Secret {

String encrypt(String key, String in)
{
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);

const auto kb = key.c_str();
const auto kl = key.length();
{
uint8_t hmac[BITS / 8];
esp_hmac_calculate(HMAC_KEY0, kb, kl, hmac);
mbedtls_aes_setkey_enc(&aes, hmac, BITS);
}

char out[in.length()];
mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT,
reinterpret_cast<const uint8_t *>(in.c_str()),
reinterpret_cast<uint8_t *>(out));
return out;
}

String decrypt(String key, String in)
{
mbedtls_aes_context aes;
mbedtls_aes_init(&aes);

const auto kb = key.c_str();
const auto kl = key.length();
{
uint8_t hmac[BITS / 8];
esp_hmac_calculate(HMAC_KEY0, kb, kl, hmac);
mbedtls_aes_setkey_dec(&aes, hmac, BITS);
}

char out[in.length()];
mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_DECRYPT,
reinterpret_cast<const uint8_t *>(in.c_str()),
reinterpret_cast<uint8_t *>(out));
return out;
}

} // namespace Secret

#else // !defined(BOARD_ESP32_PCB)

namespace Secret {

String encrypt([[maybe_unused]] String key, String in)
{
return in;
}

String decrypt([[maybe_unused]] String key, String in)
{
return in;
}

} // namespace Secret

#endif // defined(BOARD_ESP32_PCB)

13 changes: 13 additions & 0 deletions noisemeter-device/secret-store.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef SECRET_STORE_H
#define SECRET_STORE_H

#include <WString.h>

namespace Secret
{
String encrypt(String key, String in);
String decrypt(String key, String in);
}

#endif // SECRET_STORE_H