如何获得 PCCERT_CONTEXT 私钥的 NCRYPT_KEY_HANDLE?

jor*_*gen 4 c++ cryptography cng

如何从 Windows 证书存储库中NCRYPT_KEY_HANDLE的 a 的私钥获取使用 CNG 的加密/解密PCCERT_CONTEXT

CryptEncrypt函数已被NCryptEncryptBCryptEncrypt函数取代,但没有立即明显的方法PCCERT_CONTEXT从 Windows 证书存储中的a 获取这两个函数中的任何一个的句柄。

甚至可以使用 CNG 功能使用证书(的私钥)进行加密/解密,而无需解析为导出证书之类的蛮力方法?

jor*_*gen 6

我自己回答这个问题,因为我在其他地方找不到答案:

下面的代码会让你得到你想要的:

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);
    }
    ...
Run Code Online (Sandbox Code Playgroud)