/*
 * Usage of some APIs provided in
 * this code sample is confined
 * to export restrictions.
 */
import java.security.*;
import java.io.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.*;
/*
 * A class, which secures its object
 * by signing and sealing it within the
 * limits provided by the Java Cryptographic
 * Extension.
 */
public class SignNSeal implements Serializable{
	private PublicKey pubK = null;
	private PrivateKey priK = null;
	private SecretKey sKey = null;
	byte[] key;
	byte[] iv;

	/*
	 * Refer to Java Code Stack #1 and #3
	 * for info on symmetric and asymmetric encryption
	 */

	/*
	 * This method signs an object with the
	 * provided Private Key
	 */
	public Object signObject(Object obj){
		SignedObject so = null;
		try {
			Signature sig = Signature.getInstance (priK.getAlgorithm());
			so = new SignedObject ((SignNSeal)obj, priK, sig);
		} catch (Exception e){e.printStackTrace();}
		return so;
	}

	/*
	 * This method seals a signed object with the
	 * provided algorithm
	 */
	public Object sealObject(Object obj){
		SealedObject so = null;
		try {
			SecretKeyFactory skf=SecretKeyFactory.getInstance("DES");
			Class al=Class.forName("javax.crypto.spec.DESKeySpec");
        	DESKeySpec ks=(DESKeySpec)skf.getKeySpec(sKey,al);
        	key=ks.getKey();
			Cipher cip=Cipher.getInstance("DES/CFB8/NoPadding");
			cip.init(Cipher.ENCRYPT_MODE,sKey);
			iv=cip.getIV();
			so=new SealedObject((SignedObject)obj,cip);
		} catch(Exception e){e.printStackTrace();}
		return so;
	}

	/*
	 * This method tries to obtain the original
	 * object by decrypting them and also verifies
	 * the signature stored along with the object.
	 */
	public Object getObject(Object seal){
		SealedObject sealed=(SealedObject)seal;
		Object obj=null;

		try {
			DESKeySpec ks=new DESKeySpec(key);
			Cipher cip=Cipher.getInstance("DES/CFB8/NoPadding");
			cip.init(Cipher.DECRYPT_MODE,sKey,new IvParameterSpec(iv));
			SignedObject signed=(SignedObject)(sealed.getObject(cip));

			Signature sig = Signature.getInstance (priK.getAlgorithm());
			if(signed.verify(pubK, sig)){
				obj=signed.getObject();
			}
			else{
				System.out.println("Object Compromised!");
			}
		} catch(Exception e){e.printStackTrace();}
		return obj;

	}

	public String getString(){
		return "What do you want to seal today?";
	}


	public static void main(String ar[]){
		SignNSeal ss=new SignNSeal();

		try{
			KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
			keyGen.initialize(1024);
			System.out.println("Generating Public and Private Keys...");
			KeyPair keypair = keyGen.genKeyPair();
			ss.priK = keypair.getPrivate();
			ss.pubK = keypair.getPublic();
			KeyGenerator kgen=KeyGenerator.getInstance("DES");
			kgen.init(new SecureRandom());
			System.out.println("Generating Secret Key...");
			ss.sKey = kgen.generateKey();
		}catch(Exception e){e.printStackTrace();}


		System.out.println("Signing the object...");
		Object signed=(Object)ss.signObject(ss);
		System.out.println("Sealing the object...");
		Object sealed=(Object)ss.sealObject(signed);
		System.out.println("Done");
		System.out.println("Reading sealed object...");
		Object obj=(SignNSeal)ss.getObject(sealed);
		System.out.println("Done");
		System.out.println(""+ss.getString());

	}

}