lib/kms_encrypted/model.rb in kms_encrypted-0.1.4 vs lib/kms_encrypted/model.rb in kms_encrypted-0.2.0
- old
+ new
@@ -44,20 +44,39 @@
key_id: key_id,
context: context
}
ActiveSupport::Notifications.instrument("generate_data_key.kms_encrypted", event) do
if key_id == "insecure-test-key"
- encrypted_key = "insecure-data-key-#{rand(1_000_000_000_000)}"
plaintext_key = "00000000000000000000000000000000"
+ encrypted_key = "insecure-data-key-#{rand(1_000_000_000_000)}"
+ elsif key_id.start_with?("projects/")
+ # generate random AES-256 key
+ plaintext_key = OpenSSL::Random.random_bytes(32)
+
+ # encrypt it
+ request = ::Google::Apis::CloudkmsV1::EncryptRequest.new(
+ plaintext: plaintext_key,
+ additional_authenticated_data: context.to_json
+ )
+ response = KmsEncrypted::Google.kms_client.encrypt_crypto_key(key_id, request)
+ key_version = response.name
+
+ # shorten key to save space
+ short_key_id = Base64.encode64(key_version.split("/").select.with_index { |p, i| i.odd? }.join("/"))
+
+ # build encrypted key
+ # we reference the key in the field for easy rotation
+ encrypted_key = "$gc$#{short_key_id}$#{[response.ciphertext].pack(default_encoding)}"
else
+ # generate data key from API
resp = KmsEncrypted.kms_client.generate_data_key(
key_id: key_id,
encryption_context: context,
key_spec: "AES_256"
)
- encrypted_key = [resp.ciphertext_blob].pack(default_encoding)
plaintext_key = resp.plaintext
+ encrypted_key = [resp.ciphertext_blob].pack(default_encoding)
end
end
instance_variable_set(instance_var, plaintext_key)
self.send("#{key_column}=", encrypted_key)
@@ -70,11 +89,27 @@
event = {
key_id: key_id,
context: context
}
ActiveSupport::Notifications.instrument("decrypt_data_key.kms_encrypted", event) do
- if key_id == "insecure-test-key"
+ if encrypted_key.start_with?("insecure-data-key-")
plaintext_key = "00000000000000000000000000000000"
+ elsif encrypted_key.start_with?("$gc$")
+ _, _, short_key_id, ciphertext = encrypted_key.split("$", 4)
+
+ # restore key, except for cryptoKeyVersion
+ stored_key_id = Base64.decode64(short_key_id).split("/")[0..3]
+ stored_key_id.insert(0, "projects")
+ stored_key_id.insert(2, "locations")
+ stored_key_id.insert(4, "keyRings")
+ stored_key_id.insert(6, "cryptoKeys")
+ stored_key_id = stored_key_id.join("/")
+
+ request = ::Google::Apis::CloudkmsV1::DecryptRequest.new(
+ ciphertext: ciphertext.unpack(default_encoding).first,
+ additional_authenticated_data: context.to_json
+ )
+ plaintext_key = KmsEncrypted::Google.kms_client.decrypt_crypto_key(stored_key_id, request).plaintext
else
plaintext_key = KmsEncrypted.kms_client.decrypt(
ciphertext_blob: encrypted_key.unpack(default_encoding).first,
encryption_context: context
).plaintext