如何在C# .NET中正确配置CryptoConfig.AddAlgorithm以支持ECDSA?
问题
我有一个使用ecdsa-sha384签名的XMLDocument,默认情况下.NET的SignedXml不支持该算法。因此我按照相关指导,在程序开头调用了以下代码:
CryptoConfig.AddAlgorithm(typeof(Ecdsa384SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384");
调用AddAlgorithm之前,SignedXml可以正常对rsa-sha256执行CheckSignature操作,能遍历XMLDocument并完成签名验证且无报错。但调用AddAlgorithm之后,程序在XML文件的第二行抛出错误:
InvalidOperationException > There is an error in the XML document. > <MySpecialDoc xmlns='https://www.hello.com/world/1.0'> was not expected. at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events) at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader)
该XML的开头内容如下:
<?xml version="1.0"?> <MySpecialDoc xmlns='https://www.hello.com/world/1.0' id="9baedc57-c4ef-41f5-8bdf-33fb14af3f71"> ...
请问要让ECDSA-sha384正常工作,我还缺少哪些配置?若您了解相关的自定义算法注册教程文章,欢迎分享。谢谢!
解决方案
这个错误本质是XML反序列化失败,和CryptoConfig.AddAlgorithm无直接关联,但可能是注册算法后XML处理流程的间接影响。以下是具体解决步骤:
1. 匹配XML反序列化类的命名空间
XML根元素MySpecialDoc带有命名空间https://www.hello.com/world/1.0,反序列化用的实体类必须通过XmlRoot特性指定对应命名空间:
[XmlRoot(Namespace = "https://www.hello.com/world/1.0")] public class MySpecialDoc { // 类成员定义,需与XML节点一一对应 }
2. 隔离SignedXml验证与XmlSerializer反序列化流程
避免在同一个XMLReader实例中混合执行签名验证和反序列化操作,建议拆分步骤:
- 先通过
XmlDocument加载XML,完成SignedXml的ECDSA-sha384签名验证 - 验证通过后,重新创建XmlReader实例进行XML反序列化
3. 完善ECDSA384签名描述类的实现
确保Ecdsa384SignatureDescription类正确继承SignatureDescription并配置必要算法:
public class Ecdsa384SignatureDescription : SignatureDescription { public Ecdsa384SignatureDescription() { KeyAlgorithm = typeof(ECDsaCng).FullName; DigestAlgorithm = typeof(SHA384CryptoServiceProvider).FullName; FormatterAlgorithm = typeof(ECDsaSignatureFormatter).FullName; DeformatterAlgorithm = typeof(ECDsaSignatureDeformatter).FullName; } public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) { var deformatter = (ECDsaSignatureDeformatter)base.CreateDeformatter(key); deformatter.SetHashAlgorithm("SHA384"); return deformatter; } public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key) { var formatter = (ECDsaSignatureFormatter)base.CreateFormatter(key); formatter.SetHashAlgorithm("SHA384"); return formatter; } }
同时补充注册SHA384的XMLDSIG映射:
CryptoConfig.AddAlgorithm(typeof(SHA384CryptoServiceProvider), "http://www.w3.org/2001/04/xmlenc#sha384");
4. 使用正确的密钥类型验证签名
验证ECDSA-sha384签名时,需传入ECDsa类型密钥,调用SignedXml.CheckSignature(ECDsa key)重载方法,避免密钥类型不匹配引发的异常。
内容的提问来源于stack exchange,提问作者codenamezero

