I have a single password which is random bytes that encrypts a database. Right now I am using an encryption scheme of https://gist.github.com/jbtule/4336842. To summarize, we take our one password, generate a salt for an auth key and a crypt key, run PBKDF2 with 10,000 iterations to generate the keys, then use AES to encrypt and HMAC to authenticate. The salts are then stored next to the ciphertext.

My issue is that the key generation is becoming prohibitively slow. Encryption and decryption are happening along side other heavy CPU procedures and many queries, and therefore many decryptions, occur for any given procedure. Sometimes the key generation step can take ~5 seconds per element I want decrypted. But as I am reading about it, it seems key derivation functions aren't necessary for my use case as the original password is totally random.

I am thinking of just taking the single password and concatenating it with crypt and auth salts before the AES and HMAC encryption/decryption. I might also simply turn the PBKDF2 iterations down to something low like ~10, which might look sloppy but would involve changing less code and less testing. Is there a security vulnerability that I am missing here? Would either of these solutions open me up to an attack, brute-force or otherwise? From what I am reading about key generation it seems like I don't need it, but homebrew solutions are always bad so I am very cautious in removing any security we have. Thanks for your help.

  • 1
    $\begingroup$ As long as the password is at least the length of a key and is truly random (generated by a cryptographic random number generator) then you don't need to use PBKDF2. If both of those aren't true you can still use PBKDF2 and just drop the iteration count if it's really causing a performance issue. $\endgroup$ Aug 18 at 18:50
  • $\begingroup$ Note that true random keys can contain embedded NULL characters (0x00), while passwords are strings (usually UTF-8) and thus can't possibly contain embedded NULLs (and usually can't contain other non-printable characters) and therefore have less entropy than their length would indicate. A PBKDF takes in a password as a string, and outputs a sequence of bytes. So even if generating your "password" with a CSPRNG you'd still want to use a KDF to convert it from "printable" characters into a key. $\endgroup$ Aug 18 at 18:58
  • $\begingroup$ @SAIPeregrinus Yeah, I've seen some interoperability issues where one implementation could handle nulls, but another could not. $\endgroup$ Aug 18 at 19:37

Whenever PBKDF2 is used as a KDF with a key of large entropy, it's iteration parameter can safely be 1, which should markedly improve the problem at hand with little work. That applies if the key is a password that has at least 128-bit entropy (e.g. 22 characters randomly selected among 64).

If on the other hand the password is simple enough to be memorized, or conveniently keyed-in, or chosen by a user with little motivation or insufficient judgement to use a good password, then it's needed some kind of key stretching, like PBKDF2 provides. However PBKDF2 is an extremely poor key stretching method. 10,000 PBKDF2 iteration is almost transparent for an attacker using ASICs, and a surmountable obstacle for one using GPUs. I would advise switching to something better (involving memory): Argon2, scrypt, even the lesser bcrypt, as soon as possible, for the part that stretches the password. And even if you do this, you need a better option than doing it so often that it becomes a bottleneck.

The most general method is caching. It's entirely fine to thoroughly entropy-stretch the password just once to 128-bit pseudo-entropy, write that along the password (be it in RAM or whatever, as long as the access conditions are no more lenient than for the password itself), then use that instead of the password with no further stretching (only derivations, that PBKDF2 can do).


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.