Security
BlockVault implements defense-in-depth security with multiple layers protecting sensitive data — mnemonics, passwords, and private keys never leave the device.
Architecture Overview
User Password
↓
PBKDF2 (600 000 iterations)
↓
AES-256-GCM Key Derivation
↓
Hardware-Backed Storage (Android Keystore / iOS Keychain)
↓
Device Security Module (TEE / Secure Enclave)1. Mnemonic Encryption (AES-256-GCM)
Every seed phrase is encrypted before it touches any storage:
| Parameter | Value |
|---|---|
| Algorithm | AES-256-GCM (Galois/Counter Mode) |
| IV | 128-bit random per encryption |
| Salt | 256-bit random per encryption |
| Auth Tag | 128-bit (tamper detection) |
| Key Derivation | PBKDF2 — 600 000 iterations (OWASP 2023) |
Encryption flow
plaintext mnemonic
→ PBKDF2(password, random-salt, 600k) → 256-bit key
→ AES-256-GCM(key, random-iv) → ciphertext + authTag
→ JSON { version, iv, salt, authTag, encryptedSeed }The PBKDF2 key derivation runs inside a Web Worker so the UI thread never blocks.
Stored format
{
"version": 2,
"iv": "hex",
"salt": "hex",
"authTag": "hex",
"encryptedSeed": "hex"
}2. Hardware-Backed Secure Storage
The encrypted seed JSON is stored through platform-specific hardware security:
Android
- Backend: Android Keystore (Trusted Execution Environment / StrongBox)
- Encryption: AES-256-GCM at hardware level
- Guarantee: Keys never leave the TEE
iOS
- Backend: iOS Keychain + Secure Enclave
- Encryption: Hardware-bound AES
- Guarantee: Not included in device backups
This means data is encrypted twice:
- App layer — PBKDF2 + AES-256-GCM (controlled by user password)
- Hardware layer — Android Keystore / iOS Keychain AES-GCM (controlled by OS)
3. Password Protection
Hashing
User passwords are hashed with SHA-256 and stored in SecureStorage as "passhash". The hash is hardware-encrypted on mobile and never sent over the network.
Session caching
The plaintext password is held only in memory for the active session:
- Stored in a Pinia reactive ref (
SessionStore) - Cleared immediately when the app goes to background
- No timer — driven by app lifecycle events (
appStateChange)
App active → password in memory (for signing operations)
App paused → password cleared instantly
App resumed → user must re-authenticate4. Biometric Authentication
BlockVault supports platform biometrics as a convenience layer:
| Platform | Methods |
|---|---|
| iOS | Touch ID, Face ID |
| Android | Fingerprint, Face Authentication |
How it works
- Enrollment — After password verification, credentials are stored in the OS credential store via
NativeBiometric.setCredentials. - Authentication — On next unlock, the OS prompts biometric verification (
maxAttempts: 3). On success, the password is retrieved from the OS credential store. - Fallback — If biometric fails, the user enters their password manually.
Biometric data itself is never seen by BlockVault — the OS handles matching. BlockVault only receives a success/failure signal and, on success, retrieves the stored password.
5. App Attest (iOS Device Integrity)
On iOS, BlockVault uses App Attest to cryptographically prove:
- The app binary is genuine (not modified or re-signed)
- It runs on a real Apple device (not an emulator or jailbroken environment)
This is implemented via a custom Capacitor plugin (capacitor-app-attest) that interfaces with Apple's DeviceCheck framework.
6. Private Keys — Never Stored
Private keys are derived on demand from the encrypted mnemonic and held only for the duration of the signing operation:
User enters password
→ Decrypt mnemonic (AES-256-GCM)
→ Derive private key (BIP32 path)
→ Sign transaction
→ Discard key from memoryPrivate keys are never persisted to disk, database, or any storage.
Summary
| Layer | Protection |
|---|---|
| Mnemonic at rest | AES-256-GCM + PBKDF2 (600k iterations) |
| Storage backend | Android Keystore TEE / iOS Secure Enclave |
| Session password | In-memory only, cleared on background |
| Biometric unlock | OS credential store, 3-attempt limit |
| Device integrity | App Attest (iOS) |
| Private keys | Derived on demand, never stored |
| Key derivation | Web Worker (non-blocking) |