我签署了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();
}
}
getSignXML
方法:
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;
}
getSignedXMLAsString
方法:
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();
}
signatureValueAsString:
i0Ws4MjH7AfPcbHEDCzrMjV+e4O41l43ZXEMHbcCjTmP4WKl7iVH3IcoM6ugS4qMejOHctntH41w 8niOxnCMcjDEnwM6kZtMIJyjrTxMVjSUDyFcKB79Yc/v5hC3dH5deX59W4oxM6Fg72W23s3zcMDD rdRCM5wHqMZW0WvBMoM=
签名包含空格。签名中这些空格的含义是什么?我可以删除它们并连接子串吗?
答案 0 :(得分:1)
这可能是一个新行,而不是空格,它是二进制签名数据Base64 encoding的一部分(XML无法处理二进制数据,尤其是不允许使用0字节)。
Base64,它通过电子邮件发送二进制数据的根源,每行限制为76个字符,以避免触发邮件软件中的自动换行。