Tactility/tactility-headless/src/services/wifi/wifi_credentials_esp.c
Ken Van Hoeylandt 27730260e0
Project restructuring: add tactility-headless (#55)
- Created `tactility-headless` to support ESP32 firmwares that don't require graphics
- `tactility` subproject now contains both PC and ESP32 code (to avoid having to split up `tactility` and `tactility-headless` into separate projects, which would result in a very complex dependency tree)
- `tactility` subproject is now defined as component for ESP32 and as regular module for PC
- Improvements for dispatcher
- Added `project-structure.puml` to docs
- `Gui` service now depends on `Loader` service instead of the reverse
- Added `statusbar_updater` service for updating Wi-Fi and SD card icons
2024-08-31 17:56:28 +02:00

235 lines
6.7 KiB
C

#ifdef ESP_TARGET
#include "wifi_credentials.h"
#include "nvs_flash.h"
#include "log.h"
#include "hash.h"
#include "check.h"
#include "mutex.h"
#include "secure.h"
#define TAG "wifi_credentials"
#define TT_NVS_NAMESPACE "tt_wifi_cred" // limited by NVS_KEY_NAME_MAX_SIZE
#define TT_NVS_PARTITION "nvs"
static void hash_reset_all();
// region Hash
static Mutex* hash_mutex = NULL;
static int8_t hash_index = -1;
static uint32_t hashes[TT_WIFI_CREDENTIALS_LIMIT] = { 0 };
static void hash_init() {
tt_assert(hash_mutex == NULL);
hash_mutex = tt_mutex_alloc(MutexTypeNormal);
hash_reset_all();
}
static void tt_hash_mutex_lock() {
tt_assert(tt_mutex_acquire(hash_mutex, 100) == TtStatusOk);
}
static void tt_hash_mutex_unlock() {
tt_assert(tt_mutex_release(hash_mutex) == TtStatusOk);
}
static int hash_find_value(uint32_t hash) {
tt_hash_mutex_lock();
for (int i = 0; i < hash_index; ++i) {
if (hashes[i] == hash) {
tt_hash_mutex_unlock();
return i;
}
}
tt_hash_mutex_unlock();
return -1;
}
static bool hash_contains_value(uint32_t value) {
return hash_find_value(value) != -1;
}
static void hash_add(const char* ssid) {
uint32_t hash = tt_hash_string_djb2(ssid);
if (!hash_contains_value(hash)) {
tt_hash_mutex_lock();
tt_check((hash_index + 1) < TT_WIFI_CREDENTIALS_LIMIT, "exceeding wifi credentials list size");
hash_index++;
hashes[hash_index] = hash;
tt_hash_mutex_unlock();
}
}
static void hash_reset_all() {
hash_index = -1;
}
// endregion Hash
// region Wi-Fi Credentials - static
static esp_err_t tt_wifi_credentials_nvs_open(nvs_handle_t* handle, nvs_open_mode_t mode) {
return nvs_open(TT_NVS_NAMESPACE, NVS_READWRITE, handle);
}
static void tt_wifi_credentials_nvs_close(nvs_handle_t handle) {
nvs_close(handle);
}
static bool tt_wifi_credentials_contains_in_flash(const char* ssid) {
nvs_handle_t handle;
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READONLY);
if (result != ESP_OK) {
TT_LOG_E(TAG, "Failed to open NVS handle: %s", esp_err_to_name(result));
return false;
}
hash_reset_all();
nvs_iterator_t iterator;
result = nvs_entry_find(TT_NVS_PARTITION, TT_NVS_NAMESPACE, NVS_TYPE_BLOB, &iterator);
bool contains_ssid = false;
while (result == ESP_OK) {
nvs_entry_info_t info;
nvs_entry_info(iterator, &info); // Can omit error check if parameters are guaranteed to be non-NULL
if (strcmp(info.key, ssid) == 0) {
contains_ssid = true;
break;
}
result = nvs_entry_next(&iterator);
}
nvs_release_iterator(iterator);
tt_wifi_credentials_nvs_close(handle);
return contains_ssid;
}
// endregion Wi-Fi Credentials - static
// region Wi-Fi Credentials - public
bool tt_wifi_credentials_contains(const char* ssid) {
uint32_t hash = tt_hash_string_djb2(ssid);
if (hash_contains_value(hash)) {
return tt_wifi_credentials_contains_in_flash(ssid);
} else {
return false;
}
}
void tt_wifi_credentials_init() {
TT_LOG_I(TAG, "init started");
hash_init();
nvs_handle_t handle;
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READWRITE);
if (result != ESP_OK) {
TT_LOG_E(TAG, "Failed to open NVS handle for init: %s", esp_err_to_name(result));
return;
}
nvs_iterator_t iterator;
result = nvs_entry_find(TT_NVS_PARTITION, TT_NVS_NAMESPACE, NVS_TYPE_BLOB, &iterator);
while (result == ESP_OK) {
nvs_entry_info_t info;
nvs_entry_info(iterator, &info); // Can omit error check if parameters are guaranteed to be non-NULL
hash_add(info.key);
result = nvs_entry_next(&iterator);
}
nvs_release_iterator(iterator);
tt_wifi_credentials_nvs_close(handle);
TT_LOG_I(TAG, "init finished");
}
bool tt_wifi_credentials_get(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]) {
nvs_handle_t handle;
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READONLY);
if (result != ESP_OK) {
TT_LOG_E(TAG, "Failed to open NVS handle: %s", esp_err_to_name(result));
return false;
}
char password_encrypted[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT];
size_t length = TT_WIFI_CREDENTIALS_PASSWORD_LIMIT;
result = nvs_get_blob(handle, ssid, password_encrypted, &length);
uint8_t iv[16];
tt_secure_get_iv_from_string(ssid, iv);
int decrypt_result = tt_secure_decrypt(
iv,
(uint8_t*)password_encrypted,
(uint8_t*)password,
TT_WIFI_CREDENTIALS_PASSWORD_LIMIT
);
if (decrypt_result != 0) {
result = ESP_FAIL;
TT_LOG_E(TAG, "Failed to decrypt credentials for \"%s\": %d", ssid, decrypt_result);
}
if (result != ESP_OK && result != ESP_ERR_NVS_NOT_FOUND) {
TT_LOG_E(TAG, "Failed to get credentials for \"%s\": %s", ssid, esp_err_to_name(result));
}
tt_wifi_credentials_nvs_close(handle);
return result == ESP_OK;
}
bool tt_wifi_credentials_set(const char* ssid, char password[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT]) {
nvs_handle_t handle;
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READWRITE);
if (result != ESP_OK) {
TT_LOG_E(TAG, "Failed to open NVS handle: %s", esp_err_to_name(result));
return false;
}
char password_encrypted[TT_WIFI_CREDENTIALS_PASSWORD_LIMIT];
uint8_t iv[16];
tt_secure_get_iv_from_string(ssid, iv);
int encrypt_result = tt_secure_encrypt(
iv,
(uint8_t*)password,
(uint8_t*)password_encrypted,
TT_WIFI_CREDENTIALS_PASSWORD_LIMIT
);
if (encrypt_result != 0) {
result = ESP_FAIL;
TT_LOG_E(TAG, "Failed to encrypt credentials for \"%s\": %d", ssid, encrypt_result);
}
if (result == ESP_OK) {
result = nvs_set_blob(handle, ssid, password_encrypted, TT_WIFI_CREDENTIALS_PASSWORD_LIMIT);
if (result != ESP_OK) {
TT_LOG_E(TAG, "Failed to get credentials for \"%s\": %s", ssid, esp_err_to_name(result));
}
}
tt_wifi_credentials_nvs_close(handle);
return result == ESP_OK;
}
bool tt_wifi_credentials_remove(const char* ssid) {
nvs_handle_t handle;
esp_err_t result = tt_wifi_credentials_nvs_open(&handle, NVS_READWRITE);
if (result != ESP_OK) {
TT_LOG_E(TAG, "Failed to open NVS handle to store \"%s\": %s", ssid, esp_err_to_name(result));
return false;
}
result = nvs_erase_key(handle, ssid);
if (result != ESP_OK) {
TT_LOG_E(TAG, "Failed to erase credentials for \"%s\": %s", ssid, esp_err_to_name(result));
}
tt_wifi_credentials_nvs_close(handle);
return result == ESP_OK;
}
// end region Wi-Fi Credentials - public
#endif // ESP_TARGET