import java.io.Serializable;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
import java.util.*;
import java.security.spec.*;

public class MySobre 
{
	private	final static String aesalgo = "DESede"; 
	MySobre(String fname, String cfname, PublicKey pub , PrivateKey pri) 
		throws Exception
	{
	     KeyGenerator kg = KeyGenerator.getInstance(aesalgo);
	     SecretKey sessionkey = kg.generateKey();

	     Cipher rsaC = Cipher.getInstance("RSA");
	     Cipher aes = Cipher.getInstance(aesalgo);
	     Signature rsaS = Signature.getInstance("SHA1withRSA");

	     rsaC.init(Cipher.ENCRYPT_MODE,pub);
	     aes.init(Cipher.ENCRYPT_MODE,sessionkey);
	     rsaS.initSign(pri);

	     // mas rapido si fitjero leido solamente una vez
	     // pero codigo mas feo
	     readFileintoSignature(rsaS,fname);
	     processCipher(aes,fname,cfname);


	     this.ds = new DadesSobre(
			     rsaC.doFinal(sessionkey.getEncoded()),
			     rsaS.sign(),
			     cfname
			   );
	}

	MySobre(DadesSobre ds, String tfname, PublicKey pub , PrivateKey pri ) 
		throws Exception 
	{
	     Cipher rsaC = Cipher.getInstance("RSA");
	     Cipher aes = Cipher.getInstance(aesalgo);
	     Signature rsaS = Signature.getInstance("SHA1withRSA");
	     rsaS.initVerify(pub);

	     rsaC.init(Cipher.DECRYPT_MODE,pri);
	     SecretKeyFactory kf = SecretKeyFactory.getInstance(aesalgo);
	     SecretKey sessionkey = kf.generateSecret( 
			     new DESedeKeySpec( rsaC.doFinal( ds.getClau() ) )  ) ;

	     aes.init(Cipher.DECRYPT_MODE,sessionkey);
	     processCipher(aes,ds.getFilename(),tfname);

	     readFileintoSignature(rsaS,tfname);
	     if ( ! rsaS.verify(ds.getSignatura()) ) 
		     throw new Exception("security violation, signatura incorecta");

	}

	private void readFileintoSignature(Signature sig, String fname) throws Exception 
	{
	     int buffersize = 8;
	     InputStream is = new FileInputStream(new File(fname));
	     byte[] buffer = new byte[buffersize];

	     int numread=0;
	     while ( (numread=is.read(buffer,0,buffersize)) >= 0 ) {
		if ( numread < buffersize ) {
			byte[] temp = new byte[numread];
			for (int i=0;i<numread;i++) temp[i]=buffer[i];
			sig.update(temp);
		}
		else {
			sig.update(buffer);
		}
	     };
	}
	private void processCipher(Cipher c, String infname, String offname) throws Exception
   	{
	     int buffersize = c.getBlockSize();
	     FileInputStream is = new FileInputStream(new File(infname));
	     FileOutputStream os = new FileOutputStream(new File(offname));

	     byte[] buffer = new byte[buffersize];

	     int numread=0;
	     while ( (numread=is.read(buffer,0,buffersize)) >= 0 ) {
		     if ( numread < buffersize ) {
			     for (int i=numread;i<buffersize;i++) buffer[i]=0;
		     }
		     os.write(c.update(buffer));
	     };
     
	     os.write(c.doFinal());
	     is.close();
	     os.close();
	}

	public DadesSobre getDadesSobre()
	{
		return ds;
	}

	DadesSobre ds = null;

}


