You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何设置CRYPT_FORCE_KEY_PROTECTION_HIGH实现RSACryptoServiceProvider高等级私钥保护?

为导入的PFX证书启用高等级强私钥保护问题

补充说明:正如Luke指出,此前我将CRYPT_FORCE_KEY_PROTECTION_HIGH传入了错误的函数,且标志值也不正确。修正这两处后,用户会弹出设置密钥保护密码的窗口,但访问密钥时仍无需输入密码,目前仍在排查原因。

我需要将公证书和私钥以PFX文件形式导入.NET,目标是将证书添加到当前用户证书存储时,启用高等级强私钥保护——要求添加证书时需输入密码,访问密钥时也需验证密码。我知道可以使用CRYPT_FORCE_KEY_PROTECTION_HIGH标志来设置高等级保护。

我的思路是创建带有该标志的私钥副本,再将其与证书的公钥副本关联。

目前代码运行无异常,证书和私钥已成功添加到存储中,也能正常进行加密/解密操作,但强密钥保护并未启用,操作过程中也没有弹出预期的密码验证窗口。

// certData 来自现有证书的 X509Certificate2.Export(X509ContentType.Pfx) 方法
public static void AddCertificateStrongKeyProtection(byte[] certData)
{
    using (X509Certificate2 certificate = new X509Certificate2(certData, "", X509KeyStorageFlags.Exportable | X509KeyStorageFlags.UserKeySet))
    {
        IntPtr hProv = IntPtr.Zero;
        IntPtr hKey = IntPtr.Zero;

        const string providerName = "Microsoft Enhanced Cryptographic Provider v1.0";
        const string containerName = "HighProtectionContainer";

        // 获取设置了强保护标志的加密上下文
        if (!NCrypt.CryptAcquireContext(ref hProv, containerName, providerName, NCrypt.PROV_RSA_FULL, NCrypt.CRYPT_NEWKEYSET))
        {
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
        }

        const uint AT_KEYEXCHANGE = 1;
        const uint CRYPT_FORCE_KEY_PROTECTION_HIGH = 0x00008000;

        // 生成新密钥
        if (!NCrypt.CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_FORCE_KEY_PROTECTION_HIGH, ref hKey))
        {
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
        }

        // 通过导出/导入RSA参数将原始RSACng转换为RSACryptoServiceProvider
        RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider();
        RSAParameters parameters = certificate.GetRSAPrivateKey().ExportParameters(true);
        rsaCryptoServiceProvider.ImportParameters(parameters);

        // 获取RSACryptoServiceProvider的句柄
        var keyField = typeof(RSACryptoServiceProvider).GetField("_safeKeyHandle", BindingFlags.NonPublic | BindingFlags.Instance);

        if (keyField == null)
        {
            throw new InvalidOperationException("无法访问 _safeKeyHandle 字段。");
        }

        var safeKeyHandle = (SafeHandle)keyField.GetValue(rsaCryptoServiceProvider);
        IntPtr originalKey = safeKeyHandle.DangerousGetHandle();

        const uint PRIVATEKEYBLOB = 0x7;
        int blobLength = 0;

        // 导出原始密钥数据
        if (!NCrypt.CryptExportKey(originalKey, IntPtr.Zero, PRIVATEKEYBLOB, 0, null, ref blobLength))
        {
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
        }

        byte[] keyBlob = new byte[blobLength];

        if (!NCrypt.CryptExportKey(originalKey, IntPtr.Zero, PRIVATEKEYBLOB, 0, keyBlob, ref blobLength))
        {
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
        }

        // 将原始密钥数据导入到新生成的密钥中
        if (!NCrypt.CryptImportKey(hProv, keyBlob, keyBlob.Length, IntPtr.Zero, 0, out hKey))
        {
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
        }

        CspParameters cspParams = new CspParameters
        {
            ProviderType = (int)NCrypt.PROV_RSA_FULL,
            KeyContainerName = "HighProtectionContainer",  // 需与步骤2中使用的容器名一致
            Flags = CspProviderFlags.UseExistingKey
         };

         RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider(cspParams);
         using (X509Certificate2 cert = new X509Certificate2(certificate.RawData))
         {
             X509Certificate2 newCert = cert.CopyWithPrivateKey(rsaProvider);

             using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
             {
                 store.Open(OpenFlags.ReadWrite);
                 store.Add(newCert);
                 store.Close();
             }
         }
    }             
}

我的P/Invoke签名如下:

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool CryptAcquireContext(
    ref IntPtr hProv,
    string pszContainer,
    string pszProvider,
    uint dwProvType,
    uint dwFlags);

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptGenKey(
    IntPtr hProv,
    uint Algid,
    uint dwFlags,
    ref IntPtr phKey);

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptExportKey(
    IntPtr hKey, 
    IntPtr hExpKey, 
    uint dwBlobType, 
    uint dwFlags, 
    byte[] pbData, 
    ref int pdwDataLen);

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool CryptImportKey(
    IntPtr hProv,
    byte[] pbData,
    int dwDataLen,
    IntPtr hPubKey,
    uint dwFlags,
    out IntPtr phKey);

内容的提问来源于stack exchange,提问作者t.probst

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 02:17:02