Skip to content
9 changes: 9 additions & 0 deletions cpp/src/gandiva/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ set(SRC_FILES
engine.cc
date_utils.cc
encrypt_utils.cc
encrypt_utils_gcm.cc
encrypt_mode_dispatcher.cc
encrypt_utils_cbc.cc
encrypt_utils_common.cc
encrypt_utils_ecb.cc
expr_decomposer.cc
expr_validator.cc
expression.cc
Expand Down Expand Up @@ -259,6 +264,10 @@ add_gandiva_test(internals-test
annotator_test.cc
tree_expr_test.cc
encrypt_utils_test.cc
encrypt_utils_gcm_test.cc
encrypt_utils_cbc_test.cc
encrypt_utils_ecb_test.cc
encrypt_utils_common_test.cc
expr_decomposer_test.cc
exported_funcs_registry_test.cc
expression_registry_test.cc
Expand Down
138 changes: 138 additions & 0 deletions cpp/src/gandiva/encrypt_mode_dispatcher.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// 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 "gandiva/encrypt_mode_dispatcher.h"
#include <sstream>
#include <stdexcept>
#include <string>
#include <vector>
#include "arrow/util/string.h"
#include "gandiva/encrypt_utils_cbc.h"
#include "gandiva/encrypt_utils_ecb.h"
#include "gandiva/encrypt_utils_gcm.h"

namespace gandiva {

namespace {

// Supported encryption modes
const std::vector<std::string_view> SUPPORTED_MODES = {
AES_ECB_MODE, AES_ECB_PKCS7_MODE, AES_ECB_NONE_MODE, AES_CBC_MODE,
AES_CBC_PKCS7_MODE, AES_CBC_NONE_MODE, AES_GCM_MODE};

// Internal enum for dispatching to the right encryption implementation
enum class EncryptionMode {
ECB,
ECB_PKCS7,
ECB_NONE,
CBC,
CBC_PKCS7,
CBC_NONE,
GCM,
UNKNOWN
};

EncryptionMode ParseEncryptionMode(std::string_view mode_str) {
if (mode_str == AES_ECB_MODE) return EncryptionMode::ECB;
if (mode_str == AES_ECB_PKCS7_MODE) return EncryptionMode::ECB_PKCS7;
if (mode_str == AES_ECB_NONE_MODE) return EncryptionMode::ECB_NONE;
if (mode_str == AES_CBC_MODE) return EncryptionMode::CBC;
if (mode_str == AES_CBC_PKCS7_MODE) return EncryptionMode::CBC_PKCS7;
if (mode_str == AES_CBC_NONE_MODE) return EncryptionMode::CBC_NONE;
if (mode_str == AES_GCM_MODE) return EncryptionMode::GCM;
return EncryptionMode::UNKNOWN;
}

} // namespace

int32_t EncryptModeDispatcher::encrypt(const char* plaintext, int32_t plaintext_len,
const char* key, int32_t key_len, const char* mode,
int32_t mode_len, const char* iv, int32_t iv_len,
const char* aad, int32_t aad_len,
unsigned char* cipher) {
std::string mode_str = arrow::internal::AsciiToUpper(std::string_view(mode, mode_len));

switch (ParseEncryptionMode(mode_str)) {
case EncryptionMode::ECB:
case EncryptionMode::ECB_PKCS7:
// Shorthand AES-ECB and explicit AES-ECB-PKCS7 both use ECB with PKCS7 padding
return aes_encrypt_ecb(plaintext, plaintext_len, key, key_len, true, cipher);
case EncryptionMode::ECB_NONE:
// ECB without padding
return aes_encrypt_ecb(plaintext, plaintext_len, key, key_len, false, cipher);
case EncryptionMode::CBC:
case EncryptionMode::CBC_PKCS7:
// Shorthand AES-CBC and explicit AES-CBC-PKCS7 both use CBC with PKCS7
return aes_encrypt_cbc(plaintext, plaintext_len, key, key_len, iv, iv_len, true,
cipher);
case EncryptionMode::CBC_NONE:
// CBC without padding
return aes_encrypt_cbc(plaintext, plaintext_len, key, key_len, iv, iv_len, false,
cipher);
case EncryptionMode::GCM:
return aes_encrypt_gcm(plaintext, plaintext_len, key, key_len, iv, iv_len, aad,
aad_len, cipher);
case EncryptionMode::UNKNOWN:
default: {
std::string modes_str = arrow::internal::JoinStrings(SUPPORTED_MODES, ", ");
std::ostringstream oss;
oss << "Unsupported encryption mode: " << mode_str
<< ". Supported modes: " << modes_str;
throw std::runtime_error(oss.str());
}
}
}

int32_t EncryptModeDispatcher::decrypt(const char* ciphertext, int32_t ciphertext_len,
const char* key, int32_t key_len, const char* mode,
int32_t mode_len, const char* iv, int32_t iv_len,
const char* aad, int32_t aad_len,
unsigned char* plaintext) {
std::string mode_str = arrow::internal::AsciiToUpper(std::string_view(mode, mode_len));

switch (ParseEncryptionMode(mode_str)) {
case EncryptionMode::ECB:
case EncryptionMode::ECB_PKCS7:
// Shorthand AES-ECB and explicit AES-ECB-PKCS7 both use ECB with PKCS7 padding
return aes_decrypt_ecb(ciphertext, ciphertext_len, key, key_len, true, plaintext);
case EncryptionMode::ECB_NONE:
// ECB without padding
return aes_decrypt_ecb(ciphertext, ciphertext_len, key, key_len, false, plaintext);
case EncryptionMode::CBC:
case EncryptionMode::CBC_PKCS7:
// Shorthand AES-CBC and explicit AES-CBC-PKCS7 both use CBC with PKCS7
return aes_decrypt_cbc(ciphertext, ciphertext_len, key, key_len, iv, iv_len, true,
plaintext);
case EncryptionMode::CBC_NONE:
// CBC without padding
return aes_decrypt_cbc(ciphertext, ciphertext_len, key, key_len, iv, iv_len, false,
plaintext);
case EncryptionMode::GCM:
return aes_decrypt_gcm(ciphertext, ciphertext_len, key, key_len, iv, iv_len, aad,
aad_len, plaintext);
case EncryptionMode::UNKNOWN:
default: {
std::string modes_str = arrow::internal::JoinStrings(SUPPORTED_MODES, ", ");
std::ostringstream oss;
oss << "Unsupported decryption mode: " << mode_str
<< ". Supported modes: " << modes_str;
throw std::runtime_error(oss.str());
}
}
}

} // namespace gandiva
77 changes: 77 additions & 0 deletions cpp/src/gandiva/encrypt_mode_dispatcher.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// 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.

#pragma once

#include <cstdint>

namespace gandiva {

/**
* Dispatcher for AES encryption/decryption based on mode string.
* Routes calls to appropriate implementation.
*/
class EncryptModeDispatcher {
public:
/**
* Encrypt data using the specified mode
*
* @param plaintext The data to encrypt
* @param plaintext_len Length of plaintext in bytes
* @param key The encryption key
* @param key_len Length of key in bytes
* @param mode Mode string
* @param mode_len Length of mode string in bytes
* @param iv The initialization vector (optional, only for modes that support it).
* It is caller-managed: GCM needs a nonce that is unique per key and CBC an
* unpredictable IV.
* @param iv_len Length of the IV in bytes
* @param aad Additional authenticated data (optional, only used by GCM)
* @param aad_len Length of aad in bytes
* @param cipher Output buffer for encrypted data
* @return Length of encrypted data in bytes
* @throws std::runtime_error on encryption failure or unsupported mode
*/
static int32_t encrypt(const char* plaintext, int32_t plaintext_len, const char* key,
int32_t key_len, const char* mode, int32_t mode_len,
const char* iv, int32_t iv_len, const char* aad, int32_t aad_len,
unsigned char* cipher);

/**
* Decrypt data using the specified mode
*
* @param ciphertext The data to decrypt
* @param ciphertext_len Length of ciphertext in bytes
* @param key The decryption key
* @param key_len Length of key in bytes
* @param mode Mode string
* @param mode_len Length of mode string in bytes
* @param iv The initialization vector (optional, only for modes that support it)
* @param iv_len Length of the IV in bytes
* @param aad Additional authenticated data (optional, only used by GCM)
* @param aad_len Length of aad in bytes
* @param plaintext Output buffer for decrypted data
* @return Length of decrypted data in bytes
* @throws std::runtime_error on decryption failure or unsupported mode
*/
static int32_t decrypt(const char* ciphertext, int32_t ciphertext_len, const char* key,
int32_t key_len, const char* mode, int32_t mode_len,
const char* iv, int32_t iv_len, const char* aad, int32_t aad_len,
unsigned char* plaintext);
};

} // namespace gandiva
Loading
Loading