XML签名(Java)

时间:2015-12-30 15:03:01

标签: java xml-signature

我正在尝试签署一个看起来像这样的小xml:

<?xml version="1.0" encoding="UTF-8"?><test/>    

我必须有这样的东西:

<soapenv:Envelope xmlns:elc="http://schemas.datacontract.org/2004/07/Arise.and.shine" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
    <soapenv:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
            <wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" wsu:Id="X509-F86143B2B1BBA025BF144915430086958">MYCERTIFICAT</wsse:BinarySecurityToken>
            <ds:Signature Id="SIG-F86143B2B1BBA025BF144915430086961" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:SignedInfo>
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                        <ec:InclusiveNamespaces PrefixList="elc soapenv tem" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    </ds:CanonicalizationMethod>
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                    <ds:Reference URI="#id-C412303BE3B390B3D114265182390669">
                        <ds:Transforms>
                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                                <ec:InclusiveNamespaces PrefixList="elc tem" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                            </ds:Transform>
                        </ds:Transforms>
                        <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                        <ds:DigestValue>dx3Bq2k18snVIR+CzEoyLZ3/jRc=</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>KSvaK2EneWvtLXFMmynnBFd0h9PPnuipBa3Lib2pchGOtt8K3g8GsHAT5Vg6nGsNpo1e8SeikrNK4KRtUDne3CjvMh+LOajCpfWwl3u7W1yjp52HUODy+uZOfjL+B+9/kcDLyeJTdbB6KLVCwmD3TDuVA7tApR92VFXKTDT8X8DXrKaEl5a7fPLeb6mYfdAWsxY6Ua5KLZN+IGZAJsWi2SdOEhfHtMzbBvFOXokwysmLaYTmcY0GAkMq74Khna36SVUgxpSDDZoeDiHFGyu5CT9ClbJy8WTEAcJzlok1tvtikGzU//Md0ky0u4fuFiKeQlF+Qw/AxRG7SDqbdcLWrA==</ds:SignatureValue>
                <ds:KeyInfo Id="KI-F86143B2B1BBA025BF144915430086959">
                    <wsse:SecurityTokenReference wsu:Id="STR-F86143B2B1BBA025BF144915430086960">
                        <wsse:Reference URI="#X509-F86143B2B1BBA025BF144915430086958" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
            </ds:Signature>
        </wsse:Security>
    </soapenv:Header>
    <soapenv:Body wsu:Id="id-C412303BE3B390B3D114265182390669" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <tem:SendMessage>
            <tem:request>
                <elc:XmlData>
                    <![CDATA[<?xml version="1.0" encoding="UTF-8"?><test/>]]></elc:XmlData>
            </tem:request>
        </tem:SendMessage>
    </soapenv:Body>
</soapenv:Envelope>

您可以看到要在标题中放入大量信息,并且签名与要发送的真实消息分开。这是我的代码:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.KeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;

import javax.security.cert.X509Certificate;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.XMLStructure;
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.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.KeyValue;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
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;

public class Sign {

