As an exercise, I am writing some code that accepts a list of possibly secret properties (e.g. user ID, password, IP address), adds a timestamp, encrypts it, and signs it.
Here's a high-level overview of what the code does - does this look correct from the point of view that it should ensure secrecy and integrity?
The main thing I am unsure about is deriving the encryption key and the signing key from the same user-provided secret key, but this seems a little paranoid given that there should be no relationship between the two assuming the strength of the underlying hash function of the key derivation algorithm.
If anyone is interested the source code together with a small test suite, packaged up with setuptools, can be found here.
Implementation
The user supplies a private key and two optional salts which we use to derive encryption and signing keys using PBKDF2. If no salt is provided two are generated using urandom
.
Next, the user supplies a list of property strings, ['a', 'b', 'c',...]
which is converted to a |-delimited string and to which str(time.time())
is prepended. This plaintext is padded using PKCS#7 method. An Initialization Vector (IV) is generated using urandom
and the plaintext is then encrypted with AES-256 (CBC mode) using the key described above and the IV.
The IV + ciphertext are then signed using Python's native HMAC-MD5 implementation with the signing key derived as described above, and this signature is appended to the message.
The decryption and verification process follow roughly the opposite process as above, with extra care taken in the verification step to use the built-in compare_hash
method to prevent vulnerability due to timing attack.