【问题标题】:Digital signature verification error for accessing webservice访问webservice的数字签名验证错误
【发布时间】:2016-10-22 20:27:57
【问题描述】:

我需要将数字签名作为参数之一发送到外部 Web 服务。

按照文档创建的步骤是:

  1. 创建XML 数据的DOM 表示
  2. 创建DOM 数据的规范化表示。规范化的表示应遵循http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments 中描述的形式;
  3. 为规范化表示的SHA1摘要创建签名RSA加密。签名使用参与者的私钥加密;
  4. 将二进制签名编码为 base64 编码字符串
  5. 将签名字符串放在SOAP消息ReqDigSig元素中;
  6. 存储 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


【解决方案1】:

在第 3 步,数字签名与加密摘要并不完全相同。 pkcs#1 格式的 rsa 数字签名将摘要算法 OID(标识符)与摘要值连接起来。所以你正在生成无效签名。

所有编程语言都有一种无需处理摘要和密码即可执行数字签名的方法。我不是 C# 程序员,但我猜你必须使用 RSACryptoServiceProvider.SignData

也可以使用VerifyData 来验证签名

【讨论】:

  • 感谢您的回复。我已经重新编辑了帖子。我尝试了另一种创建签名的方法。我使用了验证方法,它返回true。但它仍然从网络服务失败。
  • 您正在哈希两次。 RSA 签名也执行散列。应该是byte[] signature = digitalSignature.SignData(document);bool verified = digitalSignature.VerifySignature(document, signature);
  • 我修改了它。但它在 DigitalSignature class.rsaFormatter.CreateSignature(hashOfDataToSign);
  • 对不起,我误读了文档'RSAPKCS1SignatureFormatter。它需要一个哈希。您可以使用一些在线工具来验证 XML 签名。您也可以使用 SoapUI 来调用 Web 服务,但似乎签名格式不标准。你有例子吗?
  • 我已经用外部 web 服务帮助台提供的 java 代码重新编辑了这篇文章。
猜你喜欢
  • 2016-07-21
  • 1970-01-01
  • 1970-01-01
  • 2014-01-18
  • 1970-01-01
  • 2019-05-11
  • 2016-03-09
  • 2019-11-24
相关资源
最近更新 更多