Получение исключения Указан недопустимый тип поставщика или ключ не существует при получении закрытого ключа от X509Certificate2 Иногда

Я получаю одно из следующих исключений при попытке получить закрытый ключ из сертификата X509Certificate2:

System.Security.Cryptography.CryptographicException: указан недопустимый тип поставщика.

OR

System.Security.Cryptography.CryptographicException: ключ не существует в следующей строке кода: RSACryptoServiceProvider rsaKey = (RSACryptoServiceProvider) digiSignCert.PrivateKey;

Трассировки стека:

System.Security.Cryptography.CryptographicException: ключ не существует. на System.Security.Cryptography.Utils.GetKeyPairHelper (CspAlgorithmType KeyType, параметры CspParameters, булевой randomKeyContainer, Int32 dwKeySize, SafeProvHandle & safeProvHandle, SafeKeyHandle & safeKeyHandle) в System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair () в System.Security.Cryptography.RSACryptoServiceProvider. .ctor (Int32 dwKeySize, параметры CspParameters, логическое значение useDefaultKeySize) в System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey () в Api.CertificateUtil.GetSignedXml (String xml, X509Certificate2 private)

Код:

public static RSACryptoServiceProvider rsaKey = null;
public X509Certificate2 _PrivateCert;

public APISearch()
{
    byte[] privateCert = null;//We get the actual certificate file data here
    GetPrivateCerificate(privateCert, "abc@123");
    GetSignedXml(_PrivateCert);
}

public void GetPrivateCerificate(byte[] privateCert, string pwd)
{
    _PrivateCert = new X509Certificate2(privateCert, pwd, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
}

public void GetSignedXml(X509Certificate2 privateCert)
{
    rsaKey = (RSACryptoServiceProvider)privateCert.PrivateKey; //Occassional Exception
}

Ожидаемый результат: (RSACryptoServiceProvider)privateCert.PrivateKey всегда должен выдавать закрытый ключ.

Фактический результат: Иногда вышеупомянутые исключения выбрасываются в эту строку:

rsaKey = (RSACryptoServiceProvider)privateCert.PrivateKey;

а иногда закрытый ключ успешно извлекается из файла сертификата. На данный момент нам не удалось отследить характер этой проблемы.


person Narendra Vaghamshi    schedule 01.08.2017    source источник


Ответы (1)


RSACryptoServiceProvider - это тип, который выполняет RSA через библиотеку Window Cryptographic API (CAPI). Когда впервые был создан .NET, CAPI был новым и всегда правильным ответом (в Windows). Начиная с Windows Vista появилась новая библиотека: Cryptography: Next Generation (CNG). CNG, для совместимости, понимает, как работать с CAPI. Но CAPI не может быть CAPI и понимать CNG. Исключения, которые вы видите, - это когда PFX указывает, что закрытые ключи должны храниться через CNG (или сертификат в магазине указывает, что его закрытые ключи хранятся через CNG).

Когда .NET Framework добавляла RSACng, было решено, что слишком много людей уже написали строку (RSACryptoServiceProvider)cert.PrivateKey, поэтому это свойство никогда не может вернуть экземпляр RSACng. Вместо этого в .NET 4.6 были созданы новые методы (расширения): cert.GetRSAPublicKey() и cert.GetRSAPrivateKey(), они возвращают RSA вместо AsymmetricAlgorithm. Также в .NET 4.6 базовый класс RSA был расширен: операции Sign / Verify и Encrypt / Decrypt были перемещены вниз (хотя и с другими подписями, поскольку RSA получил новые параметры с момента написания CAPI).

Ожидаемый результат: (RSACryptoServiceProvider)privateCert.PrivateKey всегда должен выдавать закрытый ключ.

На самом деле cert.PrivateKeycert.PublicKey.Key) мягко устарели. Вы не должны больше называть это / их. RSA (4.6), ECDSA (4.6.1) и DSA (4.6.2) имеют методы Get [Algorithm] {Public | Private} Key.

  • (RSACryptoServiceProvider)cert.PrivateKey => cert.GetRSAPrivateKey()
  • rsaCSP.Encrypt(data, false) => rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1)
  • rsaCSP.Encrypt(data, true) => rsa.Encrypt(data, RSAEncryptionPadding.OaepSHA1)
  • rsaCSP.SignData(data, "SHA256") => rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)

Аналогично Decrypt, SignHash, VerifyData, VerifyHash; и аналогично для ECDsa и DSA.

Наконец, пожалуйста, не жестко приводите возвращаемое значение этих методов, оно изменяется по мере необходимости ... в Windows он может возвращать либо RSACng, либо RSACryptoServiceProvider, в Linux (.NET Core) он в настоящее время возвращает RSAOpenSsl, а в macOS (.NET Core) он возвращает некастируемый объект.

person bartonjs    schedule 01.08.2017