My question is about use case with CNG API and Microsoft providers. I don't write code sample because I ask for your help about the best way to use CNG API in my application compared to CSP API.
I built an application which use symetric keys stored using these steps:
Then, when a key is found, my application performs signature function using private key found using CSP API:
All is OK with CSP function.
Now I try signature operation using CNG API:
This error happens when the private key is stored in Microsoft Software Key Storage Provider. Reading Microsoft documentation I understand that type of provider is KSP provider, and only functions about key management. That's why it fails when I try a primitive function, I need to use a "Primitive Provider".
I found the way to use CNG provider following these setps:
So here are my questions:
Is it normal I can't perform primitive function with "Microsoft Software Key Storage Provider" ?
If I can't perform primitive functions (signature, encryption, decryption, hash) with Microsoft KSP (which is KSP provider), how can I make my private key stored and managed in a Microsoft Primitive Provider?
My trouble here, is that with CSP API, default Microsoft CSP provider performs signature (and decyrption, encryption, etc) function. But with CNG API, default provider only performs key storage management.
For asymmetric keys, the functionality supported by a CNG Key Storage Provider is comparable to that of a Primitive Provider, apart of course from the the fact that the KSP (Key Storage Provider) allows you to persist and load keys.
In fact, the KSP API calls for doing the crypto operations look much the same as the primitive ones, except the KSP ones start with N
and the primitive ones start with B
.
For example:
What is missing from the KSP is symmetric functionality (including hashing), and this may be where the confusion has arisen. Compared to CAPI (CSP/Crypto API), the CNG signing functions are a bit more low-level - you hash the data separately first, and then pass that hash byteblock to NCryptSignHash
(no hash object handle like in CAPI).
To re-iterate, as this is a source of confusion for people coming from CAPI, you can hash with any primitive provider, MS_PRIMITIVE_PROVIDER
or a third-party provider, and then pass the result to any Key Storage Provider's NCryptSignHash
, because it's just bytes of data, it doesn't matter who did the hashing. The NCRYPT_KEY_HANDLE
passed to NCryptSignHash
determines what KSP is used to do the signing; there is no CNG equivalent of HCRYPTHASH
passed to NCryptSignHash
.
So, if you want to sign with a KSP, you should hash the message to be signed first with a primitive provider (using BCryptCreateHash
/BCryptHashData
/BCryptFinishHash
), and pass the result to NCryptSignHash
.