Подписание 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;
И эти решения отлично работали даже со старым ключом!