I tried everything to make it working, so i decided to do full example. I hope someone would help me.
Message to sign: Hello World
Signing example:
https://gchq.github.io/CyberChef/#recipe=RSA_Sign('-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQDCLDny1MwbGVFrjtNXH+HFxZ/4C5Gz0q2b5exrJLHums5YDSFl\n6c55QLYNZ4MOlVrahVsAOO0ENkqA5QdswTi+53nP7zJsxmLnpN5J8QEQJgTlkw+k\nIa8+c8j0FWJCRFcZ4vlxcqIymJc/tpBuHfVIXpQpGuPpUTCtyfRmBNuGbQIDAQAB\nAoGABH78qoRF45y+92Qbvak105wDW7181rKapYD56/MyEYnRHFXVf6QdzU3zyTSr\n4rMPov6ygDtRNadCK2DiPqDsvOiQU+y7ZSt+t0hdUv8nkQOzR167dM8dLAoVMVtm\nKgUYO1MUnERvh+pmPKOmYozBAZbJJshOLbmqfGoJH1wUzCECQQDkC1SDsmLbT9uA\n8MR6u4sn+kghli5oxP3dnj/1WRAATt3SrQNGUyJsLCCDc70EOPwx/nIY4aDog/3K\nixut8zVdAkEA2fnp0rCOXXikNV69z5Y2lj4OYpLtJiaJQK6NOYF997zso2oln/xX\nddxle0+a5KufdkP4DGP0QSnZKA+6qIf0UQJAf9hOQCrQuwzRDT9tlzTu9bGdoJ62\nU+wkOotOZfjRPKr6NvLhxBo1URmH/Mn07JoZ4Nk6E/LiJ5hfvp4wHVwczQJAIDxR\nVBNAOpqIzkvAjl6MnBN5VSKdZ7LzQVmPER4RXv3VkSU1gz9yP7/kUiQnqAGph3ft\nywdNLAXgU4hf9mSEwQJAbLV0c7GWXPCSk3k0gwOZCjHKaIxDIBjZudv5cvO9sPQx\nsqE17eyl5+ufQq1xOQZL4HL+nUjlOcgT/pIdI9430A==\n-----END RSA PRIVATE KEY-----','','MD5')To_Hex('0x with comma',0)&input=SGVsbG8gV29ybGQ
Verification example: https://gchq.github.io/CyberChef/#recipe=From_Hex('Auto')RSA_Verify('-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCLDny1MwbGVFrjtNXH+HFxZ/4\nC5Gz0q2b5exrJLHums5YDSFl6c55QLYNZ4MOlVrahVsAOO0ENkqA5QdswTi+53nP\n7zJsxmLnpN5J8QEQJgTlkw+kIa8+c8j0FWJCRFcZ4vlxcqIymJc/tpBuHfVIXpQp\nGuPpUTCtyfRmBNuGbQIDAQAB\n-----END PUBLIC KEY-----','Hello World','MD5')&input=YjU5ODE1MzYwNjUyZWU3MWE1OTlhNTljZDQzM2Q4MmMyMzFhY2UzNzdjZWRkZDc3YzBkNTBhMmJkYWZhNDJmMjM0OTVkODVhNDg4Y2RiZmUwNDczNjNkOTI3NGE0MWM0MzgwZTgyNzJjMTEzNTExNDZkYmM4NDFhNTNkMTVkZGE0NTE2MGEyMzM4YzQxMzcwZDg2NzFhMTZmYTlkZTExNzQzZjY1N2UzZjMzYzA5MTBmMzYwMWY0MzQzNTZlNzllMWQ3NTEzNzRmOGVkZmZkZmY3MWMxMWZjOWUzNDI0ZmJlNmY0OWI2ZWI3Yzc4Zjc2MDRlZWZhYTU5ZTBhNmNhOA
Public and private key are generated only for that example purpose
C code:
#include <iostream>
#include <cstdio>
#include <string>
#include <vector>
#include "windows.h"
#include "wincrypt.h"
using namespace std;
std::string GetLastErrorAsString() {
//Get the error message ID, if any.
DWORD errorMessageID = ::GetLastError();
if (errorMessageID == 0) {
return std::string(); //No error message has been recorded
}
LPSTR messageBuffer = nullptr;
//Ask Win32 to give us the string version of that message ID.
//The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
size_t size = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &messageBuffer, 0, NULL);
//Copy the error message into a std::string.
std::string message(messageBuffer, size);
//Free the Win32's string's buffer.
LocalFree(messageBuffer);
return message;
}
int test4(const vector<unsigned char> &signature, const vector<unsigned char> &data_to_verify) {
string rsaKey = "-----BEGIN PUBLIC KEY-----\n"
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCLDny1MwbGVFrjtNXH HFxZ/4\n"
"C5Gz0q2b5exrJLHums5YDSFl6c55QLYNZ4MOlVrahVsAOO0ENkqA5QdswTi 53nP\n"
"7zJsxmLnpN5J8QEQJgTlkw kIa8 c8j0FWJCRFcZ4vlxcqIymJc/tpBuHfVIXpQp\n"
"GuPpUTCtyfRmBNuGbQIDAQAB\n"
"-----END PUBLIC KEY-----";
char derPubKey[2048];
size_t derPubKeyLen = 2048;
CERT_PUBLIC_KEY_INFO *publicKeyInfo;
int publicKeyInfoLen;
HCRYPTPROV hProv = 0;
HCRYPTKEY hKey = 0;
/*
* Convert from PEM format to DER format - removes header and footer and decodes from base64
*/
if (!CryptStringToBinaryA(rsaKey.data(), 0, CRYPT_STRING_BASE64HEADER, reinterpret_cast<BYTE *>(derPubKey),
reinterpret_cast<DWORD *>(&derPubKeyLen), NULL, NULL)) {
fprintf(stderr, "CryptStringToBinary failed. Err: %d\n", GetLastError());
}
/*
* Decode from DER format to CERT_PUBLIC_KEY_INFO
*/
if (!CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, reinterpret_cast<const BYTE *>(derPubKey),
derPubKeyLen,
CRYPT_ENCODE_ALLOC_FLAG, NULL, &publicKeyInfo,
reinterpret_cast<DWORD *>(&publicKeyInfoLen))) {
fprintf(stderr, "CryptDecodeObjectEx 1 failed. Err: %p\n", GetLastError());
return -1;
}
/*
* Acquire context
*/
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
{
printf("CryptAcquireContext failed - err=0x%x.\n", GetLastError());
return -1;
}
}
/*
* Import the public key using the context
*/
if (!CryptImportPublicKeyInfo(hProv, X509_ASN_ENCODING, publicKeyInfo, &hKey)) {
fprintf(stderr, "CryptImportPublicKeyInfo failed. error: %d\n", GetLastError());
return -1;
}
LocalFree(publicKeyInfo);
/*
* Now use hKey to encrypt whatever you need.
*/
// Hash the data_to_verify
HCRYPTHASH hHash = 0;
if (!CryptCreateHash(hProv, CALG_MD5, NULL, 0, &hHash)) {
printf("CryptCreateHash failed with error 0x%.8lX\n", GetLastError());
return -1;
}
if (!CryptHashData(hHash, data_to_verify.data(), data_to_verify.size(), 0)) {
printf("CryptHashData failed with error 0x%.8lX\n", GetLastError());
return -1;
}
// Sign the hash using our imported key
if (!CryptVerifySignature(hHash, signature.data(), signature.size(), hKey, nullptr, 0)) {
printf("Signature verification failed with error");
cout << GetLastErrorAsString() << endl;
return false;
} else {
printf("Signature verification succeeded.\n");
return true;
}
return 0;
}
//vector<unsigned char> to hex
std::string to_hex(const std::vector<unsigned char> &v) {
std::string result;
char hex[] = "0123456789abcdef";
for (unsigned char c : v) {
result = hex[c >> 4];
result = hex[c & 15];
}
return result;
}
int main() {
vector<unsigned char> signature = {0xb5, 0x98, 0x15, 0x36, 0x06, 0x52, 0xee, 0x71, 0xa5, 0x99, 0xa5, 0x9c, 0xd4,
0x33, 0xd8, 0x2c, 0x23, 0x1a, 0xce, 0x37, 0x7c, 0xed, 0xdd, 0x77, 0xc0, 0xd5,
0x0a, 0x2b, 0xda, 0xfa, 0x42, 0xf2, 0x34, 0x95, 0xd8, 0x5a, 0x48, 0x8c, 0xdb,
0xfe, 0x04, 0x73, 0x63, 0xd9, 0x27, 0x4a, 0x41, 0xc4, 0x38, 0x0e, 0x82, 0x72,
0xc1, 0x13, 0x51, 0x14, 0x6d, 0xbc, 0x84, 0x1a, 0x53, 0xd1, 0x5d, 0xda, 0x45,
0x16, 0x0a, 0x23, 0x38, 0xc4, 0x13, 0x70, 0xd8, 0x67, 0x1a, 0x16, 0xfa, 0x9d,
0xe1, 0x17, 0x43, 0xf6, 0x57, 0xe3, 0xf3, 0x3c, 0x09, 0x10, 0xf3, 0x60, 0x1f,
0x43, 0x43, 0x56, 0xe7, 0x9e, 0x1d, 0x75, 0x13, 0x74, 0xf8, 0xed, 0xff, 0xdf,
0xf7, 0x1c, 0x11, 0xfc, 0x9e, 0x34, 0x24, 0xfb, 0xe6, 0xf4, 0x9b, 0x6e, 0xb7,
0xc7, 0x8f, 0x76, 0x04, 0xee, 0xfa, 0xa5, 0x9e, 0x0a, 0x6c, 0xa8};
string message = "Hello World";
vector<unsigned char> data = vector<unsigned char>(message.begin(), message.end());
cout << "Signature: " << to_hex(signature) << endl;
cout << "Message: " << message << endl;
test4(signature, data);
}
After executing that code, i'm getting NTE_BAD_SIGNATURE
error
I used PEM import from Load an PEM encoded X.509 certificate into Windows CryptoAPI
I really hope someone would help me resolving that issue
CodePudding user response:
better use CNG api (if not need support xp) and always need free allocated memory and other resources, what you not do. this code work ok
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
HRESULT StringToBin(_Out_ PDATA_BLOB pdb, _In_ ULONG dwFlags, _In_ PCSTR pszString, _In_ ULONG cchString = 0)
{
PUCHAR pb = 0;
ULONG cb = 0;
while (CryptStringToBinaryA(pszString, cchString, dwFlags, pb, &cb, 0, 0))
{
if (pb)
{
pdb->pbData = pb, pdb->cbData = cb;
return S_OK;
}
if (!(pb = (PUCHAR)LocalAlloc(LMEM_FIXED, cb)))
{
break;
}
}
return HRESULT_FROM_WIN32(GetLastError());
}
HRESULT VerifyTest(_In_ PCWSTR pszAlgId,
_In_ PCSTR szKey,
_In_ PCSTR szSig,
_In_ const UCHAR *pbData,
_In_ ULONG cbData)
{
DATA_BLOB db, db2;
HRESULT hr;
if (NOERROR == (hr = StringToBin(&db, CRYPT_STRING_BASE64HEADER, szKey)))
{
ULONG cb;
CERT_PUBLIC_KEY_INFO *publicKeyInfo;
hr = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
db.pbData, db.cbData, CRYPT_DECODE_ALLOC_FLAG, 0, &publicKeyInfo, &cb));
LocalFree(db.pbData);
if (NOERROR == hr)
{
BCRYPT_KEY_HANDLE hKey;
hr = BOOL_TO_ERROR(CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, publicKeyInfo, 0, 0, &hKey));
LocalFree(publicKeyInfo);
if (NOERROR == hr)
{
UCHAR hash[32];
if (NOERROR == (hr = BOOL_TO_ERROR(CryptHashCertificate2(pszAlgId, 0, 0, pbData, cbData, hash, &(cb = sizeof(hash))))))
{
if (0 <= (hr = StringToBin(&db, CRYPT_STRING_BASE64, szSig)))
{
hr = StringToBin(&db2, CRYPT_STRING_HEXRAW, (PCSTR)db.pbData, db.cbData);
LocalFree(db.pbData);
if (0 <= hr)
{
BCRYPT_PKCS1_PADDING_INFO pi = { pszAlgId };
if (0 > (hr = BCryptVerifySignature(hKey, &pi, hash, cb, db2.pbData, db2.cbData, BCRYPT_PAD_PKCS1)))
{
hr |= FACILITY_NT_BIT;
}
LocalFree(db2.pbData);
}
}
}
BCryptDestroyKey(hKey);
}
}
}
return HRESULT_FROM_WIN32(hr);
}
void VerifyTest()
{
static const CHAR szKey[] =
"-----BEGIN PUBLIC KEY-----\n"
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCLDny1MwbGVFrjtNXH HFxZ/4\n"
"C5Gz0q2b5exrJLHums5YDSFl6c55QLYNZ4MOlVrahVsAOO0ENkqA5QdswTi 53nP\n"
"7zJsxmLnpN5J8QEQJgTlkw kIa8 c8j0FWJCRFcZ4vlxcqIymJc/tpBuHfVIXpQp\n"
"GuPpUTCtyfRmBNuGbQIDAQAB\n"
"-----END PUBLIC KEY-----";
static const CHAR szSig[] =
"YjU5ODE1MzYwNjUyZWU3MWE1OTlhNTljZDQzM2Q4MmMyMzFhY2UzNzdjZWRkZDc3"
"YzBkNTBhMmJkYWZhNDJmMjM0OTVkODVhNDg4Y2RiZmUwNDczNjNkOTI3NGE0MWM0"
"MzgwZTgyNzJjMTEzNTExNDZkYmM4NDFhNTNkMTVkZGE0NTE2MGEyMzM4YzQxMzcw"
"ZDg2NzFhMTZmYTlkZTExNzQzZjY1N2UzZjMzYzA5MTBmMzYwMWY0MzQzNTZlNzll"
"MWQ3NTEzNzRmOGVkZmZkZmY3MWMxMWZjOWUzNDI0ZmJlNmY0OWI2ZWI3Yzc4Zjc2"
"MDRlZWZhYTU5ZTBhNmNhOA";
static const UCHAR data[] = "Hello World";
VerifyTest(BCRYPT_MD5_ALGORITHM, szKey, szSig, data, sizeof(data) - 1);
}
for sign can be used next code:
void PrintStr(PSTR psz, ULONG cch)
{
ULONG len;
do
{
DbgPrint("%.*s", len = min(0x100, cch), psz);
} while (psz = len, cch -= len);
}
NTSTATUS ImportRsaKey(_Out_ BCRYPT_KEY_HANDLE* phKey, _In_ PBYTE pbKey, _In_ ULONG cbKey)
{
if (CryptDecodeObjectEx(X509_ASN_ENCODING, CNG_RSA_PRIVATE_KEY_BLOB,
pbKey, cbKey, CRYPT_DECODE_ALLOC_FLAG|CRYPT_DECODE_NOCOPY_FLAG, 0, &pbKey, &cbKey))
{
BCRYPT_ALG_HANDLE hAlgorithm;
NTSTATUS status;
if (0 <= (status = BCryptOpenAlgorithmProvider(&hAlgorithm, BCRYPT_RSA_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0)))
{
status = BCryptImportKeyPair (hAlgorithm, 0, BCRYPT_PRIVATE_KEY_BLOB, phKey, pbKey, cbKey, 0);
BCryptCloseAlgorithmProvider(hAlgorithm, 0);
}
LocalFree(pbKey);
return 0 > status ? HRESULT_FROM_NT(status) : S_OK;
}
return HRESULT_FROM_WIN32(GetLastError());
}
HRESULT BinToString(_Out_ PSTR *ppszString, _In_ ULONG dwFlags, _In_ const UCHAR* pb, _In_ ULONG cb)
{
PSTR pszString = 0;
ULONG cch = 0;
while (CryptBinaryToStringA(pb, cb, dwFlags, pszString, &cch))
{
if (pszString)
{
*ppszString = pszString;
return S_OK;
}
if (!(pszString = (PSTR)LocalAlloc(LMEM_FIXED, cch)))
{
break;
}
}
return HRESULT_FROM_WIN32(GetLastError());
}
HRESULT SignTest(_In_ PCWSTR pszAlgId,
_In_ PCSTR szKey,
_In_ const UCHAR *pbData,
_In_ ULONG cbData)
{
DATA_BLOB db;
HRESULT hr;
if (NOERROR == (hr = StringToBin(&db, CRYPT_STRING_BASE64HEADER, szKey)))
{
BCRYPT_KEY_HANDLE hKey=0;
hr = ImportRsaKey(&hKey, db.pbData, db.cbData);
LocalFree(db.pbData);
if (0 <= hr)
{
UCHAR hash[32];
ULONG cb = sizeof(hash);
if (NOERROR == (hr = BOOL_TO_ERROR(CryptHashCertificate2(pszAlgId, 0, 0, pbData, cbData, hash, &cb))))
{
BCRYPT_PKCS1_PADDING_INFO pi = { pszAlgId };
PUCHAR pbSig = 0;
ULONG cbSig = 0;
while (0 <= (hr = BCryptSignHash(hKey, &pi, hash, cb, pbSig, cbSig, &cbSig, BCRYPT_PAD_PKCS1)))
{
if (pbSig)
{
PSTR psz, psz2;
if (NOERROR == BinToString(&psz, CRYPT_STRING_HEXRAW|CRYPT_STRING_NOCRLF, pbSig, cbSig))
{
if (NOERROR == BinToString(&psz2, CRYPT_STRING_BASE64, (PUCHAR)psz, (ULONG)strlen(psz)))
{
PrintStr(psz2, (ULONG)strlen(psz2));
LocalFree(psz2);
}
LocalFree(psz);
}
break;
}
pbSig = (PUCHAR)alloca(cbSig);
}
}
BCryptDestroyKey(hKey);
}
}
return HRESULT_FROM_WIN32(hr);
}
void sign()
{
static const UCHAR data[] = "Hello World";
static const CHAR szPrivKey[] =
"-----BEGIN RSA PRIVATE KEY-----"
"MIICWwIBAAKBgQDCLDny1MwbGVFrjtNXH HFxZ/4C5Gz0q2b5exrJLHums5YDSFl"
"6c55QLYNZ4MOlVrahVsAOO0ENkqA5QdswTi 53nP7zJsxmLnpN5J8QEQJgTlkw k"
"Ia8 c8j0FWJCRFcZ4vlxcqIymJc/tpBuHfVIXpQpGuPpUTCtyfRmBNuGbQIDAQAB"
"AoGABH78qoRF45y 92Qbvak105wDW7181rKapYD56/MyEYnRHFXVf6QdzU3zyTSr"
"4rMPov6ygDtRNadCK2DiPqDsvOiQU y7ZSt t0hdUv8nkQOzR167dM8dLAoVMVtm"
"KgUYO1MUnERvh pmPKOmYozBAZbJJshOLbmqfGoJH1wUzCECQQDkC1SDsmLbT9uA"
"8MR6u4sn kghli5oxP3dnj/1WRAATt3SrQNGUyJsLCCDc70EOPwx/nIY4aDog/3K"
"ixut8zVdAkEA2fnp0rCOXXikNV69z5Y2lj4OYpLtJiaJQK6NOYF997zso2oln/xX"
"ddxle0 a5KufdkP4DGP0QSnZKA 6qIf0UQJAf9hOQCrQuwzRDT9tlzTu9bGdoJ62"
"U wkOotOZfjRPKr6NvLhxBo1URmH/Mn07JoZ4Nk6E/LiJ5hfvp4wHVwczQJAIDxR"
"VBNAOpqIzkvAjl6MnBN5VSKdZ7LzQVmPER4RXv3VkSU1gz9yP7/kUiQnqAGph3ft"
"ywdNLAXgU4hf9mSEwQJAbLV0c7GWXPCSk3k0gwOZCjHKaIxDIBjZudv5cvO9sPQx"
"sqE17eyl5 ufQq1xOQZL4HL nUjlOcgT/pIdI9430A=="
"-----END RSA PRIVATE KEY-----";
SignTest(BCRYPT_MD5_ALGORITHM, szPrivKey, data, sizeof(data) - 1);
}
CodePudding user response:
Working example after some edit:
#include <iostream>
#include <cstdio>
#include "windows.h"
#include "wincrypt.h"
#include "comdef.h"
using namespace std;
inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
HRESULT StringToBin(_Out_ PDATA_BLOB pdb, _In_ ULONG dwFlags, _In_ PCSTR pszString, _In_ ULONG cchString = 0)
{
PUCHAR pb = 0;
ULONG cb = 0;
while (CryptStringToBinaryA(pszString, cchString, dwFlags, pb, &cb, 0, 0))
{
if (pb)
{
pdb->pbData = pb, pdb->cbData = cb;
return S_OK;
}
if (!(pb = (PUCHAR)LocalAlloc(LMEM_FIXED, cb)))
{
break;
}
}
return HRESULT_FROM_WIN32(GetLastError());
}
#define SIGNATURE_SIZE 128
HRESULT VerifyTest(_In_ PCWSTR algorithm,
_In_ PCSTR keyAsPem,
_In_ BYTE *signatureBase64,
_In_ const UCHAR *dataToCheck,
_In_ ULONG dataToCheckSize)
{
DATA_BLOB db, db2;
HRESULT hr;
if (NOERROR == (hr = StringToBin(&db, CRYPT_STRING_BASE64HEADER, keyAsPem)))
{
ULONG cb;
CERT_PUBLIC_KEY_INFO *publicKeyInfo;
hr = BOOL_TO_ERROR(CryptDecodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO,
db.pbData, db.cbData, CRYPT_DECODE_ALLOC_FLAG, 0, &publicKeyInfo, &cb));
LocalFree(db.pbData);
if (NOERROR == hr)
{
BCRYPT_KEY_HANDLE hKey;
hr = BOOL_TO_ERROR(CryptImportPublicKeyInfoEx2(X509_ASN_ENCODING, publicKeyInfo, 0, 0, &hKey));
LocalFree(publicKeyInfo);
if (NOERROR == hr)
{
UCHAR hash[32];
if (NOERROR == (hr = BOOL_TO_ERROR(CryptHashCertificate2(algorithm, 0, 0, dataToCheck, dataToCheckSize, hash, &(cb = sizeof(hash))))))
{
BCRYPT_PKCS1_PADDING_INFO pi = {algorithm };
if (0 > (hr = BCryptVerifySignature(hKey, &pi, hash, cb, signatureBase64, SIGNATURE_SIZE, BCRYPT_PAD_PKCS1)))
{
hr |= FACILITY_NT_BIT;
}
}
BCryptDestroyKey(hKey);
}
}
}
return HRESULT_FROM_WIN32(hr);
}
void VerifyTest()
{
static const CHAR szKey[] =
"-----BEGIN PUBLIC KEY-----\n"
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCLDny1MwbGVFrjtNXH HFxZ/4\n"
"C5Gz0q2b5exrJLHums5YDSFl6c55QLYNZ4MOlVrahVsAOO0ENkqA5QdswTi 53nP\n"
"7zJsxmLnpN5J8QEQJgTlkw kIa8 c8j0FWJCRFcZ4vlxcqIymJc/tpBuHfVIXpQp\n"
"GuPpUTCtyfRmBNuGbQIDAQAB\n"
"-----END PUBLIC KEY-----";
static BYTE dataToVerify[] = {0xb5, 0x98, 0x15, 0x36, 0x06, 0x52, 0xee, 0x71, 0xa5, 0x99, 0xa5, 0x9c, 0xd4,
0x33, 0xd8, 0x2c, 0x23, 0x1a, 0xce, 0x37, 0x7c, 0xed, 0xdd, 0x77, 0xc0, 0xd5,
0x0a, 0x2b, 0xda, 0xfa, 0x42, 0xf2, 0x34, 0x95, 0xd8, 0x5a, 0x48, 0x8c, 0xdb,
0xfe, 0x04, 0x73, 0x63, 0xd9, 0x27, 0x4a, 0x41, 0xc4, 0x38, 0x0e, 0x82, 0x72,
0xc1, 0x13, 0x51, 0x14, 0x6d, 0xbc, 0x84, 0x1a, 0x53, 0xd1, 0x5d, 0xda, 0x45,
0x16, 0x0a, 0x23, 0x38, 0xc4, 0x13, 0x70, 0xd8, 0x67, 0x1a, 0x16, 0xfa, 0x9d,
0xe1, 0x17, 0x43, 0xf6, 0x57, 0xe3, 0xf3, 0x3c, 0x09, 0x10, 0xf3, 0x60, 0x1f,
0x43, 0x43, 0x56, 0xe7, 0x9e, 0x1d, 0x75, 0x13, 0x74, 0xf8, 0xed, 0xff, 0xdf,
0xf7, 0x1c, 0x11, 0xfc, 0x9e, 0x34, 0x24, 0xfb, 0xe6, 0xf4, 0x9b, 0x6e, 0xb7,
0xc7, 0x8f, 0x76, 0x04, 0xee, 0xfa, 0xa5, 0x9e, 0x0a, 0x6c, 0xa8};
static const UCHAR data[] = "Hello World";
HRESULT i = VerifyTest(BCRYPT_MD5_ALGORITHM, szKey, dataToVerify, data, sizeof(data) - 1);
_com_error err(i);
LPCTSTR errMsg = err.ErrorMessage();
cout << "Result: " << errMsg << endl;
}
int main() {
VerifyTest();
}
I used code in answer below