import java.awt.*;
import java.applet.Applet;
import java.math.BigInteger;

public class MonoApplet extends Applet
{
	public void init()
	{
		 // Log start time
		long time = System.currentTimeMillis();
		
		// Some constants to work with
		final BigInteger zero = new BigInteger("0");
		final BigInteger one = new BigInteger("1");
		final BigInteger blockSize = new BigInteger("10000");
		
		// Pick two primes to get modulus, another to yield encryption key
		final BigInteger p = new BigInteger("4093");
		final BigInteger q = new BigInteger("1021");
		final BigInteger n = p.subtract(one).multiply(q.subtract(one));
		final BigInteger pq = p.multiply(q);
		final BigInteger e = new BigInteger("8573");
		final BigInteger d = e.modInverse(n);
		
		// Create a message and convert it to 16-bit chunks
		String message="This is the decrypted message.";
		BigInteger original[] = new BigInteger[15];
		for (int k = 0; k < 15; k++)
			original[k] = BigInteger.valueOf(256*(long)message.charAt(2*k) + (long)message.charAt(2*k+1));
		
		// Encrypt the chunks
		BigInteger encrypted[] = new BigInteger[15];
		for (int k = 0; k < 15; k++)
			encrypted[k] = original[k].modPow(e, pq);
		
		// Assume we know first four characters, and use brute force to find a working
		// decryption key
		BigInteger power = new BigInteger("0");
		for (; power.compareTo(pq) < 1 ; power = power.add(one))
		{
			if ((encrypted[0].modPow(power, pq)).compareTo(original[0]) == 0 &&
				(encrypted[1].modPow(power, pq)).compareTo(original[1]) == 0)
				break;
			if (power.mod(blockSize).compareTo(zero) == 0)
				System.out.println("Block " + power);
		}
		System.out.println("Decryption key:  " + power);
		
		// Decrypt using the key we found
		BigInteger decrypted[] = new BigInteger[15];
		for (int k = 0; k < 15; k++)
			decrypted[k] = encrypted[k].modPow(power, pq);
			
		// Extract characters from 16-bit chunks
		StringBuffer output = new StringBuffer(30);
		for (int k = 0; k < 15; k++)
		{
			long t = decrypted[k].longValue();
			output.append((char) (t/256));
			output.append((char) (t%256));
		}
		
		// Output the decoded message
		System.out.println(output);
		
		// Note total time taken
		System.out.println("Time taken:  " + ((System.currentTimeMillis() - time)/1000.0) + " seconds");
	
		repaint();
	}
	
	public void paint( Graphics g )
	{
	}

}
