| 52 | } |
| 53 | |
| 54 | std::string FileKeyWrapper::GetEncryptionKeyMetadata(const SecureString& data_key, |
| 55 | const std::string& master_key_id, |
| 56 | bool is_footer_key, |
| 57 | std::string key_id_in_file) { |
| 58 | if (kms_client_ == NULLPTR) { |
| 59 | throw ParquetException("No KMS client available. See previous errors."); |
| 60 | } |
| 61 | |
| 62 | std::string encoded_kek_id; |
| 63 | std::string encoded_wrapped_kek; |
| 64 | std::string encoded_wrapped_dek; |
| 65 | if (!double_wrapping_) { |
| 66 | encoded_wrapped_dek = kms_client_->WrapKey(data_key, master_key_id); |
| 67 | } else { |
| 68 | // Find in cache, or generate KEK for Master Key ID |
| 69 | KeyEncryptionKey key_encryption_key = kek_per_master_key_id_->GetOrInsert( |
| 70 | master_key_id, [this, master_key_id]() -> KeyEncryptionKey { |
| 71 | return this->CreateKeyEncryptionKey(master_key_id); |
| 72 | }); |
| 73 | // Encrypt DEK with KEK |
| 74 | const std::string& aad = key_encryption_key.kek_id(); |
| 75 | const SecureString& kek_bytes = key_encryption_key.kek_bytes(); |
| 76 | encoded_wrapped_dek = internal::EncryptKeyLocally(data_key, kek_bytes, aad); |
| 77 | encoded_kek_id = key_encryption_key.encoded_kek_id(); |
| 78 | encoded_wrapped_kek = key_encryption_key.encoded_wrapped_kek(); |
| 79 | } |
| 80 | |
| 81 | bool store_key_material_internally = (nullptr == key_material_store_); |
| 82 | |
| 83 | std::string serialized_key_material = |
| 84 | KeyMaterial::SerializeToJson(is_footer_key, kms_connection_config_.kms_instance_id, |
| 85 | kms_connection_config_.kms_instance_url, master_key_id, |
| 86 | double_wrapping_, encoded_kek_id, encoded_wrapped_kek, |
| 87 | encoded_wrapped_dek, store_key_material_internally); |
| 88 | |
| 89 | // Internal key material storage: key metadata and key material are the same |
| 90 | if (store_key_material_internally) { |
| 91 | return serialized_key_material; |
| 92 | } |
| 93 | // External key material storage: key metadata is a reference to a key in the material |
| 94 | // store |
| 95 | if (key_id_in_file.empty()) { |
| 96 | // The key id may be specified explicitly to support key rotation, but usually |
| 97 | // we generate an arbitrary identifier that just needs to be unique across |
| 98 | // columns and the footer. |
| 99 | if (is_footer_key) { |
| 100 | key_id_in_file = KeyMaterial::kFooterKeyIdInFile; |
| 101 | } else { |
| 102 | // Generate a new unique identifier using an incrementing counter |
| 103 | key_id_in_file = |
| 104 | KeyMaterial::kColumnKeyIdInFilePrefix + std::to_string(key_counter_); |
| 105 | key_counter_++; |
| 106 | } |
| 107 | } |
| 108 | key_material_store_->AddKeyMaterial(key_id_in_file, std::move(serialized_key_material)); |
| 109 | std::string serialized_key_metadata = |
| 110 | KeyMetadata::CreateSerializedForExternalMaterial(key_id_in_file); |
| 111 | return serialized_key_metadata; |