java xml数字签名工具类

package test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLObject;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.keyinfo.X509IssuerSerial;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

/**
 * xml数字签名 工具类  
 * @author Administrator
 *
 */
@SuppressWarnings("restriction")
public class XMLSignUtils {
    
    private static String keyStoreSignFilePath = "e:/gdmlh.keystore";  //"e:/gdmlh.pfx" 签名证书可以是经过转换后的keystore,也可以是pfx证书  用不同store,初始化实例类型不一样 keystore<==>jks pfx<==>pkcs12
    private static String keyStoreSignFilePassword = "12345678"; //store 保护密码
    private static String privateKey = "dss"; //别名
    private static String privateKeyPassword = "12345678"; //私钥保护密码

    /**
     * 1\封装模式    签名和原始xml文件内容在同一个XML文档中,原始xml文件内容作为签名的内部节点;Enveloping-数据对象包含在与Signature元素相同的XML文档中,并且被进一步包含在Signature元素(例如作为Object的子元素)中。
     * @param originalXmlFilePath 待签名xml文件路径
     * @param destnSignedXmlFilePath 签名后xml文件输出路径
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     * @throws KeyException
     * @throws FileNotFoundException
     * @throws SAXException
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws MarshalException
     * @throws XMLSignatureException
     * @throws TransformerException
     * @throws KeyStoreException
     * @throws CertificateException
     * @throws UnrecoverableEntryException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     * @author wyl
     * @date 2016-10-13
     */
    /*示例:
        <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
        <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
        <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
        <Reference URI="#DataObjectId">
        <Transforms>
        <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
        <DigestValue>pHdUADSXDNMmM7py0zuNlx6gQKE=</DigestValue>
        </Reference>
        </SignedInfo>
        <SignatureValue>Ym9uW9ePzi1f0F6vMtTMIpiUC2gNI0o2X8gYvF7yiuXLtUPqN4G1yavil/VTrbFvPxpfEZkdlxL7PU+9oYie4k4pF+fbQhxbkSr5v81t+JHtt37evQyTvWi+8gi7kU/ZbjpF4Msk7PuwrDUOez1e6bWBBvyIvet6UfMN3YXP92U=</SignatureValue>
        <KeyInfo>
        <X509Data>
        <X509IssuerSerial>
        <X509IssuerName>CN=NETCA Individual ClassA CA, OU=Individual ClassA CA, O=NETCA Certificate Authority, C=CN</X509IssuerName>
        <X509SerialNumber>53721960771501034418789216508892913400</X509SerialNumber>
        </X509IssuerSerial>
        <X509Certificate>MIID9zCCAt+gAwIBAgIQKGp5KavX8ujDBgo/bvee+DANBgkqhkiG9w0BAQUFADB3MQswCQYDVQQGEwJDTjEkMCIGA1UEChMbTkVUQ0EgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR0wGwYDVQQLExRJbmRpdmlkdWFsIENsYXNzQSBDQTEjMCEGA1UEAxMaTkVUQ0EgSW5kaXZpZHVhbCBDbGFzc0EgQ0EwHhcNMTIwNDE4MTYwMDAwWhcNMTMwNDE5MTU1OTU5WjBkMQswCQYDVQQGEwJDTjESMBAGA1UECBMJR3Vhbmdkb25nMSUwIwYDVQQDHhxOKk66bUuL1QAyADAAMQAxADAANAAyADIAMQA2MRowGAYJKoZIhvcNAQkBFgt6c0BjbmNhLm5ldDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1ydRUYSdoofmMeyrY2i/pwzjUaGYLWQyS1W2Z30+V/uSiRRR/QwpeiSOuJcnPAkjuvgiTMz4+eWzWn9rHS56I5RPJaf27juRQoA3Ej+xSahRZSWs2hv0rBXRikAStuwo4uk3hI+Tct98dN9EWBJLPJdYj7ZNMnY8wg+wG91C88kCAwEAAaOCARQwggEQMB8GA1UdIwQYMBaAFLFHZEQZX2XMQLsGS+l5BOAe7LVOMB0GA1UdDgQWBBS6/ou1RSKMmjcY8p2cNjRL/3aaxDBXBgNVHSAEUDBOMEwGCisGAQQBgZJIAQowPjA8BggrBgEFBQcCARYwaHR0cDovL3d3dy5jbmNhLm5ldC9jcy9rbm93bGVkZ2Uvd2hpdGVwYXBlci9jcHMvMBYGA1UdEQQPMA2BC3pzQGNuY2EubmV0MAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgbAMD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly9jbGFzc2FjYTEuY25jYS5uZXQvY3JsL0luZGl2aWR1YWxDQS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAAYW3lOrOLP27xPsec3TvYYTjSdl8sTLaxy3UtFFt3Bgx0CgjiGyoDtacr+2xUk57VLK7XtmtZx/aN+GGjJUpiKni9em1KoxyXQDIrEMjhzS5VEkwlO0xrJsAASICtM9smGWe5yCVm3RGD5U7F9xi8l1BgIsaRWUVzQ2ObzXjA8AMviTmcqMEZGDmNVlyxRyg5yN9GqOWQBthDWZsdqU8wEoI4e+gHyMwCIs4baDtkrb1fyDrcxsuDKnSU0zcfgwpOzFLTht+Ibu4J00s95ciDjXCQ5h2Z2aW6r3cMf/ap5g9FvCm/A2DEAS2Hqws1fvALNJgPehnDdfhOiFz/2MiXY=</X509Certificate>
        </X509Data>
        </KeyInfo>
        <Object Id="DataObjectId">
        <dj xmlns="http://cmsland.com/yjj_qyjk_kc.xsd" pdsj="2012-07-01"><tm bwm="98265089672103" bzgg="30片/盒" scph="20120501" scrq="2012-05-01" yxqz="2015-05-01" kcsl="100" /><tm bwm="98265089672103" bzgg="30片/盒" scph="20120701" scrq="2012-07-01" yxqz="2015-07-01" kcsl="200" /></dj>
        </Object>
        </Signature>*/
    public static void generateXMLDigitalSignatureByEnveloping(String originalXmlFilePath, String destnSignedXmlFilePath)
             throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyException, FileNotFoundException, SAXException, IOException, ParserConfigurationException, MarshalException, XMLSignatureException, TransformerException, KeyStoreException, CertificateException, UnrecoverableEntryException, InstantiationException, IllegalAccessException, ClassNotFoundException
           {
             XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
             Reference ref = fac.newReference
                      ("#DataObjectId", fac.newDigestMethod(DigestMethod.SHA1, null),
                       Collections.singletonList
                        (fac.newTransform
                         (Transform.ENVELOPED, (TransformParameterSpec) null)),
                          null, null);
             DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
             dbf.setNamespaceAware(true);
             org.w3c.dom.Document doc = dbf.newDocumentBuilder().parse(new FileInputStream(originalXmlFilePath));
             org.w3c.dom.Element documentElement = doc.getDocumentElement();
             DOMStructure domStructure = new DOMStructure(documentElement);
             XMLObject newXMLObject = fac.newXMLObject(Collections.singletonList(domStructure), "DataObjectId", null, null);
             SignedInfo si = fac.newSignedInfo
               (fac.newCanonicalizationMethod(
                       CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec)null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
               Collections.singletonList(ref));

             KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
//             KeyStore ks = KeyStore.getInstance("PKCS12");  //可以不经转换直接用pfx证书
             ks.load(new FileInputStream(keyStoreSignFilePath), keyStoreSignFilePassword.toCharArray());
             KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry)ks.getEntry(privateKey, new KeyStore.PasswordProtection(privateKeyPassword.toCharArray()));
             X509Certificate cert = (X509Certificate)keyEntry.getCertificate();
          /*   //直接读取证书
             CertificateFactory cf = CertificateFactory.getInstance("X.509");
             FileInputStream fis = new FileInputStream(new File("e:/gdmlhenc.cer"));
             X509Certificate cert = (X509Certificate) cf.generateCertificate(fis);
             fis.close();
             PublicKey publicKey = cert.getPublicKey();*/
           //创建签名对象
             KeyInfoFactory kif = fac.getKeyInfoFactory();
             X509IssuerSerial newX509IssuerSerial = kif.newX509IssuerSerial(cert.getIssuerX500Principal().getName(), cert.getSerialNumber());
             List x509Content = new ArrayList();
             x509Content.add(newX509IssuerSerial);
             x509Content.add(cert);
             X509Data xd = kif.newX509Data(x509Content);
             KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));

             XMLSignature signature = fac.newXMLSignature(si, ki,Collections.singletonList(newXMLObject),null,null);
             Document newDocument = dbf.newDocumentBuilder().newDocument();
             DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), newDocument);
             signature.sign(dsc);
             OutputStream os = new FileOutputStream(destnSignedXmlFilePath);
             TransformerFactory tf = TransformerFactory.newInstance();
             Transformer trans = tf.newTransformer();
             trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");//不要头信息
             trans.transform(new DOMSource(newDocument.getDocumentElement()), new StreamResult(os));
             os.close();
           }
    /**
     * 2\ Enveloped-数据对象包含在与Signature元素相同的XML文档中,并且实际上把Signature包括为一个子元素。
     * @param originalXmlFilePath
     * @param destnSignedXmlFilePath
     * @throws NoSuchAlgorithmException
     * @throws InvalidAlgorithmParameterException
     * @throws KeyException
     * @throws FileNotFoundException
     * @throws SAXException
     * @throws IOException
     * @throws ParserConfigurationException
     * @throws MarshalException
     * @throws XMLSignatureException
     * @throws TransformerException
     * @throws KeyStoreException
     * @throws CertificateException
     * @throws UnrecoverableEntryException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     * @author wyl
     * @date 2016-10-13
     */
    /*示列
    <?xml version="1.0" encoding="UTF-8"?>
    <PurchaseOrder>
     <Item number="130046593231">
      <Description>Video Game</Description>
      <Price>10.29</Price>
     </Item>
     <Buyer id="8492340">
      <Name>My Name</Name>
      <Address>
       <Street>One Network Drive</Street>
       <Town>Burlington</Town>
       <State>MA</State>
       <Country>United States</Country>
       <PostalCode>01803</PostalCode>
      </Address>
     </Buyer>
     <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
      <SignedInfo>
       <CanonicalizationMethod
        Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
       <SignatureMethod
        Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
       <Reference URI="">
        <Transforms>
         <Transform
          Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
        <DigestValue>tVicGh6V+8cHbVYFIU91o5+L3OQ=</DigestValue>
       </Reference>
      </SignedInfo>
      <SignatureValue>
       dJDHiGQMaKN8iPuWApAL57eVnxz2BQtyujwfPSgE7HyKoxYtoRB97ocxZ
       8ZU440wHtE39ZwRGIjvwor3WfURxnIgnI1CChMXXwoGpHH//Zc0z4ejaz
       DuCNEq4Mm4OUVTiEVuwcWAOMkfDHaM82awYQiOGcwMbZe38UX0oPJ2DOE=
      </SignatureValue>
      <KeyInfo>
       <X509Data>
        <X509SubjectName>
         CN=My Name,O=Test Certificates Inc.,C=US
        </X509SubjectName>
        <X509Certificate>
         MIIB9zCCAWCgAwIBAgIERZwdkzANBgkqhkiG9w0BAQUFADBAMQswCQYD
         VQQGEwJVUzEfMB0GA1UEChMWVGVzdCBDZXJ0aWZpY2F0ZXMgSW5jLjEQ
         MA4GA1UEAxMHTXkgTmFtZTAeFw0wNzAxMDMyMTE4MTFaFw0zMTA4MjUy
         ...
        </X509Certificate>
       </X509Data>
      </KeyInfo>
     </Signature>
    </PurchaseOrder>*/
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void generateXMLDigitalSignatureByEnveloed(String originalXmlFilePath, String destnSignedXmlFilePath)
            throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, KeyException, FileNotFoundException, SAXException, IOException, ParserConfigurationException, MarshalException, XMLSignatureException, TransformerException, KeyStoreException, CertificateException, UnrecoverableEntryException, InstantiationException, IllegalAccessException, ClassNotFoundException
            {
        // Create a DOM XMLSignatureFactory that will be used to
        // generate the enveloped signature.
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Create a Reference to the enveloped document (in this case,
        // you are signing the whole document, so a URI of "" signifies
        // that, and also specify the SHA1 digest algorithm and
        // the ENVELOPED Transform.
        Reference ref = fac.newReference
         ("", fac.newDigestMethod(DigestMethod.SHA1, null),
          Collections.singletonList
           (fac.newTransform
            (Transform.ENVELOPED, (TransformParameterSpec) null)),
             null, null); //这里与上面有点区别注意
        // Create the SignedInfo.
        SignedInfo si = fac.newSignedInfo
         (fac.newCanonicalizationMethod
          (CanonicalizationMethod.INCLUSIVE,
           (C14NMethodParameterSpec) null),
            fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
             Collections.singletonList(ref));
        // Load the KeyStore and get the signing key and certificate.
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(new FileInputStream(keyStoreSignFilePath), keyStoreSignFilePassword.toCharArray());
        KeyStore.PrivateKeyEntry keyEntry =
            (KeyStore.PrivateKeyEntry) ks.getEntry
                (privateKey, new KeyStore.PasswordProtection(privateKeyPassword.toCharArray()));
        X509Certificate cert = (X509Certificate) keyEntry.getCertificate();

        // Create the KeyInfo containing the X509Data.
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        List x509Content = new ArrayList();
        x509Content.add(cert.getSubjectX500Principal().getName());
        x509Content.add(cert);
        X509Data xd = kif.newX509Data(x509Content);
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
        // Instantiate the document to be signed.
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = dbf.newDocumentBuilder().parse
            (new FileInputStream(originalXmlFilePath));

        // Create a DOMSignContext and specify the RSA PrivateKey and
        // location of the resulting XMLSignature's parent element.
        DOMSignContext dsc = new DOMSignContext
            (keyEntry.getPrivateKey(), doc.getDocumentElement());

        // Create the XMLSignature, but don't sign it yet.
        XMLSignature signature = fac.newXMLSignature(si, ki);

        // Marshal, generate, and sign the enveloped signature.
        signature.sign(dsc);
        // Output the resulting document.
        OutputStream os = new FileOutputStream(destnSignedXmlFilePath);
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
        os.close();
            }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值