Created
January 19, 2019 14:06
-
-
Save Barakat/e9b0f212e24cb2455cc8f47594b6ac6e to your computer and use it in GitHub Desktop.
Hashing with Cryptography API: Next Generation (CNG)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _WIN32_WINNT 0x0600 // Windows Vista | |
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#include <bcrypt.h> | |
#include <cstddef> | |
#include <memory> | |
#include <cassert> | |
#pragma comment(lib, "bcrypt.lib") | |
static bool Checksum(LPCWSTR algorithm_id, | |
const void* data, | |
std::size_t data_size, | |
void* output, | |
std::size_t output_size) | |
{ | |
NTSTATUS status; | |
BCRYPT_ALG_HANDLE algorithm; | |
status = BCryptOpenAlgorithmProvider(&algorithm, algorithm_id, nullptr, 0); | |
if (SUCCEEDED(status)) | |
{ | |
DWORD result; | |
#ifndef NDEBUG | |
DWORD hash_length; | |
status = BCryptGetProperty(algorithm, | |
BCRYPT_HASH_LENGTH, | |
reinterpret_cast<PUCHAR>(&hash_length), | |
sizeof(hash_length), | |
&result, | |
0); | |
assert(SUCCEEDED(status)); | |
assert(hash_length == output_size); | |
#endif | |
DWORD object_length; | |
status = BCryptGetProperty(algorithm, | |
BCRYPT_OBJECT_LENGTH, | |
reinterpret_cast<PUCHAR>(&object_length), | |
sizeof(object_length), | |
&result, | |
0); | |
if (SUCCEEDED(status)) | |
{ | |
BCRYPT_HASH_HANDLE hash; | |
const auto object_value = std::make_unique<UCHAR[]>(object_length); | |
status = BCryptCreateHash(algorithm, | |
&hash, | |
object_value.get(), | |
object_length, | |
nullptr, | |
0, | |
0); | |
if (SUCCEEDED(status)) | |
{ | |
status = BCryptHashData(hash, reinterpret_cast<PUCHAR>(const_cast<void *>(data)), data_size, 0); | |
if (SUCCEEDED(status)) | |
{ | |
status = BCryptFinishHash(hash, reinterpret_cast<PUCHAR>(output), output_size, 0); | |
} | |
} | |
} | |
BCryptCloseAlgorithmProvider(algorithm, 0); | |
} | |
return SUCCEEDED(status); | |
} | |
bool MD5Checksum(const void* data, std::size_t data_size, void* output, std::size_t output_size) | |
{ | |
return Checksum(BCRYPT_MD5_ALGORITHM, data, data_size, output, output_size); | |
} | |
bool SHA1Checksum(const void* data, std::size_t data_size, void* output, std::size_t output_size) | |
{ | |
return Checksum(BCRYPT_SHA1_ALGORITHM, data, data_size, output, output_size); | |
} | |
bool SHA256Checksum(const void* data, std::size_t data_size, void* output, std::size_t output_size) | |
{ | |
return Checksum(BCRYPT_SHA256_ALGORITHM, data, data_size, output, output_size); | |
} | |
void PrintHex(const void* data, std::size_t data_size) | |
{ | |
const auto bytes = reinterpret_cast<const UCHAR*>(data); | |
for (std::size_t i = 0; i < data_size; ++i) | |
{ | |
const auto byte = bytes[i]; | |
const auto upper = byte >> 4; | |
const auto lower = byte & 0xf; | |
#define HEX_NIBBLE(n) (n <= 9 ? '0' + n : 'a' - (10 - n)) | |
std::putchar(HEX_NIBBLE(upper)); | |
std::putchar(HEX_NIBBLE(lower)); | |
#undef HEX_NIBBLE | |
} | |
} | |
int main() | |
{ | |
const auto data = "Hello world!"; | |
const auto size = 12; | |
// MD5 | |
unsigned char md5checksum[16]; | |
MD5Checksum(data, size, md5checksum, sizeof(md5checksum)); | |
printf("md5('%s') = ", data); | |
PrintHex(md5checksum, sizeof(md5checksum)); | |
std::putchar('\n'); | |
// SHA-1 | |
unsigned char sha1checksum[20]; | |
SHA1Checksum(data, size, sha1checksum, sizeof(sha1checksum)); | |
printf("sha1('%s') = ", data); | |
PrintHex(sha1checksum, sizeof(sha1checksum)); | |
std::putchar('\n'); | |
// SHA-256 | |
unsigned char sha256checksum[32]; | |
SHA256Checksum(data, size, sha256checksum, sizeof(sha256checksum)); | |
printf("sha256('%s') = ", data); | |
PrintHex(sha256checksum, sizeof(sha256checksum)); | |
std::putchar('\n'); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment