Skip to content

Shubhjaiswal408/SecureKey

Repository files navigation

🔐 SecureKey

An offline, hardware password manager that types your passwords for you — over USB‑C and Bluetooth.

Built on a 1.8" AMOLED touchscreen ESP32‑S3. No cloud. No app account. Your vault never leaves the device.

Platform Framework Language Build License: MIT PRs Welcome Capacity

SecureKey is a DIY hardware password manager — a tiny touchscreen "keyboard emulator." Pick an entry, tap a field, and the device types it into whatever it's plugged into (PC over USB‑C) or paired with (phone/laptop over Bluetooth). Because it presents itself as a HID keyboard, it works on any OS with zero drivers, zero browser extensions, and zero software installed. The secrets live in flash on the device, behind a PIN — never synced, never uploaded.

SecureKey on-device screens — Lock, Home, and password Detail
Illustrative renders of the on‑device UI · 368 × 448 AMOLED


🔑 What it does, in one picture

flowchart LR
    V["Your vault<br/>lives on the device"] --> P["Pick an entry,<br/>tap a field"]
    P --> Q{"Connected<br/>how?"}
    Q -->|USB-C cable| U["Types into your<br/>PC / Mac as a keyboard"]
    Q -->|Bluetooth| W["Types into your phone<br/>or laptop, wirelessly"]
Loading

To the computer it just looks like someone typing — no app, no browser extension, no account.


🆚 How it compares

SecureKey Cloud manager Browser autofill
Where the secrets live 🔒 on the device ☁️ a company server 💻 your browser profile
Needs an account
Needs software on the host
Works on any device, no install
Usable fully offline
Open hardware + firmware

✨ Features

