1
$\begingroup$

I'm trying to make a password manager for Windows installed computers, and after researching the best ways to encrypt the passwords in the database (I'm new to cryptography) I think I've come up with a good way to do it, but I'm still not sure.

How the key is made when the user first opens the program:

  • The user inputs the master password, the password that will unlock the password database.
  • A random salt of 16 bytes and the master password will be put through a KDF (PBKDF2 using SHA512) to derive a key $k$. $$k = \operatorname{PBKDF2-SHA-512}(password, salt)$$

How the database is encrypted:

  • Using the $k$, the database is encrypted using AES 256 bit CBC. $$ c = \operatorname{AES-CBC}(k,IV, database)$$

  • The $IV$ and the encrypted database $c$ are then encoded to base64 before store.

Where and how the database, salt (for the key $k$) and the $IV$ (for AES) are stored:

  • The salt, $IV$ and encrypted database will be dumped into a python dictionary, and written to a txt file e.g. {"salt": "T\x96\x829\xed\...", "iv": "00/JOAIsHs9XtB5acawBhA==", "database": "TE4nhDRTJ+JW..."}

  • The decrypted database file is then deleted and overwritten with random encrypted data multiple times to properly wipe it.

  • This txt file is then encrypted with AES 256 bit CBC, the key is 32 random bytes which is then hidden somewhere on the computer (could this part be skipped?).

I would prefer if no external devices would have to be used to store the second encryption key.

Also, every time the database is decrypted, and then encrypted back again when the user is done, a new key with a different salt is produced, and a new IV for encryption is produced.

Is this how it's supposed to be done? Or am I completely wrong?

$\endgroup$
14
  • 2
    $\begingroup$ So, why the others is not good and yours is good while there are tons of good solutions, like keepass, etc. Can you share a password as others did? You use the pepper terminology wrongly! Note, this is actually off-topic! $\endgroup$ – kelalaka Jan 10 at 14:26
  • $\begingroup$ Now see keepass.info/help/base/security.html#seckeyhash and why that is not better? $\endgroup$ – kelalaka Jan 10 at 16:41
  • 1
    $\begingroup$ You'd normally decrypt to memory, not disk. Overwriting data doesn't do much on an SSD - if you're going to overwrite with random data then a single pass would be sufficient (just to make sure that it isn't logically retrievable). PBKDF2 also requires an iteration count which you may want to update. You would want to make sure that nobody can change your DB undetected, e.g. using a HMAC. $\endgroup$ – Maarten Bodewes Jan 10 at 16:50
  • 1
    $\begingroup$ Where it is accessible. They do not need to be secret. They can be stored with the ciphertext; this is common knowledge. $\endgroup$ – kelalaka Jan 10 at 17:33
  • 1
    $\begingroup$ Authentication is ensuring that attackers can't change the ciphertext. KeePass does it by using AES-CBC-HMAC-SHA-256 (HMAC the ciphertext from AES. When decrypcing, check the MAC first and refuse to decrypt if it isn't valid.) CBC is only used for legacy compatibility, these days SIV mode is probably a better fit for your use. Or GCM if you're very careful to never reuse a nonce. Both are provided by pycryptodome. Also their docs do mention not to use CBC alone, read them first. $\endgroup$ – SAI Peregrinus Jan 11 at 0:30
1
$\begingroup$

If the key is derived from the password there is no reason to store it anywhere. The main problem in your outline is not the cryptography. You are explicitly writing the passwords to disk. This is a really bad idea. The deletion may not happen at all, e.g powe failure. Even if it does on a modern hard drive it is really hard to overwrite data it won't actually be written to the same place and thus traces of previous data may remain.

A secure implementation will not only avoid writing to disk it would explicitly request from the OS to not swap out the sensitive memory parts. The OS may allow you to do this for only a small piece of memory. If the password DB is large decrypting the whole thing may be problematic and you should consider only decrypting the part you want but that causes a behaviour change you may or not want.

You may want an authentication if you worry about someone mangling your db.

You didn't mention IV selection, needs to be from a strong random source and replaced everytime you change anything and need to reencrypt.

$\endgroup$
5
  • $\begingroup$ I am going to copy what kneepass does and open the decrypted db in memory. I can't select what parts of the db I want when its encrypted though, its just one table containing the username, email, password and site its for, theres not one part thats particularly more important than another part. The IV is generated by a python module called pycryptodome. $\endgroup$ – user86121 Jan 10 at 21:16
  • 1
    $\begingroup$ Note that Keepass doesn't decrypt the whole DB at once. It decrypts a header which lists the entries (with username, password, attachments, url, etc), and each entry has its own encryption key. Those keys are all derived from the main key and a per-entry IV. Also, pycryptodome has a bunch of low-level methods in its "hazmat" module. Avoid those, they're hazardous and intended for some very niche uses. $\endgroup$ – SAI Peregrinus Jan 11 at 0:24
  • $\begingroup$ @SAIPeregrinus By entry do you mean theres an encryption key for every single field in the db? Or is it a key per record or per column? $\endgroup$ – user86121 Jan 11 at 12:33
  • $\begingroup$ There's a key for every row, basically. So the password and associated secret fields are encrypted independently of the database header. $\endgroup$ – SAI Peregrinus Jan 11 at 16:04
  • $\begingroup$ @SAIPeregrinus Oh ok. $\endgroup$ – user86121 Jan 11 at 18:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.