В вашем фрагменте есть пара вещей, которые я не понимаю.
- Почему вы открываете MaxAllowed. Если вы просто хотите прочитать, используйте ReadOnly.
- Почему вы читаете магазин. Сертификаты [4]. Но, по-видимому, это просто место для «чтения сертификата».
- Почему вы экспортируете и повторно импортируете ключ. (Тем более, что это должно было бы побудить, что бы победить вашу цель «она должна подсказывать»).
Для # 3 Я предполагаю, что вы просто хотите иметь уникальный экземпляр, и в этом случае: Хорошие новости! .NET 4.6 добавила метод GetRSAPrivateKey (расширение) в X509Certificate2, который всегда возвращает уникальный экземпляр. (И вам может быть интересно узнать о новой перегрузке в SignData, которая не поощряет отправку объектов в очередь финализатора: https://msdn.microsoft.com/en-us/library/mt132675(v=vs.110).aspx)
В любом случае, то, что я написал здесь, работает для среды (согласия) или высокой (парольной) защиты , Подход, основанный на CngKey, может отличать среду от высокой, но классический резерв CAPI не может определить, что именно. (Классический резерв CAPI произойдет только с неясными HSM, у которых нет совместимого с CNG драйвером).
private static bool HasProtectedKey(X509Certificate2 cert)
{
if (!cert.HasPrivateKey)
{
return false;
}
using (RSA rsa = cert.GetRSAPrivateKey())
{
return HasProtectedKey(rsa);
}
}
private static bool HasProtectedKey(RSA rsa)
{
RSACng rsaCng = rsa as RSACng;
if (rsaCng != null)
{
return rsaCng.Key.UIPolicy.ProtectionLevel != CngUIProtectionLevels.None;
}
RSACryptoServiceProvider rsaCsp = rsa as RSACryptoServiceProvider;
if (rsaCsp != null)
{
CspKeyContainerInfo info = rsaCsp.CspKeyContainerInfo;
// First, try with the CNG API, it can answer the question directly:
try
{
var openOptions = info.MachineKeyStore
? CngKeyOpenOptions.MachineKey
: CngKeyOpenOptions.UserKey;
var cngProvider = new CngProvider(info.ProviderName);
using (CngKey cngKey =
CngKey.Open(info.KeyContainerName, cngProvider, openOptions))
{
return cngKey.UIPolicy.ProtectionLevel != CngUIProtectionLevels.None;
}
}
catch (CryptographicException)
{
}
// Fallback for CSP modules which CNG cannot load:
try
{
CspParameters silentParams = new CspParameters
{
KeyContainerName = info.KeyContainerName,
KeyNumber = (int)info.KeyNumber,
ProviderType = info.ProviderType,
ProviderName = info.ProviderName,
Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.NoPrompt,
};
if (info.MachineKeyStore)
{
silentParams.Flags |= CspProviderFlags.UseMachineKeyStore;
}
using (new RSACryptoServiceProvider(silentParams))
{
}
return false;
}
catch (CryptographicException e)
{
const int NTE_SILENT_CONTEXT = unchecked((int)0x80090022);
if (e.HResult == NTE_SILENT_CONTEXT)
{
return true;
}
throw;
}
}
// Some sort of RSA we don't know about, assume false.
return false;
}