#pragma once #include #include // Persistent 32-byte AES-256-GCM key for BLE payload encryption. // Generated on first boot, stored at /ble.keyfile, pulled to the host // during every profile upload via the get_ble_key serial command. class BLEKeyStore { public: static constexpr size_t KEY_LEN = 32; static constexpr const char* KEY_PATH = "/ble.keyfile"; // Loads the key from LittleFS, or generates and persists a new one // if no key exists. Assumes LittleFS is already mounted. bool begin() { if (LittleFS.exists(KEY_PATH)) { File f = LittleFS.open(KEY_PATH, "r"); if (f && f.size() == KEY_LEN && f.read(_key, KEY_LEN) == KEY_LEN) { f.close(); _loaded = true; Serial.println("[BLE] Key loaded"); return true; } if (f) f.close(); // Corrupt or wrong-size file — regenerate. } esp_fill_random(_key, KEY_LEN); File f = LittleFS.open(KEY_PATH, "w"); if (!f) { Serial.println("[BLE] Failed to open key file for write"); return false; } size_t wrote = f.write(_key, KEY_LEN); f.close(); if (wrote != KEY_LEN) { Serial.println("[BLE] Failed to write full key"); return false; } _loaded = true; Serial.println("[BLE] Generated new key"); return true; } bool hasKey() const { return _loaded; } const uint8_t* key() const { return _key; } private: uint8_t _key[KEY_LEN] = {0}; bool _loaded = false; };