diff --git a/noisemeter-device/UUID/UUID.cpp b/noisemeter-device/UUID/UUID.cpp index ac1e4e3..56e56ff 100644 --- a/noisemeter-device/UUID/UUID.cpp +++ b/noisemeter-device/UUID/UUID.cpp @@ -75,7 +75,7 @@ void UUID::generate() } -char * UUID::toCharArray() +const char * UUID::toCharArray() const { // if (_upperCase) // { diff --git a/noisemeter-device/UUID/UUID.h b/noisemeter-device/UUID/UUID.h index 8b15704..0895ca2 100644 --- a/noisemeter-device/UUID/UUID.h +++ b/noisemeter-device/UUID/UUID.h @@ -47,11 +47,11 @@ class UUID : public Printable * Make a UUID string * @return String representation of UUID */ - char * toCharArray(); + const char * toCharArray() const; /** * Implicit conversion to a String object. */ - operator String() { + operator String() const { return toCharArray(); } diff --git a/noisemeter-device/config.h.example b/noisemeter-device/config.h.example index 2ec53a8..4584af3 100644 --- a/noisemeter-device/config.h.example +++ b/noisemeter-device/config.h.example @@ -17,8 +17,8 @@ #ifndef CONFIG_H #define CONFIG_H -// Uncomment to print passkey over serial (for debugging). -//#define STORAGE_SHOW_PASSKEY +// Uncomment to print credentials over serial (for debugging). +//#define STORAGE_SHOW_CREDENTIALS // Define only *one* of the follwoing board options. // If using PlatformIO, the selected 'env' will override this selection. diff --git a/noisemeter-device/noisemeter-device.ino b/noisemeter-device/noisemeter-device.ino index 66ae3f7..a4ef60d 100644 --- a/noisemeter-device/noisemeter-device.ino +++ b/noisemeter-device/noisemeter-device.ino @@ -31,7 +31,6 @@ #include "certs.h" #include "secret.h" #include "spl-meter.h" -#include "secret-store.h" #include "storage.h" #include "ota-update.h" #include "UUID/UUID.h" @@ -151,7 +150,10 @@ void setup() { SERIAL.println(buildDeviceId()); SERIAL.println("Initializing..."); - Creds.begin(); + Creds.begin(buildDeviceId()); +#ifdef STORAGE_SHOW_CREDENTIALS + SERIAL.println(Creds); +#endif SPL.initMicrophone(); packets.emplace_front(); @@ -299,9 +301,8 @@ void printReadingToConsole(double reading) { void saveNetworkCreds(WebServer& httpServer) { // Confirm that the form was actually submitted. if (httpServer.hasArg("ssid") && httpServer.hasArg("psk")) { - const auto id = String(buildDeviceId()); - const auto ssid = Secret::encrypt(id, httpServer.arg("ssid")); - const auto psk = Secret::encrypt(id, httpServer.arg("psk")); + const auto ssid = httpServer.arg("ssid"); + const auto psk = httpServer.arg("psk"); // Confirm that the given credentials will fit in the allocated EEPROM space. if (!ssid.isEmpty() && Creds.canStore(ssid) && Creds.canStore(psk)) { @@ -326,20 +327,8 @@ UUID buildDeviceId() int tryWifiConnection() { - //const auto ssid = Creds.get(Storage::Entry::SSID); - - //if (ssid.isEmpty()) - // return -1; - - //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); - const auto id = String(buildDeviceId()); - const auto stat = WiFi.begin(Secret::decrypt(id, ssid).c_str(), Secret::decrypt(id, psk).c_str()); + const auto stat = WiFi.begin(Creds.get(Storage::Entry::SSID).c_str(), Creds.get(Storage::Entry::Passkey).c_str()); if (stat == WL_CONNECT_FAILED) return -1; diff --git a/noisemeter-device/secret-store.cpp b/noisemeter-device/secret-store.cpp index 4cdf479..012e70e 100644 --- a/noisemeter-device/secret-store.cpp +++ b/noisemeter-device/secret-store.cpp @@ -14,75 +14,61 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "board.h" #include "secret-store.h" +#include "board.h" #if defined(BOARD_ESP32_PCB) #include #include -constexpr static unsigned BITS = 256; // do not change - -namespace Secret { - -String encrypt(String key, String in) +void SecretStore::encrypt(const char *in, uint8_t *out, unsigned N) const noexcept { mbedtls_aes_context aes; mbedtls_aes_init(&aes); - const auto kb = key.c_str(); - const auto kl = key.length(); + String k (key); { uint8_t hmac[BITS / 8]; - esp_hmac_calculate(HMAC_KEY0, kb, kl, hmac); + esp_hmac_calculate(HMAC_KEY0, k.c_str(), k.length(), hmac); mbedtls_aes_setkey_enc(&aes, hmac, BITS); } - char out[in.length()]; - mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_ENCRYPT, - reinterpret_cast(in.c_str()), - reinterpret_cast(out)); - return out; + uint8_t iv[16]; + mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, N, iv, + reinterpret_cast(in), out); } -String decrypt(String key, String in) +void SecretStore::decrypt(const uint8_t *in, char *out, unsigned N) const noexcept { mbedtls_aes_context aes; mbedtls_aes_init(&aes); - const auto kb = key.c_str(); - const auto kl = key.length(); + String k (key); { uint8_t hmac[BITS / 8]; - esp_hmac_calculate(HMAC_KEY0, kb, kl, hmac); + esp_hmac_calculate(HMAC_KEY0, k.c_str(), k.length(), hmac); mbedtls_aes_setkey_dec(&aes, hmac, BITS); } - char out[in.length()]; - mbedtls_aes_crypt_ecb(&aes, MBEDTLS_AES_DECRYPT, - reinterpret_cast(in.c_str()), - reinterpret_cast(out)); - return out; + uint8_t iv[16]; + mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, N, iv, + in, reinterpret_cast(out)); } -} // namespace Secret - #else // !defined(BOARD_ESP32_PCB) -namespace Secret { +#include -String encrypt([[maybe_unused]] String key, String in) +void SecretStore::encrypt(const char *in, uint8_t *out, unsigned N) const noexcept { - return in; + std::copy(in, in + N, out); } -String decrypt([[maybe_unused]] String key, String in) +void SecretStore::decrypt(const uint8_t *in, char *out, unsigned N) const noexcept { - return in; + std::copy(in, in + N, out); } -} // namespace Secret - #endif // defined(BOARD_ESP32_PCB) diff --git a/noisemeter-device/secret-store.h b/noisemeter-device/secret-store.h index 54e7c2e..4bed509 100644 --- a/noisemeter-device/secret-store.h +++ b/noisemeter-device/secret-store.h @@ -19,28 +19,31 @@ #ifndef SECRET_STORE_H #define SECRET_STORE_H -#include +#include "UUID/UUID.h" -namespace Secret +struct SecretStore { + UUID key; + /** - * Encrypts the given string with the given key. - * Uses the HMAC peripheral to modify the key in a secure way. - * @param key Key to use for encryption. - * @param in String of data to be encrypted. - * @return The encrypted string. + * Securely encrypts the given string. + * @param in Pointer to `len` bytes of input data. + * @param out Pre-allocated buffer to store encrypted output. + * @param len Number of bytes to process. */ - String encrypt(String key, String in); + void encrypt(const char *in, uint8_t *out, unsigned int len) const noexcept; /** - * Decrypts the given string with the given key. - * Uses the HMAC peripheral to modify the key in a secure way. - * @param key Key to use for decryption. - * @param in String of data to be decrypted. - * @return The decrypted string. + * Securely decrypts the given string. + * @param in Pointer to `len` bytes of input data. + * @param out Pre-allocated buffer to store decrypted output. + * @param len Number of bytes to process. */ - String decrypt(String key, String in); -} + void decrypt(const uint8_t *in, char *out, unsigned int len) const noexcept; + +private: + constexpr static unsigned BITS = 256; // do not change +}; #endif // SECRET_STORE_H diff --git a/noisemeter-device/storage.cpp b/noisemeter-device/storage.cpp index 3c18154..2d99aef 100644 --- a/noisemeter-device/storage.cpp +++ b/noisemeter-device/storage.cpp @@ -14,15 +14,18 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +#include "config.h" #include "storage.h" #include #include -#include +#include -void Storage::begin() noexcept +void Storage::begin(UUID key) { + secret.key = key; + EEPROMClass::begin(addrOf(Entry::TotalSize)); delay(2000); // Ensure the eeprom peripheral has enough time to initialize. } @@ -50,16 +53,20 @@ void Storage::clear() noexcept String Storage::get(Entry entry) const noexcept { - if (entry != Entry::Checksum) - return String(_data + addrOf(entry), StringSize - 1); - else + if (entry != Entry::Checksum) { + std::array buf; + secret.decrypt(_data + addrOf(entry), buf.data(), StringSize); + return buf.data(); + } else { return {}; + } } void Storage::set(Entry entry, String str) noexcept { - if (entry != Entry::Checksum && canStore(str)) - writeBytes(addrOf(entry), str.begin(), StringSize); + if (entry != Entry::Checksum && canStore(str)) { + secret.encrypt(str.c_str(), _data + addrOf(entry), StringSize); + } } void Storage::commit() noexcept @@ -69,15 +76,15 @@ void Storage::commit() noexcept EEPROMClass::commit(); } +#ifdef STORAGE_SHOW_CREDENTIALS Storage::operator String() const noexcept { return String() + "SSID \"" + get(Entry::SSID) + -#ifdef STORAGE_SHOW_PASSKEY "\" Passkey \"" + get(Entry::Passkey) + -#endif '\"'; } +#endif uint32_t Storage::calculateChecksum() const noexcept { diff --git a/noisemeter-device/storage.h b/noisemeter-device/storage.h index 1d597ca..dc3f9d4 100644 --- a/noisemeter-device/storage.h +++ b/noisemeter-device/storage.h @@ -19,6 +19,8 @@ #ifndef STORAGE_H #define STORAGE_H +#include "secret-store.h" + #include #include @@ -42,9 +44,10 @@ class Storage : protected EEPROMClass }; /** - * Prepares flash memory for access. + * Initializes the instance and prepares flash memory for access. + * @param key Key (i.e. seed) to use for encryption */ - void begin() noexcept; + void begin(UUID key); /** * Validates the stored settings against the stored checksum. @@ -83,12 +86,17 @@ class Storage : protected EEPROMClass */ void commit() noexcept; +#ifdef STORAGE_SHOW_CREDENTIALS /** * Returns a string describing the stored settings. */ operator String() const noexcept; +#endif private: + /** Encryption instance. */ + SecretStore secret; + /** * Calculates a CRC32 checksum of all stored settings. * @return The checksum for the stored settings