3

I need to sign some data with the SHA256withRSA algorithm (RSASSA-PKCS1-V1_5-SIGN with SHA-256 hash function) in Windows, and I'm having some validation errors. I was wondering if anyone has experience trying to do it.

The summary of what I'm doing:

CryptAcquireContextW with MS_ENH_RSA_AES_PROV and PROV_RSA_AES
CryptImportKey after running CryptStringToBinary on a pem and applying to that CryptDecodeObjectEx with PKCS_RSA_PRIVATE_KEY
CryptCreateHash with CALG_SHA_256
CryptHashData and CryptSignHash using AT_KEYEXCHANGE to use the imported key (AT_SIGNATURE didn't work)

If you want the detailed version, it's here:

Create a CSP

WCHAR const container[] = L"ContainerName";
HCRYPTPROV provider;
CryptAcquireContextW(
    &provider,
    container,
    MS_ENH_RSA_AES_PROV,
    PROV_RSA_AES,
    0));

Import my private key

char const key_string[] = "-----BEGIN RSA PRIVATE KEY-----"
                          "<base64 encoded key>"
                          "-----END RSA PRIVATE KEY-----";
DWORD key_bytes_size;
BYTE* key_bytes;
CryptStringToBinaryA(
    key_string,
    0,
    CRYPT_STRING_BASE64HEADER,
    nullptr, &key_bytes_size,
    nullptr, nullptr);
key_bytes = new BYTE[key_bytes_size];
CryptStringToBinaryA(
    key_string,
    0,
    CRYPT_STRING_BASE64HEADER,
    key_bytes, &key_bytes_size,
    nullptr, nullptr);

DWORD key_blob_size;
BYTE* key_blob;
CryptDecodeObjectEx(
    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
    PKCS_RSA_PRIVATE_KEY,
    key_bytes, key_bytes_size,
    0, nullptr, 
    nullptr, &key_blob_size);
key_blob = new BYTE[key_blob_size];
CryptDecodeObjectEx(
    X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
    PKCS_RSA_PRIVATE_KEY,
    key_bytes, key_bytes_size,
    0, nullptr, 
    key_blob, &key_blob_size);

HCRYPTKEY key_handle;
CryptImportKey(
    provider,  // The one I created before
    key_blob, key_blob_size, 
    nullptr, 0,
    &key_handle);

(I hate that the API is so verbose, especially the two-step dance to ask for a length and then fill the buffer) Once I've done this, I then hash and sign my data:

char const data[] = "Stuff to sign";
HCRYPTHASH hash_handle;
CryptCreateHash(provider, CALG_SHA_256, 0, 0, &hash_handle);

DWORD data_length = std::strlen(data);
CryptHashData(
    hash_handle,
    reinterpret_cast<const BYTE*>(data), data_length,
    0); 

DWORD signature_size;
BYTE* signature;
CryptSignHash(
    hash_handle,
    AT_KEYEXCHANGE,  // AT_SIGNATURE didn't work
    nullptr, 0,
    nullptr, signature_size);
signature = new BYTE[signature_size];
CryptSignHash(
    hash_handle,
    AT_KEYEXCHANGE,  // AT_SIGNATURE didn't work
    nullptr, 0,
    signature, signature_size);

Will this produce the kind of signature I want? Should I set different parameters for the AcquireContext call?

Kian
  • 1,654
  • 1
  • 14
  • 22
  • 1
    You don't you use [Cryptography Next Generation](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376210(v=vs.85).aspx). [Instructions on how to sign data with CNG](https://msdn.microsoft.com/en-us/library/windows/desktop/aa376304(v=vs.85).aspx) – Mgetz Mar 19 '15 at 20:12
  • 1
    @Mgetz I'll certainly keep it in mind going forward, but project requirements force me to compile in XP. So CNG is not available ("CNG is supported beginning with Windows Server 2008 and Windows Vista"). – Kian Mar 19 '15 at 20:37
  • 1
    No way you can change the XP requirement? That OS is out of support with Microsoft, so even if you do succeed there is no guarantee of security. – Mgetz Mar 19 '15 at 20:49
  • Eventually? Maybe (I hope). By the time I need to do this? No. – Kian Mar 19 '15 at 20:51
  • um ..... what "XP requirement" are you talking about? – specializt Mar 19 '15 at 22:29
  • 1
    AT_KEYEXCHANGE is used only to encrypt the session keys. You will have to use AT_SIGNATURE key. Why are you importing key's? You haven't explained what the actual issue is? – Raj Mar 20 '15 at 09:23
  • @specializt "XP requirement" = Windows XP – Kian Mar 20 '15 at 15:19
  • 1
    @Raj I'm importing keys because my source is a pem file. I can use openssl to convert from PKCS8 to PKCS1 (change the headers from BEGIN PRIVATE KEY to BEGIN RSA PRIVATE KEY), but I still need to feed the key to the CryptoAPI and I found no other way to do it. I use AT_KEYEXCHANGE because SignHash refused to wok with AT_SIGNATURE. The issue is the signature does not appear to be validating correctly. – Kian Mar 20 '15 at 15:23
  • what is the error you are getting? Is your signature detached one or one with cert and data with in the blob? – Raj Mar 20 '15 at 15:38
  • @Kian Exactly - thats why im asking, there is no requirement for WinXP mentioned anywhere ..... – specializt Mar 20 '15 at 15:52
  • @Kian did it's work finally ? – zeus Oct 23 '20 at 20:14

0 Answers0