package gr.duth.eece.cryptographyLesson.asymmetric.elgamal;

import gr.duth.eece.cryptographyLesson.asymmetric.paillier.PaillierPrivateKey;
import gr.duth.eece.cryptographyLesson.asymmetric.paillier.PaillierPublicKey;
import gr.duth.eece.cryptographyLesson.asymmetric.rsa.RSAPrivateKey;
import gr.duth.eece.cryptographyLesson.asymmetric.rsa.RSAPublicKey;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;

import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
import org.bouncycastle.jce.interfaces.ElGamalPublicKey;
import org.bouncycastle.jce.provider.JDKKeyPairGenerator;
import org.bouncycastle.jce.spec.ElGamalParameterSpec;

public class ElgamalKeyPair {
	
	public ElgamalPublicKey PublicKey;
	public ElgamalPrivateKey PrivateKey;

	public static BigInteger g512 = new BigInteger(
			"153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc",
			16);
	public static BigInteger p512 = new BigInteger(
			"9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b",
			16);

	public static BigInteger g768 = new BigInteger(
			"7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1",
			16);
	public static BigInteger p768 = new BigInteger(
			"8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f",
			16);

	public static BigInteger g1024 = new BigInteger(
			"1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf",
			16);
	public static BigInteger p1024 = new BigInteger(
			"a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7",
			16);

	public ElgamalKeyPair() {
		// TODO Auto-generated constructor stub
	}
	
	public ElgamalKeyPair(int bitLengthVal) {
		KeyGeneration(bitLengthVal);
	}
	
	public ElgamalKeyPair(BigInteger P, BigInteger G) {
		KeyPair pair = null;
		try {
			pair = generateElGamalKeyPair(P, G);

		} catch (Exception er) {
			System.err.println("Error with generateElGamalKeyPair !!!");
		}
		Key pubKey = pair.getPublic();
		ElGamalPublicKey elGamalPubKey = (ElGamalPublicKey) pubKey;
		ElGamalParameterSpec elGamalParameterSpec = elGamalPubKey.getParameters();
		PublicKey = new ElgamalPublicKey();
		PublicKey.bitLength = elGamalParameterSpec.getP().bitLength();
		PublicKey.p = elGamalParameterSpec.getP();
		PublicKey.g = elGamalParameterSpec.getG();
		PublicKey.y = elGamalPubKey.getY();

		PrivateKey = new ElgamalPrivateKey();
		PrivateKey.bitLength = elGamalParameterSpec.getP().bitLength();
		PrivateKey.p = elGamalParameterSpec.getP();
		PrivateKey.a = ((ElGamalPrivateKey)pair.getPrivate()).getX();
		
	}
	
	private void KeyGeneration(int bitLengthVal) {
			System.out.println("Creating ElGamalParameterSpec");
			System.out.println();
			System.out.println("Creating SecureRandom");
			SecureRandom random = new SecureRandom();

			// create the keys
			System.out.println("Creating KeyPairGenerator");
			// KeyPairGenerator generator =
			// KeyPairGenerator.getInstance("ElGamal","BC");
			JDKKeyPairGenerator.ElGamal generator = new JDKKeyPairGenerator.ElGamal();

			System.out.println("Initializing KeyPairGenerator with keySize "+ bitLengthVal);
			generator.initialize(bitLengthVal, random);

			System.out.println("Creating KeyPair");
			KeyPair pair = generator.generateKeyPair();
			Key pubKey = pair.getPublic();
			ElGamalPublicKey elGamalPubKey = (ElGamalPublicKey) pubKey;
			ElGamalParameterSpec elGamalParameterSpec = elGamalPubKey.getParameters();
			PublicKey = new ElgamalPublicKey();
			PublicKey.bitLength = bitLengthVal;
			PublicKey.p = elGamalParameterSpec.getP();
			PublicKey.g = elGamalParameterSpec.getG();
			PublicKey.y = elGamalPubKey.getY();

			PrivateKey = new ElgamalPrivateKey();
			PrivateKey.bitLength = bitLengthVal;
			PrivateKey.p = elGamalParameterSpec.getP();
			PrivateKey.a = ((ElGamalPrivateKey)pair.getPrivate()).getX();

			System.out.println("Terminating ...");
	}

	public ElGamalParameterSpec loadElGamalParameterSpecification(
			String Filename) {
		// Load ElGamalParameterSpecification
		ElGamalParameterSpec elGamalParameterSpec = null;
		try {
			FileInputStream fis;

			fis = new FileInputStream(Filename);
			ObjectInputStream ois = new ObjectInputStream(fis);

			BigInteger gPub1 = (BigInteger) ois.readObject();
			BigInteger pPub1 = (BigInteger) ois.readObject();
			elGamalParameterSpec = new ElGamalParameterSpec(pPub1, gPub1);
			return elGamalParameterSpec;

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return elGamalParameterSpec;
	}

	public void CreateNewElGamalParameterSpec(int keySize, String fileName) {

		try {
			System.out.println("Creating ElGamalParameterSpec");
			System.out.println();
			System.out.println("Creating SecureRandom");
			SecureRandom random = new SecureRandom();

			// create the keys
			System.out.println("Creating KeyPairGenerator");
			// KeyPairGenerator generator =
			// KeyPairGenerator.getInstance("ElGamal","BC");
			JDKKeyPairGenerator.ElGamal generator = new JDKKeyPairGenerator.ElGamal();

			System.out.println("Initializing KeyPairGenerator with keySize "
					+ keySize);
			generator.initialize(keySize, random);

			System.out.println("Creating KeyPair");
			KeyPair pair = generator.generateKeyPair();
			Key pubKey = pair.getPublic();
			ElGamalPublicKey elGamalPubKey = (ElGamalPublicKey) pubKey;

			System.out.println("Extracting ElGamalParameterSpec");
			ElGamalParameterSpec elGamalParameterSpec = elGamalPubKey
					.getParameters();

			System.out.println("Extracting parameters P and G");
			BigInteger bigP = elGamalParameterSpec.getP();
			BigInteger bigG = elGamalParameterSpec.getG();
			FileOutputStream fos = new FileOutputStream(fileName);
			ObjectOutputStream oos = new ObjectOutputStream(fos);

			System.out.println("Writing P and G to file " + fileName);
			oos.writeObject(bigP);
			oos.writeObject(bigG);
			oos.flush();
			oos.close();
			fos.close();

			System.out.println("Terminating ...");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public KeyPair generateElGamalKeyPair(
			ElGamalParameterSpec elGamalParameterSpec)
			throws NoSuchAlgorithmException, NoSuchProviderException,
			InvalidAlgorithmParameterException {

		// KeyPairGenerator generator =
		// KeyPairGenerator.getInstance("ElGamal","BC");
		JDKKeyPairGenerator.ElGamal generator = new JDKKeyPairGenerator.ElGamal();
		generator.initialize(elGamalParameterSpec);
		KeyPair pair = generator.generateKeyPair();
		return pair;
	}

	public KeyPair generateElGamalKeyPair(BigInteger P, BigInteger G)
			throws NoSuchAlgorithmException, NoSuchProviderException,
			InvalidAlgorithmParameterException {

		// KeyPairGenerator generator =
		// KeyPairGenerator.getInstance("ElGamal","BC");
		JDKKeyPairGenerator.ElGamal generator = new JDKKeyPairGenerator.ElGamal();
		ElGamalParameterSpec ee = new ElGamalParameterSpec(P, G);
		generator.initialize(ee);
		KeyPair pair = generator.generateKeyPair();
		return pair;
	}
}
