Home > other >  NTE_BAD_SIGNATURE while verifying rsa using Win32 API
NTE_BAD_SIGNATURE while verifying rsa using Win32 API

Time:01-09

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

  • Related