PasswordVault

1. Overview

The PasswordVault.cpp file is a Encrypted password-vault implementation in BastionGuard.

Implements PBKDF2 verification and key derivation, AES-256-GCM authenticated encryption, atomic JSON writes, an in-memory secret cache, asynchronous persistence, bulk import, deletion, and CSV export.

The documentation below is generated from the supplied source and covers its API surface, runtime responsibilities, data flow, filesystem or command interactions, concurrency model, and security considerations.


2. Source Inventory

  • Original path: password_manager/PasswordVault.cpp
  • Language: C++
  • Source type: .cpp
  • Line count: 613
  • SHA-256: 3bb583c9e685cb44681ccc5d178b23e1ba3577d2ade01c1d7409e248385e23f8

3. Dependencies

The file declares the following compile-time dependencies:

Project

  • PasswordVault.hpp

GTK/GLib

  • giomm/file.h
  • glibmm/miscutils.h
  • glibmm/dispatcher.h

Security/Data

  • nlohmann/json.hpp
  • openssl/evp.h
  • openssl/rand.h

C/C++ Runtime

  • fstream
  • iomanip
  • random
  • sstream
  • ctime
  • cstring
  • thread
  • unordered_set

4. Types and Public Contract

No standalone class, structure, or enumeration is declared directly in this file.


5. API and Method Inventory

The following functions or methods are implemented in this file:

  • PasswordVault::atomicWriteFile(const std::string& path, const std::string& content) – Implements the operation represented by this API.
  • PasswordVault::aesDecrypt(const std::string& key32, const std::string& nonce12, const std::string& ciphertext, const std::string& tag16, std::string& plaintext) – Implements the operation represented by this API.
  • PasswordVault::deriveKey(const std::string& saltHex) – Implements the operation represented by this API.
  • PasswordVault::generateSaltHex() – Implements the operation represented by this API.
  • PasswordVault::generateNonceHex() – Implements the operation represented by this API.
  • PasswordVault::saveSecretsFile(const std::unordered_map<std::string,std::string>& secrets) – Persists the corresponding data.
  • PasswordVault::loadSecretsFile(std::unordered_map<std::string,std::string>& secrets) – Loads and validates the corresponding data.
  • PasswordVault::PasswordVault() – Implements the operation represented by this API.
  • PasswordVault::initialize() – Initializes persistent state and creates required storage structures.
  • PasswordVault::isUnlocked() – Returns whether the vault currently accepts secret operations.
  • PasswordVault::isFirstRun() – Checks whether the master-password verifier exists.
  • PasswordVault::createMasterPassword(const std::string& masterPassword) – Creates the initial verifier and unlocks the new vault.
  • PasswordVault::unlock(const std::string& masterPassword) – Verifies the master password and starts loading decrypted secrets.
  • PasswordVault::lock() – Clears unlocked state and removes cached secret material.
  • PasswordVault::getIndexPath() – Returns the requested value or computed resource.
  • PasswordVault::loadIndex() – Loads non-secret entry metadata from the JSON index.
  • PasswordVault::saveIndex(const std::vector<PasswordEntry>& entries) – Serializes the metadata index using an atomic replacement.
  • PasswordVault::flushAsync(std::unordered_map<std::string,std::string> snapshot) – Implements the operation represented by this API.
  • PasswordVault::addEntry(const PasswordEntry& entry, const std::string& secret) – Adds one metadata record and its associated secret.
  • PasswordVault::updateEntry(const PasswordEntry& entry, const std::string& secret) – Replaces an existing record and updates its secret.
  • PasswordVault::deleteEntry(const std::string& id) – Removes one metadata record and secret.
  • PasswordVault::deleteAllEntries(std::function<void(bool)> onDone) – Clears all entries and removes encrypted secret storage asynchronously.
  • PasswordVault::addEntriesBulk(const std::vector<std::pair<PasswordEntry, std::string>>& items, std::function<void(int ok, int fail)> onDone) – Adds multiple entries and reports successful and failed items.
  • PasswordVault::exportToCSV(std::function<void(std::string csv, std::string err)> onDone) – Builds a cleartext CSV export asynchronously.
  • PasswordVault::getSecretAsync(const std::string& id, std::function<void(std::string)> callback) – Returns a cached secret asynchronously when the cache is ready.
  • PasswordVault::setSecret(const std::string& id, const std::string& secret) – Updates a secret in memory and schedules encrypted persistence.
  • PasswordVault::generateId() – Generates a UUID-like identifier for a new entry.
  • secureClear(std::string& s) – Implements the operation represented by this API.
  • toHex(const unsigned char* data, size_t len) – Implements the operation represented by this API.
  • toHex(const std::string& s) – Implements the operation represented by this API.
  • fromHex(const std::string& hex) – Implements the operation represented by this API.
  • csvEscape(const std::string& s) – Implements the operation represented by this API.

