I apologize in advance for the incoming Wall-O-Text. This is (at least, to me) a fairly complex issue that I've put quite a bit of thought into. You can read my question and also see a test implementation in Ruby (very hastily built, not database-backed, and probably very ugly) at this GitHub Gist if you are so inclined.
Imagine one was required to create a web-based password management system (over SSL! :) with the following requirements:
I'm no expert in cryptography. After thinking about it for a while, I came up with the following. My question is: is this implementation secure? Am I missing something? If so, is the above spec even implementable? Or is this overkill?
The database is set up as such:
+------------------------------------------------------------------------------+
| users |
+---------+--------------+--------------+---------------+----------------------+
| salt | pub_key | enc_priv_key | priv_key_hmac | |
+---------+--------------+--------------+---------------+----------------------+
| entries |
+---------+--------------+--------------+---------------+----------+-----------+
| user_id | parent_entry | enc_sym_key | sym_key_sig | enc_data | data_hmac |
+---------+--------------+--------------+---------------+----------+-----------+
Let's imagine two users of the system, Alice and Bob.
Bob signs up for the site:
salt
field.pub_key
field. The private key is encrypted via AES-256
using the hash generated from Bob's password and salt as the key and
stored in the enc_priv_key
field.priv_key_hmac
field.Bob stores an entry in the system:
enc_data
field.data_hmac
field.enc_sym_key
field.Bob retrieves his stored entry:
priv_key_hmac
.enc_sym_key
field
using Bob's private key.sym_key_sign
using Bob's public key.data_hmac
field.Bob shares an entry with Alice:
parent_entry
is set to Bob's entry.parent_entry
causes the system to use Bob's public key to verify
the signature (since his private key was used to create it).Bob changes the data in his shared entry:
parent_entry
equal to the entry
that was just modified, and for each one overwrites the data created in
"Bob shares an entry with Alice."Advantages:
Disadvantages/Problems (that I can think of):
Repeated from the introduction: my question is: is this implementation secure? Am I missing something? If so, is the above spec even implementable? Or is this overkill?
Thanks for sticking it out this long. I'm interested in your opinions! Am I on the right track, or a complete moron? YOU DECIDE! :)
No IV storage? I guess you could use AES-256-ECB, but that only lets users store 32 byte passwords, and you need to make sure that the generated private key is only ever used for one encryption. (Your current design seems safe in this respect, but if you want to allow passwords longer than 32 bytes, or ever think of making this key do double-duty, you'll need to store an IV for every encryption with it.)
I don't see the security value of priv_key_hmac
and data_hmac
; if either the private key or the encrypted data has been tampered with, then garbage output will result from decrypting with the private key or the symmetric key. Bob will surely be suspicious when he can't figure out how to type the BEL
character. :) (Will humans ever see the output? A human will likely realize the returned password is incorrect without needing to be told. A computer couldn't tell the difference, so if automated systems will ever use the resulting passwords, then sure, keep the fields.)
There is no mechanism for "I forgot my password". Make sure your users know that there is no recovering their data if they forget their password. Users are coddled these days, and might expect to be coddled with your service too.
I see no mechanism for users to specify which entry Bob wants decrypted. You should store a name, or, as ssh(1)
does in known_hosts
, a hashed version of a name, for each entry. Storing a name directly would remove an SHA-256 operation, but a database compromise that reports the cleartext names of services that a user has accounts with might be every bit as damaging. (Perhaps an online escort service, or off-shore bank, or fight club.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With