Having stumbled on Signing and encrypting data with tools built-in to Rails I was quite pleased to see this approach use the same tools that Rails uses for encrypting the user session (cookie).
This lead me to building Nygma to allow encrypting tokens received from Stripe. Since this was built rather quickly, I haven't been able to document its API as I normally do, but I will be cleaning this up in due course.
For those curious engineers amongst us, Rails' encrypted cookie implementation looks like
class EncryptedCookieJar #:nodoc:
include ChainedCookieJars
def initialize(parent_jar, key_generator, options = {})
if ActiveSupport::LegacyKeyGenerator === key_generator
raise "You didn't set config.secret_key_base, which is required for this cookie jar. " +
"Read the upgrade documentation to learn more about this new config option."
end
@parent_jar = parent_jar
@options = options
secret = key_generator.generate_key(@options[:encrypted_cookie_salt])
sign_secret = key_generator.generate_key(@options[:encrypted_signed_cookie_salt])
@encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret)
end
def [](name)
if encrypted_message = @parent_jar[name]
decrypt_and_verify(encrypted_message)
end
end
def []=(name, options)
if options.is_a?(Hash)
options.symbolize_keys!
else
options = { :value => options }
end
options[:value] = @encryptor.encrypt_and_sign(options[:value])
raise CookieOverflow if options[:value].size > MAX_COOKIE_SIZE
@parent_jar[name] = options
end
private
def decrypt_and_verify(encrypted_message)
@encryptor.decrypt_and_verify(encrypted_message)
rescue ActiveSupport::MessageVerifier::InvalidSignature, ActiveSupport::MessageEncryptor::InvalidMessage
nil
end
end