Подписание SHA256 перестает работать в .NET 4.5

У нас есть фрагмент кода, который создает объект SigningCredentials для использования для подписи документа xml с использованием алгоритма SHA256. Он отлично работает с .NET 3.5. Однако, когда мы обновляем нашу кодовую базу до .NET 4.5, она перестает работать. Тот же код, тот же сертификат! Я потратил часы на отладку и поиск в Интернете без везения.

Может кто-нибудь, пожалуйста, скажите мне, в чем проблема? Заранее благодарю вас.

Код для создания SigningCredentials:

public SigningCredentials CreateSigningCredentials(X509Certificate2 cert)
{
    var ski = new SecurityKeyIdentifier(new X509RawDataKeyIdentifierClause(cert));
    return new SigningCredentials(new X509AsymmetricSecurityKey(cert), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "http://www.w3.org/2001/04/xmlenc#sha256", ski);
}

Исключение:

[CryptographicException: Invalid algorithm specified.
]
   System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr) +41
   System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash, Int32 cbHash, ObjectHandleOnStack retSignature) +0
   System.Security.Cryptography.Utils.SignValue(SafeKeyHandle hKey, Int32 keyNumber, Int32 calgKey, Int32 calgHash, Byte[] hash) +118
   System.Security.Cryptography.RSACryptoServiceProvider.SignHash(Byte[] rgbHash, Int32 calgHash) +334
   System.Security.Cryptography.RSAPKCS1SignatureFormatter.CreateSignature(Byte[] rgbHash) +321
   System.IdentityModel.SignedXml.ComputeSignature(HashAlgorithm hash, AsymmetricSignatureFormatter formatter, String signatureMethod) +323
   System.IdentityModel.SignedXml.ComputeSignature(SecurityKey signingKey) +690
   System.IdentityModel.EnvelopedSignatureWriter.ComputeSignature() +338
   System.IdentityModel.EnvelopedSignatureWriter.OnEndRootElement() +278
   System.IdentityModel.Metadata.MetadataSerializer.WriteEntityDescriptor(XmlWriter inputWriter, EntityDescriptor entityDescriptor) +1109

Ответы

Ответ 1

Хотя этот вопрос задавался почти год назад, он недавно получил несколько голосов, что может указывать на то, что некоторые другие люди сталкиваются с той же проблемой. Надеюсь, этот ответ может помочь:) Короче говоря, ошибка не происходит на всех машинах, но только в некоторых из них. Я думаю, это зависит от того, какие CSP были зарегистрированы на конкретной машине. Во всяком случае, в моем конкретном случае сертификат был сгенерирован с помощью "Microsoft RSA SChannel..." или "сильного поставщика криптографии Microsoft" в качестве CSP. Я сгенерировал новый сертификат, но использовал "Microsoft Enhanced RSA и AES Cryptographic Provider" в качестве CSP, и подпись SHA256 начала работать для меня.

Некоторые ссылки:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/e391ba75-ce6e-431c-bfc9-26a71ae1b033/sha256-signing-stops-working-in-net-45?forum=Geneva (как вы можете видеть, миллион благодаря Павлу, который помог мне решить эту проблему)

http://hintdesk.com/c-how-to-fix-invalid-algorithm-specified-when-signing-with-sha256/

Ответ 2

Была та же проблема с XmlDsig (попытка сделать обертывающую подпись XML-документа с помощью алгоритма RSA-SHA256). Сначала я получаю исключение

System.Security.Cryptography.CryptographicException: SignatureDescription не может быть создан для алгоритма подписи в комплект поставки.

Затем я нашел упоминание о реализации описания RSAPKCS1SHA256SignatureDescription - подписи для подписей RSA-SHA256.
Полная реализация здесь:
http://clrsecurity.codeplex.com/SourceControl/changeset/view/47833#269110
или здесь: https://gist.github.com/sneal/f35de432115b840c4c1f

Вам необходимо вручную вызвать один раз на приложение:

CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");

После этого у меня появилось новое исключение:

System.Security.Cryptography.CryptographicException: неверный алгоритм указано.

Это привело меня к вашему вопросу. После того, как вы прочитали предложенную статью, я создал новый ключ и сертификат (с OpenSSL) с помощью Microsoft Enhanced RSA and AES Cryptographic Provider.
К моему удивлению, этот новый сертификат позволил мне успешно сделать подпись.

После еще нескольких исследований я нашел интересный ответ Андрея здесь fooobar.com/info/353014/..., где использовал RSACryptoServiceProvider для подготовки SecretKey для класса SignedXml. В частности, эта часть (моя интерпретация):

var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
var certificates =  store.Certificates.Find(X509FindType.FindBySerialNumber,  "54dba096", true);
var certificate = certificates[0];

// next three lines
var cspParams = new CspParameters(24) { KeyContainerName = "XML_DISG_RSA_KEY" };
var key = new RSACryptoServiceProvider(cspParams);
key.FromXmlString(certificate.PrivateKey.ToXmlString(true));

SignedXml sxml = new SignedXml(doc);
sxml.SigningKey = key;

И эти решения отлично работали даже со старым ключом!