/***************************************************************************************************************************************************

Demo application for generating widget signatures.

Olli Immonen, Nokia, 18.5.2007


Based largely on
http://java.sun.com/developer/technicalArticles/xml/dig_signature_api/

***************************************************************************************************************************************************/

/***************************************************************************************************************************************************

Note:

The following command needs to be run to create the Java Keystore, private key and a (self-signed) certificate:

  keytool -genkey -keyalg rsa -dname "cn=Widget testing, o=Testing, c=FI" -alias Testkey -keypass abc123 -keystore testkeystore.jks -storepass abc123

***************************************************************************************************************************************************/


import java.io.*;
import java.util.*;
import java.security.*;

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import javax.xml.crypto.dsig.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import java.security.cert.*;

import org.w3c.dom.*;


class SignWidget {
   public static void main(String[] args) {

	String[] files = {"config.xml", "index.html", "pictures/picture1.gif", ""};

	String sigfilename = "signature.xml"; 

	// Strings for using the Java KeyStore
	String keystorename = "testkeystore.jks";
	String keystorepw = "abc123";
	String keyname = "Testkey";
	String keypw = "abc123";

	try {

		// Create a DOM XMLSignatureFactory that will be used to
		// generate the signature.
		System.out.println("Create a DOM XMLSignatureFactory");
		XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

		// Create the a list of references to the files.
		List manrefs = new ArrayList();

		for (int i = 0; (files[i] != "") ; i++)
		{
			System.out.println("Add reference: " + files[i]);
			Boolean b = manrefs.add(fac.newReference(files[i], 
			  fac.newDigestMethod(DigestMethod.SHA1, null), null, null, null, digestFile(files[i])));
		}

		System.out.println("Create Manifest");
		Manifest manifest = fac.newManifest(manrefs, "references");

		Reference ref = fac.newReference("#references", fac.newDigestMethod(DigestMethod.SHA1, null));

		List content = Collections.singletonList(manifest);
		XMLObject object = fac.newXMLObject(content, null, null, null);

		// Create the SignedInfo.
		System.out.println("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.
		System.out.println("Load the KeyStore and get the signing key and certificate");
		KeyStore ks = KeyStore.getInstance("JKS");
		ks.load(new FileInputStream(keystorename), keystorepw.toCharArray());
		KeyStore.PrivateKeyEntry keyEntry =
		    (KeyStore.PrivateKeyEntry) ks.getEntry
        	    (keyname, new KeyStore.PasswordProtection(keypw.toCharArray()));
		X509Certificate cert = (X509Certificate) keyEntry.getCertificate();

		// Create the KeyInfo containing the X509Data.
		System.out.println("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.
		System.out.println("Instantiate the document to be signed");
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		dbf.setNamespaceAware(true);
		Document doc = dbf.newDocumentBuilder().newDocument();

		// Create a DOMSignContext and specify the RSA PrivateKey and
		// location of the resulting XMLSignature's parent element.
		System.out.println("Create a DOMSignContext");
		DOMSignContext dsc = new DOMSignContext
		    (keyEntry.getPrivateKey(), doc);

		// Create the XMLSignature, but don't sign it yet.
		System.out.println("Create the XMLSignature");
		XMLSignature signature = fac.newXMLSignature(si, ki, Collections.singletonList(object), null, null);

		// Marshal, generate, and sign the enveloped signature.
		System.out.println("Marshal, generate, and sign");
		signature.sign(dsc);
 
		// Output the resulting document.
		OutputStream os = new FileOutputStream(sigfilename);
		TransformerFactory tf = TransformerFactory.newInstance();
		Transformer trans = tf.newTransformer();
		trans.transform(new DOMSource(doc), new StreamResult(os)); 

	} catch (Exception e) {
    		e.printStackTrace();
	}

    }



    static byte[] digestFile(String fname)
	{

  	byte[] mdbytes = null;
  	try{
    		MessageDigest md = MessageDigest.getInstance("SHA1");
    		FileInputStream fis = new FileInputStream(fname);
    		byte[] dataBytes = new byte[1024];
    		int nread = fis.read(dataBytes);
    		while (nread > 0) {
    		  md.update(dataBytes, 0, nread);
    		  nread = fis.read(dataBytes);
    		}
    		mdbytes = md.digest(); 
  	}
  	catch (Exception e) {
    		e.printStackTrace(); 
  	}
  	return mdbytes;
   }

}