

import java.math.BigInteger ;
import java.util.* ;
import java.io.* ;
import java.sql.*;

/**
 * Class for RSAprob Algorithm (RSA.java).
 *
 * Generates Prime numbers and Public/Private Keys. Performs Encryption and Decryption.
 *
 * @author  Chue Wai Lian
 * @version
 *
 * 1.0.0	11 Apr 2001
 * <br>		1st release.
 */
public class RSAprob
{
	/**
	 * Bit length of each prime number.
	 */
	int primeSize ;
            
	/**
	 * Two distinct large prime numbers p and q.
	 */
	BigInteger p, q ;

	/**
	 * Modulus N.
	 */
	BigInteger N ;

	/**
	 * phi_n = ( p - 1 ) * ( q - 1 )
	 */
	BigInteger phi_n ;

	/**
	 * Public exponent E and Private exponent D
	 */
	BigInteger E, D ;


	/**
	 * Constructor.
	 *
	 * @param	primeSize		Bit length of each prime number.
	 * @param	prob			Parameter to decide prob of generating prime numbers.
	 */
	public RSAprob( int primeSize, int prob )
	{
		this.primeSize = primeSize ;

		
		// Generate two distinct large prime numbers p and q.
		generatePrimeNumbers(prob) ;

		// Generate Public and Private Keys.
		generatePublicPrivateKeys() ;
		
	}


	/**
	 * Generate two distinct large prime numbers p and q.
	 */
	public void generatePrimeNumbers(int prob)
	{
		p = new BigInteger( primeSize, prob, new Random() ) ;

		do
		{
			q = new BigInteger( primeSize, prob, new Random() ) ;
		}
		while( q.compareTo( p ) == 0 ) ;
                
	}

	public static long getCurrentTime()
	{
		long currentTime=System.currentTimeMillis();

                return currentTime;
	}



	/**
	 * Generate Public and Private Keys.
	 */
	public void generatePublicPrivateKeys()
	{
		// N = p * q
		N = p.multiply( q ) ;


		// phi_n = ( p - 1 ) * ( q - 1 )
		phi_n = p.subtract( BigInteger.valueOf( 1 ) ) ;
		phi_n = phi_n.multiply( q.subtract( BigInteger.valueOf( 1 ) ) ) ;


		// Choose E, coprime to and less than phi_n
		do
		{
			E = new BigInteger( 2 * primeSize, new Random() ) ;
		}
		while( ( E.compareTo( phi_n ) != -1 ) || ( E.compareTo( phi_n ) >= 0 ) || ( E.gcd( phi_n ).compareTo( BigInteger.valueOf( 1 ) ) != 0 ) ) ;


		// Compute D, the inverse of E mod phi_n
		D = E.modInverse( phi_n ) ;
	}

	/**
	 * RSA Main program for Unit Testing.
	 */
	public static void main( String[] args ) throws IOException
	{
		if( args.length != 2 )
		{
			System.out.println( "Syntax: java RSA PrimeSize probVal" ) ;
			System.out.println( "e.g. java RSA 8 10" ) ;
			System.out.println( "e.g. java RSA 512 100" ) ;
			System.out.println( "Exiting program ..." ) ;
      
			System.exit( -1 ) ;
		}

		long sKey, eKey, sEnc, eEnc, sDec, eDec;

		// Get bit length of each prime number
		int primeSize = Integer.parseInt( args[0] ) ;

		int prob = Integer.parseInt( args[1] ) ;
		sKey = getCurrentTime();

		// Generate Public and Private Keys

		RSAprob rsa = new RSAprob( primeSize, prob ) ;
		eKey = getCurrentTime();
		System.out.println(prob + " " + (eKey-sKey));

	}
}

