There’s a few variants of password managers. The simplest are a list of password entries in am encrypted file. Some are fancier and can automatically fill in your password for you when logging in on websites. Some supports authentication types that aren’t passwords (HOTP/TOTP secrets, etc). But I’m thinking more of the backend here, since all those other features can be added on top.
I want a password manager where you can add entries without unlocking it first. This isn’t difficult to achieve, just use public key encryption with a keypair associated to the password database. But the details can be finicky. What if you have several devices synced via online file storage services, which are online and offline at varying times, and where you sometimes make offline edits on several devices independently before syncing? My idea here is for how to make syncing easy to achieve silently, while being able to add password entries from anywhere, anytime (and yes, this turns the password database into an append-only database during normal usage, but you can clear out old entries manually to save space).
First of all we need an encrypted database, and SQLCipher should do just fine. Password entries are database entries with all the relevant data: entry name, service name and address, username, authentication details (passwords would be the standard but not the only one), comments. To add entries when it is locked we need a keypair for asymmetric encryption, so the private key is stored in the database with the public key stored unencrypted in the same type as the database.
But how exactly should entries by added? The simplest method is to create a fresh encrypted SQLCipher database with its encryption key itself being encrypted with the public key of the main password database. This is stored in a separate file. The encrypted key is stored appended to the encrypted new entries, with a flag that identifies the password database it should be merged into. When you unlock the main database, the private key is used to decrypt the key for the new entries, and they are then added to the main database. This allows for adding passwords from several devices in parallel and merging them in. Once merged with the main one, those temporary database files can be deleted.
And how do we handle conflicts? What if you end up doing password resets from a library computer you don’t trust much to access some service, and then do it again elsewhere, create entries at both occasions and don’t sync them until later? The simplest way is to keep all versions and store a version history for every entry, so you don’t lose what might be the real current password because you thought it got changed or thought it happened in a different order. But what about devices that have been offline for a while? How would your old laptop know how to sync in a new version of the database with its old version when it hasn’t seen every added entry up until the latest version (considering the new version might lack entries the laptop has, but have others)? The simplest method would be to let the devices use a separate working copy from the one on the file syncing service so it can compare the versions, and then it compare all entries. The history of entries should be identified by hashes of the details, so that a direct comparison is simple (add all entries with unknown hashes). But when the histories differ, what do you do? You could sort the entry versions by timestamp and assume the latest timestamp is the current correct password, allowing the user to change later. It would also keep a history of deleted entries by their hashes, to simplify sync with devices that have been offline for a while (so they don’t add back old deleted entries).
(More details and a simplified summary coming later)