0

Whenever I need to generate a token (email account confirmation, password reset, remember me cookie, view email in browser etc) I generate a string of random bytes (typically 32 using the Fortuna PRNG) and use PBKDF2 to create a hash which is stored in a database. I then use base64 (a URL safe version) to encode the random bytes before issuing the token to the user prefixed with a unique 7 character alpha-numeric ID which is used to retrieve the PBKDF2 hash when the token is returned. The base64 string is decoded and verified against the PBKDF2 hash from the database. If the verification returns true then access is granted.

However, given that I'm working with random bytes and not user generated input, would it not make more sense to just use sha1 for storing the bytes in the database and verifying against the token? Each time I need to both generate and verify a token I'm doing 10,000 sha256 iterations on an input I already know has excellent entropy. The more I think about it, the less efficient this seems.

  • Why cannot you just use random numbers, without hashing them, using the CSPRNG provided by your operating system? – A. Hersean Apr 16 at 11:36
  • @A. Hersean Whatever format the token is, it still needs to be hashed in the database. If my database became compromised and the "remember me" tokens were leaked for example, those un-hashed tokens could essentially be used as master passwords to login to any account. Hashing the tokens just seems like a safer option. – Adam Apr 16 at 11:40
  • 1
    This question is similar. No need to use a password hash. (But, for passwords, PBKDF2 < bcrypt ≪ Argon2.) The fast hash algorithm used instead can be any preimage resistant function. – Future Security Apr 16 at 18:11
1

PBKDF2 is a "password-based key derivation function", as its name suggests it. It is intended to make harder to bruteforce passwords with low entropy. When using a source with at least 128 bits of entropy, there is no need to use a PBKDF to strengthen it, because bruteforcing a hash will need, in average, at least (2^127)/n iterations ("n" being the number of users of your system). Using 32 bytes (256 bits) would be safe even with billions of users using billions of accounts.

You will be fine using one iteration of sha256 on a token of 32 bytes generated by a CSPRNG.

  • That makes sense. I think I became a little paranoid about token security when I first implemented my token system and over-compensated a bit. I suggested sha1 as it would obviously use less space in my database compared to sha2 which generates a 60% larger hash. Would sha1 be acceptable, or would you recommend I stick with sha2? – Adam Apr 16 at 12:13
  • In your case SHA1 would be acceptable. Its flaws do not apply here. – A. Hersean Apr 16 at 12:55
  • However, a paranoid auditor might view the usage of SHA1 as a vulnerability because it is deprecated in some contexts. So for the peace of mind, you could instead use SHA3 with a 160 bits output: it will have the same output size than SHA1, with better performance. – A. Hersean Apr 16 at 12:59
  • The hashing component I'm using (Chilkat) doesn't support changing the bit output for SHA. It does support it with a hashing algorithm called HAVAL, but I'm not familiar with that one. I think I will just use sha256. Thank you very much for your help. A well deserved correct answer tick! – Adam Apr 16 at 13:39
  • 1
    @Adam Do not confuse SHA384 with SHA3. There is the SHA-1 algorithm which is old, flawed and produce hashes of 160 bits; the SHA-2 algorithm which produce hashes of 256, 384 or 512 bits (using the names SHA256, SHA384, SHA512); and the newest SHA-3 algorithm which can produce hashes of any size. – A. Hersean Apr 17 at 9:22

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.