A command-line password manager written in modern C++ (C++17), using real, audited cryptography from OpenSSL — not a hand-rolled cipher. It stores credentials in a single vault file that is encrypted and authenticated with AES-256-GCM, unlocked by a master password that is never written to disk.
Author: Syed Muhammad Waleed Bukhari (@WalBuk28) · Cybersecurity Engineer
| Concern | Choice | Why |
|---|---|---|
| Confidentiality + integrity | AES-256-GCM | Authenticated encryption — a modified vault is detected, not silently mis-decrypted. |
| Master-password → key | PBKDF2-HMAC-SHA256, 200 000 iterations, 16-byte random salt | Slows brute-force; a per-vault salt defeats rainbow tables. |
| Nonce | Fresh 96-bit random IV every save | GCM nonces must never repeat under one key. |
| Master password | Derived to a key, never stored | Only the salt + iteration count live in the file. |
| Secret entry | Terminal echo disabled (termios) |
Secrets don't hit the screen or scrollback. |
| Key material in RAM | OPENSSL_cleanse on buffers |
Best-effort wipe; not optimised away by the compiler. |
magic "SPM1" | salt(16) | iterations(4, big-endian) | iv(12) | tag(16) | AES-256-GCM ciphertext
The ciphertext is a length-prefixed serialisation of the credential entries, so there is no plaintext structure to leak on disk.
include/spm/ crypto.hpp · vault.hpp · entry.hpp (public API)
src/ crypto.cpp OpenSSL EVP wrappers (PBKDF2, AES-256-GCM)
vault.cpp load/save, (de)serialisation, entry management
main.cpp CLI (init/add/get/list/remove, hidden input)
tests/ test_spm.cpp unit tests (CTest)
CMakeLists.txt OpenSSL discovery, warnings-as-signal, test registration
crypto knows nothing about vaults; vault composes it; main is a thin CLI.
Requires CMake ≥ 3.16, a C++17 compiler and OpenSSL (libcrypto) dev headers.
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
ctest --test-dir build --output-on-failureexport SPM_VAULT=~/.spm/vault.spm # optional; defaults to ./vault.spm
./build/spm init # create a vault (prompts master password twice)
./build/spm add github walbuk28 # prompts for the secret, stores it
./build/spm get github # prints username + password
./build/spm list # lists services
./build/spm remove github# wrong master password
$ spm get github
error: authentication failed — wrong password or tampered vault (exit 1)
# flip a single byte of vault.spm, then open it
$ spm list
error: authentication failed — wrong password or tampered vault (exit 1)
# the stored secret never appears in the file in plaintext
$ grep -c "super-secret-value" vault.spm
0
ctest runs a suite covering key derivation (deterministic per salt, unique
across salts/passwords), the AES-256-GCM encrypt/decrypt round-trip, wrong-key
rejection, single-bit tamper detection, and a full vault save/load
round-trip including entry replacement and wrong-password failure.
Designed to protect credentials at rest — against theft or modification of
the vault file. It does not defend against a compromised host that can read
process memory or keystrokes while the vault is unlocked. A production successor
would add: a memory-locked (mlock) secret buffer, clipboard-free retrieval,
and Argon2id in place of PBKDF2.
MIT © Syed Muhammad Waleed Bukhari