diff options
Diffstat (limited to 'activesupport/test/message_encryptor_test.rb')
-rw-r--r-- | activesupport/test/message_encryptor_test.rb | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb index 1fbe655642..17baf3550b 100644 --- a/activesupport/test/message_encryptor_test.rb +++ b/activesupport/test/message_encryptor_test.rb @@ -115,6 +115,124 @@ class MessageEncryptorTest < ActiveSupport::TestCase assert_equal "Ruby on Rails", encryptor.decrypt_and_verify(encrypted_message) end + def test_with_rotated_raw_key + old_raw_key = SecureRandom.random_bytes(32) + old_encryptor = ActiveSupport::MessageEncryptor.new(old_raw_key, cipher: "aes-256-gcm") + old_message = old_encryptor.encrypt_and_sign("message encrypted with old raw key") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + encryptor.rotate raw_key: old_raw_key, cipher: "aes-256-gcm" + + assert_equal "message encrypted with old raw key", encryptor.decrypt_and_verify(old_message) + end + + def test_with_rotated_secret_and_salt + old_secret, old_salt = SecureRandom.random_bytes(32), "old salt" + old_raw_key = ActiveSupport::KeyGenerator.new(old_secret, iterations: 1000).generate_key(old_salt, 32) + + old_encryptor = ActiveSupport::MessageEncryptor.new(old_raw_key, cipher: "aes-256-gcm") + old_message = old_encryptor.encrypt_and_sign("message encrypted with old secret and salt") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + encryptor.rotate secret: old_secret, salt: old_salt, cipher: "aes-256-gcm" + + assert_equal "message encrypted with old secret and salt", encryptor.decrypt_and_verify(old_message) + end + + def test_with_rotated_key_generator + old_key_gen, old_salt = ActiveSupport::KeyGenerator.new(SecureRandom.random_bytes(32), iterations: 256), "old salt" + + old_raw_key = old_key_gen.generate_key(old_salt, 32) + old_encryptor = ActiveSupport::MessageEncryptor.new(old_raw_key, cipher: "aes-256-gcm") + old_message = old_encryptor.encrypt_and_sign("message encrypted with old key generator and salt") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + encryptor.rotate key_generator: old_key_gen, salt: old_salt, cipher: "aes-256-gcm" + + assert_equal "message encrypted with old key generator and salt", encryptor.decrypt_and_verify(old_message) + end + + def test_with_rotated_aes_cbc_encryptor_with_raw_keys + old_raw_key, old_raw_signed_key = SecureRandom.random_bytes(32), SecureRandom.random_bytes(16) + + old_encryptor = ActiveSupport::MessageEncryptor.new(old_raw_key, old_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1") + old_message = old_encryptor.encrypt_and_sign("message encrypted with old raw keys") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret) + encryptor.rotate raw_key: old_raw_key, raw_signed_key: old_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1" + + assert_equal "message encrypted with old raw keys", encryptor.decrypt_and_verify(old_message) + end + + def test_with_rotated_aes_cbc_encryptor_with_secret_and_salts + old_secret, old_salt, old_signed_salt = SecureRandom.random_bytes(32), "old salt", "old signed salt" + + old_key_gen = ActiveSupport::KeyGenerator.new(old_secret, iterations: 1000) + old_raw_key = old_key_gen.generate_key(old_salt, 32) + old_raw_signed_key = old_key_gen.generate_key(old_signed_salt) + + old_encryptor = ActiveSupport::MessageEncryptor.new(old_raw_key, old_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1") + old_message = old_encryptor.encrypt_and_sign("message encrypted with old secret and salts") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret) + encryptor.rotate secret: old_secret, salt: old_salt, signed_salt: old_signed_salt, cipher: "aes-256-cbc", digest: "SHA1" + + assert_equal "message encrypted with old secret and salts", encryptor.decrypt_and_verify(old_message) + end + + def test_with_rotating_multiple_encryptors + older_raw_key, older_raw_signed_key = SecureRandom.random_bytes(32), SecureRandom.random_bytes(16) + old_raw_key, old_raw_signed_key = SecureRandom.random_bytes(32), SecureRandom.random_bytes(16) + + older_encryptor = ActiveSupport::MessageEncryptor.new(older_raw_key, older_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1") + older_message = older_encryptor.encrypt_and_sign("message encrypted with older raw key") + + old_encryptor = ActiveSupport::MessageEncryptor.new(old_raw_key, old_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1") + old_message = old_encryptor.encrypt_and_sign("message encrypted with old raw key") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret) + encryptor.rotate raw_key: old_raw_key, raw_signed_key: old_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1" + encryptor.rotate raw_key: older_raw_key, raw_signed_key: older_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1" + + assert_equal "encrypted message", encryptor.decrypt_and_verify(encryptor.encrypt_and_sign("encrypted message")) + assert_equal "message encrypted with old raw key", encryptor.decrypt_and_verify(old_message) + assert_equal "message encrypted with older raw key", encryptor.decrypt_and_verify(older_message) + end + + def test_on_rotation_instance_callback_is_called_and_returns_modified_messages + callback_ran, message = nil, nil + + older_raw_key, older_raw_signed_key = SecureRandom.random_bytes(32), SecureRandom.random_bytes(16) + old_raw_key, old_raw_signed_key = SecureRandom.random_bytes(32), SecureRandom.random_bytes(16) + + older_encryptor = ActiveSupport::MessageEncryptor.new(older_raw_key, older_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1") + older_message = older_encryptor.encrypt_and_sign(encoded: "message") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret) + encryptor.rotate raw_key: old_raw_key, raw_signed_key: old_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1" + encryptor.rotate raw_key: older_raw_key, raw_signed_key: older_raw_signed_key, cipher: "aes-256-cbc", digest: "SHA1" + + message = encryptor.decrypt_and_verify(older_message, on_rotation: proc { callback_ran = true }) + + assert callback_ran, "callback was ran" + assert_equal({ encoded: "message" }, message) + end + + def test_with_rotated_metadata + old_secret, old_salt = SecureRandom.random_bytes(32), "old salt" + old_raw_key = ActiveSupport::KeyGenerator.new(old_secret, iterations: 1000).generate_key(old_salt, 32) + + old_encryptor = ActiveSupport::MessageEncryptor.new(old_raw_key, cipher: "aes-256-gcm") + old_message = old_encryptor.encrypt_and_sign( + "message encrypted with old secret, salt, and metadata", purpose: "rotation") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + encryptor.rotate secret: old_secret, salt: old_salt, cipher: "aes-256-gcm" + + assert_equal "message encrypted with old secret, salt, and metadata", + encryptor.decrypt_and_verify(old_message, purpose: "rotation") + end + private def assert_aead_not_decrypted(encryptor, value) assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do |