2

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:

  • enumerate certificates in "My" store using CertFindCertificateInStore
  • for each certificate found, asking for private key informations using CertGetCertificateContextProperty
  • for each private key informations found, storing provider name pwszProvName and container name pwszContainerName

Then, when a key is found, my application performs signature function using private key found using CSP API:

  • Initialize provider operation using CryptAcquireContext with pwszProvName and pwszContainerName
  • Compute signature using CSP functions: CryptCreateHash, CryptHashData and CryptSignHash

All is OK with CSP function.

Now I try signature operation using CNG API:

  • Initialize provider operation using NCryptOpenStorageProvider with pwszProvName
  • Open algorithm provider using CNG function BCryptOpenAlgorithmProvider fails with STATUS_NOT_FOUND

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:

  • Windows Server 2008: create a certificate template with provider requirement (on "encryption" tab). And the only one provider availabe is "Microsoft Software Key Storage Provider
  • Windows 7: user ask for key generation, the key is stored in Microsoft KSP.

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.

jww
  • 97,681
  • 90
  • 411
  • 885
TheFrancisOne
  • 2,667
  • 9
  • 38
  • 58

1 Answers1

1

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.

softwariness
  • 4,022
  • 4
  • 33
  • 41
  • Thanks for your answer @softwariness I understand that before to sign data with **NCryptSignHash**, I need to hash data with **BCryptCreateHash** / **BCryptHashData** / **BCryptFinishHash**. But to perform these BCryptXXX functions, I need start acquire provider with **BCryptOpenAlgorithmProvider** and the provider name which store my key (here Microsoft KSP). And this fails with **STATUS_NOT_FOUND**. So, should I acquire default provider with NULL for provider name and perform hash function? Because, with CSP Microsoft provider, I can ask it to hash data, no need to use another provider. – TheFrancisOne Jan 26 '15 at 08:18
  • Yes, provide NULL to use the default provider, or you could specify MS_PRIMITIVE_PROVIDER explicitly when using the BCryptXXX functions. If you look at the documentation for NCryptSignHash, for example, you'll notice that it takes a buffer for the hash data, not a handle like the equivalent CSP function, so it doesn't matter that you've not hashed with the same provider. – softwariness Jan 26 '15 at 08:50
  • OK, I got it. Compared to CSP API where we ask hash function to the provider storing the key, her ewith CNG API, we ask to default provider to do it. It's a big change of implementation. I did not notice that detail in Microsoft documentation. – TheFrancisOne Jan 26 '15 at 10:32
  • I've updated my answer to re-iterate and clarify this point. Does that cover everything you needed in your question? – softwariness Jan 26 '15 at 13:32