/**
 * 
 */
package fr.cryptis.des;

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 CipherDes extends Applet {

	private DESKey deskey;
    private Cipher cipher;
	final short dataOffset = (short) ISO7816.OFFSET_CDATA;
	static byte[] DESKeySingle = { (byte) 0x38, (byte) 0x12, (byte) 0xA4, (byte) 0x19, (byte) 0xC6, (byte) 0x3B, (byte) 0xE7, (byte) 0x71 };

	
	
	public CipherDes() {
		deskey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES, false);
		deskey.setKey(DESKeySingle, (short)0);
		cipher = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD,false);
	}

	public static void install(byte[] bArray, short bOffset, byte bLength) {
		// GP-compliant JavaCard applet registration
		new CipherDes()
				.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] !=(byte) 0) || (buf[ISO7816.OFFSET_INS] != (byte) (0xAA)))
		{
			ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
		}

		switch (buf[ISO7816.OFFSET_P1])
		{
		case (byte) 0x01:
			doSingleDES(apdu);
			return;
		default:
			ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
		}

	}
	
	//  EncDecDES method
	// Takes an input 24 byte message from the incomming APDU and Encrypts it using
	// a DES Key. It then Decrypts the cryptogram using the same DES Key. 
	// Response APDU sends the message (24 bytes) plus Cryptogram (24 bytes) plus decrypted message (24 bytes))
	private void doSingleDES(APDU apdu)
	{
		byte a[] = apdu.getBuffer();

		short incomingLength = (short) (apdu.setIncomingAndReceive());
		if (incomingLength != 24) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

		//perform encryption and append results in APDU Buffer a[] automatically 

		cipher.init(deskey, Cipher.MODE_ENCRYPT);
		cipher.doFinal(a, (short) dataOffset, incomingLength, a, (short) (dataOffset + 24));
		cipher.init(deskey, Cipher.MODE_DECRYPT);
		cipher.doFinal(a, (short) (dataOffset + 24), incomingLength, a, (short) (dataOffset + 48));

		// Send results
		apdu.setOutgoing();
		apdu.setOutgoingLength((short) 72);
		apdu.sendBytesLong(a, (short) dataOffset, (short) 72);
	}
}