import javacard.framework.*;
import javacard.security.*;
import javacardx.crypto.*;

/**
 */

public class RSA extends Applet
{
    private byte[] echoBytes;
    private static final short LENGTH_ECHO_BYTES = 256;
    final static short ARRAY_LENGTH                   = (short) 0xff;
    final static byte  RSA_BLOCK_LENGTH               = (short) 0x08;

    private   RSAPublicKey   m_rsaPublicKey = null;
    private   RSAPrivateKey   m_rsaPrivKey = null;
    private   RSAPrivateCrtKey   m_rsaPrivateCRTKey = null;
    private   Cipher         m_encryptCipher = null;
    private   Cipher         m_decryptCipher = null;
    private   RandomData     m_secureRandom = null;
    // TEMPORARRY ARRAY IN RAM
    private   byte        m_ramArray[] = null;
    // PERSISTENT ARRAY IN EEPROM
    private   byte       m_dataArray[] = null;
    /**
     * Only this class's install method should create the applet object.
     */
    protected RSA()
    {
        echoBytes = new byte[LENGTH_ECHO_BYTES];

        m_dataArray = new byte[ARRAY_LENGTH];
        Util.arrayFillNonAtomic(m_dataArray, (short) 0, ARRAY_LENGTH, (byte) 0);

        // CREATE DES KEY OBJECT
        m_rsaPublicKey = (RSAPublicKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, KeyBuilder.LENGTH_RSA_512, false);
        m_rsaPrivKey = (RSAPrivateKey) KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, KeyBuilder.LENGTH_RSA_512, false);
        //m_desKey = (DESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_DES, KeyBuilder.LENGTH_DES, false);
        // CREATE OBJECTS FOR CBC CIPHERING
        m_encryptCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);


        // SET KEY VALUE
        m_rsaPublicKey.setExponent(echoBytes, ARRAY_LENGTH, ARRAY_LENGTH);
        //m_desKey.setKey(m_dataArray, (short) 0);
        m_encryptCipher.init(m_rsaPrivKey, RSA_BLOCK_LENGTH);
        //m_encryptCipher.init(m_desKey, Cipher.MODE_ENCRYPT);

        // CREATE RANDOM DATA GENERATORS
        m_secureRandom = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);


        register();
    }

    /**
     * Installs this applet.
     * @param bArray the array containing installation parameters
     * @param bOffset the starting offset in bArray
     * @param bLength the length in bytes of the parameter data in bArray
     */
    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new RSA();
    }

    public boolean select() {

        m_secureRandom.generateData(m_dataArray, (short) 0, RSA_BLOCK_LENGTH);

        m_encryptCipher.doFinal(m_dataArray, (short) 0, RSA_BLOCK_LENGTH, m_dataArray, (short) 0);

        m_secureRandom.generateData(m_dataArray, (short) 0, RSA_BLOCK_LENGTH);

        return true;
    }
    /**
     * Processes an incoming APDU.
     * @see APDU
     * @param apdu the incoming APDU
     * @exception ISOException with the response bytes per ISO 7816-4
     */
    public void process(APDU apdu)
    {

        byte buffer[] = apdu.getBuffer();
		short bytesRead = apdu.setIncomingAndReceive();
		short echoOffset = (short)0;

		while ( bytesRead > 0 ) {
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, echoBytes, echoOffset, bytesRead);
            echoOffset += bytesRead;
            bytesRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
        }

        apdu.setOutgoing();
        apdu.setOutgoingLength( (short) (echoOffset + 5) );

        // echo header
        apdu.sendBytes( (short)0, (short) 5);
        // echo data
        apdu.sendBytesLong( echoBytes, (short) 0, echoOffset );

    }

}
