Skip to content
Return to Projects
Case Study

FrostVault

A zero-knowledge Windows password manager with deception built in.

The Problem

Mainstream password managers are cloud-first and ask you to trust a third party with your most sensitive secrets. FrostVault keeps everything local and encrypted — and fights back when someone tries to break in.

My Role

Built solo with AI-assisted development — cryptographic design, application logic, the PySide6 UI, and Windows packaging.

Highlights

  • AES-256-GCM authenticated encryption for all vault data at rest
  • Honey Vault serves believable decoy credentials under a wrong master key or duress
  • Freeze Mode and Ice Crystal Fingerprints provide tamper detection
  • Ships as a single standalone Windows executable — no installer, no cloud

Stack

Python 3.12PySide6AES-256-GCMCryptographyPyInstaller

Constraints

  • Offline-first: vault data must never leave the user's machine.
  • Single-binary distribution — no installer, no runtime to ship.
  • Threat model includes coerced access, not just remote attackers.

System Architecture

Interface
PySide6 Desktop UI
Application
Vault Manager
Honey Vault
Freeze Mode
Cryptography
AES-256-GCM
Key Derivation
Ice Crystal Fingerprints
Storage
Encrypted local vault file

Key Trade-offs

The decisions worth defending — what I chose, what I turned down, and why.

Storage architecture

Chose

Single encrypted local file

Rejected

Cloud-synced vault

Removes the third-party trust dependency entirely; matches the offline-first threat model at the cost of cross-device sync.

Wrong-password behaviour

Chose

Honey Vault returns plausible decoys

Rejected

Hard fail with a clear error

A loud failure tells an attacker they have the wrong key. A believable decoy buys time and frustrates duress scenarios.

Crypto stack

Chose

AES-256-GCM via the `cryptography` library

Rejected

Custom-built primitives

Authenticated encryption out of the box, audited implementation, zero novel crypto risk.

What I'd Do Differently

An honest retrospective — the stuff I'd change with more time, more users, or a second pass.

  1. 1Add an automated integrity self-test that runs on every launch and surfaces tampering visibly to the user.
  2. 2Move key derivation parameters to a versioned header so future Argon2 tuning doesn't break old vaults.
  3. 3Ship a portable Linux build — Windows-only narrows the audience more than I expected.

Technical Deep-Dive

Architecture, specifications, and implementation details.

Threat Model

FrostVault v1.0.0 — IceLegends


#1. STRIDE Analysis

STRIDE is a threat classification framework: Spoofing · Tampering · Repudiation · Information Disclosure · Denial of Service · Elevation of Privilege.


##S — Spoofing

ThreatDescriptionMitigationResidual Risk
S1Attacker presents a fake FrostVault window to harvest master passwordApp runs locally; no authentication handshake to interceptLow — attacker needs prior physical/remote access
S2Malicious vault.db file planted to trigger exploitInput validated; AES-GCM tag verification rejects tampered blobsVery Low
S3Attacker copies vault.db and runs own FrostVault instanceWithout master password, derived key is unrecoverable (Argon2id)Negligible

##T — Tampering

ThreatDescriptionMitigationResidual Risk
T1Attacker modifies vault.db ciphertextGCM auth tag fails; decrypt() raises InvalidTag exceptionVery Low
T2Attacker replaces crypto.py with weakened versionCode signing (future); PyInstaller bundle integrityMedium (unsigned binary)
T3Attacker modifies fail_count table to reset honey triggerHoney vault is a deception layer, not a security boundaryLow

##R — Repudiation

ThreatDescriptionMitigationResidual Risk
R1Attacker denies accessing the vaultintrusion_log table records all failed attempts with timestampsMedium — log is local, not write-protected
R2User denies having created a vault entryNo audit log for successful operations in v1.0Low (single-user app)

##I — Information Disclosure

