diff options
author | danielsdeleo <dan@opscode.com> | 2013-04-26 13:43:24 -0700 |
---|---|---|
committer | danielsdeleo <dan@opscode.com> | 2013-04-30 11:47:10 -0700 |
commit | 5b9d52b696ad0f1b28804719751c31457377ea13 (patch) | |
tree | 20f9adf27921b55e30f692f13f1de6ac81a5e0c5 /lib/chef/encrypted_data_bag_item.rb | |
parent | e0544ef514602bd2a62a6c3328de18ccfe3a0f23 (diff) | |
download | chef-5b9d52b696ad0f1b28804719751c31457377ea13.tar.gz |
[CHEF-3858] ensure invalid key always fails to decrypt
In Ci, we occasionally see test failures when decryption with an
incorrect key does not raise an error, but instead returns garbage.
This fixes that issue by adding an HMAC-SHA2-256 of the encrypted data
to the version 1 format. For backwards compatibility, decryption will
continue if the hmac is missing; therefore, this does not increase the
security of encrypted data bag items.
Diffstat (limited to 'lib/chef/encrypted_data_bag_item.rb')
-rw-r--r-- | lib/chef/encrypted_data_bag_item.rb | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/lib/chef/encrypted_data_bag_item.rb b/lib/chef/encrypted_data_bag_item.rb index 816ea13864..4f96b171fa 100644 --- a/lib/chef/encrypted_data_bag_item.rb +++ b/lib/chef/encrypted_data_bag_item.rb @@ -86,6 +86,7 @@ class Chef::EncryptedDataBagItem def for_encrypted_item { "encrypted_data" => encrypted_data, + "hmac" => hmac, "iv" => Base64.encode64(iv), "version" => 1, "cipher" => ALGORITHM @@ -122,6 +123,15 @@ class Chef::EncryptedDataBagItem end end + # Generates an HMAC-SHA2-256 of the encrypted data (encrypt-then-mac) + def hmac + @hmac ||= begin + digest = OpenSSL::Digest::Digest.new("sha256") + raw_hmac = OpenSSL::HMAC.digest(digest, key, encrypted_data) + Base64.encode64(raw_hmac) + end + end + # Wraps the data in a single key Hash (JSON Object) and converts to JSON. # The wrapper is required because we accept values (such as Integers or # Strings) that do not produce valid JSON when serialized without the @@ -182,7 +192,6 @@ class Chef::EncryptedDataBagItem raise DecryptionFailure, "Error decrypting data bag value. Most likely the provided key is incorrect" end - def encrypted_bytes Base64.decode64(@encrypted_data["encrypted_data"]) end @@ -193,6 +202,7 @@ class Chef::EncryptedDataBagItem def decrypted_data @decrypted_data ||= begin + validate_hmac! plaintext = openssl_decryptor.update(encrypted_bytes) plaintext << openssl_decryptor.final rescue OpenSSL::Cipher::CipherError => e @@ -200,6 +210,24 @@ class Chef::EncryptedDataBagItem end end + def validate_hmac! + return nil unless @encrypted_data.key?("hmac") + + digest = OpenSSL::Digest::Digest.new("sha256") + raw_hmac = OpenSSL::HMAC.digest(digest, key, @encrypted_data["encrypted_data"]) + expected_bytes = raw_hmac.bytes.to_a + actual_bytes = Base64.decode64(@encrypted_data["hmac"]).bytes.to_a + valid = expected_bytes.size ^ actual_bytes.size + expected_bytes.zip(actual_bytes) { |x, y| valid |= x ^ y.to_i } + if valid == 0 + # correct hmac + true + else + raise DecryptionFailure, "Error decrypting data bag value: invalid hmac. Most likely the provided key is incorrect" + end + end + + def openssl_decryptor @openssl_decryptor ||= begin assert_valid_cipher! |