|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma once |
|
|
|
#include <map> |
|
#include <memory> |
|
#include <string> |
|
#include <utility> |
|
|
|
#include "parquet/exception.h" |
|
#include "parquet/schema.h" |
|
#include "parquet/types.h" |
|
|
|
namespace parquet { |
|
|
|
static constexpr ParquetCipher::type kDefaultEncryptionAlgorithm = |
|
ParquetCipher::AES_GCM_V1; |
|
static constexpr int32_t kMaximalAadMetadataLength = 256; |
|
static constexpr bool kDefaultEncryptedFooter = true; |
|
static constexpr bool kDefaultCheckSignature = true; |
|
static constexpr bool kDefaultAllowPlaintextFiles = false; |
|
static constexpr int32_t kAadFileUniqueLength = 8; |
|
|
|
class ColumnDecryptionProperties; |
|
using ColumnPathToDecryptionPropertiesMap = |
|
std::map<std::string, std::shared_ptr<ColumnDecryptionProperties>>; |
|
|
|
class ColumnEncryptionProperties; |
|
using ColumnPathToEncryptionPropertiesMap = |
|
std::map<std::string, std::shared_ptr<ColumnEncryptionProperties>>; |
|
|
|
class PARQUET_EXPORT DecryptionKeyRetriever { |
|
public: |
|
virtual std::string GetKey(const std::string& key_metadata) = 0; |
|
virtual ~DecryptionKeyRetriever() {} |
|
}; |
|
|
|
|
|
class PARQUET_EXPORT IntegerKeyIdRetriever : public DecryptionKeyRetriever { |
|
public: |
|
void PutKey(uint32_t key_id, const std::string& key); |
|
std::string GetKey(const std::string& key_metadata) override; |
|
|
|
private: |
|
std::map<uint32_t, std::string> key_map_; |
|
}; |
|
|
|
|
|
class PARQUET_EXPORT StringKeyIdRetriever : public DecryptionKeyRetriever { |
|
public: |
|
void PutKey(const std::string& key_id, const std::string& key); |
|
std::string GetKey(const std::string& key_metadata) override; |
|
|
|
private: |
|
std::map<std::string, std::string> key_map_; |
|
}; |
|
|
|
class PARQUET_EXPORT HiddenColumnException : public ParquetException { |
|
public: |
|
explicit HiddenColumnException(const std::string& columnPath) |
|
: ParquetException(columnPath.c_str()) {} |
|
}; |
|
|
|
class PARQUET_EXPORT KeyAccessDeniedException : public ParquetException { |
|
public: |
|
explicit KeyAccessDeniedException(const std::string& columnPath) |
|
: ParquetException(columnPath.c_str()) {} |
|
}; |
|
|
|
inline const uint8_t* str2bytes(const std::string& str) { |
|
if (str.empty()) return NULLPTR; |
|
|
|
char* cbytes = const_cast<char*>(str.c_str()); |
|
return reinterpret_cast<const uint8_t*>(cbytes); |
|
} |
|
|
|
inline ::arrow::util::span<const uint8_t> str2span(const std::string& str) { |
|
if (str.empty()) { |
|
return {}; |
|
} |
|
|
|
return {reinterpret_cast<const uint8_t*>(str.data()), str.size()}; |
|
} |
|
|
|
class PARQUET_EXPORT ColumnEncryptionProperties { |
|
public: |
|
class PARQUET_EXPORT Builder { |
|
public: |
|
|
|
explicit Builder(const std::string& name) : Builder(name, true) {} |
|
|
|
|
|
explicit Builder(const std::shared_ptr<schema::ColumnPath>& path) |
|
: Builder(path->ToDotString(), true) {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
Builder* key(std::string column_key); |
|
|
|
|
|
|
|
Builder* key_metadata(const std::string& key_metadata); |
|
|
|
|
|
|
|
|
|
|
|
Builder* key_id(const std::string& key_id); |
|
|
|
std::shared_ptr<ColumnEncryptionProperties> build() { |
|
return std::shared_ptr<ColumnEncryptionProperties>( |
|
new ColumnEncryptionProperties(encrypted_, column_path_, key_, key_metadata_)); |
|
} |
|
|
|
private: |
|
const std::string column_path_; |
|
bool encrypted_; |
|
std::string key_; |
|
std::string key_metadata_; |
|
|
|
Builder(const std::string path, bool encrypted) |
|
: column_path_(path), encrypted_(encrypted) {} |
|
}; |
|
|
|
std::string column_path() const { return column_path_; } |
|
bool is_encrypted() const { return encrypted_; } |
|
bool is_encrypted_with_footer_key() const { return encrypted_with_footer_key_; } |
|
std::string key() const { return key_; } |
|
std::string key_metadata() const { return key_metadata_; } |
|
|
|
ColumnEncryptionProperties() = default; |
|
ColumnEncryptionProperties(const ColumnEncryptionProperties& other) = default; |
|
ColumnEncryptionProperties(ColumnEncryptionProperties&& other) = default; |
|
|
|
~ColumnEncryptionProperties() { key_.clear(); } |
|
|
|
private: |
|
const std::string column_path_; |
|
bool encrypted_; |
|
bool encrypted_with_footer_key_; |
|
std::string key_; |
|
std::string key_metadata_; |
|
explicit ColumnEncryptionProperties(bool encrypted, const std::string& column_path, |
|
const std::string& key, |
|
const std::string& key_metadata); |
|
}; |
|
|
|
class PARQUET_EXPORT ColumnDecryptionProperties { |
|
public: |
|
class PARQUET_EXPORT Builder { |
|
public: |
|
explicit Builder(const std::string& name) : column_path_(name) {} |
|
|
|
explicit Builder(const std::shared_ptr<schema::ColumnPath>& path) |
|
: Builder(path->ToDotString()) {} |
|
|
|
|
|
|
|
|
|
|
|
Builder* key(const std::string& key); |
|
|
|
std::shared_ptr<ColumnDecryptionProperties> build(); |
|
|
|
private: |
|
const std::string column_path_; |
|
std::string key_; |
|
}; |
|
|
|
ColumnDecryptionProperties() = default; |
|
ColumnDecryptionProperties(const ColumnDecryptionProperties& other) = default; |
|
ColumnDecryptionProperties(ColumnDecryptionProperties&& other) = default; |
|
|
|
~ColumnDecryptionProperties() { key_.clear(); } |
|
|
|
std::string column_path() const { return column_path_; } |
|
std::string key() const { return key_; } |
|
|
|
private: |
|
const std::string column_path_; |
|
std::string key_; |
|
|
|
|
|
|
|
|
|
explicit ColumnDecryptionProperties(const std::string& column_path, |
|
const std::string& key); |
|
}; |
|
|
|
class PARQUET_EXPORT AADPrefixVerifier { |
|
public: |
|
|
|
|
|
|
|
|
|
|
|
virtual void Verify(const std::string& aad_prefix) = 0; |
|
virtual ~AADPrefixVerifier() {} |
|
}; |
|
|
|
class PARQUET_EXPORT FileDecryptionProperties { |
|
public: |
|
class PARQUET_EXPORT Builder { |
|
public: |
|
Builder() { |
|
check_plaintext_footer_integrity_ = kDefaultCheckSignature; |
|
plaintext_files_allowed_ = kDefaultAllowPlaintextFiles; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Builder* footer_key(const std::string footer_key); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Builder* column_keys( |
|
const ColumnPathToDecryptionPropertiesMap& column_decryption_properties); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Builder* key_retriever(const std::shared_ptr<DecryptionKeyRetriever>& key_retriever); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Builder* disable_footer_signature_verification() { |
|
check_plaintext_footer_integrity_ = false; |
|
return this; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
Builder* aad_prefix(const std::string& aad_prefix); |
|
|
|
|
|
Builder* aad_prefix_verifier(std::shared_ptr<AADPrefixVerifier> aad_prefix_verifier); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Builder* plaintext_files_allowed() { |
|
plaintext_files_allowed_ = true; |
|
return this; |
|
} |
|
|
|
std::shared_ptr<FileDecryptionProperties> build() { |
|
return std::shared_ptr<FileDecryptionProperties>(new FileDecryptionProperties( |
|
footer_key_, key_retriever_, check_plaintext_footer_integrity_, aad_prefix_, |
|
aad_prefix_verifier_, column_decryption_properties_, plaintext_files_allowed_)); |
|
} |
|
|
|
private: |
|
std::string footer_key_; |
|
std::string aad_prefix_; |
|
std::shared_ptr<AADPrefixVerifier> aad_prefix_verifier_; |
|
ColumnPathToDecryptionPropertiesMap column_decryption_properties_; |
|
|
|
std::shared_ptr<DecryptionKeyRetriever> key_retriever_; |
|
bool check_plaintext_footer_integrity_; |
|
bool plaintext_files_allowed_; |
|
}; |
|
|
|
~FileDecryptionProperties() { footer_key_.clear(); } |
|
|
|
std::string column_key(const std::string& column_path) const; |
|
|
|
std::string footer_key() const { return footer_key_; } |
|
|
|
std::string aad_prefix() const { return aad_prefix_; } |
|
|
|
const std::shared_ptr<DecryptionKeyRetriever>& key_retriever() const { |
|
return key_retriever_; |
|
} |
|
|
|
bool check_plaintext_footer_integrity() const { |
|
return check_plaintext_footer_integrity_; |
|
} |
|
|
|
bool plaintext_files_allowed() const { return plaintext_files_allowed_; } |
|
|
|
const std::shared_ptr<AADPrefixVerifier>& aad_prefix_verifier() const { |
|
return aad_prefix_verifier_; |
|
} |
|
|
|
private: |
|
std::string footer_key_; |
|
std::string aad_prefix_; |
|
std::shared_ptr<AADPrefixVerifier> aad_prefix_verifier_; |
|
|
|
const std::string empty_string_ = ""; |
|
ColumnPathToDecryptionPropertiesMap column_decryption_properties_; |
|
|
|
std::shared_ptr<DecryptionKeyRetriever> key_retriever_; |
|
bool check_plaintext_footer_integrity_; |
|
bool plaintext_files_allowed_; |
|
|
|
FileDecryptionProperties( |
|
const std::string& footer_key, |
|
std::shared_ptr<DecryptionKeyRetriever> key_retriever, |
|
bool check_plaintext_footer_integrity, const std::string& aad_prefix, |
|
std::shared_ptr<AADPrefixVerifier> aad_prefix_verifier, |
|
const ColumnPathToDecryptionPropertiesMap& column_decryption_properties, |
|
bool plaintext_files_allowed); |
|
}; |
|
|
|
class PARQUET_EXPORT FileEncryptionProperties { |
|
public: |
|
class PARQUET_EXPORT Builder { |
|
public: |
|
explicit Builder(const std::string& footer_key) |
|
: parquet_cipher_(kDefaultEncryptionAlgorithm), |
|
encrypted_footer_(kDefaultEncryptedFooter) { |
|
footer_key_ = footer_key; |
|
store_aad_prefix_in_file_ = false; |
|
} |
|
|
|
|
|
|
|
Builder* set_plaintext_footer() { |
|
encrypted_footer_ = false; |
|
return this; |
|
} |
|
|
|
|
|
|
|
Builder* algorithm(ParquetCipher::type parquet_cipher) { |
|
parquet_cipher_ = parquet_cipher; |
|
return this; |
|
} |
|
|
|
|
|
|
|
Builder* footer_key_id(const std::string& key_id); |
|
|
|
|
|
|
|
Builder* footer_key_metadata(const std::string& footer_key_metadata); |
|
|
|
|
|
Builder* aad_prefix(const std::string& aad_prefix); |
|
|
|
|
|
|
|
Builder* disable_aad_prefix_storage(); |
|
|
|
|
|
|
|
|
|
Builder* encrypted_columns( |
|
const ColumnPathToEncryptionPropertiesMap& encrypted_columns); |
|
|
|
std::shared_ptr<FileEncryptionProperties> build() { |
|
return std::shared_ptr<FileEncryptionProperties>(new FileEncryptionProperties( |
|
parquet_cipher_, footer_key_, footer_key_metadata_, encrypted_footer_, |
|
aad_prefix_, store_aad_prefix_in_file_, encrypted_columns_)); |
|
} |
|
|
|
private: |
|
ParquetCipher::type parquet_cipher_; |
|
bool encrypted_footer_; |
|
std::string footer_key_; |
|
std::string footer_key_metadata_; |
|
|
|
std::string aad_prefix_; |
|
bool store_aad_prefix_in_file_; |
|
ColumnPathToEncryptionPropertiesMap encrypted_columns_; |
|
}; |
|
|
|
~FileEncryptionProperties() { footer_key_.clear(); } |
|
|
|
bool encrypted_footer() const { return encrypted_footer_; } |
|
|
|
EncryptionAlgorithm algorithm() const { return algorithm_; } |
|
|
|
std::string footer_key() const { return footer_key_; } |
|
|
|
std::string footer_key_metadata() const { return footer_key_metadata_; } |
|
|
|
std::string file_aad() const { return file_aad_; } |
|
|
|
std::shared_ptr<ColumnEncryptionProperties> column_encryption_properties( |
|
const std::string& column_path); |
|
|
|
ColumnPathToEncryptionPropertiesMap encrypted_columns() const { |
|
return encrypted_columns_; |
|
} |
|
|
|
private: |
|
EncryptionAlgorithm algorithm_; |
|
std::string footer_key_; |
|
std::string footer_key_metadata_; |
|
bool encrypted_footer_; |
|
std::string file_aad_; |
|
std::string aad_prefix_; |
|
bool store_aad_prefix_in_file_; |
|
ColumnPathToEncryptionPropertiesMap encrypted_columns_; |
|
|
|
FileEncryptionProperties(ParquetCipher::type cipher, const std::string& footer_key, |
|
const std::string& footer_key_metadata, bool encrypted_footer, |
|
const std::string& aad_prefix, bool store_aad_prefix_in_file, |
|
const ColumnPathToEncryptionPropertiesMap& encrypted_columns); |
|
}; |
|
|
|
} |
|
|