The following is the reply:
And what's the difference between BCrypt and NCrypt APIs?
BCrypt APIs are the CNG Crypto Primitive functions - CNG Cryptographic Primitive Functions - Win32 apps | Microsoft Learn.
These are used for non-persistent keys (ephemeral).
NCrypt APIs are the CNG Key Storage Functions - CNG Key Storage Functions - Win32 apps | Microsoft Learn
These are used when keys need to be persistent.
So in the case, we have to use NCrypt APIs. And you are actually correct about the APIs:
NCryptOpenStorageProvider
NCryptCreatePersistedKey
For NCryptCreatePersistedKey:
SECURITY_STATUS NCryptCreatePersistedKey(
[in] NCRYPT_PROV_HANDLE hProvider,
[out] NCRYPT_KEY_HANDLE *phKey,
[in] LPCWSTR pszAlgId,
[in, optional] LPCWSTR pszKeyName,
[in] DWORD dwLegacyKeySpec,
[in] DWORD dwFlags
);
The pszKeyName is the same as the szContainer name that you passed to CryptAcquireContext.
pszAldId should be BCRYPT_RSA_ALGORITHM.
dwLegacyKeySpec should be 0 (you don't need a legacy key) and dwFlags would be NCRYPT_MACHINE_KEY_FLAG.
With this structure, you need to set the private key context for the certificate:
CRYPT_KEY_PROV_INFO
.pwszProvName = MS_ENHANCED_PROV;
.dwProvType = PROV_RSA_FULL;
.dwFlags = CRYPT_MACHINE_KEYSET | CRYPT_SILENT;
.dwKeySpec = AT_KEYEXCHANGE;
This changes to
CRYPT_KEY_PROV_INFO
.pwszProvName = MS_KEY_STORAGE_PROVIDER;
.dwProvType = 0;
.dwFlags = NCRYPT_MACHINE_KEY_FLAG | NCRYPT_SILENT_FLAG;
.dwKeySpec = 0;
He says he calls CreateSelfSignedCertificate:
PCCERT_CONTEXT CertCreateSelfSignCertificate(
[in, optional] HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey,
[in] PCERT_NAME_BLOB pSubjectIssuerBlob,
[in] DWORD dwFlags,
[in, optional] PCRYPT_KEY_PROV_INFO pKeyProvInfo,
[in, optional] PCRYPT_ALGORITHM_IDENTIFIER pSignatureAlgorithm,
[in, optional] PSYSTEMTIME pStartTime,
[in, optional] PSYSTEMTIME pEndTime,
[optional] PCERT_EXTENSIONS pExtensions
);
The first parameter can be an HCRYPTPROV (his old code) or an NCRYPT_KEY_HANDLE which he gets from NCryptCreatePersistedKey.
For pKeyProvInfo, he needs to pass the structure indicated above.