Skip to content

Commit af0651d

Browse files
committed
feat(config): secure storage
Make a "secure storage", eeprom emulation This storage is used for wifi creds or api keys We need to make a salted hardware based later
1 parent c533d7a commit af0651d

6 files changed

Lines changed: 354 additions & 26 deletions

File tree

include/config/ConfigManager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#define CONFIG_MANAGER_H
2222

2323
#include <ArduinoJson.h>
24+
#include "config/SecureStorage.h"
2425
#include <string>
2526
#include <cstdint>
2627

@@ -65,6 +66,7 @@ class ConfigManager {
6566
uint32_t getLCDSpiHz() const;
6667
int8_t getLCDBacklightGpio() const;
6768
bool getLCDBacklightActiveLow() const;
69+
bool migrateWiFiToSecureStorage(String ssid, String password);
6870

6971
public:
7072
bool getLCDEnableSafe() const { return lcd_enable; }
@@ -88,6 +90,7 @@ class ConfigManager {
8890
std::string ssid;
8991
std::string password;
9092
std::string filename;
93+
SecureStorage secure;
9194
bool lcd_enable = true;
9295
int16_t lcd_w = 240;
9396
int16_t lcd_h = 240;

include/config/SecureStorage.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// SPDX-License-Identifier: GPL-3.0-or-later
2+
/*
3+
* GeekMagic Open Firmware
4+
* Copyright (C) 2026 Times-Z
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
#ifndef SECURE_STORAGE_H
21+
#define SECURE_STORAGE_H
22+
23+
#include <Arduino.h>
24+
#include <ArduinoJson.h>
25+
26+
class SecureStorage {
27+
public:
28+
SecureStorage(size_t eepromSize = 2048);
29+
bool begin();
30+
bool put(const char* key, const char* value);
31+
bool remove(const char* key);
32+
String get(const char* key, const char* defaultValue = nullptr);
33+
34+
private:
35+
size_t _eepromSize;
36+
bool loadToMemory();
37+
bool flushToEEPROM();
38+
JsonDocument _doc;
39+
bool _ready = false;
40+
};
41+
42+
#endif // SECURE_STORAGE_H

readme.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,15 @@ From there, select and flash the filesystem using the `littlefs.bin` file
275275

276276
Once the device reboots, the setup is complete!
277277

278+
Note: The Wi-Fi credentials in config.json are migrated to EEPROM “secure storage” on first boot. After that, the Wi-Fi credentials are erased from config.json
279+
280+
Data stored in EEPROM (or flash-based EEPROM emulation) is not secure by default
281+
All values (API keys, Wi-Fi credentials, tokens, etc.) are currently stored in clear text and can be recovered by anyone with physical access to the device or the ability to read the flash memory
282+
283+
This project does not provide hardware-backed security
284+
285+
Do not assume confidentiality against a determined attacker
286+
278287
## License
279288

280289
This project is licensed under the **GPLv3 License** - see the [LICENSE](LICENSE) file for details

src/config/ConfigManager.cpp

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@
2222

2323
#include <Logger.h>
2424
#include "config/ConfigManager.h"
25+
#include "config/SecureStorage.h"
2526

26-
ConfigManager::ConfigManager(const char* filename) : filename(filename) {}
27+
ConfigManager::ConfigManager(const char* filename) : filename(filename), secure() {}
2728

2829
/**
2930
* @brief Loads the configuration from a file stored in SPIFFS
@@ -61,25 +62,44 @@ auto ConfigManager::load() -> bool {
6162
return false;
6263
}
6364

64-
ssid = doc["wifi_ssid"].as<const char*>();
65-
password = doc["wifi_password"].as<const char*>();
66-
67-
lcd_enable = doc["lcd_enable"] | lcd_enable;
68-
lcd_w = doc["lcd_w"] | lcd_w;
69-
lcd_h = doc["lcd_h"] | lcd_h;
70-
lcd_rotation = doc["lcd_rotation"] | lcd_rotation;
71-
lcd_mosi_gpio = doc["lcd_mosi_gpio"] | lcd_mosi_gpio;
72-
lcd_sck_gpio = doc["lcd_sck_gpio"] | lcd_sck_gpio;
73-
lcd_cs_gpio = doc["lcd_cs_gpio"] | lcd_cs_gpio;
74-
lcd_dc_gpio = doc["lcd_dc_gpio"] | lcd_dc_gpio;
75-
lcd_rst_gpio = doc["lcd_rst_gpio"] | lcd_rst_gpio;
76-
lcd_cs_active_high = doc["lcd_cs_active_high"] | lcd_cs_active_high;
77-
lcd_dc_cmd_high = doc["lcd_dc_cmd_high"] | lcd_dc_cmd_high;
78-
lcd_spi_mode = doc["lcd_spi_mode"] | lcd_spi_mode;
79-
lcd_keep_cs_asserted = doc["lcd_keep_cs_asserted"] | lcd_keep_cs_asserted;
80-
lcd_spi_hz = doc["lcd_spi_hz"] | lcd_spi_hz;
81-
lcd_backlight_gpio = doc["lcd_backlight_gpio"] | lcd_backlight_gpio;
82-
lcd_backlight_active_low = doc["lcd_backlight_active_low"] | lcd_backlight_active_low;
65+
String ssid = doc["wifi_ssid"] | "";
66+
String password = doc["wifi_password"] | "";
67+
68+
this->lcd_enable = doc["lcd_enable"] | lcd_enable;
69+
this->lcd_w = doc["lcd_w"] | lcd_w;
70+
this->lcd_h = doc["lcd_h"] | lcd_h;
71+
this->lcd_rotation = doc["lcd_rotation"] | lcd_rotation;
72+
this->lcd_mosi_gpio = doc["lcd_mosi_gpio"] | lcd_mosi_gpio;
73+
this->lcd_sck_gpio = doc["lcd_sck_gpio"] | lcd_sck_gpio;
74+
this->lcd_cs_gpio = doc["lcd_cs_gpio"] | lcd_cs_gpio;
75+
this->lcd_dc_gpio = doc["lcd_dc_gpio"] | lcd_dc_gpio;
76+
this->lcd_rst_gpio = doc["lcd_rst_gpio"] | lcd_rst_gpio;
77+
this->lcd_cs_active_high = doc["lcd_cs_active_high"] | lcd_cs_active_high;
78+
this->lcd_dc_cmd_high = doc["lcd_dc_cmd_high"] | lcd_dc_cmd_high;
79+
this->lcd_spi_mode = doc["lcd_spi_mode"] | lcd_spi_mode;
80+
this->lcd_keep_cs_asserted = doc["lcd_keep_cs_asserted"] | lcd_keep_cs_asserted;
81+
this->lcd_spi_hz = doc["lcd_spi_hz"] | lcd_spi_hz;
82+
this->lcd_backlight_gpio = doc["lcd_backlight_gpio"] | lcd_backlight_gpio;
83+
this->lcd_backlight_active_low = doc["lcd_backlight_active_low"] | lcd_backlight_active_low;
84+
85+
String nvs_ssid = secure.get("wifi_ssid", "");
86+
String nvs_password = secure.get("wifi_password", "");
87+
88+
if ((ssid.length() != 0 && nvs_ssid.length() == 0) || (password.length() != 0 && nvs_password.length() == 0)) {
89+
secure.put("wifi_ssid", ssid.c_str());
90+
secure.put("wifi_password", password.c_str());
91+
92+
this->ssid = secure.get("wifi_ssid").c_str();
93+
this->password = secure.get("wifi_password").c_str();
94+
95+
// Ensure we delete the wifi credentials from the json config after migrating
96+
ConfigManager::save();
97+
98+
Logger::info("WiFi credentials migrated to SecureStorage", "ConfigManager");
99+
} else {
100+
this->ssid = secure.get("wifi_ssid").c_str();
101+
this->password = secure.get("wifi_password").c_str();
102+
}
83103

84104
return true;
85105
}
@@ -226,6 +246,8 @@ auto ConfigManager::setWiFi(const char* newSsid, const char* newPassword) -> voi
226246
/**
227247
* @brief Save the current configuration to the file
228248
*
249+
* @param clearWifiCreds If true wifi credentials will be cleared from json config
250+
*
229251
* @return true if the configuration was successfully saved false otherwise
230252
*/
231253
auto ConfigManager::save() -> bool {
@@ -245,11 +267,9 @@ auto ConfigManager::save() -> bool {
245267

246268
JsonDocument doc;
247269

248-
doc["wifi_ssid"] = ssid.c_str();
249-
doc["wifi_password"] = password.c_str();
250-
doc["lcd_enable"] = lcd_enable;
251-
doc["lcd_w"] = lcd_w;
252-
doc["lcd_h"] = lcd_h;
270+
secure.put("wifi_ssid", this->getSSID());
271+
secure.put("wifi_password", this->getPassword());
272+
253273
doc["lcd_rotation"] = lcd_rotation;
254274

255275
if (serializeJson(doc, file) == 0) {
@@ -264,3 +284,21 @@ auto ConfigManager::save() -> bool {
264284

265285
return true;
266286
}
287+
288+
/**
289+
* @brief Migrate WiFi credentials to SecureStorage
290+
*
291+
* @param ssid The SSID to store
292+
* @param password The password to store
293+
* @return true on success false on failure
294+
*/
295+
auto ConfigManager::migrateWiFiToSecureStorage(String ssid, String password) -> bool {
296+
secure.put("wifi_ssid", ssid.c_str());
297+
secure.put("wifi_password", password.c_str());
298+
299+
ConfigManager::save();
300+
301+
Logger::info("WiFi credentials migrated to SecureStorage", "ConfigManager");
302+
303+
return true;
304+
}

0 commit comments

Comments
 (0)