【发布时间】:2016-10-22 20:27:57
【问题描述】:
我需要将数字签名作为参数之一发送到外部 Web 服务。
按照文档创建的步骤是:
- 创建
XML数据的DOM表示 - 创建
DOM数据的规范化表示。规范化的表示应遵循http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments 中描述的形式; - 为规范化表示的
SHA1摘要创建签名RSA加密。签名使用参与者的私钥加密; - 将二进制签名编码为 base64 编码字符串
- 将签名字符串放在
SOAP消息ReqDigSig元素中; - 存储 XML 数据,因为以后可能需要它来支持提交的 XML 数据的不可否认性。
我使用了以下代码:
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类的createsignature方法有什么区别?
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 信息。
返回的错误是我相信用户已处理并声明“数字签名验证错误”
[已编辑]
请在下面找到在 java 中生成数字签名的代码的 sn-p。这是由第三方发送以供参考。我不是 Java 开发人员。有人可以让我知道我编写的 C#code 是否对应于 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;
}
【问题讨论】:
-
你能把错误返回给你吗?我们需要更多信息。 wsdl 是什么样的?你签名的长度是多少?
标签: java c# rsa digital-signature canonicalization