title: Windows CryptoAPI: CryptSignHash with CALG_SHA_256 and private key from MY keystore
body: <p>I am trying to generate digital signatures on Windows (from XP SP3, but currently testing with Windows 7) with CryptoAPI that will be compatible with the following openssl commands:</p>
  <pre><code>openssl dgst -sha256 -sign &lt;parameters&gt; (for signing)
  openssl dgst -sha256 -verify &lt;parameters&gt; (for validation)
  </code></pre>
  <p>I want to use a private key from the Windows &quot;MY&quot; keystore for signing.</p>
  <p>I managed to sign files using the SHA1 digest algorithm by using the following CryptoAPI functions (omitting parameters for brevity):</p>
  <pre><code>CertOpenStore
  CertFindCertificateInStore
  CryptAcquireCertificatePrivateKey
  CryptCreateHash (with CALG_SHA1)
  CryptHashData
  CryptSignHash
  </code></pre>
  <p>The generated signature is compatible with &quot;openssl dgst -sha1 -verify&quot; (once the byte order is reversed).</p>
  <p>My problem is: when I try to use CALG_SHA_256 with CryptCreateHash, it fails with error 80090008 (NTE_BAD_ALGID). By googling <a href="https://docs.microsoft.com/en-us/archive/blogs/alejacma/sha-2-support-on-windows-xp" rel="nofollow noreferrer">around</a>, I found that I needed to use a specific provider (PROV_RSA_AES) instead of the default one. Since I would have a provider handle, I would also need to replace CryptAcquireCertificatePrivateKey by CryptGetUserKey. So I modified my program to look like:</p>
  <pre><code>CryptAcquireContext (with PROV_RSA_AES)
  CertOpenStore
  CertFindCertificateInStore
  CryptGetUserKey
  CryptCreateHash (with CALG_SHA256)
  CryptHashData
  CryptSignHash
  </code></pre>
  <p>Unfortunately, this didn't work as expected: CryptGetUserKey failed with error 8009000D (NTE_NO_KEY). If I remove the CryptGetUserKey call, the program runs until CryptSignHash, which fails with error 80090016 (NTE_BAD_KEYSET). I know the keyset does exist and works fine, since I was able to use it to sign the SHA1 digest.</p>
  <p>I tried acquiring the context again with information from the certificate context I got from CertFindCertificateInStore: the best I could do was a successful CryptGetUserKey call, but CryptSignHash would always fail with the same error.</p>
  <p>The private key I am trying to use is 2048 bits long, but I don't expect it to be a problem since it works with the SHA1 digest. I am at a loss, so any suggestion would be very welcome!</p>