5

How can I get a NCRYPT_KEY_HANDLE for encryption/decryption with CNG from the private key of a PCCERT_CONTEXT from the windows certificate store?

The CryptEncrypt function has been superceded by the NCryptEncrypt and BCryptEncrypt functions, but there is no immediately apparent way of obtaining a handle for either of these functions from a PCCERT_CONTEXT from the Windows certificate store.

Is it even possible to use the CNG functions for encryption/decryption using (private keys of) certificates without resolving to brute force approaches like exporting the certificate?

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
jorgen
  • 535
  • 1
  • 5
  • 12

1 Answers1

8

I'm answering this myself since I found answers nowhere else:

The following code will get you what you want:

const HCERTSTORE store(CertOpenStore(CERT_STORE_PROV_SYSTEM_W, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG, (const void*)L"MY"));
const PCCERT_CONTEXT certContext(CertFindCertificateInStore(store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_FIND_SUBJECT_STR_W, subjectName, nullptr));
if (certContext)
{
  HCRYPTPROV_OR_NCRYPT_KEY_HANDLE keyHandle;
  DWORD keySpec;
  BOOL callerFreesKeyHandle;

  // Get NCrypt key handle from certificate.
  // Might fail for instance if certificate private key is not accessible to current user.
  if (CryptAcquireCertificatePrivateKey(certContext, CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, nullptr, &keyHandle, &keySpec, &callerFreesKeyHandle))
  {
    check(keySpec == CERT_NCRYPT_KEY_SPEC); //< Should always have this value when giving CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG.
    UNIQUE_NCRYPT_KEY_HANDLE keyHandleKeeper;
    if (callerFreesKeyHandle)
    {
      keyHandleKeeper.reset(keyHandle);
    }
    ...
jorgen
  • 535
  • 1
  • 5
  • 12