rails/activesupport/test/message_encryptor_test.rb
Vipul A M ae32b69ab9
Follow up of #25602
Since keys are truncated, ruby 2.4 doesn't accept keys greater than their lenghts.
keys of same value but different lenght and greater than key size of cipher, produce the same results
as reproduced at https://gist.github.com/rhenium/b81355fe816dcfae459cc5eadfc4f6f9
Since our default cipher is 'aes-256-cbc', key length for which is 32 bytes, limit the length of key being passed to Encryptor to 32 bytes.
This continues to support backwards compat with any existing signed data, already encrupted and signed with 32+ byte keys.
Also fixes the passing of this value in multiple tests.
2016-09-01 02:53:48 +05:30

121 lines
4.8 KiB
Ruby

require "abstract_unit"
require "openssl"
require "active_support/time"
require "active_support/json"
class MessageEncryptorTest < ActiveSupport::TestCase
class JSONSerializer
def dump(value)
ActiveSupport::JSON.encode(value)
end
def load(value)
ActiveSupport::JSON.decode(value)
end
end
def setup
@secret = SecureRandom.random_bytes(32)
@verifier = ActiveSupport::MessageVerifier.new(@secret, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
@encryptor = ActiveSupport::MessageEncryptor.new(@secret)
@data = { some: "data", now: Time.local(2010) }
end
def test_encrypting_twice_yields_differing_cipher_text
first_message = @encryptor.encrypt_and_sign(@data).split("--").first
second_message = @encryptor.encrypt_and_sign(@data).split("--").first
assert_not_equal first_message, second_message
end
def test_messing_with_either_encrypted_values_causes_failure
text, iv = @verifier.verify(@encryptor.encrypt_and_sign(@data)).split("--")
assert_not_decrypted([iv, text] * "--")
assert_not_decrypted([text, munge(iv)] * "--")
assert_not_decrypted([munge(text), iv] * "--")
assert_not_decrypted([munge(text), munge(iv)] * "--")
end
def test_messing_with_verified_values_causes_failures
text, iv = @encryptor.encrypt_and_sign(@data).split("--")
assert_not_verified([iv, text] * "--")
assert_not_verified([text, munge(iv)] * "--")
assert_not_verified([munge(text), iv] * "--")
assert_not_verified([munge(text), munge(iv)] * "--")
end
def test_signed_round_tripping
message = @encryptor.encrypt_and_sign(@data)
assert_equal @data, @encryptor.decrypt_and_verify(message)
end
def test_backwards_compat_for_64_bytes_key
# 64 bit key
secret = ["3942b1bf81e622559ed509e3ff274a780784fe9e75b065866bd270438c74da822219de3156473cc27df1fd590e4baf68c95eeb537b6e4d4c5a10f41635b5597e"].pack('H*')
# Encryptor with 32 bit key, 64 bit secret for verifier
encryptor = ActiveSupport::MessageEncryptor.new(secret[0..31], secret)
# Message generated with 64 bit key
message = "eHdGeExnZEwvMSt3U3dKaFl1WFo0TjVvYzA0eGpjbm5WSkt5MXlsNzhpZ0ZnbWhBWFlQZTRwaXE1bVJCS2oxMDZhYVp2dVN3V0lNZUlWQ3c2eVhQbnhnVjFmeVVubmhRKzF3WnZyWHVNMDg9LS1HSisyakJVSFlPb05ISzRMaXRzcFdBPT0=--831a1d54a3cda8a0658dc668a03dedcbce13b5ca"
assert_equal 'data', encryptor.decrypt_and_verify(message)[:some]
end
def test_alternative_serialization_method
prev = ActiveSupport.use_standard_json_time_format
ActiveSupport.use_standard_json_time_format = true
encryptor = ActiveSupport::MessageEncryptor.new(SecureRandom.random_bytes(32), SecureRandom.random_bytes(128), serializer: JSONSerializer.new)
message = encryptor.encrypt_and_sign(:foo => 123, "bar" => Time.utc(2010))
exp = { "foo" => 123, "bar" => "2010-01-01T00:00:00.000Z" }
assert_equal exp, encryptor.decrypt_and_verify(message)
ensure
ActiveSupport.use_standard_json_time_format = prev
end
def test_message_obeys_strict_encoding
bad_encoding_characters = "\n!@#"
message, iv = @encryptor.encrypt_and_sign("This is a very \n\nhumble string"+bad_encoding_characters)
assert_not_decrypted("#{::Base64.encode64 message.to_s}--#{::Base64.encode64 iv.to_s}")
assert_not_verified("#{::Base64.encode64 message.to_s}--#{::Base64.encode64 iv.to_s}")
assert_not_decrypted([iv, message] * bad_encoding_characters)
assert_not_verified([iv, message] * bad_encoding_characters)
end
def test_aead_mode_encryption
encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm")
message = encryptor.encrypt_and_sign(@data)
assert_equal @data, encryptor.decrypt_and_verify(message)
end
def test_messing_with_aead_values_causes_failures
encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm")
text, iv, auth_tag = encryptor.encrypt_and_sign(@data).split("--")
assert_not_decrypted([iv, text, auth_tag] * "--")
assert_not_decrypted([munge(text), iv, auth_tag] * "--")
assert_not_decrypted([text, munge(iv), auth_tag] * "--")
assert_not_decrypted([text, iv, munge(auth_tag)] * "--")
assert_not_decrypted([munge(text), munge(iv), munge(auth_tag)] * "--")
assert_not_decrypted([text, iv] * "--")
assert_not_decrypted([text, iv, auth_tag[0..-2]] * "--")
end
private
def assert_not_decrypted(value)
assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do
@encryptor.decrypt_and_verify(@verifier.generate(value))
end
end
def assert_not_verified(value)
assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do
@encryptor.decrypt_and_verify(value)
end
end
def munge(base64_string)
bits = ::Base64.strict_decode64(base64_string)
bits.reverse!
::Base64.strict_encode64(bits)
end
end