-
Notifications
You must be signed in to change notification settings - Fork 13
rails cookies in crystal
Stephen von Takach edited this page Apr 20, 2020
·
5 revisions
Structure of the rails cookie
+--------------------------- URI Encode --------------------------+
| +--------------------------- base64 -------+------+-----------+ |
| | +---------------- base64 --------------+ | | | |
| | | encrypted data | "--" | init. vector | | "--" | signature | |
| | +----------------+------+--------------+ | | | |
| +------------------------------------------+------+-----------+ |
+-----------------------------------------------------------------+
Verifying and decrypting the cookie in crystal lang
require "openssl"
require "openssl/hmac"
# Rails cookie config
encrypt_salt = "encrypted cookie"
signing_salt = "signed encrypted cookie"
iterations = 1000
key_size = 64
digest_alg = OpenSSL::Algorithm::SHA1
# Application config
secret = "543fb68b2d592546583b1b982fb99381bad5c6fc7784fa0e95631413440cd4b854d795e5f3cc7069de53f9193c4c599f56615f01e74231b8ff4d31aa851398cc"
# Example Rails Cookie (4+ signed and encrypted)
cookie = URI.decode "ajcxdGdscHJuRytvdDk2azN0L3Z0ZHludTh0NDg3VkNwYTZRcjA2T3MxUTZDbmJXc0NWc2RWeXJiSlU0V3Q4My0tUFJsVzZBZGV0YXI3bUlVWUs2REEydz09--8f206ffc3a9e2a04b5696a1f7137e5686e7ac3d0"
# Rails adjusts the secret
signing_secret = OpenSSL::PKCS5.pbkdf2_hmac_sha1(secret, signing_salt, iterations, key_size)
# Validate the cookie
data, digest = cookie.split("--")
check_digest = OpenSSL::HMAC.hexdigest(digest_alg, signing_secret, data)
valid = check_digest == digest
# Grab the encryption components from the data above
parts = String.new(::Base64.decode(data)).split("--").map { |part| ::Base64.decode(part) }
encrypted_data = parts[0]
iv = parts[1]
auth_tag = parts[2] if parts.size == 3
# https://github.com/crystal-lang/crystal/issues/4593
raise "unsupported in crystal currently" if auth_tag
# Define the encryption algorithm
cipher_algorithm = "aes-256-cbc"
encryption_secret = OpenSSL::PKCS5.pbkdf2_hmac_sha1(secret, encrypt_salt, iterations, key_size)
# Decrypt the data
cipher = OpenSSL::Cipher.new(cipher_algorithm)
cipher.decrypt
cipher.key = encryption_secret
cipher.iv = iv
decrypted_data = IO::Memory.new
decrypted_data.write cipher.update(encrypted_data)
decrypted_data.write cipher.final
decrypted_data.to_s
Then hopefully you've configured rails to use the JSON cookie serializer