ThreatDescriptionMitigationResidual Risk
I1vault.db file stolen from diskAll credential fields AES-256-GCM encrypted; master password never storedLow
I2Process memory dump while vault is unlockedDerived key + plaintext entries in Python memoryMedium — Python does not securely zero memory
I3Windows page file / hibernation file contains decrypted dataNo mitigation in v1.0Medium
I4Clipboard contains password after copy30-second auto-clear via QTimerLow
I5Screen recording / shoulder surfingFreeze Mode (Ctrl+Shift+F) calculator camouflageLow
I6Application crash dump contains sensitive dataNo crash reporting configured; dumps go to Windows Error ReportingMedium
I7Password visible in Entry dialogEcho mode = Password; eye-button toggle requires user intentVery Low

##D — Denial of Service

ThreatDescriptionMitigationResidual Risk
D1Attacker deletes or corrupts vault.dbNo backup mechanism in v1.0Medium — data loss risk
D2Attacker fills disk preventing vault writesSQLite write failure → unhandled exception in v1.0Low
D3Argon2id exhausts RAM during unlock64 MB allocation; negligible on modern hardwareVery Low

##E — Elevation of Privilege

ThreatDescriptionMitigationResidual Risk
E1App runs with elevated privileges unnecessarilyPrivilegesRequired=lowest in installer; user-level onlyVery Low
E2keyboard library (global hotkey) requires elevated accesskeyboard library uses OS hooks at user level on WindowsVery Low
E3SQLite injection via credential fieldsAll DB interactions use parameterized queriesVery Low

#2. Attacker Profiles

ProfileGoalCapabilityPrimary Threat
Casual attackerAccess saved passwordsPhysical device access, no technical skillHoney Vault, Freeze Mode
Technical insiderRead vault.db from diskFile system access, Python knowledgeAES-256-GCM encryption
Remote attackerExfiltrate vault dataRemote code execution on victim machineNo network surface; local-only
Forensic investigatorRecover plaintext from memoryRAM dump tools, disk forensicsMemory exposure (residual risk I2, I3)
Nation-stateCryptanalytic attackCryptanalysis resourcesAES-256 / Argon2id — no known attacks

#3. Out of Scope (v1.0.0)

The following threats are explicitly out of scope and are not mitigated in this version:

  • Keyloggers — If a keylogger captures the master password as it is typed, all protections fail. Mitigation requires OS-level secure input (e.g., Secure Desktop) — planned for v2.0.
  • Evil maid attack — Attacker with physical access who replaces the FrostVault binary. Requires code signing and binary verification — planned for v2.0.
  • Side-channel attacks — Timing/power analysis against Argon2id. Out of scope for a local desktop app.
  • Secure memory zeroing — Python's garbage collector does not allow deterministic memory zeroing. A future C extension could zero memory explicitly.
  • Backup / sync — No encrypted backup mechanism. Data loss on disk failure is the user's responsibility.

#4. Risk Summary Matrix

           │ Likelihood
Impact     │  Very Low  │  Low   │  Medium │  High
───────────┼────────────┼────────┼─────────┼──────
Critical   │            │        │ I3(swap)│
High       │  T2(tamper)│I2(mem) │         │
Medium     │  S1,R1     │ D1,I6  │         │
Low        │  T1,E1,I7  │S3,T3   │         │

Highest priority items for v2.0:

  1. Secure memory zeroing (I2)
  2. Code signing to prevent binary tampering (T2)
  3. Encrypted automatic backup (D1)
  4. Secure input mode / virtual keyboard option (keylogger defense)

#5. Compliance Alignment

StandardRelevant ControlsFrostVault Status
OWASP ASVS L1Password hashing, encryption at rest✅ Meets
NIST SP 800-63BMemory-hard KDF for stored passwords✅ Meets (Argon2id)
NIST SP 800-38DAEAD encryption✅ Meets (AES-256-GCM)
CIS BenchmarkAuto-lock on idle✅ Meets (5-min timeout)
GDPR Art. 32Appropriate technical measures for personal data✅ Meets (encryption at rest, local only)
~ End of Document ~