XML digital signatures are mainly used for authentication of the sender, to ensure data integrity,to prevent modification of the data during transmission etc.In this tutorial  we will see how to create XML Digital Signatures and how to use them in order to sign xml documents.

An xml digital signature consists of several elements.The structure of the signature is shown in the below snippet

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
            <CanonicalizationMethod />
            <SignatureMethod />
            <Reference URI="">
                <Transforms>
                    <Transform />
                </Transforms>
                <DigestMethod />
                <DigestValue></DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>
        </SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate/>
            </X509Data>
            <KeyValue>
                <RSAKeyValue>
                    <Modulus>
                    </Modulus>
                    <Exponent/>
                </RSAKeyValue>
            </KeyValue>
        </KeyInfo>
    </Signature>
 

Before we proceed in the implementation lets see the meaning of the above mentioned elements:

SignedInfo:A container element that consists of the canonicalization algorithm,the signature algorithm and one or more references.

CanonicalizationMethod: Defines the canocalization algorithm that will be used
Signature Method: Defines the algorithm that will be used for creating and validating the signature

Reference:A container element that contains the digest algorithm and value and also the trasformations that can be applied to the data before digesting.

Transforms:Also a container element that contains the transformations that will be applied to the data.

DigestMethod:Specifies the hashing algorithm for the digest calculation

Digest Value:Contains the digest value in an encoded form

KeyInfo:This element contain all the appropriate data such as keys and certificates that the recipients of the document can use for validating the document.In the above mentioned signature keyInfo elements contain the X509 certifcate and  RSA key data.

In this example we will use RSA-SHA1 as a signature method and also a keystore file (.ks) from which we will take the needed data for the X509 certificate.
 

package com.javaonly.xmlDigitalSignatures;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStore.Entry;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.UnrecoverableEntryException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Collections;

import javax.xml.crypto.MarshalException;
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.crypto.dsig.keyinfo.X509Data;
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.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;

public class XMLDigitalSignatureTest {

    public static void main(String args[]) {

        String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
        try {

            XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM", (Provider) Class.forName(providerName).newInstance());
            DigestMethod digestMethod = factory.newDigestMethod(DigestMethod.SHA1, null);
            Transform transform = factory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null);
            Reference reference = factory.newReference("", digestMethod, Collections.singletonList(transform), null, null);
            CanonicalizationMethod canonicalizationMethod = factory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, (C14NMethodParameterSpec) null);
            SignatureMethod signatureMethod = factory.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
            SignedInfo signedInfo = factory.newSignedInfo(canonicalizationMethod, signatureMethod, Collections.singletonList(reference));

            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            kpg.initialize(512);
            KeyPair keyPair = kpg.generateKeyPair();
            KeyInfoFactory keyInfoFactory = factory.getKeyInfoFactory();

            KeyStore keyStore = KeyStore.getInstance("JKS");
            keyStore.load(new FileInputStream("C:\\keystore.ks"), null);
            KeyStore.TrustedCertificateEntry entry = (KeyStore.TrustedCertificateEntry) keyStore.getEntry("gw2test", null);
            KeyValue keyValue = keyInfoFactory.newKeyValue(entry.getTrustedCertificate().getPublicKey());

           
            
            X509Certificate cert = (X509Certificate) entry.getTrustedCertificate();
            List x509 = new ArrayList();

            x509.add(cert);
            X509Data x509Data = keyInfoFactory.newX509Data(x509);
            List items = new ArrayList();

            items.add(x509Data);
            items.add(keyValue);
            KeyInfo keyInfo = keyInfoFactory.newKeyInfo(items);

            DocumentBuilderFactory dbf =
                    DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            Document doc =
                    dbf.newDocumentBuilder().
                    parse(new FileInputStream("C:\\XmlFile.xml"));

            DOMSignContext dsc = new DOMSignContext(keyPair.getPrivate(), doc.getDocumentElement());

