访问网络服务的数字签名验证错误

时间:2016-06-21 10:26:35

标签: java c# rsa digital-signature canonicalization

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

根据文档创建的步骤是:

  1. 创建DOM数据的XML表示
  2. 创建DOM数据的规范化表示。规范化表示应遵循http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments;
  3. 中描述的形式
  4. 为规范化表示的RSA摘要创建签名SHA1加密。签名使用Participant的私钥加密;
  5. 将二进制签名编码为base64编码的字符串
  6. 将签名字符串放在SOAP消息ReqDigSig元素中;
  7. 存储以后可能需要的XML数据,以支持提交的XML数据的不可否认性。
  8. 我使用了以下代码:

    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;
    }
    

1 个答案:

答案 0 :(得分:0)

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

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

还可以使用VerifyData来验证签名