Feature What it does
⌨️ Dual‑transport typing Types passwords as real keystrokes over USB‑C HID and Bluetooth LE HID — both can be live at once.
🔢 PIN lock + brute‑force backoff 4‑digit unlock with escalating lockout (30 s → 60 s → 2 m → 5 m) that survives reboots.
📶 On‑device BLE pairing gate A connecting phone is blocked until you tap Accept on the device. Reject, or Block for 5 min. Shows the peer's Bluetooth address.
🗂️ 30,000‑entry vault Fixed‑size binary records on FFat, with a PSRAM index so the list scrolls instantly.
🔎 Instant search & favorites Live filtering with an on‑screen keyboard, plus a ❤️ favorites view.
🌐 Wi‑Fi import/export portal Spin up a captive‑portal web app to bulk‑import a CSV (Chrome/Google export auto‑detected) or export your vault — code‑protected.
Drag‑to‑rearrange home Long‑press a home tile and drag it, just like arranging apps on a phone. Order persists.
🅰️ Android @ fix One‑tap toggle that fixes the classic US↔UK keycode swap (where @ types as ") on Android hosts.
🔒 Auto‑lock, sleep, factory reset Idle auto‑lock, double‑tap‑to‑sleep, PIN‑gated factory wipe, change‑PIN flow.
🎨 Hand‑drawn AMOLED UI A custom, double‑buffered graphics UI (no LVGL) tuned for pure‑black AMOLED — glow effects, color avatars, pill toggles.

🧭 Getting around

flowchart LR
    L["Lock"] --> P["PIN"]
    P --> H["Home"]
    H --> List["Passwords"]
    H --> Add["Add new"]
    H --> Fav["Favorites"]
    H --> Set["Settings"]
    List --> D["Detail<br/>tap a field → it types"]
Loading

The renders at the top show the Lock, Home, and Detail screens. Real device photos are welcome — drop them in docs/img/ and link them here.


🧰 Hardware

Part Detail
Board MaTouch ESP32‑S3 1.8" AMOLED (FT3168) — ESP32‑S3 R8
MCU ESP32‑S3, dual‑core, 8 MB OPI PSRAM, 16 MB flash
Display 1.8" AMOLED, 368 × 448, SH8601 controller over QSPI
Touch FT3168 capacitive, I²C
LED WS2812 (single RGB pixel) — status feedback
USB USB‑C, native ESP32‑S3 (USB‑OTG / TinyUSB)
Power USB‑C, optional 3.7 V LiPo

🚀 Quick start

1. Install the toolchain (use these exact versions)

Tool Version Where
Arduino IDE 2.3.x arduino.cc
esp32 boards core 2.0.16 Boards Manager — do not use 3.x
GFX Library for Arduino 1.3.7 Library Manager
NimBLE‑Arduino 1.4.3 Library Manager — do not use 2.x
ESP32 BLE Keyboard (T‑vK) latest Library Manager (+ 2 small patches, below)
Adafruit NeoPixel latest Library Manager

Add this Boards Manager URL first (File → Preferences → Additional URLs):

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

2. Patch the BLE keyboard library (two one‑line edits)

The stock ESP32 BLE Keyboard ships with the heavyweight Bluedroid backend and MITM‑required pairing, which break USB+BLE coexistence and silent‑fail on Windows/Android. In your …/Arduino/libraries/ESP32_BLE_Keyboard/ copy:

// BleKeyboard.h
- // #define USE_NIMBLE
+ #define USE_NIMBLE          // half the RAM; coexists with native USB HID

// BleKeyboard.cpp  (inside begin(), the USE_NIMBLE branch)
- BLEDevice::setSecurityAuth(true, true, true);
+ BLEDevice::setSecurityAuth(true, false, true);   // SC "Just Works" pairing

3. Arduino IDE board settings (Tools menu)

Board:              ESP32S3 Dev Module
PSRAM:              OPI PSRAM                       ← REQUIRED (canvas lives here)
Flash Size:         16MB (128Mb)
Partition Scheme:   16M Flash (3MB APP/9.9MB FATFS)
USB CDC On Boot:    Enabled
USB Mode:           USB-OTG (TinyUSB)               ← REQUIRED for USB HID typing
Upload Mode:        UART0 / Hardware CDC
CPU Frequency:      240MHz
Flash Mode:         QIO 80MHz

4. Flash

Open 06_PasswordManager/06_PasswordManager.ino and Upload. First boot seeds a few demo entries so you can see the UI immediately.

Prefer the command line? (arduino-cli)
arduino-cli compile \
  --fqbn "esp32:esp32:esp32s3:PartitionScheme=app3M_fat9M_16MB,PSRAM=opi,FlashSize=16M,USBMode=default,CDCOnBoot=cdc" \
  06_PasswordManager

(USBMode=default is USB‑OTG/TinyUSB.) This is exactly what the CI workflow runs on every push.

5. Unlock

Default PIN is 1234 — change it in Settings → Change PIN.


🕹️ Using it

  1. Tap to wake → enter PIN → Home.
  2. Open Passwords, tap an entry.
  3. On the detail screen, tap any field (Title / User / Pass / URL / Note) — SecureKey types it into the focused field on your computer/phone.
  4. Password is masked; first tap reveals it, second tap types it.
  5. Bottom bar: EDIT · ❤️ · DELETE.

To type over USB: plug the USB‑C into a PC data port → tap a field. To type over Bluetooth: Settings → turn on Bluetooth → pair "SecureKey" from your phone → unlock the device → tap Accept on the request → tap a field.

💡 If @ comes out as " on Android, enable Settings → Android @ Fix.


🧠 Feature concepts (how it actually works)

A short tour of the interesting engineering. For the full deep dive see docs/ARCHITECTURE.md.

⌨️ HID — "the device is a keyboard"

Both USB and Bluetooth expose a standard HID keyboard. The OS sees a normal keyboard, so typing works everywhere with no software. The firmware sends scancodes, and the host applies its own keyboard layout — which is why the Android @" swap exists (see below).

🔀 Dual transport on a dual‑core chip

USB HID uses TinyUSB; Bluetooth HID uses NimBLE (chosen over Bluedroid because it uses ~half the RAM and coexists with native USB). The ESP32‑S3 has two cores and NimBLE runs its own radio task, so both transports can be live simultaneouslytypeViaHID() sends to every ready transport instead of picking one.

📶 The Bluetooth pairing gate

A BLE central (your phone) can connect to the device any time, but SecureKey types nothing until you physically accept it on‑screen — and the prompt only appears after you've entered your PIN. You can Accept, Reject (snoozes the prompt so an auto‑reconnecting phone doesn't nag), or Block 5 min (drops the radio). The prompt shows the peer's Bluetooth MAC. (A BLE central doesn't transmit a friendly name to a keyboard, so the address is what's identifiable.)

sequenceDiagram
    participant Phone
    participant SecureKey
    participant You
    Phone->>SecureKey: BLE connect
    Note over SecureKey: typing stays BLOCKED
    SecureKey->>You: "A device wants to connect" (after PIN unlock)
    You-->>SecureKey: Accept / Reject / Block 5 min
    Note over SecureKey: only Accept unlocks typing
    SecureKey->>Phone: now types your password
Loading

🔑 The Android @" fix

HID sends key positions, not characters. On a host set to a UK/Android layout, Shift+2 is " (not @), and @ lives on Shift+'. The Android @ Fix toggle swaps those two keycodes on the BLE path so symbols land correctly — the classic US↔UK keyboard difference, solved in firmware.

🗂️ Storage: flat binary + PSRAM index

The vault is fixed‑size 256‑byte records appended to a single FFat file (db.bin). At boot a compact 64‑byte index per entry is loaded into PSRAM, so searching, sorting, and scrolling never touch flash. Deletes are tombstoned; edits rewrite in place. This scales to 30,000 entries (≈1.9 MB index in PSRAM, ≈7.3 MB on the 9 MB FAT partition).

