java - 如何在 Java 中生成内部分离的 XML 签名
问题描述
我无法理解如何将签名节点作为数据节点的兄弟节点。我发现的示例来自 Oracle,但仅涵盖了正常的分离签名,其中 XML 作为 URI 传递给 Reference 对象。
参考 Oracle 示例:https ://docs.oracle.com/javase/8/docs/technotes/guides/security/xmldsig/GenDetached.java
解决方案
一种方法如下:
第 1 步- 将签名 XML 作为字符串获取。
如下更改GenDetached
链接中的示例代码,使输出为字符串。
在类的底部进行了以下更改:
// output the resulting document
OutputStream os = System.out;
//if (args.length > 0) {
// os = new FileOutputStream(args[0]);
//} else {
// os = System.out;
//}
// my changes, to write to a string:
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
StringWriter writer = new StringWriter();
trans.transform(new DOMSource(doc), new StreamResult(writer));
return writer.toString();
还要更改方法签名,使其返回一个字符串 - 例如:
public class GenDetached {
public static String generate() throws Exception {
// code not shown
}
}
第 2 步- 将签名数据添加到目标 XML 文档。
假设我们有以下目标文档:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<data>all your data in here...</data>
</root>
以下代码<Signature>
从签名 XML 中提取节点并将其添加为<root>
文档中节点的子节点:
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xml.sax.InputSource;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import java.io.StringReader;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;
...
String signatureXml = GenDetached.generate();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
// My test document to hold the data and the signature:
String xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><root><data>foo</data></root>";
Document doc = db.parse(new InputSource(new StringReader(xmlString)));
Node docRootNode = doc.getFirstChild();
Document sig = db.parse(new InputSource(new StringReader(signatureXml)));
NodeList sigNodeList = sig.getElementsByTagName("Signature");
Node sigNode = sigNodeList.item(0);
// First import the signature node into the main document:
Node docImportedNode = doc.importNode(sigNode, true);
// Then add the signature node to the main document's root:
docRootNode.appendChild(docImportedNode);
// Show the output (as a String in this case, for the demo):
TransformerFactory tf = TransformerFactory.newInstance();
Transformer trans = tf.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
trans.transform(new DOMSource(doc), new StreamResult(writer));
System.out.println(writer.toString());
结果是这样的(细节省略):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<data>foo</data>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
...
</SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo>
<KeyValue>
<DSAKeyValue>
...
</DSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</root>
希望有帮助。
关于问题中“内部分离”术语的小问题(由Wikipedia提供):
用于在其包含的 XML 文档之外对资源进行签名的 XML 签名称为分离签名;如果它用于签署其包含文档的某些部分,则称为信封签名。
我假设这个例子是后者。
推荐阅读
- c - 如何停止输入换行符
- flutter - 多个颤振模拟器实例
- amazon-web-services - 外部视图查询在 athena 控制台中工作,但在 aws quicksight 中使用时无法工作
- python - 使用循环绘制具有自定义线格式的大型数据集的强大解决方案
- c++ - 在 OMNET++ 中接收到上一个模块的所有消息后如何将一个消息发送到下一个模块
- r - 基于多个条件创建新变量的问题
- typescript - 使用引用将打字稿文件加载到另一个打字稿文件中
- javascript - 有没有办法按类过滤所有以前的元素?
- javascript - 不推荐使用 Node/Express 未处理的承诺拒绝
- flutter - SliverAppBar 仅在滚动后向上推