// project ·
Password Management Desktop Application
Built a local password app to learn desktop security basics. Stack: JavaFX, MySQL, JUnit.
Role: Personal project · Year: 2023 - 2024 · Status: archived
tldr: A JavaFX desktop password manager built to learn credential handling properly. The login password is hashed with BCrypt. Saved site passwords are encrypted with AES-256-GCM under a key derived from the login password, so the database never holds them in plain text.
Problem
A password manager has two kinds of secret, and they need opposite treatment. The login password only ever has to be checked, never read back. Saved site passwords have to be shown and copied later. Hash everything and the vault is useless. Encrypt everything with a key stored next to the data and the database is the only lock.
Constraints
- Several users, one MySQL database. Anyone holding only the database must not be able to read a user’s saved passwords.
- The key can’t be stored. It has to come from something only the user knows.
- Existing rows. Entries saved before encryption existed still had to load.
- The desktop UI stays responsive while it waits on the database.
Decisions
- BCrypt for the login password, through Spring Security’s implementation. It is checked at sign-in and never decrypted.
- AES-256-GCM for vault entries. Each value gets a random 12-byte IV, and the GCM tag detects tampering.
- PBKDF2-HMAC-SHA256 with 120,000 iterations derives the vault key from the login password at sign-in. The key is held in memory only.
- Versioned ciphertext. Encrypted values start with
v1:, so older plain rows are recognized on load and encrypted on their next save. - MVC with DAOs and HikariCP, and
CompletableFuturearound authentication so the JavaFX thread never blocks on MySQL. - Small usability pieces: Jsoup fetches each site’s favicon, passwords stay masked until revealed, and credentials can be copied without being shown.
Outcome
Saved passwords in a stolen database dump are unreadable without the owner’s login password. JUnit and Mockito cover user storage and authentication. There is one weakness I’d fix first: the PBKDF2 salt is the username, which is predictable. A random per-user salt stored next to the BCrypt hash would close it.