We are currently implementing envelope encryption for our app. That means, we need to derive a key from a user's password, which then will be used as a key encryption key(KEK) to wrap another key using the AES-KW algorithm. Basically, on our database the wrapped key (which is the data encryption key in our case) will be stored in the same schema as BCrypt hashes of the user password.
My concern: according RFC 3394, §2.2.3.1 there is always a constant initial value prefixed with the wrapped key to check key integrity. However, in that case an attacker could just try to brute-force the PBKDF2 algorithm by iterating the password space, try to unwrap the key with the derived KEK, and check whether the initial value of the unwrapped key is A6A6A6A6A6A6A6A6. In case of a match he will not only be able to unwrap the key, but also get the user password, thus circumventing BCrypt.
An example:
Let's assume a user chooses a password with 5 characters of [A-Za-z0-9]. That means, the password space cardinality is (26 + 26 + 10)^5 = 62^5 ~ 9.16e8.
Our current idea:
PBKDF2 with HMAC-SHA512 @ 100.000 iterations
BCrypt (lets assume an average run time of 0.1s per hash)
Thus, to brute- force PBKDF2, it would require ~9.16e13 SHA512 hash evaluations. I have searched on ebay and found racks (mostly for mining bitcoin) for $150 with a hash rate of 1TH/s (that means 1e12 H/s). That means, on average it would take 9.16e1=91.6s to brute-force a 5 character password.
Using the BCrypt example, let's assume 16 cores+ hyperthreading -> 320 BCrypt H/s on a single device. Thus it would take 2862915.1s to brute- force the same password on BCrypt, what is 33days.
Now the main question:
why OWASP still recommends PBKDF2 despite the easy paralellization of SHA hashes on GPU? Would it maybe be better to derive a key with sha256(bcrypt(password, salt))
instead of pbkdf2(password, salt)
? Or maybe even pbkdf2(bcrypt(password, salt), salt)
?