[vcpkg hash] Refactor to reduce code duplication

This commit is contained in:
Alexander Karatarakis 2018-04-05 17:03:45 -07:00
parent e712308554
commit c1257f988a

View File

@ -18,7 +18,7 @@ namespace vcpkg::Commands::Hash
{
namespace
{
static std::string to_hex(const unsigned char* string, const size_t bytes)
std::string to_hex(const unsigned char* string, const size_t bytes)
{
static constexpr char HEX_MAP[] = "0123456789abcdef";
@ -58,86 +58,93 @@ namespace vcpkg::Commands::Hash
if (handle) BCryptDestroyHash(handle);
}
};
struct BCryptHasher
{
explicit BCryptHasher(const std::string& hash_type)
{
NTSTATUS error_code =
BCryptOpenAlgorithmProvider(&this->algorithm_handle.handle,
Strings::to_utf16(Strings::ascii_to_uppercase(hash_type)).c_str(),
nullptr,
0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to open the algorithm provider");
DWORD hash_buffer_bytes;
DWORD cb_data;
error_code = BCryptGetProperty(this->algorithm_handle.handle,
BCRYPT_HASH_LENGTH,
reinterpret_cast<PUCHAR>(&hash_buffer_bytes),
sizeof(DWORD),
&cb_data,
0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to get hash length");
this->length_in_bytes = hash_buffer_bytes;
}
std::string hash_file(const fs::path& path) const
{
BCryptHashHandle hash_handle;
this->initialize_hash_handle(hash_handle);
FILE* file = nullptr;
const auto ec = _wfopen_s(&file, path.c_str(), L"rb");
Checks::check_exit(VCPKG_LINE_INFO, ec == 0, "Failed to open file: %s", path.u8string());
unsigned char buffer[4096];
while (const auto actual_size = fread(buffer, 1, sizeof(buffer), file))
{
hash_data(hash_handle, buffer, actual_size);
}
fclose(file);
return this->finalize_hash_handle(hash_handle);
}
std::string hash_string(const std::string& s) const
{
BCryptHashHandle hash_handle;
this->initialize_hash_handle(hash_handle);
hash_data(hash_handle, reinterpret_cast<unsigned char*>(const_cast<char*>(s.c_str())), s.size());
return this->finalize_hash_handle(hash_handle);
}
private:
void initialize_hash_handle(BCryptHashHandle& hash_handle) const
{
const NTSTATUS error_code =
BCryptCreateHash(this->algorithm_handle.handle, &hash_handle.handle, nullptr, 0, nullptr, 0, 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to initialize the hasher");
}
void hash_data(BCryptHashHandle& hash_handle, unsigned char* buffer, const size_t& data_size) const
{
const NTSTATUS error_code =
BCryptHashData(hash_handle.handle, buffer, static_cast<ULONG>(data_size), 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to hash data");
}
std::string finalize_hash_handle(const BCryptHashHandle& hash_handle) const
{
std::unique_ptr<unsigned char[]> hash_buffer = std::make_unique<UCHAR[]>(this->length_in_bytes);
const NTSTATUS error_code =
BCryptFinishHash(hash_handle.handle, hash_buffer.get(), this->length_in_bytes, 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash");
return to_hex(hash_buffer.get(), this->length_in_bytes);
}
BCryptAlgorithmHandle algorithm_handle;
ULONG length_in_bytes;
};
}
std::string get_file_hash(const fs::path& path, const std::string& hash_type)
{
BCryptAlgorithmHandle algorithm_handle;
NTSTATUS error_code = BCryptOpenAlgorithmProvider(
&algorithm_handle.handle, Strings::to_utf16(Strings::ascii_to_uppercase(hash_type)).c_str(), nullptr, 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to open the algorithm provider");
DWORD hash_buffer_bytes;
DWORD cb_data;
error_code = BCryptGetProperty(algorithm_handle.handle,
BCRYPT_HASH_LENGTH,
reinterpret_cast<PUCHAR>(&hash_buffer_bytes),
sizeof(DWORD),
&cb_data,
0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to get hash length");
const ULONG length_in_bytes = hash_buffer_bytes;
BCryptHashHandle hash_handle;
error_code = BCryptCreateHash(algorithm_handle.handle, &hash_handle.handle, nullptr, 0, nullptr, 0, 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to initialize the hasher");
FILE* file = nullptr;
const auto ec = _wfopen_s(&file, path.c_str(), L"rb");
Checks::check_exit(VCPKG_LINE_INFO, ec == 0, "Failed to open file: %s", path.u8string());
unsigned char buffer[4096];
while (const auto actual_size = fread(buffer, 1, sizeof(buffer), file))
{
error_code = BCryptHashData(hash_handle.handle, buffer, static_cast<ULONG>(actual_size), 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to hash data");
}
fclose(file);
std::unique_ptr<unsigned char[]> hash_buffer = std::make_unique<UCHAR[]>(length_in_bytes);
error_code = BCryptFinishHash(hash_handle.handle, hash_buffer.get(), length_in_bytes, 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash");
return to_hex(hash_buffer.get(), length_in_bytes);
return BCryptHasher{hash_type}.hash_file(path);
}
std::string get_string_hash(const std::string& s, const std::string& hash_type)
{
BCryptAlgorithmHandle algorithm_handle;
NTSTATUS error_code = BCryptOpenAlgorithmProvider(
&algorithm_handle.handle, Strings::to_utf16(Strings::ascii_to_uppercase(hash_type)).c_str(), nullptr, 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to open the algorithm provider");
DWORD hash_buffer_bytes;
DWORD cb_data;
error_code = BCryptGetProperty(algorithm_handle.handle,
BCRYPT_HASH_LENGTH,
reinterpret_cast<PUCHAR>(&hash_buffer_bytes),
sizeof(DWORD),
&cb_data,
0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to get hash length");
const ULONG length_in_bytes = hash_buffer_bytes;
BCryptHashHandle hash_handle;
error_code = BCryptCreateHash(algorithm_handle.handle, &hash_handle.handle, nullptr, 0, nullptr, 0, 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to initialize the hasher");
auto* const buffer = reinterpret_cast<unsigned char*>(const_cast<char*>(s.c_str()));
error_code = BCryptHashData(hash_handle.handle, buffer, static_cast<ULONG>(s.size()), 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to hash data");
std::unique_ptr<unsigned char[]> hash_buffer = std::make_unique<UCHAR[]>(length_in_bytes);
error_code = BCryptFinishHash(hash_handle.handle, hash_buffer.get(), length_in_bytes, 0);
Checks::check_exit(VCPKG_LINE_INFO, NT_SUCCESS(error_code), "Failed to finalize the hash");
return to_hex(hash_buffer.get(), length_in_bytes);
return BCryptHasher{hash_type}.hash_string(s);
}
}