

Bcrypt - symmetric encryption - uonce

I'm investigating whether I can use bcrypt not just for password hashing, but to encrypt database contents as well.<p>The idea would be to run a strong password through bcrypt (with an appropriately high work factor, so that the operation takes perhaps 10ms), and then use the digest created as a symmetric key to encrypt the database record.<p>I would obviously NOT store the digest in the database; rather, to authenticate the user, I'd decrypt their database entry and verify that it was correct (something cheap like checking the first few bytes for a known value, for instance).<p>I would certainly store the work factor and the salt, as those would be needed to re-hash the provided password and generate the symmetric key.<p>It looks like bcrypt outputs a 186-bit hash (31 base64 chars, and I don't know why it says 184 bits here: http://stackoverflow.com/questions/5881169/storing-a-hashed-password-bcrypt-in-a-database-type-length-of-column).<p>Not sure if it would it be safe to pad that out and use 192-bit AES as my symmetric algorithm... or is there something insecure about that which I don't realize? Would it make sense to use a different algorithm?<p>Would love some feedback on whether this scheme makes sense, whether there's something better to do, and any pointers to additional reading.
======
JoachimSchipper
Stackoverflow is right: the last two bits are just padding, and not at all
unpredictable. AES was not designed to work with a partially-known key, so I
wouldn't recommend it.

Unlike bcrypt, PBKDF2 was explicitly designed for this purpose, so I'd
recommend using that if you do go this route. It'll also get you a strong
256-bit key (in the correct variant). (If you really want to use bcrypt, just
truncate at 128 bits and use AES-128, which is good enough. Really.)

Whether using bcrypt or PBKDF2, you'll want to use a salt, which should be
stored in the database. Whether using bcrypt or PBKDF2, some users will choose
pitifully weak passwords and allow their data to be decrypted (no password
hash can save you if you pick "password" or "iloveyou"). You can more-or-less
solve this by integrating e.g. <http://www.openwall.com/passwdqc/>.

All that said, I'm not sure this is a good idea:

\- you expose yourself to DDoS by repeated logins, fixable only by setting the
work factor for bcrypt/PBKDF2 dangerously low (100 POST
"/create_new_account.php" requests per second is _not_ much);

\- if your front-end machines are compromised, the attacker can gather
passwords from legitimate logins, so you still need to secure your front-end
machines;

\- encrypting everything that could be useful to an attacker means that you
can only use your RDBMS as a networked hash table;

\- crypto is hard, and easy to get subtly wrong.

Then again, implementing this would most likely increase your security quite a
bit. Just don't rely on it.

~~~
uonce
Wonderful reply, thank you! Glad to know about PBKDF2. It seems like the right
fit.

In this application, I'm actually generating strong passwords and assigning
them to users — it's a unique case where that's not a usability concern, and
the data is very rarely accessed. My thought with this setup is that I could
assign, say, a 64-bit password, which I'd then use to generate longer keys for
AES with a purposefully slow algorithm. I'd prefer not to assign users 128-bit
AES keys directly because it will be harder for them to deal with the longer
string.

In thinking about the code length, I'm trying to form an estimate with rough
numbers like so: \- I'd like to be able to generate the AES key in 10
microseconds (I lowered that based on your DDoS concern) \- I'd like a brute-
force attack to take 100 years \- An adversary could devote 10,000 times my
computing power to cracking (really not sure how to estimate this though...
botnets, gpus...)

Given those numbers, my keys need log2(100 years * 10,000 / 10 microseconds) =
62 bits of entropy. So I'd assume 64-bit keys would be secure, if I generate
them correctly.

Basically I'm trading off computation time on my server for giving users
shorter keys.

I do want to rely on this. Most of the user data should be visible only to the
user, although I'll keep some parts (account info) in plaintext or encrypted
with a master key. I don't know of a way of avoiding the front-end risk other
than making sure to secure it, because the key has to come from the user; only
they have it.

Any thoughts on my estimate of the key length and the feasibility of this
system?

~~~
JoachimSchipper
[Sorry, I haven't forgotten about this message, but things are really hectic
right now. I'll try to get to it tomorrow.]

~~~
uonce
That is so kind! Thank you for this advice. I'll pay it forward online....

