## What Started This Project
I wanted a physical 2FA device that I could trust completely. Most authenticator apps live on my phone - which means they're connected to the internet, running closed-source code, and vulnerable to remote attacks. Hardware tokens like YubiKey are great, but they're expensive and you can't see your codes or manage passwords.
So I built SecureGen: an open-source hardware security device on the ESP32 T-Display that combines a TOTP authenticator with a password manager, and can type passwords directly into your computer via Bluetooth.
## Video Demo## How It Works### Hardware FoundationThe device is built on the LILYGO T-Display ESP32 board, which gives us:
- Dual-core ESP32 processor with hardware AES encryption
- 1.14" color display (135x240 ST7789)
- Two physical buttons for navigation
- Built-in battery charging circuit
- WiFi and Bluetooth 5.0 LE
### Core Functionality
**TOTP Authenticator Mode:**
The device generates time-based one-time passwords (TOTP) just like Google Authenticator. After initial NTP time sync via WiFi, it works completely offline. Each code rotates every 30 seconds with a visual countdown timer.
**Password Manager Mode:**
Stores encrypted passwords locally. When you need to log in somewhere, press both buttons and the device connects via BLE HID keyboard to type your password automatically - no clipboard, no typing, no shoulder surfing.
### The Technical Challenges
**1. BLE HID Keyboard Implementation**
Getting the ESP32 to act as a Bluetooth keyboard was harder than expected. The BLE HID descriptor needed manual configuration to support all special characters (!, @, #, $, etc.). Different keyboard layouts handle symbols differently - for example, @ is Shift+2 on US layout but Shift+' on UK layout.
I implemented configurable layout mapping so users can select thei
r keyboard layout in the web interface. The device then translates each character to the correct key combination for that layout.
**2. BLE Security with LE Secure Connections**
Standard Bluetooth is not secure enough for transmitting passwords. I implemented LE Secure Connections with MITM (Man-in-the-Middle) protection using Numeric Comparison pairing.
When you pair the device, a 6-digit PIN appears on both screens (device and computer). You verify they match before confirming. This prevents anyone from intercepting the pairing process. Once paired, all communication uses AES-128 encryption at the BLE layer.
The tricky part was iOS compatibility - Apple enforces stricter security requirements than Android. I had to implement adaptive bonding parameters that detect the connecting device type and adjust security settings accordingly.
**3. Memory Management: BLE + WiFi Simultaneously**
The ESP32's BLE stack alone consumes about 70KB of RAM. When you enable WiFi, heap memory becomes critically tight. Running both simultaneously would cause random crashes.
My solution: strict mode separation. TOTP mode uses WiFi only for initial NTP sync, then disables it completely. Password manager mode runs pure offline with only BLE active. When transmitting passwords via BLE, WiFi is always off.
**4. Secure Storage on ESP32**
The ESP32's built-in NVS (Non-Volatile Storage) provides basic flash storage, but it's not encrypted by default. I added an additional AES-256 encryption layer on top of NVS.
The encryption key is generated from hardware-specific parameters (MAC address, chip ID, flash ID) combined with user's master password using PBKDF2 key derivation. This means even if someone extracts the flash chip, they can't decrypt the data without the master password.
Flash memory has limited write cycles, so I implemented wear leveling on top of the standard NVS wear leveling to extend lifespan.
**5. Web Interface Security**
The device runs a web server for configuration and management. To protect against network attacks, I implemented multiple security layers:
- **ECDH Key Exchange:** Establishes session encryption keys using elliptic curve cryptography
- **Dynamic API Endpoints:** URL paths are obfuscated using SHA-256 hashes and rotate on each reboot
- **Header Obfuscation:** HTTP headers are dynamically mapped to hide sensitive metadata
- **CSRF Protection:** Tokens prevent cross-site request forgery
- **Rate Limiting:** Prevents brute force attacks
**6. Power Optimization**
Battery life was crucial. The display is the biggest power consumer, so after 30 seconds of inactivity, the device enters light sleep mode with the display off. Button 2 wakes it instantly.
WiFi is disabled by default and only enabled when needed for time sync or web management. The ADC for battery monitoring required calibration - ESP32's ADC is quite non-linear, so I created a lookup table mapping voltage to percentage.
**7. Display After Deep Sleep**
The TFT_eSPI library had a bug where the ST7789 display wouldn't reinitialize properly after deep sleep. The GPIO states weren't being reset correctly. I had to implement a full hardware reset sequence with specific delays to reliably wake the display.
## Security Architecture: 8 Layers of Defense
SecureGen implements defense-in-depth security with 8 independent layers. Each layer protects against different attack vectors, ensuring that breaching one layer doesn't compromise the system.
### Layer 1: ECDH Key Exchange 🔐
**What it does:** Generates unique encryption keys for each session using P-256 elliptic curve cryptography.
**Why it matters:** Even if traffic is intercepted during key exchange, attackers can't compute the shared secret without the private keys. Keys are ephemeral and never reused.
**Prevents:** Man-in-the-Middle (MITM) attacks
### Layer 2: Session Encryption 🔒
**What it does:** Double encryption - AES-128 at the Bluetooth (BLE) layer plus AES-256 at the application layer.
**Why it matters:** If an attacker breaks BLE encryption (unlikely but possible), they still face application-layer AES-256 encryption.
**Prevents:** Eavesdropping and packet sniffing
### Layer 3: Dynamic API Endpoints 🎲
**What it does:** API URLs are obfuscated using SHA-256 and change on each device reboot.
**Why it matters:** Automated scanners expect endpoints like `/api/totp` or `/passwords`. When they encounter `/a7f3c9e8b2d4f1a6...`, they don't know what it does without manual reverse engineering.
**Prevents:** Automated API discovery and vulnerability scanning
```python
# Example: Endpoint generation
def generate_endpoint(base, seed):
hash_input = f"{base}-{seed}"
hash_hex = hashlib.sha256(hash_input.encode()).hexdigest()
return f"/{hash_hex}"
# Result: /a7f3c9e8b2d4f1a6c8e5d7f9b3a1c5e8d2f4a6b8c0e2d4f6a8b0c2e4f6a8b0c2
```### Layer 4: Header Obfuscation 🎭
**What it does:** HTTP headers are dynamically mapped and metadata is hidden. Tech stack stays secret.
**Why it matters:** Headers like `Server: nginx/1.18.0` tell attackers exactly which vulnerabilities to target. Obfuscation makes targeted exploits much harder.
**Prevents:** Tech stack fingerprinting and known vulnerability exploitation
**Before:**
```http
Server: ESP-AsyncWebServer/1.2.3
X-ESP32-Chip: ESP32-D0WDQ6
Content-Type: application/json
```**After:**
```http
X-k8f3a2: application/json
X-AspNetMvc-Version: 5.2.7
X-Powered-By: PHP/7.4.3```
### Layer 5: Anti-Fingerprinting 👻
**What it does:** Injects fake HTTP headers and randomizes response patterns. Device pretends to be different each time.
**Why it matters:** Reconnaissance tools get conflicting data, wasting attacker's time with misleading information.
**Prevents:** Device fingerprinting and traffic analysis
### Layer 6: Honey Pot 🍯
**What it does:** Fake API endpoints that look vulnerable but are actually traps. Logs all intrusion attempts.
**Why it matters:** Provides early warning of attacks while wasting attacker time with decoy data. Attackers reveal themselves before finding real endpoints.
**Prevents:** Brute force attacks and automated exploitation
```cpp
// Example: Honey pot endpoint
server.on("/admin", HTTP_GET, [](AsyncWebServerRequest *request){
log_intrusion(request->client()->remoteIP(), "/admin");
// Return realistic fake data
String fake = R"({"users": ["admin", "root"], "debug": true})";
request->send(200, "application/json", fake);
});```
### Layer 7: Method Tunneling 🔀
**What it does:** HTTP request methods (GET, POST, DELETE) are masked and tunneled through different methods.
**Why it matters:** Automated scanners look for specific patterns. Masking breaks their detection logic.
**Prevents:** Pattern-based automated attacks and request forgery
### Layer 8: Timing Attack Protection ⏱️
**What it does:** Random delays added to all security-critical operations. Response times are unpredictable.
**Why it matters:** Attackers can't measure timing differences to infer password length or validity.
**Prevents:** Timing side-channel attacks and password length inference
```cpp
// Example: Constant-time verification with random delay
bool verify_credentials(const char* password) {
uint32_t start = millis();
// Constant-time comparison
bool valid = constant_time_compare(password, stored_password);
// Add random delay (100-150ms target)
uint32_t elapsed = millis() - start;
uint32_t target = 100 + (esp_random() % 50);
if(elapsed < target) {
delay(target - elapsed);
}
return valid;
}
```### Defense in Depth in Action
Here's how all layers work together during an attack:
```
[Automated scanner attempts reconnaissance]
→ Layer 3: Dynamic endpoints confuse scanner
→ Layer 4: Fake headers mislead fingerprinting
→ Scanner finds /admin endpoint (honey pot)
[Attacker accesses /admin]
→ Layer 6: Access logged, IP recorded, fake data returned
→ Attacker wastes time analyzing decoy
[Attacker intercepts BLE traffic]
→ Layer 1: ECDH keys useless without private key
→ Layer 2: Double encryption still protects data
[Attacker attempts timing attack]
→ Layer 8: Random delays hide validation timing
→ No information leaked
Result: Attack fails, logs available, attacker wasted hours
```
### Why 8 Layers?
**Single-layer security = single point of failure.**
Defense in depth means attackers need to bypass **multiple independent layers**. Each layer:
- Targets different attack vectors
- Uses different defensive techniques
- Fails independently
- Slows down attackers exponentially
For a $15 DIY device, being harder to crack than a corporate server is enough deterrent for most threat actors.
### Open Source Security
Making the code public doesn't weaken security. The architecture still requires:
- Physical access to the device
- Extracting hardware-unique encryption keys
- Bypassing multiple independent protection layers
**Security through obscurity** is not security. **Security through architecture** is.
Full security documentation and code: [GitHub Repository](https://github.com/makepkg/SecureGen)
---
## 3. **Schematics Section** - Добавить Security Architecture Diagram
- After hardening:
## Operating Modes
The device supports multiple modes depending on your security needs:
**Offline Mode (Air-Gapped):**
Maximum security. WiFi completely disabled, password manager works independently. Perfect for storing highly sensitive credentials.
**WiFi Client Mode (Self-Hosted):**
Connect to your home network and the device becomes an always-accessible password server - like self-hosted Bitwarden but with dedicated hardware. Access the web interface from any device on your network.
**Access Point Mode:**
Device creates its own WiFi hotspot for isolated configuration. Great for initial setup or managing the device when traveling.
## Security Philosophy
This project follows the principle of **verifiable security**. Everything is open source - you can audit the code, build it yourself, and verify there are no backdoors. The device works offline, so your secrets never touch the internet unless you explicitly connect it.
Multiple encryption layers protect your data:
- AES-256 for data at rest
- Hardware-unique device keys
- BLE encryption for wireless transmission
- Session encryption for web interface
- PIN protection for device startup
## What's Next
Current plans include:
- U2F/FIDO2 support for hardware security keys
- OTP backup to encrypted SD card
- Multi-device sync via encrypted protocol
- Custom mechanical enclosure design
The entire project is MIT licensed and available on GitHub. Pre-compiled binaries are ready to flash if you want to try it without setting up a build environment.
##Software Libraries:
- mbedTLS (Cryptography - ECDH, AES, SHA-256)
- ESP32 BLE Arduino (Bluetooth Low Energy stack)
- TFT_eSPI (Display driver)
- ESPAsyncWebServer (Web interface)
- ArduinoJson (JSON parsing)
### Development Tools:
- PlatformIO IDE
- Arduino Framework
## Try It Yourself
You only need:
- LILYGO T-Display ESP32 board (~$5 on AliExpress)
- USB-C cable
- Optional: 3.7V LiPo battery with JST connector
Flash the firmware, set up your master password, and you have a hardware security device you can trust because you can see exactly how it works.
**GitHub:** https://github.com/makepkg/SecureGen













Comments