提问人:t.probst 提问时间:9/15/2023 最后编辑:t.probst 更新时间:9/16/2023 访问量:90
如何设置CRYPT_FORCE_KEY_PROTECTION_HIGH以对 RSACryptoServiceProvider 强制实施高级强私钥保护?
How do I set CRYPT_FORCE_KEY_PROTECTION_HIGH to enforce high-level strong private key protection for RSACryptoServiceProvider?
问:
编辑:正如卢克所指出的那样,我CRYPT_FORCE_KEY_PROTECTION_HIGH传递给了错误的函数。我的标志值也不正确。完成这两项更正后,用户会弹出一个窗口来设置密钥保护密码,但在访问密钥时不需要密码。我仍在尝试排除故障,为什么不。
我正在将公共证书和私钥作为 .pfx 文件导入 .NET。我想将证书添加到当前用户证书存储中,并强制实施高级强私钥保护(将证书添加到存储时,用户必须输入密码,访问密钥时需要密码)。我知道有一个标志可以用来设置高保护 - 。CRYPT_FORCE_KEY_PROTECTION_HIGH
我正在尝试使用在密钥容器上设置的标志创建私钥的副本,然后将该私钥附加到证书中的公钥副本。
此代码运行时不会出现任何异常或错误。证书和私钥将添加到存储中,它们用于加密/解密。但是根本没有启用强密钥保护,也没有弹出窗口。
// certData is obtained from an existing certificate with 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";
// Acquire a cryptographic context with the flag for strong protection set
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;
// Make a new key
if (!NCrypt.CryptGenKey(hProv, AT_KEYEXCHANGE, CRYPT_FORCE_KEY_PROTECTION_HIGH, ref hKey))
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
// Convert the original RSACng to RSACryptoServiceProvider by exporting/importing RSA params
RSACryptoServiceProvider rsaCryptoServiceProvider = new RSACryptoServiceProvider();
RSAParameters parameters = certificate.GetRSAPrivateKey().ExportParameters(true);
rsaCryptoServiceProvider.ImportParameters(parameters);
// Get the handle of the RSACryptoServiceProvider
var keyField = typeof(RSACryptoServiceProvider).GetField("_safeKeyHandle", BindingFlags.NonPublic | BindingFlags.Instance);
if (keyField == null)
{
throw new InvalidOperationException("Unable to access the _safeKeyHandle field.");
}
var safeKeyHandle = (SafeHandle)keyField.GetValue(rsaCryptoServiceProvider);
IntPtr originalKey = safeKeyHandle.DangerousGetHandle();
const uint PRIVATEKEYBLOB = 0x7;
int blobLength = 0;
// Export the original key data
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());
}
// Import the original key data into the newly created key
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", // Should be the same as used in step 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);
答: 暂无答案
评论
CryptGenKey(hProv, AT_KEYEXCHANGE, 0x00000040, ref hKey)
CRYPT_FORCE_KEY_PROTECTION_HIGH
0x00008000
CryptGenKey
CryptImportKey()
CRYPT_FORCE_KEY_PROTECTION_HIGH
CRYPT_USER_PROTECTED