2013-12-14 2 views
1

При подписании данных с помощью RSACryptoServiceProvider в C# у меня есть требование обеспечить импорт сертификата с помощью сильной защиты ключа и высокий уровень безопасности, чтобы пользователь вводил пароль каждый раз, когда они подписываются с помощью ключ. Вот быстрый упрощенный пример кода подписи:Проверка защиты секретного ключа перед подписанием с помощью RSACryptoServiceProvider

X509Store myCurrentUserStore = new X509Store(StoreName.My, StoreLocation.CurrentUser); 
myCurrentUserStore.Open(OpenFlags.MaxAllowed); 
X509Certificate2 currentCertificate = myCurrentUserStore.Certificates[4]; 

RSACryptoServiceProvider key = new RSACryptoServiceProvider(); 
key.FromXmlString(currentCertificate.PrivateKey.ToXmlString(true)); 

byte[] signedData = Encoding.UTF8.GetBytes(originalFileContent); 
byte[] signature = key.SignData(signedData, CryptoConfig2.CreateFromName("SHA256CryptoServiceProvider") as HashAlgorithm);  

Так что лучший способ идти о проверке, как был установлен сертификат, так что я могу отобразить сообщение об ошибке, если он не был установлен с сильным секретным ключом охраны с высокий уровень безопасности?

ответ

0

В вашем фрагменте есть пара вещей, которые я не понимаю.

  1. Почему вы открываете MaxAllowed. Если вы просто хотите прочитать, используйте ReadOnly.
  2. Почему вы читаете магазин. Сертификаты [4]. Но, по-видимому, это просто место для «чтения сертификата».
  3. Почему вы экспортируете и повторно импортируете ключ. (Тем более, что это должно было бы побудить, что бы победить вашу цель «она должна подсказывать»).

Для # 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; 
} 
Смежные вопросы