Java 签名中的空格是什么意思?

Java 签名中的空格是什么意思?,java,cryptography,digital-signature,xml-signature,Java,Cryptography,Digital Signature,Xml Signature,我签署了XML文档,并根据该文档计算签名 签名算法:http://www.w3.org/2000/09/xmldsig#rsa-sha1 用于签名的哈希算法: http://www.w3.org/2000/09/xmldsig#sha1 下面是我的部分代码 ... initKeyAndCertificate(); Document signedXmlDoc = getSignXML(signMethod, digestMethod, decodeXmlDocAsString); St

我签署了XML文档,并根据该文档计算签名

  • 签名算法:
    http://www.w3.org/2000/09/xmldsig#rsa-sha1
  • 用于签名的哈希算法:
    http://www.w3.org/2000/09/xmldsig#sha1
下面是我的部分代码

...
initKeyAndCertificate();
Document signedXmlDoc = getSignXML(signMethod, 
   digestMethod, decodeXmlDocAsString);
String signedXMLAsString = getSignedXMLAsString(signedXmlDoc);

org.jsoup.nodes.Document document = Jsoup.parse(signedXMLAsString);
Element signatureValueTag = document.select("SignatureValue").first();
String signatureValueAsString = signatureValueTag.text();

System.out.println("=======================================");
System.out.println(signedXMLAsString);
System.out.println("=======================================");
System.out.println(signatureValueAsString);
System.out.println("=======================================");
...
initKeyAndCertificate
方法:

private void initKeyAndCertificate() throws Exception {
    String jksFileName = "C:/Java/keys/testkey.jks";
    FileInputStream fileInputStream = null;

    try {
        fileInputStream = new FileInputStream(new File(jksFileName));
    } catch (FileNotFoundException fe) {
        fe.printStackTrace();
    }

    final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    char[] KeyStorePass = null;
    keyStore.load(fileInputStream, KeyStorePass);

    key = 
       keyStore.getKey("testkey", new char[]{'t', 'e', 's', 't', 'k', 'e', 'y'});
    certificate = keyStore.getCertificate("testkey");

    try {
        fileInputStream.close();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}
public Document getSignXML(String signMethod, 
         String digestMethod, String XmlDocAsString) throws Exception {
    final DocumentBuilderFactory documentBuilderFactory = 
            DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setIgnoringElementContentWhitespace(true);
    documentBuilderFactory.setCoalescing(true);
    documentBuilderFactory.setNamespaceAware(true);

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    InputSource is = new InputSource(new StringReader(XmlDocAsString));

    Document doc = builder.parse(is);

    XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");

    List<Transform> transformList = new ArrayList<Transform>();
    Transform transformC14N = 
            xmlSignatureFactory.newTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS, 
                    (XMLStructure) null);
    transformList.add(transformC14N);

    Reference reference = xmlSignatureFactory.newReference("", 
            xmlSignatureFactory.newDigestMethod(digestMethod, null), 
                transformList, null, null);
    SignedInfo signedInfo = 
            xmlSignatureFactory.newSignedInfo(
                    xmlSignatureFactory.newCanonicalizationMethod(
                            CanonicalizationMethod.EXCLUSIVE,
                    (C14NMethodParameterSpec) null),
            xmlSignatureFactory.newSignatureMethod(signMethod, null),
            Collections.singletonList(reference));

    KeyInfoFactory keyInfoFactory = 
            xmlSignatureFactory.getKeyInfoFactory();
    X509Data x509Data = 
            keyInfoFactory.newX509Data(Collections.singletonList(certificate));
    KeyInfo keyInfo = 
            keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data));

    final Node node = doc.getDocumentElement();

    javax.xml.crypto.dsig.XMLSignature xmlSignature = 
            xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
    DOMSignContext signContext = new DOMSignContext(key, node);
    xmlSignature.sign(signContext);

    return doc;
}
private String getSignedXMLAsString(Document signedDocument) {
    DOMSource domSource = new DOMSource(signedDocument);
    StringWriter stringWriter = new StringWriter();
    StreamResult streamResult = new StreamResult(stringWriter);
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = null;

    try {
        transformer = transformerFactory.newTransformer();
    } catch (TransformerConfigurationException e) {
        e.printStackTrace();
    }

    try {
        transformer.transform(domSource, streamResult);
    } catch (TransformerException e) {
        e.printStackTrace();
    }
    return stringWriter.toString();
}
getSignXML
方法:

private void initKeyAndCertificate() throws Exception {
    String jksFileName = "C:/Java/keys/testkey.jks";
    FileInputStream fileInputStream = null;

    try {
        fileInputStream = new FileInputStream(new File(jksFileName));
    } catch (FileNotFoundException fe) {
        fe.printStackTrace();
    }

    final KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    char[] KeyStorePass = null;
    keyStore.load(fileInputStream, KeyStorePass);

    key = 
       keyStore.getKey("testkey", new char[]{'t', 'e', 's', 't', 'k', 'e', 'y'});
    certificate = keyStore.getCertificate("testkey");

    try {
        fileInputStream.close();
    } catch (IOException ex) {
        ex.printStackTrace();
    }
}
public Document getSignXML(String signMethod, 
         String digestMethod, String XmlDocAsString) throws Exception {
    final DocumentBuilderFactory documentBuilderFactory = 
            DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setIgnoringElementContentWhitespace(true);
    documentBuilderFactory.setCoalescing(true);
    documentBuilderFactory.setNamespaceAware(true);

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    InputSource is = new InputSource(new StringReader(XmlDocAsString));

    Document doc = builder.parse(is);

    XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");

    List<Transform> transformList = new ArrayList<Transform>();
    Transform transformC14N = 
            xmlSignatureFactory.newTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS, 
                    (XMLStructure) null);
    transformList.add(transformC14N);

    Reference reference = xmlSignatureFactory.newReference("", 
            xmlSignatureFactory.newDigestMethod(digestMethod, null), 
                transformList, null, null);
    SignedInfo signedInfo = 
            xmlSignatureFactory.newSignedInfo(
                    xmlSignatureFactory.newCanonicalizationMethod(
                            CanonicalizationMethod.EXCLUSIVE,
                    (C14NMethodParameterSpec) null),
            xmlSignatureFactory.newSignatureMethod(signMethod, null),
            Collections.singletonList(reference));

    KeyInfoFactory keyInfoFactory = 
            xmlSignatureFactory.getKeyInfoFactory();
    X509Data x509Data = 
            keyInfoFactory.newX509Data(Collections.singletonList(certificate));
    KeyInfo keyInfo = 
            keyInfoFactory.newKeyInfo(Collections.singletonList(x509Data));

    final Node node = doc.getDocumentElement();

    javax.xml.crypto.dsig.XMLSignature xmlSignature = 
            xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
    DOMSignContext signContext = new DOMSignContext(key, node);
    xmlSignature.sign(signContext);

    return doc;
}
private String getSignedXMLAsString(Document signedDocument) {
    DOMSource domSource = new DOMSource(signedDocument);
    StringWriter stringWriter = new StringWriter();
    StreamResult streamResult = new StreamResult(stringWriter);
    TransformerFactory transformerFactory = TransformerFactory.newInstance();
    Transformer transformer = null;

    try {
        transformer = transformerFactory.newTransformer();
    } catch (TransformerConfigurationException e) {
        e.printStackTrace();
    }

    try {
        transformer.transform(domSource, streamResult);
    } catch (TransformerException e) {
        e.printStackTrace();
    }
    return stringWriter.toString();
}
SignatureValue字符串:

i0Ws4MjH7AfPcbHEDCzrMjV+e4O41l43ZXEMHbcCjTmP4WKl7iVH3IcoM6ugS4qMejOHctntH41w 8niOxnCMcjDEnwM6kZtMIJyjrTxMVjSUDyFcKB79Yc/v5hC3dH5deX59W4oxM6Fg72W23s3zcMDD rdRCM5wHqMZW0WvBMoM=

签名包含空格。签名中这些空格的含义是什么?我可以删除它们并连接子字符串吗?

这可能是一个新行,而不是一个空格,它是二进制签名数据的一部分(XML不能处理二进制数据,特别是不允许0字节)

Base64的根目录是通过电子邮件发送二进制数据,每行限制为76个字符,以避免触发邮件软件中的自动换行