/**
 * 
 */
package fr.cryptis.rsa;

import javacard.framework.APDU;
import javacard.framework.ISO7816;
import javacard.framework.Applet;
import javacard.framework.ISOException;
import javacard.security.*;
import javacardx.crypto.*;

/**
 * @author sauveron
 *
 */
public class TestRSA extends Applet {
	
	private RSAPrivateCrtKey rsa_PrivateCrtKey;
	private RSAPublicKey rsa_PublicKey;
	private Cipher cipherRSA;
	private KeyPair kp;
	private final short dataOffset = (short) ISO7816.OFFSET_CDATA;	
	
	
	
	public TestRSA() {
		kp = new KeyPair(KeyPair.ALG_RSA_CRT,(short)512);
		kp.genKeyPair();
		rsa_PrivateCrtKey = (RSAPrivateCrtKey) kp.getPrivate();
		rsa_PublicKey = (RSAPublicKey) kp.getPublic();
		cipherRSA = Cipher.getInstance(Cipher.ALG_RSA_PKCS1, false);
	}

	public static void install(byte[] bArray, short bOffset, byte bLength) {
		// GP-compliant JavaCard applet registration
		new TestRSA().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
	}

	public void process(APDU apdu) {
		// Good practice: Return 9000 on SELECT
		if (selectingApplet()) {
			return;
		}

		byte[] buf = apdu.getBuffer();
		
		if ((buf[ISO7816.OFFSET_CLA] != 0))
		{
			ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
		}
		
		if (buf[ISO7816.OFFSET_INS] != (byte) (0xAA))
		{
			ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
		}
		
		switch (buf[ISO7816.OFFSET_P1])
		{
		case (byte) 0x01:
			encryptRSA(apdu);
			return;
		case (byte) 0x02:
			decryptRSA(apdu);
			return;
		default:
			ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
		}
	}

	//  EncDecRSA method
	private void encryptRSA(APDU apdu)
	{
		byte[] a = apdu.getBuffer();
		short byteRead = (short) (apdu.setIncomingAndReceive());


		cipherRSA.init(rsa_PrivateCrtKey, Cipher.MODE_ENCRYPT);
		short cyphertext = cipherRSA.doFinal(a, (short) dataOffset, byteRead, a, (short) dataOffset);

		// Send results
		apdu.setOutgoing();
		apdu.setOutgoingLength((short) cyphertext);
		apdu.sendBytesLong(a, (short) dataOffset, (short) cyphertext);

	}

	private void decryptRSA(APDU apdu)
	{
		byte[] a = apdu.getBuffer();
	
		short byteRead = (short) (apdu.setIncomingAndReceive());
	
		cipherRSA.init(rsa_PublicKey, Cipher.MODE_DECRYPT);
		cipherRSA.doFinal(a, (short) dataOffset, byteRead, a, (short) dataOffset);

		// Send results
		apdu.setOutgoing();
		apdu.setOutgoingLength(byteRead);
		apdu.sendBytesLong(a, (short) dataOffset, byteRead);
	}
}