6. Functional Architecture

Persistent Files

  • Metadata index: ~/.config/BastionGuard/password_manager/index.json.
  • Master-password verifier: ~/.config/BastionGuard/password_manager/master.json.
  • Encrypted secret map: ~/.config/BastionGuard/password_manager/secrets.enc.

Cryptographic Design

  • Uses PBKDF2-HMAC-SHA-256 with a 16-byte random salt.
  • Stores the master-password verifier with 200,000 PBKDF2 iterations.
  • Derives the AES secret-file key with 100,000 PBKDF2 iterations.
  • Encrypts the complete secret map using AES-256-GCM with a 12-byte nonce and 16-byte authentication tag.
  • Stores salt, nonce, ciphertext, and tag as hexadecimal JSON members.

Persistence and Cache

  • Writes JSON through a temporary .tmp file followed by rename().
  • Keeps decrypted secrets in a mutex-protected in-memory cache only while unlocked.
  • Loads the encrypted cache in a detached worker after successful unlock.
  • Clears the master-password string and cache when the vault is locked.

Bulk and Asynchronous Operations

  • Supports bulk insertion with duplicate-ID rejection.
  • Exports decrypted data to CSV on a worker thread.
  • Retrieves secrets asynchronously and waits for cache readiness through a bounded GTK timeout loop.
  • Persists secret snapshots asynchronously after add, update, delete, or set operations.

7. Operational Flow

  1. Initialize the password-manager storage directory and metadata index.
  2. Create or verify the master password and transition the vault into unlocked state.
  3. Load non-secret metadata and asynchronously populate the decrypted secret cache.
  4. Perform add, edit, reveal, import, export, or delete actions.
  5. Persist metadata atomically and rewrite the encrypted secret map.
  6. Clear cached secrets and master-password material when locking.

8. Filesystem and External Command Surface

Referenced Absolute Paths

  • /.config/BastionGuard/password_manager
  • /.config/BastionGuard/password_manager/index.json
  • /.config/BastionGuard/password_manager/master.json
  • /.config/BastionGuard/password_manager/secrets.enc

Commands or Security Primitives Referenced

  • PBKDF2
  • ip
  • sh

9. Concurrency and Lifecycle

  • Uses worker threads for operations that could block the GTK main loop.
  • Protects shared state with a mutex.
  • Uses Glib::Dispatcher to marshal worker completion to GTK.
  • Uses GLib idle callbacks to update GTK from the main thread.
  • Uses GLib timers for progress, deferred actions, polling, or cache readiness.

10. Security Considerations

  • Password metadata and encrypted secrets are separated, reducing accidental exposure through the index file.
  • Cleartext passwords exist in process memory while the vault is unlocked and during import/export workflows.
  • CSV import and export files are unencrypted and must be handled as sensitive data.
  • Background callbacks must not outlive their owning GTK objects.
  • AES-GCM authentication rejects modified ciphertext or an incorrect derived key.
  • The current implementation does not add authenticated associated data.
  • Atomic rename reduces corruption risk but file permissions should be verified by packaging and runtime setup.

11. Implementation Considerations

  • The implementation should remain synchronized with the matching header declarations.
  • Detached worker threads require careful object-lifetime protection and deterministic shutdown behavior.
  • Temporary-file replacement is atomic only when source and destination reside on the same filesystem.

12. Licensing and Branding

The source is distributed under the GNU General Public License version 3.

The source header identifies BastionGuard™ as a trademark and states that the name and branding are not licensed under the GPL.

The software is provided without warranty, including implied warranties of merchantability or fitness for a particular purpose.