I am redesigning a password reset email mechanism because the existing implementation scares the hell out of me. My goal is to generate reset codes that are:
- Tamper Resistant
- Single Use
- Resistant to replay attacks
The format of the reset code I have come up with is:
B64( B64( iv ) || B64( E( uid || timestamp ) ) )
B64 is base64 encoding and
E is for symmetric encryption. The
iv is the initialization vector used for encryption (randomly generated), and is in the clear. The
|| indicates concatenation and I actually use the string
"||" as the separator. The
uid is an opaque identifier of the user so I can look them up in the database.
timestamp allows for a code to be expired.
I am using AES 256 in Galois Counter Mode which should provide protection from modified ciphertext attacks.
The encryption key is stored on the server, and used to perform the encryption.
iv has a dual use. When the reset code is generated the
iv is stored with the user in the database. This is used to enforce single-use of a reset code (it gets cleared when a reset code is processed) as well as prevent use of reset codes generated previously. If the
iv in the database does not match the
iv used to decrypt the reset code, the request is refused. This may also help with security in the event that the encryption key on the server is somehow compromised, as the attacker has to inject the
iv into the database as well to make it work. Of course if the attacker is on the host we are pretty much toast...
Are there any weaknesses in this design I am not seeing, or does it needs additional improvement?