Goal: have token/cookie-based authentication that doesn't require keeping sessions on the server
TL;DR: What, if any, is the accepted mechanism to work around the 72-character limitation of BCrypt?
After reading this answer I attempted to implement authentication on a REST-based server using BCrypt as a hashing algorithm and a rotating server-side secret. The basic idea was that upon successful authentication with a username and password, the server would set a cookie containing a hash based on concatenating the following:
- The server-side secret
- The user ID and groups to which the user belongs
- The time at which point the token was given out
This would then be hashed with a salt, and the result would go in the cookie, to be read and verified by the server (possible because the user ID, groups and date are transmitted in the plain by the client, and the server-side secret is in memory, with the secret serving as a guarantee that the client didn't make all the other values up themselves).
This all worked well until I realized that BCrypt has a 72-character limit on the plaintext being hashed (anything after those 72 characters does not influence the output hash).
This is a problem because the above data amounted to more than 72 characters, and allowing either the time, user ID, groups or secret key to be 'last' in the input and not influence the output opens holes in the system's security (either old tokens are infinitely valid, or people can modify their user ID / role arbitrarily).
Ironically, when I finally figured out why my system was producing identical hashes based on differing input and googled around, it seems this kind of situation was foreseen by some.
Anyhow, the question: What, if any, is the accepted mechanism to work around the 72-character limitation of BCrypt?
Some pre-emptive thoughts: Making up your own variations on standard crypto algorithms is something I've been warned about for as long as I can remember, so I am not 100% sure what would be the best course of action.
Obvious options include:
- chunking the input and applying BCrypt to each in turn and/or in cascaded fashion;
- using another (non-cryptographic?) hash on the input to reduce its size
- using plain compression (but that might be ineffective with such a small bit of plaintext)
- switching to another algorithm (SHA-3 was recently finalized, for instance).
(there may be other things wrong with the above idea, in which case I would of course be happy to be corrected!)