Reputation: 18944
By default, Ruby on Rails stores session data in cookies. This has many advantages, such as the lack of need to setup any persistence layers on the server side. However, the session data is not encrypted, and the Rails app that I'm writing puts potentially sensitive data in the session. I'd like to avoid storing session data server-side if possible, and the only existing encrypted cookie store implementation for Rails seems to be abandoned, so I'm writing my own encrypted cookie store.
The Rails cookie session store works as follows:
The encrypted cookie session store that I'm writing subclasses the normal cookie store class. It works as follows:
The reason why I HMAC before encrypting (instead of HMAC after encrypting) is because I want to be able to detect changes to the encryption key or the IV. I want the software to automatically invalidate old sessions if the encryption key or IV is changed. If I HMAC after encrypting then HMAC verification will pass if I change the encryption key or IV, which is undesirable.
Is my approach secure? If not, then what's lacking?
A few notes:
Upvotes: 4
Views: 2989
Reputation: 4814
As oggy already pointed out, you should generate a unique IV and add it to each cookie. To generate a unique IV, /dev/urandom is not good enough since it is possible that it will generate the same IV for two separate cookies.
Although I'm not an expert I think one valid method to generate a unique IV is to encrypt a counter, that is incremented for each cookie, with a key that is not the same as the key used to encrypt the cookie data with.
Added much later:
There is another reason, which I have only thought of later, why it may not be such a good idea to use /dev/(u)random exclusively for IVs in the scenario that the OP outlined. In the manpage random(4), it says that users should be economical in their use of /dev/urandom, or they might degrade the quality of randomness for other users of the device. Since the quantity of data read is proportional to client-requests, you have to assume that a large amount of randomness will eventually be read in the OP's scenario.
Key-generators will probably be reading from /dev/random, which blocks, but other more legitimate users of these devices (more interested in randomness) will have their randomness degraded. Well, it's not so good to block key generators either.
So, since the OP doesn't want to depend on 3rd party libraries so much, he can reuse the AES encryption functions, using them in counter mode as I've outlined above (also in the wikipedia article under the heading Designs based on cryptographic primitives.
Upvotes: 0
Reputation: 239171
OpenSSL doesn't need a seperate CTR mode. To implement CTR mode, you keep a block-sized counter and encrypt that counter in ECB mode. You then XOR the encrypted counter with the plaintext block and increment the counter. Decryption is the same process (so the cookie must contain its initial counter value). You must never re-use the same counter value with the same key, so ensure that the counter is only ever reset if the key is changed.
Upvotes: 1
Reputation: 3571
I'm not sure I'm reading you 100% correctly, but if I am, you seem to be missing the point of using an IV. You seem to plan to have a secret IV which you will use for every cookie.
There's no need for IVs to be secret. Furthermore, you should never reuse the same IV with the same key.
Other than that, I don't see any significant flaws. Which doesn't imply that they don't exist.
Upvotes: 1