import java.util.*;
import java.security.*;
import java.security.cert.*;
import java.io.*;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

class CertOperations
{
	public static void main(String[] args)
	{
		 try
		 {

			 //java does not provide an implementation of RSA for encryption. Use an external provider
			 Security.addProvider(new BouncyCastleProvider());
			 Cipher RSACipher = Cipher.getInstance("RSA/None/NoPadding", "BC");

			//Read the data to be read
			 File f = new File("datafile.dat") ;
			 int sizecontent = ((int) f.length());
			 byte[] data = new byte[sizecontent];

			 try {
			 	FileInputStream freader = new FileInputStream(f);
			 	System.out.println("\nContent Bytes: " + freader.read(data, 0, sizecontent));
			 	freader.close();
			 }
			 catch(IOException ioe) {
			 	System.out.println(ioe.toString());
			 	return;
			 }

			// A .pfx certificate file with both the public and private keys
			FileInputStream fis =
					new FileInputStream("AlicePrivate.pfx");

			//load the keys onto a keystore object from the certificate file
			KeyStore keyStore = KeyStore.getInstance("PKCS12");
			char[] passphrase = new char[] {'c', 's', 'e', '5', '3', '9'};
			keyStore.load((InputStream)fis, passphrase);
			Enumeration e =	keyStore.aliases();
			String k2 = null;
			while(e.hasMoreElements())
			{
				k2 = (String)e.nextElement();
			}
			fis.close();

			//extract private key from key store
			Key key1 = keyStore.getKey(k2, passphrase);
			java.security.cert.Certificate [] certs = keyStore.getCertificateChain(k2);

			//extract public key from key store
			Key key2 = certs[0].getPublicKey();

			/*----------------------Exercise on encryption------------------------*/
		    //initiate the cipher for encryption
		    RSACipher.init(Cipher.ENCRYPT_MODE, key2);
			System.out.println("output size for input of " + sizecontent + " is " + RSACipher.getOutputSize(sizecontent));
			byte[] encrypteddata = RSACipher.doFinal(data);


			//re-initiate the cipher for decryption
			RSACipher.init(Cipher.DECRYPT_MODE, key1);
			byte[] decrypteddata = RSACipher.doFinal(encrypteddata);
			System.out.println("Data: \n");
			for (int i = 0; i < sizecontent; i++)
			{
				char ch = (char)data[i];
				System.out.print(ch);
			}
			System.out.println("\n");

			System.out.println("Encrypted data :\n");
			for (int i = 0; i < sizecontent; i++)
			{
					char ch = (char)encrypteddata[i];
					System.out.print(ch);
			}
			System.out.println("\n");

			System.out.println("decrytpedData : \n");
			for (int i = 0; i < sizecontent; i++)
			{
					char ch = (char)decrypteddata[i];
					System.out.print(ch);
			}
			System.out.println("\n*************************************************************************************");

			/*----------------------Exercise on verifying signatures------------------------*/
			//Read the certificate into a X509Certificate object
			InputStream inStream = new FileInputStream("Alice.cer");
			CertificateFactory cf = CertificateFactory.getInstance("X.509");
			X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);

    		InputStream inStream1 = new FileInputStream("CACert.cer");
			CertificateFactory cf1 = CertificateFactory.getInstance("X.509");
			X509Certificate CACert = (X509Certificate)cf1.generateCertificate(inStream1);
			PublicKey CAPub = CACert.getPublicKey();

			byte[] sig = cert.getSignature();
			Signature sign = Signature.getInstance("MD5withRSA");


			sign.initVerify(CAPub);
			sign.update(cert.getTBSCertificate());
			boolean verifies = sign.verify(sig);
			System.out.println("signature verifies: " + verifies);
			System.out.println("signature provider: " + sign.getProvider());



		 }
		 catch(Exception e)
		 {
			 System.out.println("oopsie" + e);
		 }

	 }

}