            XMLSignature signature = factory.newXMLSignature(signedInfo, keyInfo);
            signature.sign(dsc);
       
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(
                    new DOMSource(doc),
                    new StreamResult(
                    new FileOutputStream("C:\\mySignedFile.xml")));
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (KeyException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (TransformerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (MarshalException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (XMLSignatureException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (KeyStoreException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (CertificateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnrecoverableEntryException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

Finally the result signature will be something like this:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
        <SignedInfo>
            <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
            <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>Nrrv6wLNZV/uuy0dJUR5GDhsLE3=</DigestValue>
            </Reference>
        </SignedInfo>
        <SignatureValue>aq4zp8gmb16+YPFYC6OrSR9WAQDo3aXsK+XqLO3ZPUPn4LA3+WpI75eUeajDlrYM9CNZtIGAQb2n
            trZVVC6EMA==
        </SignatureValue>
        <KeyInfo>
            <X509Data>
                <X509Certificate>MIIHnTCCBgGgAwIBAgIIWqsaODRqwXQwDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UEBhMCREUxJTAj
                    BgNVBAoTHFQtU3lzdGVtcyBJbnRlcm5hdGlvbmFsIEdtYkgxHjAcBgNVBAsTFVRydXN0IENlbnRl
                    ciBTZXJ2aWNlczEgMB4GA1UEAxMXVGVsZVNlYyBTZXJ2ZXJQYXNzIENBIDEwHhcNMTIwNTA3MTA1
                    NDE4WhcNMTQwNTEyMjM1OTU5WjCBwDELMAkGA1UEBhMCREUxGjAYBgNVBAoTEVNDSFVGQSBIb2xk
                    aW5nIEFHMRYwFAYDVQQLEw1TeXN0ZW10ZWNobmlrMQ8wDQYDVQQIEwZIZXNzZW4xEjAQBgNVBAcT
                    CVdJRVNCQURFTjEyMDAGCSqGSIb3DQEJARYjemVydGlmaWthdGUtc3lzdGVtdGVjaG5pa0BzY2h1
                    ZmEuZGUxJDAiBgNVBAMTG3htbDItZ2F0ZXdheS10ZXN0LnNjaHVmYS5kZTCCASIwDQYJKoZIhvcN
                    AQEBBQADggEPADCCAQoCggEBAMdWBkF1V2MknNA1N4ZWxesjDFkugVWVpxOw0QgV/+nwjACxA4N/
                    AODwaid9SIbs6e0JRD7J0IZTAmJkZjlAOjB3V4zRujfwG0ZoiLtq7iFcbqMyEJ4mimTONAK3heHR
                    nGeqt493/4zbl0LL5fY6+xx+XfMYvuTo+t2/pbaSMAU5pISdfeE1kAHHgneUaqKcWv1fb/EHFvDf
                    E4LowCbcg/dALeclWg0chtlS6FztQyWQPf+t5xC0dsIWHK71PKM64kVF7H6ir0ghzXU2hGpSkfi2
                    KqxPzWb0JJ4s/5eCIeD51KXTkD1ejTK+9NeeQBY3tztEy2mmsbZugmGzd/ILKa0CAwEAAaOCA14w
                    ggNaMB8GA1UdIwQYMBaAFDPcnpbs2Og1H22QGws4pK90G8ZYMA4GA1UdDwEB/wQEAwIFoDAdBgNV
                    HSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwHQYDVR0OBBYEFLgJPSExww0ePqWbKkXBr+A6S0v1
                    ME8GA1UdIARIMEYwRAYJKwYBBAG9Rw0CMDcwNQYIKwYBBQUHAgEWKWh0dHA6Ly93d3cudGVsZXNl
                    Yy5kZS9zZXJ2ZXJwYXNzL2Nwcy5odG1sMIIBIgYDVR0fBIIBGTCCARUwRaBDoEGGP2h0dHA6Ly9j
                    cmwuc2VydmVycGFzcy50ZWxlc2VjLmRlL3JsL1RlbGVTZWNfU2VydmVyUGFzc19DQV8xLmNybDCB
                    y6CByKCBxYaBwmxkYXA6Ly9sZGFwLnNlcnZlcnBhc3MudGVsZXNlYy5kZS9jbj1UZWxlU2VjJTIw
                    U2VydmVyUGFzcyUyMENBJTIwMSxvdT1UcnVzdCUyMENlbnRlciUyMFNlcnZpY2VzLG89VC1TeXN0
                    ZW1zJTIwSW50ZXJuYXRpb25hbCUyMEdtYkgsYz1kZT9jZXJ0aWZpY2F0ZVJldm9jYXRpb25saXN0
                    P2Jhc2U/Y2VydGlmaWNhdGVSZXZvY2F0aW9ubGlzdD0qMIIBOgYIKwYBBQUHAQEEggEsMIIBKDAz
                    BggrBgEFBQcwAYYnaHR0cDovL29jc3Auc2VydmVycGFzcy50ZWxlc2VjLmRlL29jc3ByMEwGCCsG
                    AQUFBzAChkBodHRwOi8vY3JsLnNlcnZlcnBhc3MudGVsZXNlYy5kZS9jcnQvVGVsZVNlY19TZXJ2
                    ZXJQYXNzX0NBXzEuY2VyMIGiBggrBgEFBQcwAoaBlWxkYXA6Ly9sZGFwLnNlcnZlcnBhc3MudGVs
                    ZXNlYy5kZS9jbj1UZWxlU2VjJTIwU2VydmVyUGFzcyUyMENBJTIwMSxvdT1UcnVzdCUyMENlbnRl
                    ciUyMFNlcnZpY2VzLG89VC1TeXN0ZW1zJTIwSW50ZXJuYXRpb25hbCUyMEdtYkgsYz1kZT9jQUNl
                    cnRpZmljYXRlMAwGA1UdEwEB/wQCMAAwJgYDVR0RBB8wHYIbeG1sMi1nYXRld2F5LXRlc3Quc2No
                    dWZhLmRlMA0GCSqGSIb3DQEBBQUAA4IBAQByK84EpA5BZ6pbIQIC36lKWH1nZmmBopEjgkX5rg6n
                    6M3H9BwPmDX9VqyelnDfhQbG15pUzX/cC1rF0oISCO9ILs5YgNe4iaBfoHEH2P1w/sUdnPkE8nlo
                    5c4frnHTLdRLdPiAsRe9RTxahEwxZOxvebu7eHAPIuo+vuOPnGYIv5a+OGDkqD6snt+RKA7z3XDZ
                    ZRZXuu8mubhKCMT7n+pxQOznvSzkzbyfL5H1FUlo/697g7bij6BgTYm55bnZ2wdtTMS0F9FLnuSF
                    h8hVJKlNmVuhSS4eqmwFmYTi7dLeHwe/i6hk9/TQ7+iF92JbhPbnTYupdFBIkS1jZDA1zY0N
                </X509Certificate>
            </X509Data>
            <KeyValue>
                <RSAKeyValue>
                    <Modulus>x1YGQXVXYySc0DU3hlbF6yMMWS6BVZWnE7DRCBX/6fCMALEDg38A4PBqJ31Ihuzp7QlEPsnQhlMC
                        YmRmOUA6MHdXjNG6N/AbRmiIu2ruIVxuozIQniaKZM40AreF4dGcZ6q3j3f/jNuXQsvl9jr7HH5d
                        8xi+5Oj63b+ltpIwBTmkhJ194TWQAceCd5Rqopxa/V9v8QcW8N8TgujAJtyD90At5yVaDRyG2VLo
                        XO1DJZA9/63nELR2whYcrvU8ozriRUXsfqKvSCHNdTaEalKR+LYqrE/NZvQkniz/l4Ih4PnUpdOQ
                        PV6NMr70155AFje3O0TLaaaxtm6CYbN38gsprQ==
                    </Modulus>
                    <Exponent>AQAB</Exponent>
                </RSAKeyValue>
            </KeyValue>
        </KeyInfo>
    </Signature>