有没有更简单的方法在Java中签署XML文档?

时间:2010-01-12 20:49:06

标签: java xml cryptography digital-signature xml-signature

我正在尝试digitally sign an XML document使用Java。我有一个实现工作,我发现在javax.xml.crypto.dsig包中使用了各种实现。

但是,我目前的实施方式与many我所看到的examples相似 - 它相当冗长,涉及使用java.xml.crypto.dsig中不少于23种不同的API类,{ {1}}和javax.xml.transform个套餐等。感觉我已经进入了factory factory factory土地,我只花了几个小时来弄清楚发生了什么。

我的问题是,有更简单的方法吗?如果我有公钥/私钥文件,并且我想在XML文档中添加java.security,那么那里有一个图书馆,只是让我打电话:

<Signature/>

...没有所有的XMLSignatureFactory / CanonicalizationMethod / DOMSignContext疯狂?

我不是非常精通密码术,而且像我这样的开发人员试图熟悉数字签名,Java提供的API似乎相当令人生畏。如果所有这些都是必要的,或者目前没有友好的API,那很好,我愿意接受这个作为答案。我只是想知道我是否在这里不必要地采取了艰难的道路。

3 个答案:

答案 0 :(得分:10)

请看Apache XML Security。要使用该包生成并验证签名,请在src_samples/org/apache/xml/security/samples/signature/中签出样本。

答案 1 :(得分:10)

从Apache Santuario CreateSignature示例构建,我能想到的最简单的事情就是这样。没有main()及其随附的output(),它就是20行

import java.io.*;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.io.IOUtils;
import org.apache.xml.security.Init;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.ElementProxy;
import org.w3c.dom.Document;

public class CreateSignature {

    private static final String PRIVATE_KEY_ALIAS = "test-alias";
    private static final String PRIVATE_KEY_PASS = "test";
    private static final String KEY_STORE_PASS = "test";
    private static final String KEY_STORE_TYPE = "JKS";

    public static void main(String... unused) throws Exception {
        final InputStream fileInputStream = new FileInputStream("test.xml");
        try {
            output(signFile(fileInputStream, new File("keystore.jks")), "signed-test.xml");
        }
        finally {
            IOUtils.closeQuietly(fileInputStream);
        }
    }

    public static ByteArrayOutputStream signFile(InputStream xmlFile, File privateKeyFile) throws Exception {
        final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(xmlFile);
        Init.init();
        ElementProxy.setDefaultPrefix(Constants.SignatureSpecNS, "");
        final KeyStore keyStore = loadKeyStore(privateKeyFile);
        final XMLSignature sig = new XMLSignature(doc, null, XMLSignature.ALGO_ID_SIGNATURE_RSA);
        final Transforms transforms = new Transforms(doc);
        transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
        sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);
        final Key privateKey = keyStore.getKey(PRIVATE_KEY_ALIAS, PRIVATE_KEY_PASS.toCharArray());
        final X509Certificate cert = (X509Certificate)keyStore.getCertificate(PRIVATE_KEY_ALIAS);
        sig.addKeyInfo(cert);
        sig.addKeyInfo(cert.getPublicKey());
        sig.sign(privateKey);
        doc.getDocumentElement().appendChild(sig.getElement());
        final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        outputStream.write(Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_WITH_COMMENTS).canonicalizeSubtree(doc));
        return outputStream;
    }

    private static KeyStore loadKeyStore(File privateKeyFile) throws Exception {
        final InputStream fileInputStream = new FileInputStream(privateKeyFile);
        try {
            final KeyStore keyStore = KeyStore.getInstance(KEY_STORE_TYPE);
            keyStore.load(fileInputStream, KEY_STORE_PASS.toCharArray());
            return keyStore;
        }
        finally {
            IOUtils.closeQuietly(fileInputStream);
        }
    }

    private static void output(ByteArrayOutputStream signedOutputStream, String fileName) throws IOException {
        final OutputStream fileOutputStream = new FileOutputStream(fileName);
        try {
            fileOutputStream.write(signedOutputStream.toByteArray());
            fileOutputStream.flush();
        }
        finally {
            IOUtils.closeQuietly(fileOutputStream);
        }
    }
}

答案 2 :(得分:3)

我查看了签署XML文件的所有选项,并决定使用非标准方法。标准太冗长了。此外,我不需要与标准兼容 - 我只需要在XML块上签名。

“签署”XML块的最简单方法可能是使用带有分离签名的GPG。