IV(初期化ベクトル)をどこに保存してあるのだろう、どうやって復号化しているのだろうか?と調べたのでメモ。
#encrypt_and_sign
の返り値は、--
区切りで暗号化データ・初期化ベクトル・認証タグとなっている(それぞれBase64符号化を行っている)。
iv = cipher.random_iv
cipher.auth_data = "" if aead_mode?
encrypted_data = cipher.update(Messages::Metadata.wrap(@serializer.dump(value), metadata_options))
encrypted_data << cipher.final
blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
blob = "#{blob}--#{::Base64.strict_encode64 cipher.auth_tag}" if aead_mode?
blob
ref: active_support/message_encryptor.rb
実行結果
crypt = ActiveSupport::MessageEncryptor.new('a'*32)
=>
crypt.encrypt_and_sign('secret data that needs to be concealed')
=> "PnsLv1E/iLi0ZZxE4NKAavBO3UJc4Xe3KUZnvsJfqmA61Rt/iGPjtYbxy55/OUng--HcmSJhaaOrSoBGVL--oGfjcvq66Kw4i2Yk3A6neQ=="
irb(main):054:0>
上に示したように返り値は PnsLv1E/iLi0ZZxE4NKAavBO3UJc4Xe3KUZnvsJfqmA61Rt/iGPjtYbxy55/OUng--HcmSJhaaOrSoBGVL--oGfjcvq66Kw4i2Yk3A6neQ==
となっており、--
で分解するとそれぞれ
PnsLv1E/iLi0ZZxE4NKAavBO3UJc4Xe3KUZnvsJfqmA61Rt/iGPjtYbxy55/OUng
(暗号化データ)
HcmSJhaaOrSoBGVL
(IV)
oGfjcvq66Kw4i2Yk3A6neQ==
(認証タグ)
となっている。
したがって初期化ベクトルをDBに保存する必要がない。以下に引用するように、実際の処理ではは encrypted_data, iv, auth_tag = encrypted_message.split("--").map { |v| ::Base64.strict_decode64(v) }
としている。ここが attr-encrypted gemとの違いで気軽に使いやすい。
def _decrypt(encrypted_message, purpose)
cipher = new_cipher
encrypted_data, iv, auth_tag = encrypted_message.split("--").map { |v| ::Base64.strict_decode64(v) }
raise InvalidMessage if aead_mode? && (auth_tag.nil? || auth_tag.bytes.length != 16)
cipher.decrypt
cipher.key = @secret
cipher.iv = iv
if aead_mode?
cipher.auth_tag = auth_tag
cipher.auth_data = ""
end
decrypted_data = cipher.update(encrypted_data)
decrypted_data << cipher.final
message = Messages::Metadata.verify(decrypted_data, purpose)
@serializer.load(message) if message
rescue OpenSSLCipherError, TypeError, ArgumentError
raise InvalidMessage
end
ref: active_support/message_encryptor.rb
参考