import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.*;
import java.util.Collections;
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;

/**
 * This is a simple example of generating a Detached XML 
 * Signature using the JSR 105 API. The resulting signature will look 
 * like (key and signature values will be different):
 *
 * <pre><code>
 * <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#dsa-sha1"/>
 *     <Reference URI="http://www.w3.org/TR/xml-stylesheet">
 *       <DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
 *       <DigestValue>60NvZvtdTB+7UnlLp/H24p7h4bs=</DigestValue>
 *     </Reference>
 *   </SignedInfo>
 *   <SignatureValue>
 *     DpEylhQoiUKBoKWmYfajXO7LZxiDYgVtUtCNyTgwZgoChzorA2nhkQ==
 *   </SignatureValue>
 *   <KeyInfo>
 *     <KeyValue>
 *       <DSAKeyValue>
 *	   <P>
 *           rFto8uPQM6y34FLPmDh40BLJ1rVrC8VeRquuhPZ6jYNFkQuwxnu/wCvIAMhukPBL
 *           FET8bJf/b2ef+oqxZajEb+88zlZoyG8g/wMfDBHTxz+CnowLahnCCTYBp5kt7G8q
 *           UobJuvjylwj1st7V9Lsu03iXMXtbiriUjFa5gURasN8=
 *         </P>
 *         <Q>
 *           kEjAFpCe4lcUOdwphpzf+tBaUds=
 *         </Q>
 *         <G>
 *           oe14R2OtyKx+s+60O5BRNMOYpIg2TU/f15N3bsDErKOWtKXeNK9FS7dWStreDxo2
 *           SSgOonqAd4FuJ/4uva7GgNL4ULIqY7E+mW5iwJ7n/WTELh98mEocsLXkNh24HcH4
 *           BZfSCTruuzmCyjdV1KSqX/Eux04HfCWYmdxN3SQ/qqw=
 *         </G>
 *         <Y>
 *           pA5NnZvcd574WRXuOA7ZfC/7Lqt4cB0MRLWtHubtJoVOao9ib5ry4rTk0r6ddnOv
 *           AIGKktutzK3ymvKleS3DOrwZQgJ+/BDWDW8kO9R66o6rdjiSobBi/0c2V1+dkqOg
 *           jFmKz395mvCOZGhC7fqAVhHat2EjGPMfgSZyABa7+1k=
 *         </Y>
 *       </DSAKeyValue>
 *     </KeyValue>
 *   </KeyInfo>
 * </Signature>
 * </code></pre>
 */
public class GenDetached {

    //
    // Synopsis: java GenDetached [output]
    //
    // where output is the name of the file that will contain the detached
    // signature. If not specified, standard output is used.
    //
    public static void main(String[] args) throws Exception {

	// First, create a DOM XMLSignatureFactory that will be used to 
	// generate the XMLSignature and marshal it to DOM.
	XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

	// Create a Reference to an external URI that will be digested
	// using the SHA1 digest algorithm
	Reference ref = fac.newReference("http://www.w3.org/TR/xml-stylesheet", 	    fac.newDigestMethod(DigestMethod.SHA1, null));

	// Create the SignedInfo
	SignedInfo si = fac.newSignedInfo(
	    fac.newCanonicalizationMethod
	        (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS, 
		 (C14NMethodParameterSpec) null),
	    fac.newSignatureMethod(SignatureMethod.DSA_SHA1, null),
	    Collections.singletonList(ref));

	// Create a DSA KeyPair
	KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
	kpg.initialize(512);
	KeyPair kp = kpg.generateKeyPair();

	// Create a KeyValue containing the DSA PublicKey that was generated
	KeyInfoFactory kif = fac.getKeyInfoFactory();
	KeyValue kv = kif.newKeyValue(kp.getPublic());

	// Create a KeyInfo and add the KeyValue to it
	KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

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

	// Create the Document that will hold the resulting XMLSignature
	DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
	dbf.setNamespaceAware(true); // must be set
	Document doc = dbf.newDocumentBuilder().newDocument();

	// Create a DOMSignContext and set the signing Key to the DSA 
        // PrivateKey and specify where the XMLSignature should be inserted 
	// in the target document (in this case, the document root)
	DOMSignContext signContext = new DOMSignContext(kp.getPrivate(), doc);

	// Marshal, generate (and sign) the detached XMLSignature. The DOM 
	// Document will contain the XML Signature if this method returns 
 	// successfully.
	signature.sign(signContext);

	// output the resulting document
	OutputStream os;
	if (args.length > 0) {
	   os = new FileOutputStream(args[0]);
	} else { 
	   os = System.out;
	}

	TransformerFactory tf = TransformerFactory.newInstance();
	Transformer trans = tf.newTransformer();
	trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}
