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?