package org.bouncycastle.crypto.examples;

import java.io.*;
import java.lang.*;

import javax.microedition.midlet.MIDlet;
import javax.microedition.lcdui.*;

import org.bouncycastle.util.test.*;
import org.bouncycastle.util.encoders.*;

import org.bouncycastle.crypto.*;
import org.bouncycastle.crypto.paddings.*;
import org.bouncycastle.crypto.engines.*;
import org.bouncycastle.crypto.modes.*;
import org.bouncycastle.crypto.params.*;

/**
 * MIDP is a simple graphics application for the J2ME CLDC/MIDP.
 *
 * It has hardcoded values for the key and plain text. It also
 * performs the standard testing for the chosen cipher, and 
 * displays the results.
 *
 * This example shows how to use the light-weight API and 
 * a symmetric cipher.
 *
 */
public class MIDPTest extends MIDlet
{
	private Display d = null;

	private boolean doneEncrypt = false;

	private String key = "0123456789abcdef0123456789abcdef";
	private String plainText = "www.bouncycastle.org";
	private byte[] keyBytes = null;
	private byte[] cipherText = null;
	private BufferedBlockCipher cipher = null;

	private String[] cipherNames = { "DES", "DESede", "IDEA", 
								     "Rijndael", "Twofish" };

	private Form output = null;

	public void startApp()
	{
		Display.getDisplay(this).setCurrent(output);
	}

	public void pauseApp()
	{

	}

	public void destroyApp(boolean unconditional)
	{

	}

	public MIDPTest()
	{
		output = new Form("BouncyCastle");
		output.append("Key: "+key.substring(0,7)+"...\n");
		output.append("In : "+plainText.substring(0,7)+"...\n");

		cipherText = performEncrypt(Hex.decode(key.getBytes()), plainText);
		String ctS = new String(Hex.encode(cipherText));

		output.append("\nCT : "+ctS.substring(0,7)+"...\n");

		String decryptText = performDecrypt(Hex.decode(key.getBytes()), cipherText);

		output.append("PT : "+decryptText.substring(0,7)+"...\n");

		if (decryptText.compareTo(plainText) == 0)
		{
			output.append("Success");
		}
		else
		{
			output.append("Failure");
			message("["+plainText+"]");
			message("["+decryptText+"]");
		}

	}

	private final byte[] performEncrypt(byte[] key, String plainText)
	{
		byte[] ptBytes = plainText.getBytes();

		cipher = new PaddedBufferedBlockCipher(
									new CBCBlockCipher(getEngineInstance()));

		String name = cipher.getUnderlyingCipher().getAlgorithmName();
		message("Using "+name);

		cipher.init(true, new KeyParameter(key));

		byte[] rv = new byte[cipher.getOutputSize(ptBytes.length)];
	
		int oLen = cipher.processBytes(ptBytes, 0, ptBytes.length, rv, 0);
		try
		{
			cipher.doFinal(rv, oLen);
		}
		catch (CryptoException ce)
		{
			message("Ooops, encrypt exception");
			status(ce.toString());
		}
		return rv;
	}

	private final String performDecrypt(byte[] key, byte[] cipherText)
	{
		cipher.init(false, new KeyParameter(key));

		byte[] rv = new byte[cipher.getOutputSize(cipherText.length)];
	
		int oLen = cipher.processBytes(cipherText, 0, cipherText.length, rv, 0);
		try
		{
			cipher.doFinal(rv, oLen);
		}
		catch (CryptoException ce)
		{
			message("Ooops, decrypt exception");
			status(ce.toString());
		}
		return new String(rv).trim();
	}

	private int whichCipher()
	{
		return 4; // DES
	}

	private final BlockCipher getEngineInstance()
	{
		// returns a block cipher according to the current
		// state of the radio button lists.  This is only
		// done prior to encryption.
		BlockCipher rv = null;

		switch (whichCipher())
		{
			case 0:
				rv = new DESEngine();
				break;
			case 1:
				rv = new DESedeEngine();
				break;
			case 2:
				rv = new IDEAEngine();
				break;
			case 3:
				rv = new RijndaelEngine();
				break;
			case 4:
				rv = new TwofishEngine();
				break;
			default:
				rv = new DESEngine();
				break;
		}
		return rv;
	}

	public void message(String s)
	{
		System.out.println("M:"+s);
	}

	public void status(String s)
	{
		System.out.println("S:"+s);
	}

}