    public static void main(String[] args) throws 
    KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, CertificateException, IOException, 
    InvalidAlgorithmParameterException, InstantiationException, IllegalAccessException, ClassNotFoundException, 
    KeyException, SAXException, ParserConfigurationException, MarshalException, XMLSignatureException, TransformerException {
        String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM",(Provider) Class.forName(providerName).newInstance());
        Reference ref = fac.newReference("",fac.newDigestMethod(DigestMethod.SHA1, null),Collections.singletonList( fac.newTransform(Transform.ENVELOPED, (XMLStructure) null)),null, null);
        SignedInfo si = fac.newSignedInfo(
            fac.newCanonicalizationMethod(
                CanonicalizationMethod.EXCLUSIVE,
                (XMLStructure) null
            ),
            fac.newSignatureMethod(
                    SignatureMethod.RSA_SHA1, 
                    null
            ),
            Collections.singletonList(ref)
        );

        FileInputStream is = new FileInputStream("D:\\Step 1\\mock\\NewJKS.jks");

        KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystore.load(is, null);
        //Enumeration<String> myEnum = keystore.aliases();
        for (Enumeration<String> e = keystore.aliases(); e.hasMoreElements();){
            System.out.println(e.nextElement());
        }               

        String alias = "toto";
        Key key = keystore.getKey(alias, null); 
        System.out.println(key);
        KeyPair kp = null;
        if (key instanceof PrivateKey) {
          // Get certificate of public key
          Certificate cert = keystore.getCertificate(alias);
          // Get public key
          PublicKey publicKey = cert.getPublicKey();
          // Return a key pair
          kp = new KeyPair(publicKey, (PrivateKey) key);          
//        System.out.println(kp);
        }


        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(kp.getPublic());
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = dbf.newDocumentBuilder().parse(new FileInputStream("D:\\Step 1\\mock\\XMLTestData.xml"));
        DOMSignContext dsc = new DOMSignContext(kp.getPrivate(), doc.getDocumentElement());
        XMLSignature signature = fac.newXMLSignature(si, ki);
        signature.sign(dsc);
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc),new StreamResult(new FileOutputStream("D:\\Step 1\\mock\\mySignedFile2.xml")));

    }

}

我得到的是这样的:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<test>
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
            <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>iUqbN+l20aP00zS0qltBAv2oDbc=</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>NiLEgObJbPot9kUJQ3kHi2z/1e6SGCqiZbrbAtc1snZp8MxoMothOA3dyqi6sDOBiLfdz7hRdEj+
gMwvkxci+KaqBtK2Rv9l9eE+/X5rjJz0aQM2Dq9kxB3BFwCSLdK0uMoO7YKAr6e6QirRI70npERt
gzAu4mriUpSkm5gbtWg=</SignatureValue>
        <KeyInfo>
            <KeyValue>
                <RSAKeyValue>
                    <Modulus>tDcB3pWauMi0lZl7U/1g6Zj2dmeaokXJkbnytLtWCC1tyPsiWGNPxlKygVF+Pm+w4jciJxDzSxex
XY4jKTZz3a7qnq9EE/qo1ESzXpp+tus83iZFpPH+VpqBmcf1eutzSyEAqyYybAWm5p5q+2IqW+9H
UXIjgJczkCX/5nU7M6s=</Modulus>
                    <Exponent>AQAB</Exponent>
                </RSAKeyValue>
            </KeyValue>
        </KeyInfo>
    </Signature>
</test>

我的第一个问题是如何修改我的源代码以获得包络签名?

1 个答案:

答案 0 :(得分:0)

有很多方法可以做。你的<test>应该是正文。 我最喜欢的是下面的。

  1. 使用空白标题创建或模仿soap信封结构。 动态地获取你的标题并做你现在正在做的事情。正在说添加 标题中的所有内容,无论你想签名如何 发行人名称或序列号。
  2. 将最终文件传递给签名方法,以便与正文签署 信息并将其添加到标题中。
  3. 祝你好运。

    它可能会有所帮助。

       Element headerElement = null;
       NodeList nodes = doc.getElementsByTagNameNS ("http://schemas.xmlsoap.org/soap/envelope/","Header");
       headerElement = (Element)nodes.item(0);
    
       // Create an XMLSignature instance
       Element soapsec = doc.createElementNS("", "SOAP-SEC:Signature");
       soapsec.setAttributeNS("", "mustUnderstand", "1");
       soapsec.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:SOAP-SEC", "http://www.schemas.xmlsoap.org/soap/security/2000-10");
    
       Transforms transforms = new Transforms(doc);
       transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
       transforms.addTransform(Transforms.TRANSFORM_C14N_WITH_COMMENTS);
       XMLSignature sig = new XMLSignature(doc,"",XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);       
    
       soapsec.appendChild(sig.getElement());
       headerElement.appendChild(soapsec);
       // Specify the transforms
       sig.addDocument("#Body", transforms, org.apache.xml.security.utils.Constants.ALGO_ID_DIGEST_SHA1);
    
    
      // Get the certificate and send for signing it will do what you required.
         sig.sign(privateKey);