From 8e384d4eb2481396804c806bf9cba93dd480ced5 Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Tue, 15 May 2018 10:28:10 +0300 Subject: [PATCH 01/10] The C++ implementation of basic AES-GCM encryption and decryption --- src/parquet/types.h | 9 +- src/parquet/util/crypto.h | 240 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 src/parquet/util/crypto.h diff --git a/src/parquet/types.h b/src/parquet/types.h index 0f4cfc21..36cbd851 100644 --- a/src/parquet/types.h +++ b/src/parquet/types.h @@ -113,6 +113,13 @@ struct Compression { enum type { UNCOMPRESSED, SNAPPY, GZIP, LZO, BROTLI, LZ4, ZSTD }; }; +struct Encryption { + enum type { + PARQUET_AES_GCM_V1 = 1 + }; +}; + + // parquet::PageType struct PageType { enum type { DATA_PAGE, INDEX_PAGE, DICTIONARY_PAGE, DATA_PAGE_V2 }; @@ -156,7 +163,7 @@ struct ByteArray { }; inline bool operator==(const ByteArray& left, const ByteArray& right) { - return left.len == right.len && 0 == std::memcmp(left.ptr, right.ptr, left.len); + return left.len == right.len && std::equal(left.ptr, left.ptr + left.len, right.ptr); } inline bool operator!=(const ByteArray& left, const ByteArray& right) { diff --git a/src/parquet/util/crypto.h b/src/parquet/util/crypto.h new file mode 100644 index 00000000..cc3e4775 --- /dev/null +++ b/src/parquet/util/crypto.h @@ -0,0 +1,240 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + + +#ifndef PARQUET_UTIL_CRYPTO_H +#define PARQUET_UTIL_CRYPTO_H + +#include +#include +#include +#include +#include +#include +#include "parquet/exception.h" +#include "parquet/types.h" + +namespace parquet { + +inline int encrypt(Encryption::type alg_id, const uint8_t *plaintext, int plaintext_len, + uint8_t *key, int key_len, uint8_t *aad, int aad_len, + uint8_t *ciphertext) { + + if (Encryption::PARQUET_AES_GCM_V1 != alg_id) { + std::stringstream ss; + ss << "Crypto algorithm " << alg_id << " currently unsupported\n"; + throw parquet::ParquetException(ss.str()); + } + + if (16 != key_len) { + std::stringstream ss; + ss << "Key length " << key_len << " currently unsupported\n"; + throw parquet::ParquetException(ss.str()); + } + + EVP_CIPHER_CTX *ctx; + int tag_len = 16; + int iv_len = 12; + + int len; + int ciphertext_len; + uint8_t tag[tag_len]; + uint8_t iv[iv_len]; + + // Random IV + RAND_load_file("/dev/urandom", 32); + RAND_bytes(iv, sizeof(iv)); + + // Init cipher context + if(!(ctx = EVP_CIPHER_CTX_new())) { + std::stringstream ss; + ss << "Couldn't init cipher context\n"; + throw parquet::ParquetException(ss.str()); + } + + // Init AES-GCM with 128-bit key + if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { + std::stringstream ss; + ss << "Couldn't init AES_GCM_128 encryption\n"; + throw parquet::ParquetException(ss.str()); + } + + // Setting custom IV length + if (12 != iv_len) { + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) { + std::stringstream ss; + ss << "Couldn't set IV length: " << iv_len << "\n"; + throw parquet::ParquetException(ss.str()); + } + } + + // Setting key and IV + if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) { + std::stringstream ss; + ss << "Couldn't set key and IV\n"; + throw parquet::ParquetException(ss.str()); + } + + // Setting additional authenticated data + if (NULL != aad) { + if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) { + std::stringstream ss; + ss << "Couldn't set AAD\n"; + throw parquet::ParquetException(ss.str()); + } + } + + // Encryption + if(1 != EVP_EncryptUpdate(ctx, ciphertext + iv_len, &len, plaintext, plaintext_len)) { + std::stringstream ss; + ss << "Failed encryption update\n"; + throw parquet::ParquetException(ss.str()); + } + + ciphertext_len = len; + + // Finalization + if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + iv_len + len, &len)) { + std::stringstream ss; + ss << "Failed encryption finalization\n"; + throw parquet::ParquetException(ss.str()); + } + + ciphertext_len += len; + + // Getting the tag + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_len, tag)) { + std::stringstream ss; + ss << "Couldn't get AES-GCM tag\n"; + throw parquet::ParquetException(ss.str()); + } + + // Cleaning up + EVP_CIPHER_CTX_free(ctx); + + // Copying the IV and tag to ciphertext + std::copy(iv, iv+iv_len, ciphertext); + std::copy(tag, tag+tag_len, ciphertext + iv_len + ciphertext_len); + + return iv_len + ciphertext_len + tag_len; +} + +inline int decrypt(Encryption::type alg_id, const uint8_t *ciphertext, int ciphertext_len, + uint8_t *key, int key_len, uint8_t *aad, int aad_len, + uint8_t *plaintext) +{ + + if (Encryption::PARQUET_AES_GCM_V1 != alg_id) { + std::stringstream ss; + ss << "Crypto algorithm " << alg_id << " currently unsupported\n"; + throw parquet::ParquetException(ss.str()); + } + + if (16 != key_len) { + std::stringstream ss; + ss << "Key length " << key_len << " currently unsupported\n"; + throw parquet::ParquetException(ss.str()); + } + + EVP_CIPHER_CTX *ctx; + int len; + int plaintext_len; + int ret; + + int tag_len = 16; + int iv_len = 12; + uint8_t tag[tag_len]; + uint8_t iv[iv_len]; + + // Extracting IV and tag + std::copy(ciphertext, ciphertext + iv_len, iv); + std::copy(ciphertext + ciphertext_len - tag_len, ciphertext + ciphertext_len, tag); + + + // Init cipher context + if(!(ctx = EVP_CIPHER_CTX_new())) { + std::stringstream ss; + ss << "Couldn't init cipher context\n"; + throw parquet::ParquetException(ss.str()); + } + + // Init AES-GCM with 128-bit key + if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { + std::stringstream ss; + ss << "Couldn't init AES_GCM_128 decryption\n"; + throw parquet::ParquetException(ss.str()); + } + + // Setting custom IV length + if (12 != iv_len) { + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) { + std::stringstream ss; + ss << "Couldn't set IV length: " << iv_len << "\n"; + throw parquet::ParquetException(ss.str()); + } + } + + // Setting key and IV + if(1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { + std::stringstream ss; + ss << "Couldn't set key and IV\n"; + throw parquet::ParquetException(ss.str()); + } + + // Setting additional authenticated data + if (NULL != aad) { + if(1 != EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) { + std::stringstream ss; + ss << "Couldn't set AAD\n"; + throw parquet::ParquetException(ss.str()); + } + } + + // Decryption + if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext + iv_len, ciphertext_len - iv_len - tag_len)) { + std::stringstream ss; + ss << "Failed decryption update\n"; + throw parquet::ParquetException(ss.str()); + } + + plaintext_len = len; + + // Checking the tag (authentication) + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag)) { + std::stringstream ss; + ss << "Failed authentication\n"; + throw parquet::ParquetException(ss.str()); + } + + // Finalization + ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); + + // Cleaning up + EVP_CIPHER_CTX_free(ctx); + + if(ret > 0) { + plaintext_len += len; + return plaintext_len; + } + else { + return -1; + } +} + +} // namespace parquet + +#endif //PARQUET_UTIL_CRYPTO_H From 63fa9a3125a3a51d0349c923c9fa612a7184fe48 Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Tue, 15 May 2018 10:49:10 +0300 Subject: [PATCH 02/10] version fix --- src/parquet/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parquet/types.h b/src/parquet/types.h index 36cbd851..e503f49d 100644 --- a/src/parquet/types.h +++ b/src/parquet/types.h @@ -163,7 +163,7 @@ struct ByteArray { }; inline bool operator==(const ByteArray& left, const ByteArray& right) { - return left.len == right.len && std::equal(left.ptr, left.ptr + left.len, right.ptr); + return left.len == right.len && 0 == std::memcmp(left.ptr, right.ptr, left.len); } inline bool operator!=(const ByteArray& left, const ByteArray& right) { From a11507ec7a2bea9d6fdffbdb78056beb13b96f48 Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Wed, 27 Jun 2018 08:32:31 +0300 Subject: [PATCH 03/10] 2nd cipher + review comments --- src/parquet/types.h | 6 +- src/parquet/util/crypto.cc | 324 +++++++++++++++++++++++++++++++++++++ src/parquet/util/crypto.h | 215 +----------------------- 3 files changed, 335 insertions(+), 210 deletions(-) create mode 100644 src/parquet/util/crypto.cc diff --git a/src/parquet/types.h b/src/parquet/types.h index e503f49d..ea78d5b1 100644 --- a/src/parquet/types.h +++ b/src/parquet/types.h @@ -115,7 +115,8 @@ struct Compression { struct Encryption { enum type { - PARQUET_AES_GCM_V1 = 1 + AES_GCM_V1 = 0, + AES_GCM_CTR_V1 = 1 }; }; @@ -163,7 +164,8 @@ struct ByteArray { }; inline bool operator==(const ByteArray& left, const ByteArray& right) { - return left.len == right.len && 0 == std::memcmp(left.ptr, right.ptr, left.len); + //return left.len == right.len && 0 == std::memcmp(left.ptr, right.ptr, left.len); + return left.len == right.len && std::equal(left.ptr, left.ptr + left.len, right.ptr); } inline bool operator!=(const ByteArray& left, const ByteArray& right) { diff --git a/src/parquet/util/crypto.cc b/src/parquet/util/crypto.cc new file mode 100644 index 00000000..8ebe81c9 --- /dev/null +++ b/src/parquet/util/crypto.cc @@ -0,0 +1,324 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + + +#include +#include +#include +#include +#include +#include +#include "parquet/exception.h" +#include "parquet/types.h" + +#include "parquet/util/crypto.h" + +namespace parquet { + +const int gcm_tag_len = 16; +const int gcm_iv_len = 12; +const int ctr_iv_len = 16; + +void handleError(const char *message, EVP_CIPHER_CTX *ctx) { + if (NULL != ctx) EVP_CIPHER_CTX_free(ctx); + std::stringstream ss; + ss << message; + throw parquet::ParquetException(ss.str()); +} + +int gcm_encrypt(const uint8_t *plaintext, int plaintext_len, + uint8_t *key, int key_len, uint8_t *aad, int aad_len, + uint8_t *ciphertext) +{ + EVP_CIPHER_CTX *ctx = NULL; + + int len; + int ciphertext_len; + uint8_t tag[gcm_tag_len]; + uint8_t iv[gcm_iv_len]; + + // Random IV + RAND_load_file("/dev/urandom", 32); + RAND_bytes(iv, sizeof(iv)); + + // Init cipher context + if(!(ctx = EVP_CIPHER_CTX_new())) { + handleError("Couldn't init cipher context", ctx); + } + + // Init AES-GCM with 128-bit key + if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { + handleError("Couldn't init AES_GCM_128 encryption", ctx); + } + + // Setting key and IV + if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) { + handleError("Couldn't set key and IV", ctx); + } + + // Setting additional authenticated data + if (NULL != aad) { + if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) { + handleError("Couldn't set AAD", ctx); + } + } + + // Encryption + if(1 != EVP_EncryptUpdate(ctx, ciphertext + gcm_iv_len, &len, plaintext, plaintext_len)) { + handleError("Failed encryption update", ctx); + } + + ciphertext_len = len; + + // Finalization + if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + gcm_iv_len + len, &len)) { + handleError("Failed encryption finalization", ctx); + } + + ciphertext_len += len; + + // Getting the tag + if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, gcm_tag_len, tag)) { + handleError("Couldn't get AES-GCM tag", ctx); + } + + // Cleaning up + EVP_CIPHER_CTX_free(ctx); + + // Copying the IV and tag to ciphertext + std::copy(iv, iv + gcm_iv_len, ciphertext); + std::copy(tag, tag + gcm_tag_len, ciphertext + gcm_iv_len + ciphertext_len); + + return gcm_iv_len + ciphertext_len + gcm_tag_len; +} + +int ctr_encrypt(const uint8_t *plaintext, int plaintext_len, + uint8_t *key, int key_len, uint8_t *ciphertext) +{ + EVP_CIPHER_CTX *ctx; + + int len; + int ciphertext_len; + uint8_t iv[ctr_iv_len]; + + // Random IV + RAND_load_file("/dev/urandom", 32); + RAND_bytes(iv, sizeof(iv)); + + // Init cipher context + if(!(ctx = EVP_CIPHER_CTX_new())) { + handleError("Couldn't init cipher context", ctx); + } + + // Init AES-CTR with 128-bit key + if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, NULL, NULL)) { + handleError("Couldn't init AES_CTR_128 encryption", ctx); + } + + // Setting key and IV + if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) { + handleError("Couldn't set key and IV", ctx); + } + + // Encryption + if(1 != EVP_EncryptUpdate(ctx, ciphertext + ctr_iv_len, &len, plaintext, plaintext_len)) { + handleError("Failed encryption update", ctx); + } + + ciphertext_len = len; + + // Finalization + if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + ctr_iv_len + len, &len)) { + handleError("Failed encryption finalization", ctx); + } + + ciphertext_len += len; + + // Cleaning up + EVP_CIPHER_CTX_free(ctx); + + // Copying the IV ciphertext + std::copy(iv, iv + ctr_iv_len, ciphertext); + + return ctr_iv_len + ciphertext_len; +} + + +int encrypt(Encryption::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) +{ + + if (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) { + std::stringstream ss; + ss << "Crypto algorithm " << alg_id << " currently unsupported"; + throw parquet::ParquetException(ss.str()); + } + + if (16 != key_len) { + std::stringstream ss; + ss << "Key length " << key_len << " currently unsupported"; + throw parquet::ParquetException(ss.str()); + } + + if (metadata || (Encryption::AES_GCM_V1 == alg_id)) { + return gcm_encrypt(plaintext, plaintext_len, key, key_len, aad, aad_len, ciphertext); + } + + // Data (page) encryption with AES_GCM_CTR_V1 + return ctr_encrypt(plaintext, plaintext_len, key, key_len, ciphertext); +} + +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) +{ + EVP_CIPHER_CTX *ctx = NULL; + int len; + int plaintext_len; + + uint8_t tag[gcm_tag_len]; + uint8_t iv[gcm_iv_len]; + + // Extracting IV and tag + std::copy(ciphertext, ciphertext + gcm_iv_len, iv); + std::copy(ciphertext + ciphertext_len - gcm_tag_len, ciphertext + ciphertext_len, tag); + + + // Init cipher context + if(!(ctx = EVP_CIPHER_CTX_new())) { + handleError("Couldn't init cipher context", ctx); + } + + // Init AES-GCM with 128-bit key + if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { + handleError("Couldn't init AES_GCM_128 decryption", ctx); + } + + // Setting key and IV + if(1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { + handleError("Couldn't set key and IV", ctx); + } + + // Setting additional authenticated data + if (NULL != aad) { + if(1 != EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) { + handleError("Couldn't set AAD", ctx); + } + } + + // Decryption + if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext + gcm_iv_len, + ciphertext_len - gcm_iv_len - gcm_tag_len)) { + handleError("Failed decryption update", ctx); + } + + plaintext_len = len; + + // Checking the tag (authentication) + if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, gcm_tag_len, tag)) { + handleError("Failed authentication", ctx); + } + + // Finalization + if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) { + handleError("Failed decryption finalization", ctx); + } + + // Cleaning up + EVP_CIPHER_CTX_free(ctx); + + plaintext_len += len; + return plaintext_len; +} + +int ctr_decrypt(const uint8_t *ciphertext, int ciphertext_len, + uint8_t *key, int key_len, uint8_t *plaintext) +{ + EVP_CIPHER_CTX *ctx = NULL; + int len; + int plaintext_len; + + uint8_t iv[ctr_iv_len]; + + // Extracting IV and tag + std::copy(ciphertext, ciphertext + ctr_iv_len, iv); + + // Init cipher context + if(!(ctx = EVP_CIPHER_CTX_new())) { + handleError("Couldn't init cipher context", ctx); + } + + // Init AES-CTR with 128-bit key + if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, NULL, NULL)) { + handleError("Couldn't init AES_CTR_128 decryption", ctx); + } + + // Setting key and IV + if(1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { + handleError("Couldn't set key and IV", ctx); + } + + // Decryption + if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext + ctr_iv_len, + ciphertext_len - ctr_iv_len)) { + handleError("Failed decryption update", ctx); + } + + plaintext_len = len; + + // Finalization + if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) { + handleError("Failed decryption finalization", ctx); + } + + // Cleaning up + EVP_CIPHER_CTX_free(ctx); + + plaintext_len += len; + return plaintext_len; +} + +int decrypt(Encryption::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 (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) { + std::stringstream ss; + ss << "Crypto algorithm " << alg_id << " currently unsupported"; + throw parquet::ParquetException(ss.str()); + } + + if (16 != key_len) { + std::stringstream ss; + ss << "Key length " << key_len << " currently unsupported"; + throw parquet::ParquetException(ss.str()); + } + + if (metadata || (Encryption::AES_GCM_V1 == alg_id)) { + 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); +} + +} // namespace parquet + diff --git a/src/parquet/util/crypto.h b/src/parquet/util/crypto.h index cc3e4775..2aa6127d 100644 --- a/src/parquet/util/crypto.h +++ b/src/parquet/util/crypto.h @@ -19,221 +19,20 @@ #ifndef PARQUET_UTIL_CRYPTO_H #define PARQUET_UTIL_CRYPTO_H -#include -#include -#include -#include -#include -#include -#include "parquet/exception.h" #include "parquet/types.h" namespace parquet { - -inline int encrypt(Encryption::type alg_id, const uint8_t *plaintext, int plaintext_len, - uint8_t *key, int key_len, uint8_t *aad, int aad_len, - uint8_t *ciphertext) { - - if (Encryption::PARQUET_AES_GCM_V1 != alg_id) { - std::stringstream ss; - ss << "Crypto algorithm " << alg_id << " currently unsupported\n"; - throw parquet::ParquetException(ss.str()); - } - - if (16 != key_len) { - std::stringstream ss; - ss << "Key length " << key_len << " currently unsupported\n"; - throw parquet::ParquetException(ss.str()); - } - - EVP_CIPHER_CTX *ctx; - int tag_len = 16; - int iv_len = 12; - - int len; - int ciphertext_len; - uint8_t tag[tag_len]; - uint8_t iv[iv_len]; - - // Random IV - RAND_load_file("/dev/urandom", 32); - RAND_bytes(iv, sizeof(iv)); - - // Init cipher context - if(!(ctx = EVP_CIPHER_CTX_new())) { - std::stringstream ss; - ss << "Couldn't init cipher context\n"; - throw parquet::ParquetException(ss.str()); - } - - // Init AES-GCM with 128-bit key - if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { - std::stringstream ss; - ss << "Couldn't init AES_GCM_128 encryption\n"; - throw parquet::ParquetException(ss.str()); - } - - // Setting custom IV length - if (12 != iv_len) { - if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) { - std::stringstream ss; - ss << "Couldn't set IV length: " << iv_len << "\n"; - throw parquet::ParquetException(ss.str()); - } - } - - // Setting key and IV - if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) { - std::stringstream ss; - ss << "Couldn't set key and IV\n"; - throw parquet::ParquetException(ss.str()); - } - - // Setting additional authenticated data - if (NULL != aad) { - if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) { - std::stringstream ss; - ss << "Couldn't set AAD\n"; - throw parquet::ParquetException(ss.str()); - } - } - - // Encryption - if(1 != EVP_EncryptUpdate(ctx, ciphertext + iv_len, &len, plaintext, plaintext_len)) { - std::stringstream ss; - ss << "Failed encryption update\n"; - throw parquet::ParquetException(ss.str()); - } - - ciphertext_len = len; - - // Finalization - if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + iv_len + len, &len)) { - std::stringstream ss; - ss << "Failed encryption finalization\n"; - throw parquet::ParquetException(ss.str()); - } - - ciphertext_len += len; - // Getting the tag - if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_len, tag)) { - std::stringstream ss; - ss << "Couldn't get AES-GCM tag\n"; - throw parquet::ParquetException(ss.str()); - } - - // Cleaning up - EVP_CIPHER_CTX_free(ctx); - - // Copying the IV and tag to ciphertext - std::copy(iv, iv+iv_len, ciphertext); - std::copy(tag, tag+tag_len, ciphertext + iv_len + ciphertext_len); - - return iv_len + ciphertext_len + tag_len; -} - -inline int decrypt(Encryption::type alg_id, const uint8_t *ciphertext, int ciphertext_len, +int encrypt(Encryption::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 *plaintext) -{ - - if (Encryption::PARQUET_AES_GCM_V1 != alg_id) { - std::stringstream ss; - ss << "Crypto algorithm " << alg_id << " currently unsupported\n"; - throw parquet::ParquetException(ss.str()); - } - - if (16 != key_len) { - std::stringstream ss; - ss << "Key length " << key_len << " currently unsupported\n"; - throw parquet::ParquetException(ss.str()); - } - - EVP_CIPHER_CTX *ctx; - int len; - int plaintext_len; - int ret; - - int tag_len = 16; - int iv_len = 12; - uint8_t tag[tag_len]; - uint8_t iv[iv_len]; - - // Extracting IV and tag - std::copy(ciphertext, ciphertext + iv_len, iv); - std::copy(ciphertext + ciphertext_len - tag_len, ciphertext + ciphertext_len, tag); - - - // Init cipher context - if(!(ctx = EVP_CIPHER_CTX_new())) { - std::stringstream ss; - ss << "Couldn't init cipher context\n"; - throw parquet::ParquetException(ss.str()); - } - - // Init AES-GCM with 128-bit key - if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { - std::stringstream ss; - ss << "Couldn't init AES_GCM_128 decryption\n"; - throw parquet::ParquetException(ss.str()); - } - - // Setting custom IV length - if (12 != iv_len) { - if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_len, NULL)) { - std::stringstream ss; - ss << "Couldn't set IV length: " << iv_len << "\n"; - throw parquet::ParquetException(ss.str()); - } - } - - // Setting key and IV - if(1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { - std::stringstream ss; - ss << "Couldn't set key and IV\n"; - throw parquet::ParquetException(ss.str()); - } + uint8_t *ciphertext); - // Setting additional authenticated data - if (NULL != aad) { - if(1 != EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) { - std::stringstream ss; - ss << "Couldn't set AAD\n"; - throw parquet::ParquetException(ss.str()); - } - } - - // Decryption - if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext + iv_len, ciphertext_len - iv_len - tag_len)) { - std::stringstream ss; - ss << "Failed decryption update\n"; - throw parquet::ParquetException(ss.str()); - } - - plaintext_len = len; - // Checking the tag (authentication) - if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_len, tag)) { - std::stringstream ss; - ss << "Failed authentication\n"; - throw parquet::ParquetException(ss.str()); - } - - // Finalization - ret = EVP_DecryptFinal_ex(ctx, plaintext + len, &len); - - // Cleaning up - EVP_CIPHER_CTX_free(ctx); - - if(ret > 0) { - plaintext_len += len; - return plaintext_len; - } - else { - return -1; - } -} +int decrypt(Encryption::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); } // namespace parquet From fc5d77d971cfd67d1723f8fd292378546203e660 Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Wed, 27 Jun 2018 08:45:31 +0300 Subject: [PATCH 04/10] version fix --- src/parquet/types.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/parquet/types.h b/src/parquet/types.h index ea78d5b1..aec99656 100644 --- a/src/parquet/types.h +++ b/src/parquet/types.h @@ -164,8 +164,7 @@ struct ByteArray { }; inline bool operator==(const ByteArray& left, const ByteArray& right) { - //return left.len == right.len && 0 == std::memcmp(left.ptr, right.ptr, left.len); - return left.len == right.len && std::equal(left.ptr, left.ptr + left.len, right.ptr); + return left.len == right.len && 0 == std::memcmp(left.ptr, right.ptr, left.len); } inline bool operator!=(const ByteArray& left, const ByteArray& right) { From b3affc50aa7647281a10fa2a79058c7c15d4cd4e Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Thu, 28 Jun 2018 17:10:07 +0300 Subject: [PATCH 05/10] change import order --- src/parquet/util/crypto.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/parquet/util/crypto.cc b/src/parquet/util/crypto.cc index 8ebe81c9..951a2d78 100644 --- a/src/parquet/util/crypto.cc +++ b/src/parquet/util/crypto.cc @@ -23,9 +23,8 @@ #include #include #include "parquet/exception.h" -#include "parquet/types.h" - #include "parquet/util/crypto.h" +#include "parquet/types.h" namespace parquet { From 35a4830c437961db7477c7825f4d4a16d174809a Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Fri, 29 Jun 2018 08:26:04 +0300 Subject: [PATCH 06/10] fix import order --- src/parquet/util/crypto.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/parquet/util/crypto.cc b/src/parquet/util/crypto.cc index 951a2d78..7afb387a 100644 --- a/src/parquet/util/crypto.cc +++ b/src/parquet/util/crypto.cc @@ -16,6 +16,7 @@ // under the License. +#include "parquet/util/crypto.h" #include #include #include @@ -23,8 +24,6 @@ #include #include #include "parquet/exception.h" -#include "parquet/util/crypto.h" -#include "parquet/types.h" namespace parquet { From 20b496fc6fe838d8373486a26fca636407a337d9 Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Sun, 29 Jul 2018 09:02:10 +0300 Subject: [PATCH 07/10] EncryptionProperties input and other review changes --- src/parquet/util/crypto.cc | 246 +++++++++++++++++++++++-------------- src/parquet/util/crypto.h | 11 +- 2 files changed, 164 insertions(+), 93 deletions(-) diff --git a/src/parquet/util/crypto.cc b/src/parquet/util/crypto.cc index 7afb387a..15ae2c00 100644 --- a/src/parquet/util/crypto.cc +++ b/src/parquet/util/crypto.cc @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. - +#include #include "parquet/util/crypto.h" #include #include @@ -27,75 +27,89 @@ namespace parquet { -const int gcm_tag_len = 16; -const int gcm_iv_len = 12; -const int ctr_iv_len = 16; +constexpr int gcm_tag_len = 16; +constexpr int gcm_iv_len = 12; +constexpr int ctr_iv_len = 16; +constexpr long max_bytes = 32; -void handleError(const char *message, EVP_CIPHER_CTX *ctx) { - if (NULL != ctx) EVP_CIPHER_CTX_free(ctx); - std::stringstream ss; - ss << message; - throw parquet::ParquetException(ss.str()); -} +struct EvpCipherCtxDeleter { + void operator()(EVP_CIPHER_CTX *ctx) const { + if (nullptr != ctx) { + EVP_CIPHER_CTX_free(ctx); + } + } +}; + +using EvpCipherCtxPtr = std::unique_ptr; int gcm_encrypt(const uint8_t *plaintext, int plaintext_len, uint8_t *key, int key_len, uint8_t *aad, int aad_len, uint8_t *ciphertext) { - EVP_CIPHER_CTX *ctx = NULL; - int len; int ciphertext_len; uint8_t tag[gcm_tag_len]; uint8_t iv[gcm_iv_len]; // Random IV - RAND_load_file("/dev/urandom", 32); + RAND_load_file("/dev/urandom", max_bytes); RAND_bytes(iv, sizeof(iv)); // Init cipher context - if(!(ctx = EVP_CIPHER_CTX_new())) { - handleError("Couldn't init cipher context", ctx); + EvpCipherCtxPtr ctx(EVP_CIPHER_CTX_new()); + if(nullptr == ctx.get()) { + throw ParquetException("Couldn't init cipher context"); } - // Init AES-GCM with 128-bit key - if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { - handleError("Couldn't init AES_GCM_128 encryption", ctx); + if (16 == key_len) { + // Init AES-GCM with 128-bit key + if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_GCM_128 encryption"); + } + } + else if (24 == key_len) { + // Init AES-GCM with 192-bit key + if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_192_gcm(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_GCM_192 encryption"); + } + } + else if (32 == key_len) { + // Init AES-GCM with 256-bit key + if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_GCM_256 encryption"); + } } // Setting key and IV - if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) { - handleError("Couldn't set key and IV", ctx); + if(1 != EVP_EncryptInit_ex(ctx.get(), nullptr, nullptr, key, iv)) { + throw ParquetException("Couldn't set key and IV"); } // Setting additional authenticated data - if (NULL != aad) { - if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) { - handleError("Couldn't set AAD", ctx); + if (nullptr != aad) { + if(1 != EVP_EncryptUpdate(ctx.get(), nullptr, &len, aad, aad_len)) { + throw ParquetException("Couldn't set AAD"); } } // Encryption - if(1 != EVP_EncryptUpdate(ctx, ciphertext + gcm_iv_len, &len, plaintext, plaintext_len)) { - handleError("Failed encryption update", ctx); + if(1 != EVP_EncryptUpdate(ctx.get(), ciphertext + gcm_iv_len, &len, plaintext, plaintext_len)) { + throw ParquetException("Failed encryption update"); } ciphertext_len = len; // Finalization - if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + gcm_iv_len + len, &len)) { - handleError("Failed encryption finalization", ctx); + if(1 != EVP_EncryptFinal_ex(ctx.get(), ciphertext + gcm_iv_len + len, &len)) { + throw ParquetException("Failed encryption finalization"); } ciphertext_len += len; // Getting the tag - if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, gcm_tag_len, tag)) { - handleError("Couldn't get AES-GCM tag", ctx); + if(1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, gcm_tag_len, tag)) { + throw ParquetException("Couldn't get AES-GCM tag"); } - - // Cleaning up - EVP_CIPHER_CTX_free(ctx); // Copying the IV and tag to ciphertext std::copy(iv, iv + gcm_iv_len, ciphertext); @@ -107,48 +121,58 @@ int gcm_encrypt(const uint8_t *plaintext, int plaintext_len, int ctr_encrypt(const uint8_t *plaintext, int plaintext_len, uint8_t *key, int key_len, uint8_t *ciphertext) { - EVP_CIPHER_CTX *ctx; - int len; int ciphertext_len; uint8_t iv[ctr_iv_len]; // Random IV - RAND_load_file("/dev/urandom", 32); + RAND_load_file("/dev/urandom", max_bytes); RAND_bytes(iv, sizeof(iv)); // Init cipher context - if(!(ctx = EVP_CIPHER_CTX_new())) { - handleError("Couldn't init cipher context", ctx); + EvpCipherCtxPtr ctx(EVP_CIPHER_CTX_new()); + if(nullptr == ctx.get()) { + throw ParquetException("Couldn't init cipher context"); } - // Init AES-CTR with 128-bit key - if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, NULL, NULL)) { - handleError("Couldn't init AES_CTR_128 encryption", ctx); + if (16 == key_len) { + // Init AES-CTR with 128-bit key + if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_ctr(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_CTR_128 encryption"); + } + } + else if (24 == key_len) { + // Init AES-CTR with 192-bit key + if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_192_ctr(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_CTR_192 encryption"); + } + } + else if (32 == key_len) { + // Init AES-CTR with 256-bit key + if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_ctr(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_CTR_256 encryption"); + } } // Setting key and IV - if(1 != EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv)) { - handleError("Couldn't set key and IV", ctx); + if(1 != EVP_EncryptInit_ex(ctx.get(), nullptr, nullptr, key, iv)) { + throw ParquetException("Couldn't set key and IV"); } // Encryption - if(1 != EVP_EncryptUpdate(ctx, ciphertext + ctr_iv_len, &len, plaintext, plaintext_len)) { - handleError("Failed encryption update", ctx); + if(1 != EVP_EncryptUpdate(ctx.get(), ciphertext + ctr_iv_len, &len, plaintext, plaintext_len)) { + throw ParquetException("Failed encryption update"); } ciphertext_len = len; // Finalization - if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + ctr_iv_len + len, &len)) { - handleError("Failed encryption finalization", ctx); + if(1 != EVP_EncryptFinal_ex(ctx.get(), ciphertext + ctr_iv_len + len, &len)) { + throw ParquetException("Failed encryption finalization"); } ciphertext_len += len; - // Cleaning up - EVP_CIPHER_CTX_free(ctx); - // Copying the IV ciphertext std::copy(iv, iv + ctr_iv_len, ciphertext); @@ -164,13 +188,13 @@ int encrypt(Encryption::type alg_id, bool metadata, if (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) { std::stringstream ss; - ss << "Crypto algorithm " << alg_id << " currently unsupported"; + ss << "Crypto algorithm " << alg_id << " is not supported"; throw parquet::ParquetException(ss.str()); } - if (16 != key_len) { + if (16 != key_len && 24 != key_len && 32 != key_len) { std::stringstream ss; - ss << "Key length " << key_len << " currently unsupported"; + ss << "Wrong key length: " << key_len; throw parquet::ParquetException(ss.str()); } @@ -181,12 +205,21 @@ int encrypt(Encryption::type alg_id, bool metadata, // Data (page) encryption with AES_GCM_CTR_V1 return ctr_encrypt(plaintext, plaintext_len, key, key_len, ciphertext); } + +int encrypt(std::shared_ptr 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 gcm_decrypt(const uint8_t *ciphertext, int ciphertext_len, uint8_t *key, int key_len, uint8_t *aad, int aad_len, uint8_t *plaintext) { - EVP_CIPHER_CTX *ctx = NULL; int len; int plaintext_len; @@ -197,50 +230,61 @@ int gcm_decrypt(const uint8_t *ciphertext, int ciphertext_len, std::copy(ciphertext, ciphertext + gcm_iv_len, iv); std::copy(ciphertext + ciphertext_len - gcm_tag_len, ciphertext + ciphertext_len, tag); - // Init cipher context - if(!(ctx = EVP_CIPHER_CTX_new())) { - handleError("Couldn't init cipher context", ctx); + EvpCipherCtxPtr ctx(EVP_CIPHER_CTX_new()); + if(nullptr == ctx.get()) { + throw ParquetException("Couldn't init cipher context"); } - // Init AES-GCM with 128-bit key - if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_gcm(), NULL, NULL, NULL)) { - handleError("Couldn't init AES_GCM_128 decryption", ctx); + if (16 == key_len) { + // Init AES-GCM with 128-bit key + if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_GCM_128 decryption"); + } + } + else if (24 == key_len) { + // Init AES-GCM with 192-bit key + if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_192_gcm(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_GCM_192 decryption"); + } + } + else if (32 == key_len) { + // Init AES-GCM with 256-bit key + if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_GCM_256 decryption"); + } } // Setting key and IV - if(1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { - handleError("Couldn't set key and IV", ctx); + if(1 != EVP_DecryptInit_ex(ctx.get(), nullptr, nullptr, key, iv)) { + throw ParquetException("Couldn't set key and IV"); } // Setting additional authenticated data - if (NULL != aad) { - if(1 != EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) { - handleError("Couldn't set AAD", ctx); + if (nullptr != aad) { + if(1 != EVP_DecryptUpdate(ctx.get(), nullptr, &len, aad, aad_len)) { + throw ParquetException("Couldn't set AAD"); } } // Decryption - if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext + gcm_iv_len, + if(!EVP_DecryptUpdate(ctx.get(), plaintext, &len, ciphertext + gcm_iv_len, ciphertext_len - gcm_iv_len - gcm_tag_len)) { - handleError("Failed decryption update", ctx); + throw ParquetException("Failed decryption update"); } plaintext_len = len; // Checking the tag (authentication) - if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, gcm_tag_len, tag)) { - handleError("Failed authentication", ctx); + if(!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, gcm_tag_len, tag)) { + throw ParquetException("Failed authentication"); } // Finalization - if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) { - handleError("Failed decryption finalization", ctx); + if (1 != EVP_DecryptFinal_ex(ctx.get(), plaintext + len, &len)) { + throw ParquetException("Failed decryption finalization"); } - // Cleaning up - EVP_CIPHER_CTX_free(ctx); - plaintext_len += len; return plaintext_len; } @@ -248,7 +292,6 @@ int gcm_decrypt(const uint8_t *ciphertext, int ciphertext_len, int ctr_decrypt(const uint8_t *ciphertext, int ciphertext_len, uint8_t *key, int key_len, uint8_t *plaintext) { - EVP_CIPHER_CTX *ctx = NULL; int len; int plaintext_len; @@ -258,36 +301,48 @@ int ctr_decrypt(const uint8_t *ciphertext, int ciphertext_len, std::copy(ciphertext, ciphertext + ctr_iv_len, iv); // Init cipher context - if(!(ctx = EVP_CIPHER_CTX_new())) { - handleError("Couldn't init cipher context", ctx); + EvpCipherCtxPtr ctx(EVP_CIPHER_CTX_new()); + if(nullptr == ctx.get()) { + throw ParquetException("Couldn't init cipher context"); } - // Init AES-CTR with 128-bit key - if(!EVP_DecryptInit_ex(ctx, EVP_aes_128_ctr(), NULL, NULL, NULL)) { - handleError("Couldn't init AES_CTR_128 decryption", ctx); + if (16 == key_len) { + // Init AES-CTR with 128-bit key + if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_ctr(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_CTR_128 decryption"); + } + } + else if (24 == key_len) { + // Init AES-CTR with 192-bit key + if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_192_ctr(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_CTR_192 decryption"); + } + } + else if (32 == key_len) { + // Init AES-CTR with 256-bit key + if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_ctr(), nullptr, nullptr, nullptr)) { + throw ParquetException("Couldn't init AES_CTR_256 decryption"); + } } // Setting key and IV - if(1 != EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { - handleError("Couldn't set key and IV", ctx); + if(1 != EVP_DecryptInit_ex(ctx.get(), nullptr, nullptr, key, iv)) { + throw ParquetException("Couldn't set key and IV"); } // Decryption - if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext + ctr_iv_len, + if(!EVP_DecryptUpdate(ctx.get(), plaintext, &len, ciphertext + ctr_iv_len, ciphertext_len - ctr_iv_len)) { - handleError("Failed decryption update", ctx); + throw ParquetException("Failed decryption update"); } plaintext_len = len; // Finalization - if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) { - handleError("Failed decryption finalization", ctx); + if (1 != EVP_DecryptFinal_ex(ctx.get(), plaintext + len, &len)) { + throw ParquetException("Failed decryption finalization"); } - // Cleaning up - EVP_CIPHER_CTX_free(ctx); - plaintext_len += len; return plaintext_len; } @@ -300,13 +355,13 @@ int decrypt(Encryption::type alg_id, bool metadata, if (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) { std::stringstream ss; - ss << "Crypto algorithm " << alg_id << " currently unsupported"; + ss << "Crypto algorithm " << alg_id << " is not supported"; throw parquet::ParquetException(ss.str()); } - if (16 != key_len) { + if (16 != key_len && 24 != key_len && 32 != key_len) { std::stringstream ss; - ss << "Key length " << key_len << " currently unsupported"; + ss << "Wrong key length: " << key_len; throw parquet::ParquetException(ss.str()); } @@ -318,5 +373,14 @@ int decrypt(Encryption::type alg_id, bool metadata, return ctr_decrypt(ciphertext, ciphertext_len, key, key_len, plaintext); } +int decrypt(std::shared_ptr 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); +} + } // namespace parquet diff --git a/src/parquet/util/crypto.h b/src/parquet/util/crypto.h index 2aa6127d..f86b3c54 100644 --- a/src/parquet/util/crypto.h +++ b/src/parquet/util/crypto.h @@ -19,7 +19,8 @@ #ifndef PARQUET_UTIL_CRYPTO_H #define PARQUET_UTIL_CRYPTO_H -#include "parquet/types.h" +#include "parquet/types.h" +#include "parquet/properties.h" namespace parquet { @@ -27,13 +28,19 @@ int encrypt(Encryption::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 encrypt(std::shared_ptr encryption_props, bool metadata, + const uint8_t *plaintext, int plaintext_len, + uint8_t *ciphertext); int decrypt(Encryption::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 decrypt(std::shared_ptr encryption_props, bool metadata, + const uint8_t *ciphertext, int ciphertext_len, + uint8_t *plaintext); } // namespace parquet #endif //PARQUET_UTIL_CRYPTO_H From b5e40b1963db86a191136828c13e966f3fa11ac6 Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Wed, 1 Aug 2018 09:37:11 +0300 Subject: [PATCH 08/10] post-review changes --- src/parquet/util/crypto.cc | 412 +++++++++++++++++-------------------- src/parquet/util/crypto.h | 37 ++-- 2 files changed, 208 insertions(+), 241 deletions(-) diff --git a/src/parquet/util/crypto.cc b/src/parquet/util/crypto.cc index 15ae2c00..97750936 100644 --- a/src/parquet/util/crypto.cc +++ b/src/parquet/util/crypto.cc @@ -15,273 +15,277 @@ // specific language governing permissions and limitations // under the License. -#include #include "parquet/util/crypto.h" #include #include #include -#include -#include #include +#include +#include +#include #include "parquet/exception.h" -namespace parquet { +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 gcmIvLen = 12; +constexpr int ctrIvLen = 16; +constexpr long rndMaxBytes = 32; + +#define ENCRYPT_INIT(ALG) \ + if (1 != EVP_EncryptInit_ex(ctx_, ALG, nullptr, nullptr, nullptr)) \ + throw ParquetException("Couldn't init ALG encryption") + +#define DECRYPT_INIT(ALG) \ + if (1 != EVP_DecryptInit_ex(ctx_, ALG, nullptr, nullptr, nullptr)) \ + throw ParquetException("Couldn't init ALG decryption") + +class EvpCipher { + public: + explicit EvpCipher(int cipher, int key_len, int type) { + if (aesGcm != cipher && aesCtr != cipher) { + std::stringstream ss; + ss << "Wrong cipher: " << cipher; + throw parquet::ParquetException(ss.str()); + } + + if (16 != key_len && 24 != key_len && 32 != key_len) { + std::stringstream ss; + ss << "Wrong key length: " << key_len; + throw parquet::ParquetException(ss.str()); + } + + if (encryptType != type && decryptType != type) { + std::stringstream ss; + ss << "Wrong cipher type: " << type; + throw parquet::ParquetException(ss.str()); + } -constexpr int gcm_tag_len = 16; -constexpr int gcm_iv_len = 12; -constexpr int ctr_iv_len = 16; -constexpr long max_bytes = 32; + ctx_ = EVP_CIPHER_CTX_new(); + if (nullptr == ctx_) { + throw ParquetException("Couldn't init cipher context"); + } -struct EvpCipherCtxDeleter { - void operator()(EVP_CIPHER_CTX *ctx) const { - if (nullptr != ctx) { - EVP_CIPHER_CTX_free(ctx); - } + if (aesGcm == cipher) { + // Init AES-GCM with specified key length + if (16 == key_len) { + if (encryptType == type) { + ENCRYPT_INIT(EVP_aes_128_gcm()); + } else { + DECRYPT_INIT(EVP_aes_128_gcm()); + } + } else if (24 == key_len) { + if (encryptType == type) { + ENCRYPT_INIT(EVP_aes_192_gcm()); + } else { + DECRYPT_INIT(EVP_aes_192_gcm()); + } + } else if (32 == key_len) { + if (encryptType == type) { + ENCRYPT_INIT(EVP_aes_256_gcm()); + } else { + DECRYPT_INIT(EVP_aes_256_gcm()); + } + } + } else { + // Init AES-CTR with specified key length + if (16 == key_len) { + if (encryptType == type) { + ENCRYPT_INIT(EVP_aes_128_ctr()); + } else { + DECRYPT_INIT(EVP_aes_128_ctr()); + } + } else if (24 == key_len) { + if (encryptType == type) { + ENCRYPT_INIT(EVP_aes_192_ctr()); + } else { + DECRYPT_INIT(EVP_aes_192_ctr()); + } + } else if (32 == key_len) { + if (encryptType == type) { + ENCRYPT_INIT(EVP_aes_256_ctr()); + } else { + DECRYPT_INIT(EVP_aes_256_ctr()); + } + } + } } -}; -using EvpCipherCtxPtr = std::unique_ptr; + EVP_CIPHER_CTX* get() { return ctx_; } + + ~EvpCipher() { + if (nullptr != ctx_) { + EVP_CIPHER_CTX_free(ctx_); + } + } -int gcm_encrypt(const uint8_t *plaintext, int plaintext_len, - uint8_t *key, int key_len, uint8_t *aad, int aad_len, - uint8_t *ciphertext) -{ + private: + EVP_CIPHER_CTX* ctx_; +}; + +int gcm_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len, + uint8_t* aad, int aad_len, uint8_t* ciphertext) { int len; int ciphertext_len; - uint8_t tag[gcm_tag_len]; - uint8_t iv[gcm_iv_len]; - + uint8_t tag[gcmTagLen]; + uint8_t iv[gcmIvLen]; + // Random IV - RAND_load_file("/dev/urandom", max_bytes); + RAND_load_file("/dev/urandom", rndMaxBytes); RAND_bytes(iv, sizeof(iv)); // Init cipher context - EvpCipherCtxPtr ctx(EVP_CIPHER_CTX_new()); - if(nullptr == ctx.get()) { - throw ParquetException("Couldn't init cipher context"); - } - - if (16 == key_len) { - // Init AES-GCM with 128-bit key - if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_GCM_128 encryption"); - } - } - else if (24 == key_len) { - // Init AES-GCM with 192-bit key - if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_192_gcm(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_GCM_192 encryption"); - } - } - else if (32 == key_len) { - // Init AES-GCM with 256-bit key - if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_GCM_256 encryption"); - } - } + EvpCipher cipher(aesGcm, key_len, encryptType); - // Setting key and IV - if(1 != EVP_EncryptInit_ex(ctx.get(), nullptr, nullptr, key, iv)) { + // Setting key and IV + if (1 != EVP_EncryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) { throw ParquetException("Couldn't set key and IV"); } // Setting additional authenticated data if (nullptr != aad) { - if(1 != EVP_EncryptUpdate(ctx.get(), nullptr, &len, aad, aad_len)) { + if (1 != EVP_EncryptUpdate(cipher.get(), nullptr, &len, aad, aad_len)) { throw ParquetException("Couldn't set AAD"); } } // Encryption - if(1 != EVP_EncryptUpdate(ctx.get(), ciphertext + gcm_iv_len, &len, plaintext, plaintext_len)) { + if (1 != EVP_EncryptUpdate(cipher.get(), ciphertext + gcmIvLen, &len, plaintext, + plaintext_len)) { throw ParquetException("Failed encryption update"); } ciphertext_len = len; // Finalization - if(1 != EVP_EncryptFinal_ex(ctx.get(), ciphertext + gcm_iv_len + len, &len)) { + if (1 != EVP_EncryptFinal_ex(cipher.get(), ciphertext + gcmIvLen + len, &len)) { throw ParquetException("Failed encryption finalization"); } - + ciphertext_len += len; // Getting the tag - if(1 != EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_GET_TAG, gcm_tag_len, tag)) { + if (1 != EVP_CIPHER_CTX_ctrl(cipher.get(), EVP_CTRL_GCM_GET_TAG, gcmTagLen, tag)) { throw ParquetException("Couldn't get AES-GCM tag"); } - + // Copying the IV and tag to ciphertext - std::copy(iv, iv + gcm_iv_len, ciphertext); - std::copy(tag, tag + gcm_tag_len, ciphertext + gcm_iv_len + ciphertext_len); - - return gcm_iv_len + ciphertext_len + gcm_tag_len; + std::copy(iv, iv + gcmIvLen, ciphertext); + std::copy(tag, tag + gcmTagLen, ciphertext + gcmIvLen + ciphertext_len); + + return gcmIvLen + ciphertext_len + gcmTagLen; } -int ctr_encrypt(const uint8_t *plaintext, int plaintext_len, - uint8_t *key, int key_len, uint8_t *ciphertext) -{ +int ctr_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int key_len, + uint8_t* ciphertext) { int len; int ciphertext_len; - uint8_t iv[ctr_iv_len]; - + uint8_t iv[ctrIvLen]; + // Random IV - RAND_load_file("/dev/urandom", max_bytes); + RAND_load_file("/dev/urandom", rndMaxBytes); RAND_bytes(iv, sizeof(iv)); // Init cipher context - EvpCipherCtxPtr ctx(EVP_CIPHER_CTX_new()); - if(nullptr == ctx.get()) { - throw ParquetException("Couldn't init cipher context"); - } - - if (16 == key_len) { - // Init AES-CTR with 128-bit key - if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_128_ctr(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_CTR_128 encryption"); - } - } - else if (24 == key_len) { - // Init AES-CTR with 192-bit key - if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_192_ctr(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_CTR_192 encryption"); - } - } - else if (32 == key_len) { - // Init AES-CTR with 256-bit key - if(1 != EVP_EncryptInit_ex(ctx.get(), EVP_aes_256_ctr(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_CTR_256 encryption"); - } - } + EvpCipher cipher(aesCtr, key_len, encryptType); - // Setting key and IV - if(1 != EVP_EncryptInit_ex(ctx.get(), nullptr, nullptr, key, iv)) { + // Setting key and IV + if (1 != EVP_EncryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) { throw ParquetException("Couldn't set key and IV"); } // Encryption - if(1 != EVP_EncryptUpdate(ctx.get(), ciphertext + ctr_iv_len, &len, plaintext, plaintext_len)) { + if (1 != EVP_EncryptUpdate(cipher.get(), ciphertext + ctrIvLen, &len, plaintext, + plaintext_len)) { throw ParquetException("Failed encryption update"); } ciphertext_len = len; // Finalization - if(1 != EVP_EncryptFinal_ex(ctx.get(), ciphertext + ctr_iv_len + len, &len)) { + if (1 != EVP_EncryptFinal_ex(cipher.get(), ciphertext + ctrIvLen + len, &len)) { throw ParquetException("Failed encryption finalization"); } - + ciphertext_len += len; // Copying the IV ciphertext - std::copy(iv, iv + ctr_iv_len, ciphertext); - - return ctr_iv_len + ciphertext_len; -} + std::copy(iv, iv + ctrIvLen, ciphertext); + return ctrIvLen + ciphertext_len; +} -int encrypt(Encryption::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 Encrypt(Encryption::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) { if (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) { std::stringstream ss; ss << "Crypto algorithm " << alg_id << " is not supported"; throw parquet::ParquetException(ss.str()); } - - if (16 != key_len && 24 != key_len && 32 != key_len) { - std::stringstream ss; - ss << "Wrong key length: " << key_len; - throw parquet::ParquetException(ss.str()); - } - + if (metadata || (Encryption::AES_GCM_V1 == alg_id)) { return gcm_encrypt(plaintext, plaintext_len, key, key_len, aad, aad_len, ciphertext); } - + // Data (page) encryption with AES_GCM_CTR_V1 return ctr_encrypt(plaintext, plaintext_len, key, key_len, ciphertext); } -int encrypt(std::shared_ptr 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 Encrypt(std::shared_ptr 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 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 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[gcm_tag_len]; - uint8_t iv[gcm_iv_len]; - + + uint8_t tag[gcmTagLen]; + uint8_t iv[gcmIvLen]; + // Extracting IV and tag - std::copy(ciphertext, ciphertext + gcm_iv_len, iv); - std::copy(ciphertext + ciphertext_len - gcm_tag_len, ciphertext + ciphertext_len, tag); - - // Init cipher context - EvpCipherCtxPtr ctx(EVP_CIPHER_CTX_new()); - if(nullptr == ctx.get()) { - throw ParquetException("Couldn't init cipher context"); - } + std::copy(ciphertext, ciphertext + gcmIvLen, iv); + std::copy(ciphertext + ciphertext_len - gcmTagLen, ciphertext + ciphertext_len, tag); - if (16 == key_len) { - // Init AES-GCM with 128-bit key - if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_GCM_128 decryption"); - } - } - else if (24 == key_len) { - // Init AES-GCM with 192-bit key - if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_192_gcm(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_GCM_192 decryption"); - } - } - else if (32 == key_len) { - // Init AES-GCM with 256-bit key - if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_gcm(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_GCM_256 decryption"); - } - } + // Init cipher context + EvpCipher cipher(aesGcm, key_len, decryptType); - // Setting key and IV - if(1 != EVP_DecryptInit_ex(ctx.get(), nullptr, nullptr, key, iv)) { + // Setting key and IV + if (1 != EVP_DecryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) { throw ParquetException("Couldn't set key and IV"); } // Setting additional authenticated data if (nullptr != aad) { - if(1 != EVP_DecryptUpdate(ctx.get(), nullptr, &len, aad, aad_len)) { + if (1 != EVP_DecryptUpdate(cipher.get(), nullptr, &len, aad, aad_len)) { throw ParquetException("Couldn't set AAD"); } } - + // Decryption - if(!EVP_DecryptUpdate(ctx.get(), plaintext, &len, ciphertext + gcm_iv_len, - ciphertext_len - gcm_iv_len - gcm_tag_len)) { + if (!EVP_DecryptUpdate(cipher.get(), plaintext, &len, ciphertext + gcmIvLen, + ciphertext_len - gcmIvLen - gcmTagLen)) { throw ParquetException("Failed decryption update"); } - + plaintext_len = len; // Checking the tag (authentication) - if(!EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, gcm_tag_len, tag)) { + if (!EVP_CIPHER_CTX_ctrl(cipher.get(), EVP_CTRL_GCM_SET_TAG, gcmTagLen, tag)) { throw ParquetException("Failed authentication"); } // Finalization - if (1 != EVP_DecryptFinal_ex(ctx.get(), plaintext + len, &len)) { + if (1 != EVP_DecryptFinal_ex(cipher.get(), plaintext + len, &len)) { throw ParquetException("Failed decryption finalization"); } @@ -289,57 +293,34 @@ int gcm_decrypt(const uint8_t *ciphertext, int ciphertext_len, return plaintext_len; } -int ctr_decrypt(const uint8_t *ciphertext, int ciphertext_len, - uint8_t *key, int key_len, uint8_t *plaintext) -{ +int 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[ctr_iv_len]; - + + uint8_t iv[ctrIvLen]; + // Extracting IV and tag - std::copy(ciphertext, ciphertext + ctr_iv_len, iv); - - // Init cipher context - EvpCipherCtxPtr ctx(EVP_CIPHER_CTX_new()); - if(nullptr == ctx.get()) { - throw ParquetException("Couldn't init cipher context"); - } + std::copy(ciphertext, ciphertext + ctrIvLen, iv); - if (16 == key_len) { - // Init AES-CTR with 128-bit key - if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_ctr(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_CTR_128 decryption"); - } - } - else if (24 == key_len) { - // Init AES-CTR with 192-bit key - if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_192_ctr(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_CTR_192 decryption"); - } - } - else if (32 == key_len) { - // Init AES-CTR with 256-bit key - if(1 != EVP_DecryptInit_ex(ctx.get(), EVP_aes_256_ctr(), nullptr, nullptr, nullptr)) { - throw ParquetException("Couldn't init AES_CTR_256 decryption"); - } - } + // Init cipher context + EvpCipher cipher(aesCtr, key_len, decryptType); - // Setting key and IV - if(1 != EVP_DecryptInit_ex(ctx.get(), nullptr, nullptr, key, iv)) { + // Setting key and IV + if (1 != EVP_DecryptInit_ex(cipher.get(), nullptr, nullptr, key, iv)) { throw ParquetException("Couldn't set key and IV"); } - + // Decryption - if(!EVP_DecryptUpdate(ctx.get(), plaintext, &len, ciphertext + ctr_iv_len, - ciphertext_len - ctr_iv_len)) { + if (!EVP_DecryptUpdate(cipher.get(), plaintext, &len, ciphertext + ctrIvLen, + ciphertext_len - ctrIvLen)) { throw ParquetException("Failed decryption update"); } - + plaintext_len = len; // Finalization - if (1 != EVP_DecryptFinal_ex(ctx.get(), plaintext + len, &len)) { + if (1 != EVP_DecryptFinal_ex(cipher.get(), plaintext + len, &len)) { throw ParquetException("Failed decryption finalization"); } @@ -347,24 +328,15 @@ int ctr_decrypt(const uint8_t *ciphertext, int ciphertext_len, return plaintext_len; } -int decrypt(Encryption::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 Decrypt(Encryption::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 (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) { std::stringstream ss; ss << "Crypto algorithm " << alg_id << " is not supported"; throw parquet::ParquetException(ss.str()); } - - if (16 != key_len && 24 != key_len && 32 != key_len) { - std::stringstream ss; - ss << "Wrong key length: " << key_len; - throw parquet::ParquetException(ss.str()); - } - + if (metadata || (Encryption::AES_GCM_V1 == alg_id)) { return gcm_decrypt(ciphertext, ciphertext_len, key, key_len, aad, aad_len, plaintext); } @@ -373,14 +345,12 @@ int decrypt(Encryption::type alg_id, bool metadata, return ctr_decrypt(ciphertext, ciphertext_len, key, key_len, plaintext); } -int decrypt(std::shared_ptr 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); +int Decrypt(std::shared_ptr 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); } -} // namespace parquet - +} // namespace parquet_encryption diff --git a/src/parquet/util/crypto.h b/src/parquet/util/crypto.h index f86b3c54..dd7545f7 100644 --- a/src/parquet/util/crypto.h +++ b/src/parquet/util/crypto.h @@ -15,32 +15,29 @@ // specific language governing permissions and limitations // under the License. - #ifndef PARQUET_UTIL_CRYPTO_H #define PARQUET_UTIL_CRYPTO_H -#include "parquet/types.h" #include "parquet/properties.h" +#include "parquet/types.h" + +using namespace parquet; + +namespace parquet_encryption { -namespace parquet { +int Encrypt(Encryption::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 encrypt(Encryption::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 encrypt(std::shared_ptr encryption_props, bool metadata, - const uint8_t *plaintext, int plaintext_len, - uint8_t *ciphertext); +int Encrypt(std::shared_ptr encryption_props, bool metadata, + const uint8_t* plaintext, int plaintext_len, uint8_t* ciphertext); -int decrypt(Encryption::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 Decrypt(Encryption::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 decrypt(std::shared_ptr encryption_props, bool metadata, - const uint8_t *ciphertext, int ciphertext_len, - uint8_t *plaintext); -} // namespace parquet +int Decrypt(std::shared_ptr encryption_props, bool metadata, + const uint8_t* ciphertext, int ciphertext_len, uint8_t* plaintext); +} // namespace parquet_encryption -#endif //PARQUET_UTIL_CRYPTO_H +#endif // PARQUET_UTIL_CRYPTO_H From ad17fbe1dc369b336d8bd67835809e10c3e8e621 Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Wed, 1 Aug 2018 17:44:01 +0300 Subject: [PATCH 09/10] fix lint issues --- src/parquet/util/crypto.cc | 29 +++++++++++++++++------------ src/parquet/util/crypto.h | 3 ++- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/parquet/util/crypto.cc b/src/parquet/util/crypto.cc index 97750936..6fe6a9d6 100644 --- a/src/parquet/util/crypto.cc +++ b/src/parquet/util/crypto.cc @@ -19,12 +19,15 @@ #include #include #include +#include #include #include #include #include #include "parquet/exception.h" +using parquet::ParquetException; + namespace parquet_encryption { constexpr int aesGcm = 0; @@ -34,15 +37,17 @@ constexpr int decryptType = 1; constexpr int gcmTagLen = 16; constexpr int gcmIvLen = 12; constexpr int ctrIvLen = 16; -constexpr long rndMaxBytes = 32; +constexpr int rndMaxBytes = 32; -#define ENCRYPT_INIT(ALG) \ - if (1 != EVP_EncryptInit_ex(ctx_, ALG, nullptr, nullptr, nullptr)) \ - throw ParquetException("Couldn't init ALG encryption") +#define ENCRYPT_INIT(ALG) \ + if (1 != EVP_EncryptInit_ex(ctx_, ALG, nullptr, nullptr, nullptr)) { \ + throw ParquetException("Couldn't init ALG encryption"); \ + } -#define DECRYPT_INIT(ALG) \ - if (1 != EVP_DecryptInit_ex(ctx_, ALG, nullptr, nullptr, nullptr)) \ - throw ParquetException("Couldn't init ALG decryption") +#define DECRYPT_INIT(ALG) \ + if (1 != EVP_DecryptInit_ex(ctx_, ALG, nullptr, nullptr, nullptr)) { \ + throw ParquetException("Couldn't init ALG decryption"); \ + } class EvpCipher { public: @@ -50,19 +55,19 @@ class EvpCipher { if (aesGcm != cipher && aesCtr != cipher) { std::stringstream ss; ss << "Wrong cipher: " << cipher; - throw parquet::ParquetException(ss.str()); + throw ParquetException(ss.str()); } if (16 != key_len && 24 != key_len && 32 != key_len) { std::stringstream ss; ss << "Wrong key length: " << key_len; - throw parquet::ParquetException(ss.str()); + throw ParquetException(ss.str()); } if (encryptType != type && decryptType != type) { std::stringstream ss; ss << "Wrong cipher type: " << type; - throw parquet::ParquetException(ss.str()); + throw ParquetException(ss.str()); } ctx_ = EVP_CIPHER_CTX_new(); @@ -225,7 +230,7 @@ int Encrypt(Encryption::type alg_id, bool metadata, const uint8_t* plaintext, if (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) { std::stringstream ss; ss << "Crypto algorithm " << alg_id << " is not supported"; - throw parquet::ParquetException(ss.str()); + throw ParquetException(ss.str()); } if (metadata || (Encryption::AES_GCM_V1 == alg_id)) { @@ -334,7 +339,7 @@ int Decrypt(Encryption::type alg_id, bool metadata, const uint8_t* ciphertext, if (Encryption::AES_GCM_V1 != alg_id && Encryption::AES_GCM_CTR_V1 != alg_id) { std::stringstream ss; ss << "Crypto algorithm " << alg_id << " is not supported"; - throw parquet::ParquetException(ss.str()); + throw ParquetException(ss.str()); } if (metadata || (Encryption::AES_GCM_V1 == alg_id)) { diff --git a/src/parquet/util/crypto.h b/src/parquet/util/crypto.h index dd7545f7..d3beb105 100644 --- a/src/parquet/util/crypto.h +++ b/src/parquet/util/crypto.h @@ -21,7 +21,8 @@ #include "parquet/properties.h" #include "parquet/types.h" -using namespace parquet; +using parquet::Encryption; +using parquet::EncryptionProperties; namespace parquet_encryption { From 42fe1254fe0fbce87257c02005a91a5d05e0b6a9 Mon Sep 17 00:00:00 2001 From: Gidon Gershinsky Date: Thu, 2 Aug 2018 15:09:57 +0300 Subject: [PATCH 10/10] post-review changes --- src/parquet/util/crypto.cc | 60 +++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/parquet/util/crypto.cc b/src/parquet/util/crypto.cc index 6fe6a9d6..59383d18 100644 --- a/src/parquet/util/crypto.cc +++ b/src/parquet/util/crypto.cc @@ -39,19 +39,21 @@ constexpr int gcmIvLen = 12; constexpr int ctrIvLen = 16; constexpr int rndMaxBytes = 32; -#define ENCRYPT_INIT(ALG) \ - if (1 != EVP_EncryptInit_ex(ctx_, ALG, nullptr, nullptr, nullptr)) { \ - throw ParquetException("Couldn't init ALG encryption"); \ +#define ENCRYPT_INIT(CTX, ALG) \ + if (1 != EVP_EncryptInit_ex(CTX, ALG, nullptr, nullptr, nullptr)) { \ + throw ParquetException("Couldn't init ALG encryption"); \ } -#define DECRYPT_INIT(ALG) \ - if (1 != EVP_DecryptInit_ex(ctx_, ALG, nullptr, nullptr, nullptr)) { \ - throw ParquetException("Couldn't init ALG decryption"); \ +#define DECRYPT_INIT(CTX, ALG) \ + if (1 != EVP_DecryptInit_ex(CTX, ALG, nullptr, nullptr, nullptr)) { \ + throw ParquetException("Couldn't init ALG decryption"); \ } class EvpCipher { public: explicit EvpCipher(int cipher, int key_len, int type) { + ctx_ = nullptr; + if (aesGcm != cipher && aesCtr != cipher) { std::stringstream ss; ss << "Wrong cipher: " << cipher; @@ -79,42 +81,42 @@ class EvpCipher { // Init AES-GCM with specified key length if (16 == key_len) { if (encryptType == type) { - ENCRYPT_INIT(EVP_aes_128_gcm()); + ENCRYPT_INIT(ctx_, EVP_aes_128_gcm()); } else { - DECRYPT_INIT(EVP_aes_128_gcm()); + DECRYPT_INIT(ctx_, EVP_aes_128_gcm()); } } else if (24 == key_len) { if (encryptType == type) { - ENCRYPT_INIT(EVP_aes_192_gcm()); + ENCRYPT_INIT(ctx_, EVP_aes_192_gcm()); } else { - DECRYPT_INIT(EVP_aes_192_gcm()); + DECRYPT_INIT(ctx_, EVP_aes_192_gcm()); } } else if (32 == key_len) { if (encryptType == type) { - ENCRYPT_INIT(EVP_aes_256_gcm()); + ENCRYPT_INIT(ctx_, EVP_aes_256_gcm()); } else { - DECRYPT_INIT(EVP_aes_256_gcm()); + DECRYPT_INIT(ctx_, EVP_aes_256_gcm()); } } } else { // Init AES-CTR with specified key length if (16 == key_len) { if (encryptType == type) { - ENCRYPT_INIT(EVP_aes_128_ctr()); + ENCRYPT_INIT(ctx_, EVP_aes_128_ctr()); } else { - DECRYPT_INIT(EVP_aes_128_ctr()); + DECRYPT_INIT(ctx_, EVP_aes_128_ctr()); } } else if (24 == key_len) { if (encryptType == type) { - ENCRYPT_INIT(EVP_aes_192_ctr()); + ENCRYPT_INIT(ctx_, EVP_aes_192_ctr()); } else { - DECRYPT_INIT(EVP_aes_192_ctr()); + DECRYPT_INIT(ctx_, EVP_aes_192_ctr()); } } else if (32 == key_len) { if (encryptType == type) { - ENCRYPT_INIT(EVP_aes_256_ctr()); + ENCRYPT_INIT(ctx_, EVP_aes_256_ctr()); } else { - DECRYPT_INIT(EVP_aes_256_ctr()); + DECRYPT_INIT(ctx_, EVP_aes_256_ctr()); } } } @@ -136,8 +138,11 @@ int gcm_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int k uint8_t* aad, int aad_len, uint8_t* ciphertext) { int len; int ciphertext_len; + uint8_t tag[gcmTagLen]; + memset(tag, 0, gcmTagLen); uint8_t iv[gcmIvLen]; + memset(iv, 0, gcmIvLen); // Random IV RAND_load_file("/dev/urandom", rndMaxBytes); @@ -152,10 +157,9 @@ int gcm_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int k } // Setting additional authenticated data - if (nullptr != aad) { - if (1 != EVP_EncryptUpdate(cipher.get(), nullptr, &len, aad, aad_len)) { - throw ParquetException("Couldn't set AAD"); - } + if ((nullptr != aad) && + (1 != EVP_EncryptUpdate(cipher.get(), nullptr, &len, aad, aad_len))) { + throw ParquetException("Couldn't set AAD"); } // Encryption @@ -189,7 +193,9 @@ int ctr_encrypt(const uint8_t* plaintext, int plaintext_len, uint8_t* key, int k uint8_t* ciphertext) { int len; int ciphertext_len; + uint8_t iv[ctrIvLen]; + memset(iv, 0, ctrIvLen); // Random IV RAND_load_file("/dev/urandom", rndMaxBytes); @@ -255,7 +261,9 @@ int gcm_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int int plaintext_len; uint8_t tag[gcmTagLen]; + memset(tag, 0, gcmTagLen); uint8_t iv[gcmIvLen]; + memset(iv, 0, gcmIvLen); // Extracting IV and tag std::copy(ciphertext, ciphertext + gcmIvLen, iv); @@ -270,10 +278,9 @@ int gcm_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int } // Setting additional authenticated data - if (nullptr != aad) { - if (1 != EVP_DecryptUpdate(cipher.get(), nullptr, &len, aad, aad_len)) { - throw ParquetException("Couldn't set AAD"); - } + if ((nullptr != aad) && + (1 != EVP_DecryptUpdate(cipher.get(), nullptr, &len, aad, aad_len))) { + throw ParquetException("Couldn't set AAD"); } // Decryption @@ -304,6 +311,7 @@ int ctr_decrypt(const uint8_t* ciphertext, int ciphertext_len, uint8_t* key, int int plaintext_len; uint8_t iv[ctrIvLen]; + memset(iv, 0, ctrIvLen); // Extracting IV and tag std::copy(ciphertext, ciphertext + ctrIvLen, iv);