java xml數字簽名工具類
阿新 • • 發佈:2019-02-06
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();
}
}
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();
}
}