Secure password manager in C++
An AES-256-GCM credential vault in modern C++ built on real OpenSSL crypto
Problem
A password manager is only as trustworthy as its weakest cryptographic decision. The goal was to get every one right: authenticated encryption so tampering is detected, slow salted key derivation so the master password resists brute force, and a fresh random nonce on every save so the same contents never encrypt the same way twice.
The Secure Coding module (CSEC1003D) asks for correct, object-oriented, security-minded systems programming. Rather than a toy, I built a real vault: a crypto layer over OpenSSL’s EVP API, a vault/serialisation layer, and a thin CLI, with a CMake build and a CTest suite.
What I did
AES-256-GCM provides confidentiality and integrity in one primitive; PBKDF2-HMAC-SHA256 (200k iterations, random per-vault salt) derives the key; a fresh random 96-bit IV is generated on every save. RAII wraps the OpenSSL contexts, sensitive buffers are cleansed, and the master password is read with terminal echo disabled.
Cryptographic design
Every choice is deliberate and documented.
- AES-256-GCM: a modified vault fails the auth tag instead of decrypting to junk
- PBKDF2-HMAC-SHA256 with a random salt: expensive brute-force, no rainbow tables
- Fresh random 96-bit IV per save: a repeated nonce under one key is negligibly unlikely at this volume
- Master password derived to a key and never stored: only the salt and iteration count persist
Proven, not just claimed
The CTest suite checks the security properties: a wrong key or master password and a single flipped bit both fail with an authentication error. The README repeats this by hand and adds a grep of the vault file that finds no trace of a stored secret, because it is encrypted at rest.
Engineering discipline
Clean separation (crypto knows nothing about vaults; the CLI is thin), RAII around OpenSSL contexts so a context is freed exactly once even on error, OPENSSL_cleanse on key material, and a build with -Wall -Wextra -Wpedantic so warnings surface as signal.
Evidence
- GCM authenticated encryption
- AES-256
- tampering detected
- PBKDF2 iterations
- 200k
- below OWASP’s 600k; see limitations
- Plaintext at rest
- 0
- master key never stored
- OpenSSL EVP
- C++17
- CMake · CTest · -Wall
Stack and tools
Result
A tested systems-C++ project that backs the ‘I can build the code I defend’ claim: real authenticated encryption, sound key management, and a threat model that is honest about what it does and does not protect.
Limitations
200,000 PBKDF2-HMAC-SHA256 iterations is below the 600,000 that OWASP’s Password Storage Cheat Sheet now recommends, and PBKDF2 is not memory-hard (Argon2id would resist GPU cracking better). The iteration count is stored in the vault header, so it can be raised without breaking existing vaults.