🛡️ PIN lockout backoff

Wrong PINs trigger an escalating, persisted lockout (30 s → 60 s → 2 m → 5 m). The fail count lives in NVS, so power‑cycling doesn't reset the penalty — a brute‑force attacker can't just yank power to retry instantly.

🌐 Wi‑Fi import/export portal

Bulk data entry on a touchscreen is painful, so Settings can launch a SoftAP + captive‑portal web app. You join its Wi‑Fi, open the page, enter a one‑time code, and paste a CSV (Chrome/Google password exports auto‑detected) or export your vault. Every entry requires title + username + password — enforced both in the browser and server‑side.

✋ Drag‑to‑rearrange home (touch state machine)

The FT3168 driver feeds a tap/drag/swipe state machine. A long‑press on a home tile lifts it; it follows your finger; on release it drops into the nearest slot and the others shuffle to make room. The arrangement is saved to NVS and validated as a permutation on load.

🎨 Rendering on pure‑black AMOLED

The UI is hand‑drawn into a double‑buffered canvas in PSRAM and flushed over QSPI — no LVGL, no flicker. Because AMOLED black is truly off, the theme leans into glow halos (banded radial gradients), color letter‑avatars, and a blue/red accent system on black.


🗺️ Architecture

06_PasswordManager/
├── 06_PasswordManager.ino   Main: setup/loop, nav stack, HID dispatch, BLE gate, auto-lock
├── theme.h                  Palette, layout constants, PassRecord + ListItem structs, capacity
├── pin_config.h             Board pin map (display, touch, LED, USB)
│
├── hid_usb.cpp              USB-HID keyboard (TinyUSB)            ← isolated translation unit
├── hid_ble.cpp              BLE-HID keyboard (NimBLE) + @ fix     ← isolated translation unit
│
├── storage.ino             FFat binary DB: append/load/delete/update/seed
├── touch_input.ino         FT3168 reader + tap/drag/swipe/long-press state machine
├── gfx_lib.ino             Drawing helpers: text, icons, glow, avatars, status/nav bars
├── keyboard.ino            On-screen keyboard (search + add/edit)
│
├── screen_lock.ino         Branded lock screen
├── screen_pin.ino          4-digit keypad + lockout countdown
├── screen_home.ino         Home grid + drag-to-reorder
├── screen_list.ino         Virtual-scroll list + inline search + favorites
├── screen_detail.ino       Entry detail + Edit/Fav/Delete + tap-to-type
├── screen_add.ino          Multi-step add / edit form
├── screen_settings.ino     Settings, HID test, About, factory reset
├── screen_chgpin.ino       Change-PIN flow
├── screen_wifi.ino         Wi-Fi import status screen
├── wifi_portal.ino         SoftAP + HTTP server (import/export)
└── portal_html.h           The captive-portal single-page web app

⚠️ USB & BLE keyboard libraries each #define KEY_* macros, so they cannot share a translation unit. That's why hid_usb.cpp and hid_ble.cpp are separate .cpp files exposing a tiny extern "C" surface to the .ino code.


🔐 Security model & honest limitations

What it does today

  • Vault is offline and PIN‑gated; the screen locks on idle and on the physical button.
  • Brute‑force PIN backoff persists across reboots.
  • Bluetooth typing requires explicit on‑device approval per connection.

What it does not do yet (PRs very welcome 🙏)

  • 🔓 The vault on flash is not yet encrypted at rest. A determined attacker with physical access and a flash reader could dump it. Roadmap: AES‑256 with a key derived from the PIN, plus ESP32 Flash Encryption + Secure Boot v2.
  • The default PIN is 1234 — change it.

Treat this as a strong DIY / learning project, not a certified security product. See the roadmap.


🛣️ Roadmap

  • Touch UI, vault, USB + BLE HID, Wi‑Fi import, drag‑reorder
  • AES‑256 encrypted vault (key derived from PIN)
  • Flash Encryption + Secure Boot v2 (one‑way fuses, release mode)
  • TOTP / 2FA code generator (HMAC‑SHA1)
  • FIDO2 / WebAuthn passkey (ECC P‑256)
  • Custom PCB + 3D‑printed enclosure

🤝 Contributing

Contributions, bug reports, and hardware ports are welcome — see CONTRIBUTING.md. The CI compiles the firmware on every push, so make sure your branch builds green.

📜 License

MIT © Shubh Jaiswal.

🙌 Credits

If this project helped you, drop a ⭐ — it genuinely helps.

About

🔐 Offline hardware password manager on an ESP32-S3 AMOLED touchscreen — types your passwords as a keyboard over USB-C and Bluetooth (HID). No cloud, no app, vault never leaves the device.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors