On Not Rolling Your Own Verification or Encryption
November 10, 2011 § Leave a Comment
When developing code, there are somethings that you should leave to the experts. Encryption is one of them. When I wrote my encrypted cookies and encrypted cookie sessions gems, one of the the things I didn’t want to do was write any sort of encryption routines. Luckily ActiveSupport has some help in the way of ActiveSupport::MessageEncryptor. It’s used much like ActiveSupport::MessageVerifier which is used for signed cookies in Rails. People much smarter than me have put these pieces together, so it just makes sense to use them. Almost nothing good can come from trying to do this stuff yourself. Here are some examples of a verifier and encryptor being used.
> secret = ActiveSupport::SecureRandom.hex(10) => "379af645b8dcce20b607" > verifier = ActiveSupport::MessageVerifier.new(secret) => #<ActiveSupport::MessageVerifier:0x00000103d7ce50 @secret="379af645b8dcce20b607", @digest="SHA1"> > signed_message = verifier.generate("sign this!") => "BAhJIg9zaWduIHRoaXMhBjoGRVQ=--af1e810b074b1abd6d9dcd775f71b1fafa53c218" # this is "<base 64 encoded and serialized string>--<digest of string>" > verifier.verify(signed_message) => "sign this!" > verifier.verify(signed_message + "alittleextraontheend") ActiveSupport::MessageVerifier::InvalidSignature > verifier.verify("alittleextraatthebeginning" + signed_message) ActiveSupport::MessageVerifier::InvalidSignature
> secret = ActiveSupport::SecureRandom.hex(20) => "c1578de6ec2e1789940729dc9d97b335fc7df588" > encryptor = ActiveSupport::MessageEncryptor.new(secret) => #<ActiveSupport::MessageEncryptor:0x000001295337c8 @secret="c1578de6ec2e1789940729dc9d97b335fc7df588", @cipher="aes-256-cbc"> > encrypted_message = encryptor.encrypt_and_sign("Nothing to see here...") => "BAhJIl9YbDZkK0czS3o0ZkI0Yml6K05uYzgzM05meDJjWWU4QWh0YzdFeFFrbC85b3BocHFORWtRWXdDVWIxaW45TEQ5LS1yVkxGTURJYzFWb2pva0UrVkkwTkFnPT0GOgZFRg==--e61e02a818960d66c7865f5624fad63b1564283f" > encryptor.decrypt_and_verify(encrypted_message) => "Nothing to see here..."
If your secret is too short you’ll get a OpenSSL::Cipher::CipherError. Make sure your secret is at least 32 bytes. Using ActiveSupport::SecureRandom.hex(16) should satisfy this requirement, but obviously longer is better. You can also pass in a :digest => <digest> option as a second argument to both initializers to specify a different algorithm to use.
One of my thoughts is to submit these two gems into Rails so that people don’t make the mistake of trying to roll their own encryption systems for cookies. We’ll see how it goes.