首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用SignedXml计算SHA256签名

用SignedXml计算SHA256签名
EN

Stack Overflow用户
提问于 2015-03-12 09:22:55
回答 4查看 23.4K关注 0票数 23

我正在尝试使用SHA256对一个XML文档进行数字签名。

为此,我尝试使用Security.Cryptography.dll

这是我的密码-

代码语言:javascript
复制
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription),"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");

X509Certificate2 cert = new X509Certificate2(@"location of pks file", "password");
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(@"input.xml");

SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = cert.PrivateKey;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";

// 
// Add a signing reference, the uri is empty and so the whole document 
// is signed. 
Reference reference = new Reference();
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.Uri = "";
signedXml.AddReference(reference);

// 
// Add the certificate as key info, because of this the certificate 
// with the public key will be added in the signature part. 
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(cert));
signedXml.KeyInfo = keyInfo;
// Generate the signature. 
signedXml.ComputeSignature();

但我得到的是“指定的无效算法”。在signedXml.ComputeSignature();出错。有人能告诉我我做错了什么吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-03-14 13:25:01

X509Certificate2将私钥从pfx文件加载到MicrosoftExancedProcessicalProviderv1.0(提供程序类型为1 a.k.a )中。PROV_RSA_FULL),它不支持SHA-256.

基于CNG的密码提供者(在Vista和Server 2008中引入)比基于CryptoAPI的提供程序支持更多的算法,但是.NET代码似乎仍然在使用基于CryptoAPI的类,比如RSACryptoServiceProvider,而不是RSACng,所以我们必须克服这些限制。

但是,另一个CryptoAPI提供程序,微软增强了RSA和AES密码提供程序(提供程序类型24 a.k.a )。PROV_RSA_AES)确实支持SHA-256.所以如果我们把私钥拿到这个提供者那里,我们就可以用它签名了。

首先,您必须调整您的X509Certificate2构造函数,以便通过添加X509KeyStorageFlags.Exportable标志将密钥导出到X509Certificate2将其放入的提供者之外:

代码语言:javascript
复制
X509Certificate2 cert = new X509Certificate2(
    @"location of pks file", "password",
    X509KeyStorageFlags.Exportable);

并导出私钥:

代码语言:javascript
复制
var exportedKeyMaterial = cert.PrivateKey.ToXmlString(
    /* includePrivateParameters = */ true);

然后为支持SHA-256的提供程序创建一个新的RSACryptoServiceProvider实例:

代码语言:javascript
复制
var key = new RSACryptoServiceProvider(
    new CspParameters(24 /* PROV_RSA_AES */));
key.PersistKeyInCsp = false;

并将私钥导入其中:

代码语言:javascript
复制
key.FromXmlString(exportedKeyMaterial);

创建SignedXml实例后,告诉它使用key而不是cert.PrivateKey

代码语言:javascript
复制
signedXml.SigningKey = key;

现在它会起作用的。

以下是MSDN上的提供程序类型及其代码列表

下面是您的示例的完整调整代码:

代码语言:javascript
复制
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");

X509Certificate2 cert = new X509Certificate2(@"location of pks file", "password", X509KeyStorageFlags.Exportable);

// Export private key from cert.PrivateKey and import into a PROV_RSA_AES provider:
var exportedKeyMaterial = cert.PrivateKey.ToXmlString( /* includePrivateParameters = */ true);
var key = new RSACryptoServiceProvider(new CspParameters(24 /* PROV_RSA_AES */));
key.PersistKeyInCsp = false;
key.FromXmlString(exportedKeyMaterial);

XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load(@"input.xml");

SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = key;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";

// 
// Add a signing reference, the uri is empty and so the whole document 
// is signed. 
Reference reference = new Reference();
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.Uri = "";
signedXml.AddReference(reference);

// 
// Add the certificate as key info, because of this the certificate 
// with the public key will be added in the signature part. 
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(cert));
signedXml.KeyInfo = keyInfo;
// Generate the signature. 
signedXml.ComputeSignature();
票数 37
EN

Stack Overflow用户

发布于 2016-07-14 17:44:03

导出和重新导入已经有了作为回答,但是还有几个其他选项您应该知道。

1.使用GetRSAPrivateKey和.NET 4.6.2 (目前正在预览)

GetRSAPrivateKey (扩展)方法返回密钥和平台的“最佳可用类型”的RSA实例(与“每个人都知道”返回RSACryptoServiceProvider的PrivateKey属性相反)。

在99.99(etc)%的所有RSA私钥中,该方法返回的对象能够完成SHA-2签名生成。

虽然该方法是在.NET 4.6(.0)中添加的,但在这种情况下存在4.6.2的要求,因为从GetRSAPrivateKey返回的RSA实例不适用于SignedXml。这已经从固定的 (162556)开始。

2.重新打开钥匙而不出口

就我个人而言,我不喜欢这种方法,因为它使用了(现在的遗留) PrivateKey属性和RSACryptoServiceProvider类。但是,它的优点是可以在所有版本的.NET框架上工作(但在非Windows系统上不使用.NET核心,因为RSACryptoServiceProvider仅限于Windows)。

代码语言:javascript
复制
private static RSACryptoServiceProvider UpgradeCsp(RSACryptoServiceProvider currentKey)
{
    const int PROV_RSA_AES = 24;
    CspKeyContainerInfo info = currentKey.CspKeyContainerInfo;

    // WARNING: 3rd party providers and smart card providers may not handle this upgrade.
    // You may wish to test that the info.ProviderName value is a known-convertible value.

    CspParameters cspParameters = new CspParameters(PROV_RSA_AES)
    {
        KeyContainerName = info.KeyContainerName,
        KeyNumber = (int)info.KeyNumber,
        Flags = CspProviderFlags.UseExistingKey,
    };

    if (info.MachineKeyStore)
    {
        cspParameters.Flags |= CspProviderFlags.UseMachineKeyStore;
    }

    if (info.ProviderType == PROV_RSA_AES)
    {
        // Already a PROV_RSA_AES, copy the ProviderName in case it's 3rd party
        cspParameters.ProviderName = info.ProviderName;
    }

    return new RSACryptoServiceProvider(cspParameters);
}

如果您已经将cert.PrivateKey强制转换为RSACryptoServiceProvider,则可以通过UpgradeCsp发送它。因为这将打开一个现有的密钥,因此不会有额外的材料写入磁盘,因此它使用与现有密钥相同的权限,并且不需要您进行导出。

但是(当心!)不要设置PersistKeyInCsp=false,因为当克隆关闭时,它会擦除原来的键。

票数 15
EN

Stack Overflow用户

发布于 2020-11-19 15:35:32

如果您在升级到.Net 4.7.1或更高版本后遇到此问题:

.Net 4.7及以下:

代码语言:javascript
复制
SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = cert.PrivateKey;

.Net 4.7.1及以上:

代码语言:javascript
复制
SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = cert.GetRSAPrivateKey();

Vladimir 学分

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29005876

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档