blob: 8ebf60a9b880591f962eedb3294eda0097bc6425 [file] [log] [blame]
// 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/hash_utils.h"
#include <cstring>
#include "arrow/util/logging.h"
#include "gandiva/gdv_function_stubs.h"
#include "openssl/evp.h"
namespace gandiva {
/// Hashes a generic message using the SHA256 algorithm
GANDIVA_EXPORT
const char* gdv_hash_using_sha256(int64_t context, const void* message,
size_t message_length, int32_t* out_length) {
constexpr int sha256_result_length = 64;
return gdv_hash_using_sha(context, message, message_length, EVP_sha256(),
sha256_result_length, out_length);
}
/// Hashes a generic message using the SHA1 algorithm
GANDIVA_EXPORT
const char* gdv_hash_using_sha1(int64_t context, const void* message,
size_t message_length, int32_t* out_length) {
constexpr int sha1_result_length = 40;
return gdv_hash_using_sha(context, message, message_length, EVP_sha1(),
sha1_result_length, out_length);
}
/// \brief Hashes a generic message using SHA algorithm.
///
/// It uses the EVP API in the OpenSSL library to generate
/// the hash. The type of the hash is defined by the
/// \b hash_type \b parameter.
GANDIVA_EXPORT
const char* gdv_hash_using_sha(int64_t context, const void* message,
size_t message_length, const EVP_MD* hash_type,
uint32_t result_buf_size, int32_t* out_length) {
EVP_MD_CTX* md_ctx = EVP_MD_CTX_new();
if (md_ctx == nullptr) {
gdv_fn_context_set_error_msg(context,
"Could not create the context for SHA processing.");
*out_length = 0;
return "";
}
int evp_success_status = 1;
if (EVP_DigestInit_ex(md_ctx, hash_type, nullptr) != evp_success_status ||
EVP_DigestUpdate(md_ctx, message, message_length) != evp_success_status) {
gdv_fn_context_set_error_msg(context,
"Could not obtain the hash for the defined value.");
EVP_MD_CTX_free(md_ctx);
*out_length = 0;
return "";
}
// Create the temporary buffer used by the EVP to generate the hash
unsigned int hash_digest_size = EVP_MD_size(hash_type);
auto* result = static_cast<unsigned char*>(OPENSSL_malloc(hash_digest_size));
if (result == nullptr) {
gdv_fn_context_set_error_msg(context, "Could not allocate memory for SHA processing");
EVP_MD_CTX_free(md_ctx);
*out_length = 0;
return "";
}
unsigned int result_length;
EVP_DigestFinal_ex(md_ctx, result, &result_length);
if (result_length != hash_digest_size && result_buf_size != (2 * hash_digest_size)) {
gdv_fn_context_set_error_msg(context,
"Could not obtain the hash for the defined value");
EVP_MD_CTX_free(md_ctx);
OPENSSL_free(result);
*out_length = 0;
return "";
}
auto result_buffer =
reinterpret_cast<char*>(gdv_fn_context_arena_malloc(context, result_buf_size));
if (result_buffer == nullptr) {
gdv_fn_context_set_error_msg(context,
"Could not allocate memory for the result buffer");
// Free the resources used by the EVP
EVP_MD_CTX_free(md_ctx);
OPENSSL_free(result);
*out_length = 0;
return "";
}
unsigned int result_buff_index = 0;
for (unsigned int j = 0; j < result_length; j++) {
DCHECK(result_buff_index >= 0 && result_buff_index < result_buf_size);
unsigned char hex_number = result[j];
result_buff_index +=
snprintf(result_buffer + result_buff_index, result_buf_size, "%02x", hex_number);
}
// Free the resources used by the EVP to avoid memory leaks
EVP_MD_CTX_free(md_ctx);
OPENSSL_free(result);
*out_length = result_buf_size;
return result_buffer;
}
GANDIVA_EXPORT
uint64_t gdv_double_to_long(double value) {
uint64_t result;
memcpy(&result, &value, sizeof(result));
return result;
}
} // namespace gandiva