当前位置: 首页 > 面试题库 >

Java等效于C#XML签名方法

皇甫学海
2023-03-14
问题内容

我编写了以下.NET Framework 3.5
C#方法,该方法获取XML文档的位置和X509数字证书(带有私钥)的对象表示形式,并将XML文档作为嵌入了XML签名(XMLDsig)的对象返回作为根的第一个子元素。

事实是,我迫切需要能够使用Java SE 6执行完全相同的过程,但是我很久没有写过任何Java了,也不知道从哪里开始。

谁能在Java代码中提供产生 完全相同的 XML输出的等效方法吗?

private static XmlDocument SignXmlDocument(string xmlFilePath, X509Certificate2 certificate)
{
    // load xml from disk preserving whitespaces
    XmlDocument xmlDocument = new XmlDocument { PreserveWhitespace = true };
    xmlDocument.Load(xmlFilePath);

    // create signed xml with a same-document reference containing an enveloped-signature transform
    SignedXml signedXml = new SignedXml(xmlDocument) { SigningKey = certificate.PrivateKey };
    Reference reference = new Reference { Uri = "" };
    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();            
    reference.AddTransform(env);
    signedXml.AddReference(reference);

    // embed public key information for signature validation purposes
    KeyInfo keyInfo = new KeyInfo();
    KeyInfoX509Data keyInfoX509Data = new KeyInfoX509Data(certificate, X509IncludeOption.ExcludeRoot);
    keyInfo.AddClause(keyInfoX509Data);
    signedXml.KeyInfo = keyInfo;

    // compute and retreive the signature xml
    signedXml.ComputeSignature();          
    XmlElement xmldsigXmlElement = signedXml.GetXml();

    // insert the signature xml into the xml document as first child of the root element
    xmlDocument.DocumentElement.PrependChild(xmlDocument.ImportNode(xmldsigXmlElement, true));

    return xmlDocument;
}

问题答案:

以下在Java中做同样的事情。它需要磁盘上的PKCS12证书文件。

import java.util.*;
import java.io.*;
import java.security.KeyStore;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.cert.X509Certificate;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

public class XMLSigner {

    public static void signXmlDocumentOnDisk(String fileToBeSignedPath, String signedFileSavePath, String pkcs12CertificateFilePath, String password) throws Exception {
        XMLSignatureFactory fac = getXMLSignatureFactory();
        Reference ref = getSHA1WholeDocumentEnvelopedTransformReference(fac);
        SignedInfo si = getSignedInfo(fac, ref);
        PrivateKeyEntry keyEntry = loadPKCS12KeyStoreAndGetSigningKeyEntry(pkcs12CertificateFilePath, password);
        KeyInfo ki = getKeyInfoWithX509Data(keyEntry, fac);
        Document doc = instantiateDocumentToBeSigned(fileToBeSignedPath);
        signDocumentAndPlaceSignatureAsFirstChildElement(doc, keyEntry, fac, si, ki);
        writeResultingDocument(doc, signedFileSavePath);
    }

    private static XMLSignatureFactory getXMLSignatureFactory() {
        return XMLSignatureFactory.getInstance("DOM");
    }

