stateful encryptor objects

This commit is contained in:
Gidon Gershinsky committed 2019-05-28 08:31:57 +03:00
1 parent 73c8235eac
commit 4d832d66b8
2 files changed
+266 -227

No files matched your search

+207 -211
View File
@@ -17,7 +17,6 @@
#include "parquet/util/crypto.h"
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <openssl/rand.h>
#include <algorithm>
#include <iostream>
@@ -30,15 +29,10 @@ using parquet::ParquetException;
namespace parquet_encryption {
constexpr int aesGcm = 0;
constexpr int aesCtr = 1;
constexpr int encryptType = 0;
constexpr int decryptType = 1;
constexpr int gcmTagLen = 16;
constexpr int nonceLen = 12;
constexpr int ctrIvLen = 16;
constexpr int bufferSizeLen = 4;
constexpr int rndMaxBytes = 32;
constexpr int GCM_MODE = 0;
constexpr int CTR_MODE = 1;
constexpr int CTRIvLength = 16;
constexpr int BufferSizeLength = 4;
#define ENCRYPT_INIT(CTX, ALG) \
if (1 != EVP_EncryptInit_ex(CTX, ALG, nullptr, nullptr, nullptr)) { \
@@ -50,115 +44,78 @@ constexpr int rndMaxBytes = 32;
throw ParquetException("Couldn't init ALG decryption"); \
}
class EvpCipher {
public:
explicit EvpCipher(int cipher, int key_len, int type) {
ctx_ = nullptr;
AesEncryptor::AesEncryptor(ParquetCipher::type alg_id, int key_len, bool metadata) {
ctx_ = nullptr;
if (aesGcm != cipher && aesCtr != cipher) {
std::stringstream ss;
ss << "Wrong cipher: " << cipher;
throw ParquetException(ss.str());
}
if (16 != key_len && 24 != key_len && 32 != key_len) {
std::stringstream ss;
ss << "Wrong key length: " << key_len;
throw ParquetException(ss.str());
}
if (encryptType != type && decryptType != type) {
std::stringstream ss;
ss << "Wrong cipher type: " << type;
throw ParquetException(ss.str());
}
ctx_ = EVP_CIPHER_CTX_new();
if (nullptr == ctx_) {
throw ParquetException("Couldn't init cipher context");
}
if (aesGcm == cipher) {
// Init AES-GCM with specified key length
if (16 == key_len) {
if (encryptType == type) {
ENCRYPT_INIT(ctx_, EVP_aes_128_gcm());
} else {
DECRYPT_INIT(ctx_, EVP_aes_128_gcm());
}
} else if (24 == key_len) {
if (encryptType == type) {
ENCRYPT_INIT(ctx_, EVP_aes_192_gcm());
} else {
DECRYPT_INIT(ctx_, EVP_aes_192_gcm());
}
} else if (32 == key_len) {
if (encryptType == type) {
ENCRYPT_INIT(ctx_, EVP_aes_256_gcm());
} else {
DECRYPT_INIT(ctx_, EVP_aes_256_gcm());
}
}
} else {
// Init AES-CTR with specified key length
if (16 == key_len) {
if (encryptType == type) {
ENCRYPT_INIT(ctx_, EVP_aes_128_ctr());
} else {
DECRYPT_INIT(ctx_, EVP_aes_128_ctr());
}
} else if (24 == key_len) {
if (encryptType == type) {
ENCRYPT_INIT(ctx_, EVP_aes_192_ctr());
} else {
DECRYPT_INIT(ctx_, EVP_aes_192_ctr());
}
} else if (32 == key_len) {
if (encryptType == type) {
ENCRYPT_INIT(ctx_, EVP_aes_256_ctr());
} else {
DECRYPT_INIT(ctx_, EVP_aes_256_ctr());
}
}
}
if (ParquetCipher::AES_GCM_V1 != alg_id && ParquetCipher::AES_GCM_CTR_V1 != alg_id) {
std::stringstream ss;
ss << "Crypto algorithm " << alg_id << " is not supported";
throw ParquetException(ss.str());
}
EVP_CIPHER_CTX* get() { return ctx_; }
~EvpCipher() {
if (nullptr != ctx_) {
EVP_CIPHER_CTX_free(ctx_);
}
if (metadata || (ParquetCipher::AES_GCM_V1 == alg_id)) {
aes_mode_ = GCM_MODE;
} else {
aes_mode_ = CTR_MODE;
}
private:
EVP_CIPHER_CTX* ctx_;
};
if (16 != key_len && 24 != key_len && 32 != key_len) {
std::stringstream ss;
ss << "Wrong key length: " << key_len;
throw ParquetException(ss.str());
}
int gcm_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len,
uint8_t* nonce, int nonce_len, uint8_t* aad, int aad_len, uint8_t* ciphertext) {
key_length_ = key_len;
ctx_ = EVP_CIPHER_CTX_new();
if (nullptr == ctx_) {
throw ParquetException("Couldn't init cipher context");
}
if (GCM_MODE == aes_mode_) {
// Init AES-GCM with specified key length
if (16 == key_len) {
ENCRYPT_INIT(ctx_, EVP_aes_128_gcm());
} else if (24 == key_len) {
ENCRYPT_INIT(ctx_, EVP_aes_192_gcm());
} else if (32 == key_len) {
ENCRYPT_INIT(ctx_, EVP_aes_256_gcm());
}
} else {
// Init AES-CTR with specified key length
if (16 == key_len) {
ENCRYPT_INIT(ctx_, EVP_aes_128_ctr());
} else if (24 == key_len) {
ENCRYPT_INIT(ctx_, EVP_aes_192_ctr());
} else if (32 == key_len) {
ENCRYPT_INIT(ctx_, EVP_aes_256_ctr());
}
}
}
int AesEncryptor::gcm_encrypt(const uint8_t* plaintext, int plaintext_len,
uint8_t* key, int key_len, uint8_t* nonce, uint8_t* aad,
int aad_len, uint8_t* ciphertext) {
int len;
int ciphertext_len;
uint8_t tag[gcmTagLen];
memset(tag, 0, gcmTagLen);
// Init cipher context
EvpCipher cipher(aesGcm, key_len, encryptType);
uint8_t tag[GCMTagLength];
memset(tag, 0, GCMTagLength);
// Setting key and IV (nonce)
if (1 != EVP_EncryptInit_ex(cipher.get(), nullptr, nullptr, key, nonce)) {
if (1 != EVP_EncryptInit_ex(ctx_, nullptr, nullptr, key, nonce)) {
throw ParquetException("Couldn't set key and nonce");
}
// Setting additional authenticated data
if ((nullptr != aad) &&
(1 != EVP_EncryptUpdate(cipher.get(), nullptr, &len, aad, aad_len))) {
(1 != EVP_EncryptUpdate(ctx_, nullptr, &len, aad, aad_len))) {
throw ParquetException("Couldn't set AAD");
}
// Encryption
if (1 != EVP_EncryptUpdate(cipher.get(), ciphertext + bufferSizeLen + nonceLen,
if (1 != EVP_EncryptUpdate(ctx_, ciphertext + BufferSizeLength + NonceLength,
&len, plaintext, plaintext_len)) {
throw ParquetException("Failed encryption update");
}
@@ -166,58 +123,50 @@ int gcm_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int k
ciphertext_len = len;
// Finalization
if (1 != EVP_EncryptFinal_ex(cipher.get(), ciphertext + bufferSizeLen + nonce_len + len, &len)) {
if (1 != EVP_EncryptFinal_ex(ctx_, ciphertext + BufferSizeLength + NonceLength + len, &len)) {
throw ParquetException("Failed encryption finalization");
}
ciphertext_len += len;
// Getting the tag
if (1 != EVP_CIPHER_CTX_ctrl(cipher.get(), EVP_CTRL_GCM_GET_TAG, gcmTagLen, tag)) {
if (1 != EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_GET_TAG, GCMTagLength, tag)) {
throw ParquetException("Couldn't get AES-GCM tag");
}
// Copying the buffer size, nonce and tag to ciphertext
int bufferSize = nonce_len + ciphertext_len + gcmTagLen;
int bufferSize = NonceLength + ciphertext_len + GCMTagLength;
ciphertext[3] = (uint8_t)(0xff & (bufferSize >> 24));
ciphertext[2] = (uint8_t)(0xff & (bufferSize >> 16));
ciphertext[1] = (uint8_t)(0xff & (bufferSize >> 8));
ciphertext[0] = (uint8_t)(0xff & (bufferSize));
std::copy(nonce, nonce + nonce_len, ciphertext + bufferSizeLen);
std::copy(tag, tag + gcmTagLen, ciphertext + bufferSizeLen + nonce_len + ciphertext_len);
std::copy(nonce, nonce + NonceLength, ciphertext + BufferSizeLength);
std::copy(tag, tag + GCMTagLength, ciphertext + BufferSizeLength + NonceLength + ciphertext_len);
return bufferSizeLen + bufferSize;
return BufferSizeLength + bufferSize;
}
int ctr_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len,
uint8_t* ciphertext) {
int AesEncryptor::ctr_encrypt(const uint8_t* plaintext, int plaintext_len,
uint8_t* key, int key_len, uint8_t* nonce,
uint8_t* ciphertext) {
int len;
int ciphertext_len;
uint8_t nonce[nonceLen];
memset(nonce, 0, nonceLen);
// Random nonce
RAND_load_file("/dev/urandom", rndMaxBytes);
RAND_bytes(nonce, sizeof(nonce));
// Parquet CTR IVs are comprised of a 12-byte nonce and a 4-byte initial counter field.
// The first 31 bits of the initial counter field are set to 0, the last bit is set to 1.
uint8_t iv[ctrIvLen];
memset(iv, 0, ctrIvLen);
std::copy(nonce, nonce + nonceLen, iv);
iv[ctrIvLen - 1] = 1;
// Init cipher context
EvpCipher cipher(aesCtr, key_len, encryptType);
uint8_t iv[CTRIvLength];
memset(iv, 0, CTRIvLength);
std::copy(nonce, nonce + NonceLength, iv);
iv[CTRIvLength - 1] = 1;
// Setting key and IV
if (1 != EVP_EncryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) {
if (1 != EVP_EncryptInit_ex(ctx_, nullptr, nullptr, key, iv)) {
throw ParquetException("Couldn't set key and IV");
}
// Encryption
if (1 != EVP_EncryptUpdate(cipher.get(), ciphertext + bufferSizeLen + ctrIvLen, &len, plaintext,
if (1 != EVP_EncryptUpdate(ctx_, ciphertext + BufferSizeLength + CTRIvLength, &len, plaintext,
plaintext_len)) {
throw ParquetException("Failed encryption update");
}
@@ -225,70 +174,128 @@ int ctr_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int k
ciphertext_len = len;
// Finalization
if (1 != EVP_EncryptFinal_ex(cipher.get(), ciphertext + bufferSizeLen + ctrIvLen + len, &len)) {
if (1 != EVP_EncryptFinal_ex(ctx_, ciphertext + BufferSizeLength + CTRIvLength + len, &len)) {
throw ParquetException("Failed encryption finalization");
}
ciphertext_len += len;
// Copying the buffer size and nonce to ciphertext
int bufferSize = nonceLen + ciphertext_len;
int bufferSize = NonceLength + ciphertext_len;
ciphertext[3] = (uint8_t)(0xff & (bufferSize >> 24));
ciphertext[2] = (uint8_t)(0xff & (bufferSize >> 16));
ciphertext[1] = (uint8_t)(0xff & (bufferSize >> 8));
ciphertext[0] = (uint8_t)(0xff & (bufferSize));
std::copy(nonce, nonce + nonceLen, ciphertext + bufferSizeLen);
std::copy(nonce, nonce + NonceLength, ciphertext + BufferSizeLength);
return bufferSizeLen + bufferSize;
return BufferSizeLength + bufferSize;
}
int SignedFooterEncrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key,
int key_len, uint8_t* aad, int aad_len, uint8_t* nonce, int nonce_len,
uint8_t* ciphertext) {
int AesEncryptor::SignedFooterEncrypt(const uint8_t* footer, int footer_len,
uint8_t* key, int key_len, uint8_t* aad, int aad_len,
uint8_t* nonce, uint8_t* encrypted_footer) {
return gcm_encrypt(plaintext, plaintext_len, key, key_len, nonce, nonce_len, aad, aad_len, ciphertext);
if (key_length_ != key_len) {
std::stringstream ss;
ss << "Wrong key length " << key_len << ". Should be " << key_length_;
throw ParquetException(ss.str());
}
if (GCM_MODE != aes_mode_) {
throw ParquetException("Must use AES GCM (metadata) encryptor");
}
return gcm_encrypt(footer, footer_len, key, key_len, nonce, aad, aad_len, encrypted_footer);
}
int Encrypt(ParquetCipher::type alg_id, bool metadata, const uint8_t* plaintext,
int plaintext_len, uint8_t* key, int key_len, uint8_t* aad, int aad_len,
uint8_t* ciphertext) {
int AesEncryptor::Encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len,
uint8_t* aad, int aad_len, uint8_t* ciphertext) {
if (key_length_ != key_len) {
std::stringstream ss;
ss << "Wrong key length " << key_len << ". Should be " << key_length_;
throw ParquetException(ss.str());
}
uint8_t nonce[NonceLength];
memset(nonce, 0, NonceLength);
// Random nonce
RAND_bytes(nonce, sizeof(nonce));
if (GCM_MODE == aes_mode_) {
return gcm_encrypt(plaintext, plaintext_len, key, key_len, nonce,
aad, aad_len, ciphertext);
}
return ctr_encrypt(plaintext, plaintext_len, key, key_len, nonce, ciphertext);
}
AesDecryptor::AesDecryptor(ParquetCipher::type alg_id, int key_len, bool metadata) {
ctx_ = nullptr;
if (ParquetCipher::AES_GCM_V1 != alg_id && ParquetCipher::AES_GCM_CTR_V1 != alg_id) {
std::stringstream ss;
ss << "Crypto algorithm " << alg_id << " is not supported";
throw ParquetException(ss.str());
}
ciphertext_size_delta_ = BufferSizeLength + NonceLength;
if (metadata || (ParquetCipher::AES_GCM_V1 == alg_id)) {
uint8_t nonce[nonceLen];
memset(nonce, 0, nonceLen);
// Random nonce
RAND_load_file("/dev/urandom", rndMaxBytes);
RAND_bytes(nonce, sizeof(nonce));
return gcm_encrypt(plaintext, plaintext_len, key, key_len, nonce, nonceLen, aad, aad_len, ciphertext);
aes_mode_ = GCM_MODE;
ciphertext_size_delta_ += GCMTagLength;
} else {
aes_mode_ = CTR_MODE;
}
// Data (page) encryption with AES_GCM_CTR_V1
return ctr_encrypt(plaintext, plaintext_len, key, key_len, ciphertext);
if (16 != key_len && 24 != key_len && 32 != key_len) {
std::stringstream ss;
ss << "Wrong key length: " << key_len;
throw ParquetException(ss.str());
}
key_length_ = key_len;
ctx_ = EVP_CIPHER_CTX_new();
if (nullptr == ctx_) {
throw ParquetException("Couldn't init cipher context");
}
if (GCM_MODE == aes_mode_) {
// Init AES-GCM with specified key length
if (16 == key_len) {
DECRYPT_INIT(ctx_, EVP_aes_128_gcm());
} else if (24 == key_len) {
DECRYPT_INIT(ctx_, EVP_aes_192_gcm());
} else if (32 == key_len) {
DECRYPT_INIT(ctx_, EVP_aes_256_gcm());
}
} else {
// Init AES-CTR with specified key length
if (16 == key_len) {
DECRYPT_INIT(ctx_, EVP_aes_128_ctr());
} else if (24 == key_len) {
DECRYPT_INIT(ctx_, EVP_aes_192_ctr());
} else if (32 == key_len) {
DECRYPT_INIT(ctx_, EVP_aes_256_ctr());
}
}
}
int Encrypt(std::shared_ptr<EncryptionProperties> encryption_props, bool metadata,
const uint8_t* plaintext, int plaintext_len, uint8_t* ciphertext) {
return Encrypt(encryption_props->algorithm(), metadata, plaintext, plaintext_len,
encryption_props->key_bytes(), encryption_props->key_length(),
encryption_props->aad_bytes(), encryption_props->aad_length(),
ciphertext);
int AesDecryptor::CiphertextSizeDelta() {
return ciphertext_size_delta_;
}
int gcm_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int key_len,
uint8_t* aad, int aad_len, uint8_t* plaintext) {
int AesDecryptor::gcm_decrypt(const uint8_t* ciphertext, int ciphertext_len,
uint8_t* key, int key_len, uint8_t* aad, int aad_len,
uint8_t* plaintext) {
int len;
int plaintext_len;
uint8_t tag[gcmTagLen];
memset(tag, 0, gcmTagLen);
uint8_t nonce[nonceLen];
memset(nonce, 0, nonceLen);
uint8_t tag[GCMTagLength];
memset(tag, 0, GCMTagLength);
uint8_t nonce[NonceLength];
memset(nonce, 0, NonceLength);
// Extract ciphertext length
int written_ciphertext_len =
@@ -297,44 +304,42 @@ int gcm_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int
((ciphertext[1] & 0xff) << 8) |
((ciphertext[0] & 0xff));
if (ciphertext_len > 0 && ciphertext_len != (written_ciphertext_len + bufferSizeLen)) {
if (ciphertext_len > 0 && ciphertext_len != (written_ciphertext_len + BufferSizeLength)) {
throw ParquetException("Wrong ciphertext length");
}
ciphertext_len = written_ciphertext_len + bufferSizeLen;
ciphertext_len = written_ciphertext_len + BufferSizeLength;
// Extracting IV and tag
std::copy(ciphertext + bufferSizeLen, ciphertext + bufferSizeLen + nonceLen, nonce);
std::copy(ciphertext + ciphertext_len - gcmTagLen, ciphertext + ciphertext_len, tag);
std::copy(ciphertext + BufferSizeLength, ciphertext + BufferSizeLength + NonceLength, nonce);
std::copy(ciphertext + ciphertext_len - GCMTagLength, ciphertext + ciphertext_len, tag);
// Init cipher context
EvpCipher cipher(aesGcm, key_len, decryptType);
// Setting key and IV
if (1 != EVP_DecryptInit_ex(cipher.get(), nullptr, nullptr, key, nonce)) {
if (1 != EVP_DecryptInit_ex(ctx_, nullptr, nullptr, key, nonce)) {
throw ParquetException("Couldn't set key and IV");
}
// Setting additional authenticated data
if ((nullptr != aad) &&
(1 != EVP_DecryptUpdate(cipher.get(), nullptr, &len, aad, aad_len))) {
(1 != EVP_DecryptUpdate(ctx_, nullptr, &len, aad, aad_len))) {
throw ParquetException("Couldn't set AAD");
}
// Decryption
if (!EVP_DecryptUpdate(cipher.get(), plaintext, &len, ciphertext + bufferSizeLen + nonceLen,
ciphertext_len - bufferSizeLen - nonceLen - gcmTagLen)) {
if (!EVP_DecryptUpdate(ctx_, plaintext, &len, ciphertext + BufferSizeLength + NonceLength,
ciphertext_len - BufferSizeLength - NonceLength - GCMTagLength)) {
throw ParquetException("Failed decryption update");
}
plaintext_len = len;
// Checking the tag (authentication)
if (!EVP_CIPHER_CTX_ctrl(cipher.get(), EVP_CTRL_GCM_SET_TAG, gcmTagLen, tag)) {
if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_TAG, GCMTagLength, tag)) {
throw ParquetException("Failed authentication");
}
// Finalization
if (1 != EVP_DecryptFinal_ex(cipher.get(), plaintext + len, &len)) {
if (1 != EVP_DecryptFinal_ex(ctx_, plaintext + len, &len)) {
throw ParquetException("Failed decryption finalization");
}
@@ -342,13 +347,13 @@ int gcm_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int
return plaintext_len;
}
int ctr_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int key_len,
uint8_t* plaintext) {
int AesDecryptor::ctr_decrypt(const uint8_t* ciphertext, int ciphertext_len,
uint8_t* key, int key_len, uint8_t* plaintext) {
int len;
int plaintext_len;
uint8_t iv[ctrIvLen];
memset(iv, 0, ctrIvLen);
uint8_t iv[CTRIvLength];
memset(iv, 0, CTRIvLength);
// Extract ciphertext length
int written_ciphertext_len =
@@ -357,35 +362,33 @@ int ctr_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int
((ciphertext[1] & 0xff) << 8) |
((ciphertext[0] & 0xff));
if (ciphertext_len > 0 && ciphertext_len != (written_ciphertext_len + bufferSizeLen)) {
if (ciphertext_len > 0 && ciphertext_len != (written_ciphertext_len + BufferSizeLength)) {
throw ParquetException("Wrong ciphertext length");
}
ciphertext_len = written_ciphertext_len;
// Extracting nonce
std::copy(ciphertext + bufferSizeLen, ciphertext + bufferSizeLen + nonceLen, iv);
std::copy(ciphertext + BufferSizeLength, ciphertext + BufferSizeLength + NonceLength, iv);
// Parquet CTR IVs are comprised of a 12-byte nonce and a 4-byte initial counter field.
// The first 31 bits of the initial counter field are set to 0, the last bit is set to 1.
iv[ctrIvLen - 1] = 1;
iv[CTRIvLength - 1] = 1;
// Init cipher context
EvpCipher cipher(aesCtr, key_len, decryptType);
// Setting key and IV
if (1 != EVP_DecryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) {
if (1 != EVP_DecryptInit_ex(ctx_, nullptr, nullptr, key, iv)) {
throw ParquetException("Couldn't set key and IV");
}
// Decryption
if (!EVP_DecryptUpdate(cipher.get(), plaintext, &len, ciphertext + bufferSizeLen + ctrIvLen,
ciphertext_len - ctrIvLen)) {
if (!EVP_DecryptUpdate(ctx_, plaintext, &len, ciphertext + BufferSizeLength + CTRIvLength,
ciphertext_len - CTRIvLength)) {
throw ParquetException("Failed decryption update");
}
plaintext_len = len;
// Finalization
if (1 != EVP_DecryptFinal_ex(cipher.get(), plaintext + len, &len)) {
if (1 != EVP_DecryptFinal_ex(ctx_, plaintext + len, &len)) {
throw ParquetException("Failed decryption finalization");
}
@@ -393,23 +396,31 @@ int ctr_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int
return plaintext_len;
}
int Decrypt(ParquetCipher::type alg_id, bool metadata, const uint8_t* ciphertext,
int ciphertext_len, uint8_t* key, int key_len, uint8_t* aad, int aad_len,
uint8_t* plaintext) {
if (ParquetCipher::AES_GCM_V1 != alg_id && ParquetCipher::AES_GCM_CTR_V1 != alg_id) {
int AesDecryptor::Decrypt(const uint8_t* ciphertext, int ciphertext_len,
uint8_t* key, int key_len, uint8_t* aad, int aad_len,
uint8_t* plaintext) {
if (key_length_ != key_len) {
std::stringstream ss;
ss << "Crypto algorithm " << alg_id << " is not supported";
ss << "Wrong key length " << key_len << ". Should be " << key_length_;
throw ParquetException(ss.str());
}
if (metadata || (ParquetCipher::AES_GCM_V1 == alg_id)) {
if (GCM_MODE == aes_mode_) {
return gcm_decrypt(ciphertext, ciphertext_len, key, key_len, aad, aad_len, plaintext);
}
// Data (page) decryption with AES_GCM_CTR_V1
return ctr_decrypt(ciphertext, ciphertext_len, key, key_len, plaintext);
}
int Decrypt(std::shared_ptr<EncryptionProperties> encryption_props, bool metadata,
const uint8_t* ciphertext, int ciphertext_len, uint8_t* plaintext) {
return Decrypt(encryption_props->algorithm(), metadata, ciphertext, ciphertext_len,
encryption_props->key_bytes(), encryption_props->key_length(),
encryption_props->aad_bytes(), encryption_props->aad_length(),
plaintext);
}
static std::string shortToBytesLE(int16_t input) {
int8_t output[2];
memset(output, 0, 2);
@@ -420,22 +431,13 @@ static std::string shortToBytesLE(int16_t input) {
return output_str;
}
int Decrypt(std::shared_ptr<EncryptionProperties> encryption_props, bool metadata,
const uint8_t* ciphertext, int ciphertext_len, uint8_t* plaintext) {
return Decrypt(encryption_props->algorithm(), metadata, ciphertext, ciphertext_len,
encryption_props->key_bytes(), encryption_props->key_length(),
encryption_props->aad_bytes(), encryption_props->aad_length(),
plaintext);
}
std::string createModuleAAD(const std::string& fileAAD, int8_t module_type,
int16_t row_group_ordinal, int16_t column_ordinal,
int16_t page_ordinal) {
int8_t type_ordinal_bytes[1];
int16_t row_group_ordinal, int16_t column_ordinal,
int16_t page_ordinal) {
int8_t type_ordinal_bytes[1];
type_ordinal_bytes[0] = module_type;
std::string type_ordinal_bytes_str(reinterpret_cast<char const*>
(type_ordinal_bytes), 1) ;
std::string type_ordinal_bytes_str(reinterpret_cast<char const*>(type_ordinal_bytes), 1) ;
if (Footer == module_type) {
std::string result = fileAAD + type_ordinal_bytes_str;
return result;
@@ -443,31 +445,25 @@ std::string createModuleAAD(const std::string& fileAAD, int8_t module_type,
std::string row_group_ordinal_bytes = shortToBytesLE(row_group_ordinal);
std::string column_ordinal_bytes = shortToBytesLE(column_ordinal);
if (DataPage != module_type && DataPageHeader != module_type) {
std::string result = fileAAD + type_ordinal_bytes_str
+ row_group_ordinal_bytes
std::string result = fileAAD + type_ordinal_bytes_str + row_group_ordinal_bytes
+ column_ordinal_bytes;
return result;
}
std::string page_ordinal_bytes = shortToBytesLE(page_ordinal);
std::string result = fileAAD + type_ordinal_bytes_str +
row_group_ordinal_bytes
std::string result = fileAAD + type_ordinal_bytes_str + row_group_ordinal_bytes
+ column_ordinal_bytes + page_ordinal_bytes;;
return result;
}
std::string createFooterAAD(const std::string& aad_prefix_bytes) {
return createModuleAAD(aad_prefix_bytes, Footer, (int16_t) -1,
(int16_t) -1, (int16_t) -1);
return createModuleAAD(aad_prefix_bytes, Footer, (int16_t) -1, (int16_t) -1, (int16_t) -1);
}
// Update last two bytes with new page ordinal (instead of creating
// new page AAD from scratch)
// Update last two bytes with new page ordinal (instead of creating new page AAD from scratch)
void quickUpdatePageAAD(const std::string &AAD, int16_t new_page_ordinal) {
std::string page_ordinal_bytes = shortToBytesLE(new_page_ordinal);
int length = (int)AAD.size();
std::memcpy((int16_t*)(AAD.c_str()+length-2),
(int16_t*)(page_ordinal_bytes.c_str()), 2);
std::memcpy((int16_t*)(AAD.c_str()+length-2), (int16_t*)(page_ordinal_bytes.c_str()), 2);
}
} // namespace parquet_encryption
+59 -16
View File
@@ -22,12 +22,15 @@
#include "parquet/properties.h"
#include "parquet/types.h"
#include <openssl/evp.h>
using parquet::ParquetCipher;
using parquet::EncryptionProperties;
namespace parquet_encryption {
constexpr int GCMTagLength = 16;
constexpr int NonceLength = 12;
// Module types
const int8_t Footer = 0;
const int8_t ColumnMetaData = 1;
@@ -38,27 +41,67 @@ const int8_t DictionaryPageHeader = 5;
const int8_t ColumnIndex = 6;
const int8_t OffsetIndex = 7;
int SignedFooterEncrypt(const uint8_t* plaintext,
int plaintext_len, uint8_t* key, int key_len, uint8_t* aad, int aad_len,
uint8_t* nonce, int nonce_len, uint8_t* ciphertext);
int Encrypt(ParquetCipher::type alg_id, bool metadata, const uint8_t* plaintext,
int plaintext_len, uint8_t* key, int key_len, uint8_t* aad, int aad_len,
uint8_t* ciphertext);
class AesEncryptor {
public:
AesEncryptor(ParquetCipher::type alg_id, int key_len, bool metadata);
int Encrypt(std::shared_ptr<EncryptionProperties> encryption_props, bool metadata,
const uint8_t* plaintext, int plaintext_len, uint8_t* ciphertext);
int Encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len,
uint8_t* aad, int aad_len, uint8_t* ciphertext);
int Decrypt(ParquetCipher::type alg_id, bool metadata, const uint8_t* ciphertext,
int ciphertext_len, uint8_t* key, int key_len, uint8_t* aad, int aad_len,
uint8_t* plaintext);
int SignedFooterEncrypt(const uint8_t* footer, int footer_len, uint8_t* key, int key_len,
uint8_t* aad, int aad_len, uint8_t* nonce, uint8_t* encrypted_footer);
~AesEncryptor() {
if (nullptr != ctx_) {
EVP_CIPHER_CTX_free(ctx_);
}
}
private:
EVP_CIPHER_CTX* ctx_;
int aes_mode_;
int key_length_;
int gcm_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len,
uint8_t* nonce, uint8_t* aad, int aad_len, uint8_t* ciphertext);
int ctr_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len,
uint8_t* nonce, uint8_t* ciphertext);
};
class AesDecryptor {
public:
AesDecryptor(ParquetCipher::type alg_id, int key_len, bool metadata);
int CiphertextSizeDelta();
int Decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int key_len,
uint8_t* aad, int aad_len, uint8_t* plaintext);
~AesDecryptor() {
if (nullptr != ctx_) {
EVP_CIPHER_CTX_free(ctx_);
}
}
private:
EVP_CIPHER_CTX* ctx_;
int aes_mode_;
int key_length_;
int ciphertext_size_delta_;
int gcm_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int key_len,
uint8_t* aad, int aad_len, uint8_t* plaintext);
int ctr_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int key_len,
uint8_t* plaintext);
};
int Decrypt(std::shared_ptr<EncryptionProperties> encryption_props, bool metadata,
const uint8_t* ciphertext, int ciphertext_len, uint8_t* plaintext);
std::string createModuleAAD(const std::string& fileAAD, int8_t module_type,
int16_t row_group_ordinal, int16_t column_ordinal,
int16_t page_ordinal);
int16_t row_group_ordinal, int16_t column_ordinal,
int16_t page_ordinal);
std::string createFooterAAD(const std::string& aad_prefix_bytes);