murta.xyz
visitor/
← All projects

LEARNING PROJECT / 2024

Argus Password Manager

A self-hosted password manager—and an honest study of cryptography, databases, APIs, and the architectural consequences of where encryption happens.

Retrospective / disclaimer

I started the password manager as one of my first non-university projects back in early 2024. Choosing what kind of project I would do took some time; I wanted something non-trivial and useful, but not too complex for me to manage. There were also other factors, I'm sure, as I kept watching videos about what kind of project to do for some months before I actually started coding.

In any case, I had a few objectives in mind when I decided on a password manager. Firstly, I wanted to learn cryptography well and work with binaries. That was certainly a success - ingrained in my mind are all the salting and Base64 issues I had to face when developing the encryption algorithm. Looking back at it, the crypto module was the only thing there that was actually useful, mostly due to its simplicity. After all, the Fernet object from Cryptography (the Python library) did almost all of the job, so there was not that much room for mistakes. Secondly, I wanted to learn SQL, more specifically PostgreSQL. I wouldn't say it was a complete success, but given that LLMs at the time were sub-optimal, I had to manually write a ton of boilerplate SQL code to be run by psycopg2, so it made it easier for me to re-learn SQL at college a few semesters later. I did make a lot of architecturally questionable choices, however, such as using Postgres stashes as a per-user division (which I later, naturally, removed). It was also a concern of mine to try and "protect" each stash independently, even though the data inside was already encrypted - some type of double-layer security I had in mind. Due to my inexperienced self, the fact that a superuser could just access any table arbitrarily made me concerned.

Well, most of these initial, problematic decisions I eventually fixed. What sealed the death sentence of this project were two factors, one relating to the other: (1) it was a CLI application in Python, and no one, not even myself, wants to use a CLI, especially nowadays when you can just vibe-code a frontend; and (2) because I don't want to touch Tkinter, PyQt, or any Python GUI framework, for any frontend I try to implement - unless I turn the Python application into a sidecar to some Tauri frontend with a SQLite database, absolutely destroying my current Docker setup - the only logical way to connect to the backend is through an API. That was the main reason why I added FastAPI to it and decided to create a small GUI frontend. And then comes the main problem: the encryption, because it was originally designed to be a CLI application, happens server-side, so any kind of non-HTTPS traffic could be intercepted and credentials - the master password - stolen. And from there it was doomed - the client-server setup just won't work with the current stack.

Technically, it is still usable. You can use an older version through the CLI, or just use my vibe-coded frontend with unsafe HTTP. If you have a sniffer reading your packets locally and intercepting the master password, you might have bigger problems than some random password manager's safety. Well, needless to say, this is just a small project for learning. There are whole companies with cybersecurity specialists and intricate architectural designs that provide password managers, and they are probably more trustworthy than whatever this is. That being said, this is as simple as it gets. Just a small symmetric encryption algorithm, and complexity is not really ideal when it comes to security.

Current implementation

The current branch exposes an asynchronous FastAPI service for registration, login, and authenticated credential CRUD. PostgreSQL 15 stores users and encrypted password records, JWTs carry sessions, and Docker Compose starts the database and backend with a database health check and persistent volume.

The master password is never stored directly. Argon2 verifies it at login; for each credential, PBKDF2-HMAC-SHA256 derives a 32-byte key from the master password and a fresh salt using 480,000 iterations. Fernet then provides authenticated symmetric encryption, and the encrypted username, encrypted password, and salt are Base64-encoded for storage.

Trust boundary

Argus encrypts data at rest, but it is not zero-knowledge: the backend receives the plaintext master password and credential values during requests. Without HTTPS, a network observer can intercept them; even with HTTPS, the user must trust the server handling those secrets.

For that reason, the repository describes this version as suitable only for localhost or a trusted private network. It should be treated as a learning project and not as a replacement for a professionally audited password manager.

Encryption
Fernet · PBKDF2-HMAC-SHA256 · per-entry salts
Application
FastAPI · JWT · PostgreSQL 15
Intended environment
Localhost or a trusted HTTPS network