    private static Reference getSHA1WholeDocumentEnvelopedTransformReference(XMLSignatureFactory fac) throws Exception {
        return 
            fac.newReference(
                "", 
                fac.newDigestMethod(DigestMethod.SHA1, null),
                Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)),
                null, 
                null
            );
    }

    private static SignedInfo getSignedInfo(XMLSignatureFactory fac, Reference ref) throws Exception {
        return 
            fac.newSignedInfo(
                fac.newCanonicalizationMethod(
                    CanonicalizationMethod.INCLUSIVE, 
                    (C14NMethodParameterSpec) null
                ),
                fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
                Collections.singletonList(ref)
            );
    }

    private static PrivateKeyEntry loadPKCS12KeyStoreAndGetSigningKeyEntry(String pkcs12CertificateFilePath, String password) throws Exception {
        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(new FileInputStream(pkcs12CertificateFilePath), password.toCharArray());    
        return (PrivateKeyEntry)ks.getEntry(ks.aliases().nextElement(), new KeyStore.PasswordProtection(password.toCharArray()));           
    }

    private static KeyInfo getKeyInfoWithX509Data(PrivateKeyEntry keyEntry, XMLSignatureFactory fac) {
        X509Certificate cert = (X509Certificate) keyEntry.getCertificate();
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        List x509Content = new ArrayList();
        x509Content.add(cert.getSubjectX500Principal().getName());
        x509Content.add(cert);
        X509Data xd = kif.newX509Data(x509Content);
        return kif.newKeyInfo(Collections.singletonList(xd));
    }

    private static Document instantiateDocumentToBeSigned(String fileToBeSignedPath) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        return dbf.newDocumentBuilder().parse(new FileInputStream(fileToBeSignedPath));
    }

    private static void signDocumentAndPlaceSignatureAsFirstChildElement(Document doc, PrivateKeyEntry keyEntry, XMLSignatureFactory fac, SignedInfo si, KeyInfo ki) throws Exception {
        DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), doc.getDocumentElement(), doc.getDocumentElement().getFirstChild());
        XMLSignature signature = fac.newXMLSignature(si, ki);
        signature.sign(dsc);
    }

    private static void writeResultingDocument(Document doc, String signedFileSavePath) throws Exception {
        OutputStream os = new FileOutputStream(signedFileSavePath);
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}


 类似资料:
  • 问题内容: 我在Java中使用以下语句: 请提出等效的C#。 问题答案: 我不知道框架中执行此操作的任何内容,但是实现起来很容易: 或者,如果您要指定计数而不是开始/结束:

  • 问题内容: 我正在开发Java程序,我确实需要能够以一定的频率和持续时间播放声音,类似于c#方法System.Beep,我知道如何在C#中使用它,但是我找不到用Java做到这一点的一种方法。是否有等效的方法或另一种方法? 问题答案: 我认为没有办法在便携式2 Java 中用“哔”声播放音乐1。您将需要使用我认为的API …除非找到可以为您简化事情的第三方库。 如果您想走这条路,那么此页面可能会给您

  • 问题内容: 我有以下用于加密的c ++代码片段: Java中的c ++加密等效于什么? 我看到有算法,然后我看到。 这与openssl加密有关。但不知道什么是等效的。本质上,我想要与c ++代码生成的输出相同的输出。 我问什么是等效的或在这里使用的加密名称是什么,所以我可以从那里得到它。 编辑:不要求任何人将代码转换为Java,而只是要求执行相同操作的相应程序包或类。 问题答案: 您要转换的代码使

  • 问题内容: 在C#中,您可以匿名定义委托(即使它们不过是语法糖)。例如,我可以这样做: 是否可以在Java中传递这样的代码?我正在使用处理框架,该框架具有Java的较旧版本(它没有泛型)。 问题答案: Java 8之前的版本: 最接近委托的Java是单方法接口。您可以使用匿名内部类。 Java 8及更高版本: Java 8 在该语言中添加了lambda表达式。

  • 问题内容: 我是一名普通的C#开发人员,但有时我会使用Java开发应用程序。我想知道是否有Java等效于C#async / await?简单来说,java相当于什么: 问题答案: 不,在Java中-甚至在v5之前的C#中,都没有等效的异步/等待方式。 在后台构建状态机是一项相当复杂的语言功能。 Java中对异步/并发的 语言 支持相对较少,但是该软件包包含许多与此相关的有用 类 。(不完全等同于任

  • 问题内容: Go中是否有类似java finalize的方法?如果我有一个类似的类型结构 如何确保在垃圾回收对象时关闭文件? 问题答案: iirc。但是它被认为是一件坏事,并且不能保证在程序退出之前就可以运行 编辑:如下所述,当前程序包已在文件上调用。但是,不应该依赖。作为一个示例,我有一个类似文件服务器的应用程序,但我忘记了关闭打开的文件。在GC选取并打开其终结器之前,该过程通常可以获取约300