NCryptVerifySignature() failed with NTE_BAD_SIGNATURE (0x80090006).CryptVerifySignature()) but it failed with the same error.https://godbolt.org/z/9Eb97v9xE
Overview of what it does:
MS_KEY_STORAGE_PROVIDER) to create a temporary RSA key pair.LEGACY_RSAPRIVATE_BLOB for the next step.CryptSignHash() does not allow callers to pass in the data to sign and instead takes in a HCRYPTHASH handle. Thus CryptSetHashParam() is used to directly set the hash value (all zeroes), which is what we want to sign. The hash algorithm is set to CALG_SHA_512.The code above uses NCryptXxx() functions. I had tried BCryptXxx() and it failed with the same error.
The only notable difference between my application and the test code is that the former imports the DER-encoded blobs of the public and private keys instead of generating a fresh pair every time.
CAPI or VerifyDataCapi() requires the signature in little endian order (here) , CNG or VerifyDataCng() in big endian order (here). To verify sigValCng with VerifyDataCapi(), the order must therefore be reversed. Likewise, this also applies to the verification of sigValCapi with VerifyDataCng().
Sample code:
std::reverse(std::begin(sigValCng), std::end(sigValCng)); // reverse sigValCng to little endian
printf("Sign with CNG, verify with CAPI\n");
VerifyDataCapi(hKeyCapi, hProv, hashVal, sigValCng); // Result: Test passed
std::reverse(std::begin(sigValCapi), std::end(sigValCapi)); // reverse sigValCapi to big endian
printf("Sign with CAPI, verify with CNG\n");
VerifyDataCng(hKeyCng, hashVal, hashValLen, sigValCapi); // Result: Test passed