我需要将数字签名作为参数发送到外部Web服务。
根据文档创建的步骤是:
DOM
数据的XML
表示DOM
数据的规范化表示。规范化表示应遵循http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments; RSA
摘要创建签名SHA1
加密。签名使用Participant的私钥加密; SOAP
消息ReqDigSig
元素中; 我使用了以下代码:
private string SignXML(X509Certificate2 Cert, string data)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = false;
xmlDoc.LoadXml(data);
XmlDsigC14NWithCommentsTransform t = new XmlDsigC14NWithCommentsTransform();
t.LoadInput(xmlDoc);
Stream s = (Stream)t.GetOutput(typeof(Stream));
SHA1 sha1 = SHA1.Create();
byte[] hash = sha1.ComputeHash(s);
RSACryptoServiceProvider rsaKey =
(RSACryptoServiceProvider)Cert.PrivateKey;
RSAParameters rsaPrivateParams = rsaKey.ExportParameters(true);
rsaKey.ImportParameters(rsaPrivateParams);
byte[] signature = rsaKey.Encrypt(hash, false);
return Convert.ToBase64String(signature);
}
但网络服务的响应表明数字签名验证错误。
是上面的代码,根据文档中的描述? 我如何验证数字签名是否有效?有没有在线工具?
[后期编辑如下] 我尝试过使用以下内容。我已验证签名,它返回true。但是从Web服务端失败了。 signData,signHash和rsaPKCsignatureformatter类之间的区别是什么?创造签名方法?
var document = Encoding.UTF8.GetBytes(Reqdata);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = false;
xmlDoc.LoadXml(Reqdata);
//trial with XmlDsigC14NWithCommentsTransform class
XmlDsigC14NWithCommentsTransform t = new XmlDsigC14NWithCommentsTransform();
t.LoadInput(xmlDoc);
Stream s = (Stream)t.GetOutput(typeof(Stream));
//trial with SignedXML class
SignedXml signedXml = new SignedXml(xmlDoc);
signedXml.SignedInfo.CanonicalizationMethod =
SignedXml.XmlDsigC14NWithCommentsTransformUrl;
document = Encoding.UTF8.GetBytes(signedXml.ToString());
byte[] hashedDocument;
using (var sha1 = SHA1.Create())
{
//hashedDocument = sha1.ComputeHash(document);
hashedDocument = sha1.ComputeHash(s);
}
var digitalSignature = new DigitalSignature();
digitalSignature.AssignNewKey();
byte[] signature = digitalSignature.SignData(hashedDocument);
string finalsignature = Convert.ToBase64String(signature) ;
byte[] finalSignveri = Convert.FromBase64String(finalsignature);
bool verified = digitalSignature.VerifySignature(hashedDocument, finalSignveri);
,数字签名类如下:
public class DigitalSignature
{
private RSAParameters publicKey;
private RSAParameters privateKey;
public void AssignNewKey()
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.PersistKeyInCsp = false;
publicKey = rsa.ExportParameters(false);
privateKey = rsa.ExportParameters(true);
}
}
public byte[] SignData(byte[] hashOfDataToSign)
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.PersistKeyInCsp = false;
rsa.ImportParameters(privateKey);
var rsaFormatter = new RSAPKCS1SignatureFormatter(rsa);
rsaFormatter.SetHashAlgorithm("SHA1");
return rsaFormatter.CreateSignature(hashOfDataToSign);
}
}
public bool VerifySignature(byte[] hashOfDataToSign, byte[] signature)
{
using (var rsa = new RSACryptoServiceProvider())
{
rsa.ImportParameters(publicKey);
var rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
rsaDeformatter.SetHashAlgorithm("SHA1");
return rsaDeformatter.VerifySignature(hashOfDataToSign, signature);
}
}
}
您能否告诉我您在wsdl中特别寻找的数据?抱歉,我无法在此处提供完整的wsdl信息。
返回的错误是我相信用户处理并说明"数字签名验证错误"
[Redited]
请在下面找到在java中生成数字签名的代码片段。这是由第三方发送的,以供参考。我不是一个java开发人员。如果我编写的C#代码对应于Java代码,有人可以告诉我吗?如果没有,请让我知道我哪里出错。
private static String createDigitalSignature(Key key, byte[] data) {
byte[] signature = null;
try {
// Initialize xml-security library
org.apache.xml.security.Init.init();
// Build DOM document from XML data
DocumentBuilderFactory dfactory = DocumentBuilderFactory
.newInstance();
dfactory.setNamespaceAware(true);
dfactory.setValidating(true);
DocumentBuilder documentBuilder = dfactory.newDocumentBuilder();
// This is to throw away all validation errors
documentBuilder
.setErrorHandler(new org.apache.xml.security.utils.IgnoreAllErrorHandler());
Document doc = documentBuilder
.parse(new ByteArrayInputStream(data));
// Build canonicalized XML from document
Canonicalizer c14n = Canonicalizer
.getInstance("http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments");
byte[] canonBytes = c14n.canonicalizeSubtree(doc);
// Initialize signing object with SHA1 digest and RSA encryption
Signature rsa = Signature.getInstance("SHA1withRSA");
// Set private key into signing object
rsa.initSign((PrivateKey) key);
// Generate signature
rsa.update(canonBytes);
signature = rsa.sign();
} catch (Exception ex) {
System.out.println("Exception occurred in createDigitalSignature: "
+ ex.toString());
System.exit(-1);
}
// Base64 encode signature
BASE64Encoder b64e = new BASE64Encoder();
String signatureString = b64e.encode(signature);
return signatureString;
}
答案 0 :(得分:0)
在步骤3,数字签名与加密摘要不完全相同。具有pkcs#1格式的rsa数字签名将摘要算法OID(标识符)与摘要值连接起来。因此,您正在生成无效签名。
所有编程语言都有一种方法来执行数字签名而无需处理摘要和密码。我不是C#程序员,但我想你必须使用RSACryptoServiceProvider.SignData
还可以使用VerifyData来验证签名