Примеры API JavaCard

Carder

Professional
Messages
2,619
Reaction score
1,903
Points
113

Пример хеш-кода​


Code:
/*
* @file  HashSample.java
* @version v1.0
* Package AID: 4A617661436172644F53
* Applet AID: 4A617661436172644F5305
* @brief The ALgorithm of Hash Sample Code in JavaCard API Specification
* @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
*/

package JavaCardOS.Sample.Algorithm;

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

public class HashSample extends Applet
{
    private static final byte INS_GEN_HASH = (byte)0x50;

    private byte[] flags;
    private static final short OFF_INS    = (short)0;
    private static final short OFF_P1     = (short)1;
    private static final short OFF_P2     = (short)2;
    private static final short OFF_LEN    = (short)3;
    private static final short FLAGS_SIZE = (short)5;

    private InitializedMessageDigest sha1;
    private InitializedMessageDigest sha256;
    private InitializedMessageDigest sha512;

    public HashSample()
    {
        flags = JCSystem.makeTransientByteArray(FLAGS_SIZE, JCSystem.CLEAR_ON_DESELECT);
        //Creates a InitializedMessageDigest object instance of the ALG_SHA algorithm.
        sha1 = MessageDigest.getInitializedMessageDigestInstance(MessageDigest.ALG_SHA, false);
        //Creates a InitializedMessageDigest object instance of the ALG_SHA_256 algorithm.
        sha256 = MessageDigest.getInitializedMessageDigestInstance(MessageDigest.ALG_SHA_256, false);
        //Creates a InitializedMessageDigest object instance of the ALG_SHA_512 algorithm.
        sha512 = MessageDigest.getInitializedMessageDigestInstance(MessageDigest.ALG_SHA_512, false);
        JCSystem.requestObjectDeletion();
    }
    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new HashSample().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    }

    public void process(APDU apdu)
    {
        if (selectingApplet())
        {
            return;
        }

        byte[] buf = apdu.getBuffer();
        short len = apdu.setIncomingAndReceive();
        switch (buf[ISO7816.OFFSET_INS])
        {
        case (byte)INS_GEN_HASH:
            generateHash(apdu, len);
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    //Generate Hash
    private void generateHash(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        boolean hasMoreCmd = (buffer[ISO7816.OFFSET_P1] & 0x80) != 0;
        InitializedMessageDigest hash = null;
        short resultLen = 0;
        short offset = ISO7816.OFFSET_CDATA;
        switch (buffer[ISO7816.OFFSET_P1] & 0x7f)
        {
        case 0:
            hash = sha1;
            resultLen = MessageDigest.LENGTH_SHA;
            break;
        case 1:
            hash = sha256;
            resultLen = MessageDigest.LENGTH_SHA_256;
            break;
        case 2:
            hash = sha512;
            resultLen = MessageDigest.LENGTH_SHA_512;
            if (hash == null)
            {
                ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
            }
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            break;
        }

        if (buffer[ISO7816.OFFSET_P2] == 0) //first block
        {
            //Reset the MessageDigest object to the initial state.
            hash.reset();
        }

        if (hasMoreCmd)
        {
            //Accumulate a hash of the input data.
            hash.update(buffer, offset, len);
        }
        else
        {
            //Generate a hash of all the input data.
            short ret = hash.doFinal(buffer, offset, len, buffer, (short)0);
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            apdu.setOutgoingAndSend((short)0, ret);
        }
    }

}

Тестовый скрипт Hash выглядит следующим образом:

Code:
//The test script of Hash
//Hash Select Applet
00A404000B4A617661436172644F530500;
//SHA1
//expect:44ABF22AF275548BCE3639C5FE3CDFCFFFF305AA9000
80500000A36713E26AA669E98027D9FE54B457551A40599E921D39DB8970DA6FA2E18E785697375F3A63ADAE803B6021C1EB3FFFFA07D8AAD424C075284735B7C29E021E656EA345104DAA8880916117F608B1493AEA4233E00BE47ACA552E65EE76643659D69EBB74CC2720871124077B7576DAE4D0E1603F3C6D8F77810CA2AFD17E6B3BB672E9EF48EE1D9DA3F01AD998565CFFA3FB5A781D235E38B319958B17166212F565F8;
//SHA256
80508100C8ECE47FD746C16AD454D0D509979BF65DB051109F815EACBC8F3F2636AA956CD1D1780390500D4BDF2B5B0312BF5A0F0EA74D7946DD52B7EA21382C5A9F90F1E1CC07D4A091F3A1C8AB2BA10D521C61571819B4BA15F3FBA841CAA4652122F1BCA639FBF15299F6F69CE9B6E19608729ECD5DC9E17068025FB59D983E7973F6CA27B87F69DA27D1D1C63C4B78D447CD4C8CC0BEA538DA5478465A0FCDEFAA8773162968F273C6BBC1F0CD67B95300F7CA1EEA9DEDB3707759BCA912FACAF02D1F3C37BF73639E3B2E;
80508101C8E444128C5D5C797F4B846EA02B53F56CDF31A8AD546C6E3662888BD3F3D6D980684854D93883DCD2DA3637A8E6AA5618779BD9CED347D5204EC4D4FC6B961D1F458136882D9CA82D95A702EC2D9E20C44B8EAD4590A8E745C994A2D5130890744398BF8284D063F74280D6544757DDDA24B32DFAD3B82E0E9AA0FE463251B9E52935F8AD85469797AA68BCC87EFC14C1CAB260D6E49E31E18B8FEF37129C20DBC1FFE7F27827CB779508BA3018B64EE105324FBF0A83782762097E90F90F4EBFD19F963AA49A88FE;
//expect:959727571EE31D59A2F504A90B38B0103F350BAD27100844381C4B77609635789000
805001023CCB08DB745EAC12A29DDB009E8E8F8C49E8B8B23930D2CAF722BC0D6B52C85594130F247D9807E86C59577D5CB8E9F4ADE541931BFF0E1CED7CFF536E;

Пример кода DES​


Code:
/*
* @file  DESSample.java
* @version v1.0
* Package AID: 4A617661436172644F53
* Applet AID: 4A617661436172644F5302
* @brief The ALgorithm of DES Sample Code in JavaCard API Specification
* @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
*/

package JavaCardOS.Sample.Algorithm;

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

public class DESSample extends Applet
{
    private static final byte INS_SET_DES_KEY              = (byte)0x20;
    private static final byte INS_SET_DES_ICV              = (byte)0x21;
    private static final byte INS_DO_DES_CIPHER            = (byte)0x22;

    private byte desKeyLen;
    private byte[] desKey;
    private byte[] desICV;

    private Cipher desEcbCipher;
    private Cipher desCbcCipher;

    private Key tempDesKey2;
    private Key tempDesKey3;

    public DESSample()
    {
        desKey = new byte[32];
        desICV = new byte[8];
        desKeyLen = 0;
        //Create a DES ECB/CBS object instance of the DES algorithm.
        desEcbCipher = Cipher.getInstance(Cipher.ALG_DES_ECB_NOPAD, false);
        desCbcCipher = Cipher.getInstance(Cipher.ALG_DES_CBC_NOPAD, false);
        //Creates uninitialized TDES cryptographic keys for signature and cipher algorithms.
        tempDesKey3 = KeyBuilder.buildKey(KeyBuilder.TYPE_DES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_DES3_3KEY, false);

        JCSystem.requestObjectDeletion();
    }

    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new DESSample().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    }

    public void process(APDU apdu)
    {
        if (selectingApplet())
        {
            return;
        }

        byte[] buf = apdu.getBuffer();
        short len = apdu.setIncomingAndReceive();
        switch (buf[ISO7816.OFFSET_INS])
        {
        case INS_SET_DES_KEY:
            //SET_DES_KEY
            setDesKey(apdu, len);
            break;
        case INS_SET_DES_ICV:
            //SET_DES_ICV
            setDesICV(apdu, len);
            break;
        case INS_DO_DES_CIPHER:
            //DO_DES_CIPHER
            doDesCipher(apdu, len);
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    //Set the key of TDES Encrypt/Decrypt
    private void setDesKey(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        byte keyLen = 0;
        switch (buffer[ISO7816.OFFSET_P1])
        {
        case (byte)0x01: // The length of key is 16 bytes
            if (len != 16)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            keyLen = (byte)16;
            break;
        case (byte)0x02:
            if (len != 24) // The length of key is 24 bytes
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            keyLen = (byte)24;
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            break;
        }

        JCSystem.beginTransaction();
        //Copy the incoming TDES Key value to the global variable 'desKey'
        Util.arrayCopy(buffer, ISO7816.OFFSET_CDATA, desKey, (short)0, len);
        desKeyLen = keyLen;
        JCSystem.commitTransaction();
    }

    //Set DES ICV, ICV is the initial vector
    private void setDesICV(APDU apdu, short len)
    {
        if (len != 8)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        //Copy the incoming ICV value to the global variable 'desICV'
        Util.arrayCopy(apdu.getBuffer(), ISO7816.OFFSET_CDATA, desICV, (short)0, (short)8);
    }

    //Get the key that set into the 'desKey' in setDesKey() function, and return the DESKey object.
    //The plain text length of input key data is 8 bytes for DES, 16 bytes for 2-key triple DES and 24 bytes for 3-key triple DES.
    private Key getDesKey()
    {
        Key tempDesKey = null;
        switch (desKeyLen)
        {
        case (byte)16:
            tempDesKey = tempDesKey2;
            break;
        case (byte)24:
            tempDesKey = tempDesKey3;
            break;
        default:
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
            break;
        }
        //Set the 'desKey' key data value into the internal representation
        ((DESKey)tempDesKey).setKey(desKey, (short)0);
        return tempDesKey;
    }

    //DES algorithm encrypt and decrypt
    private void doDesCipher(APDU apdu, short len)
    {
        //In Des algorithm the byte length to be encrypted/decrypted must be a multiple of 8
        if (len <= 0 || len % 8 != 0)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        byte[] buffer = apdu.getBuffer();
        Key key = getDesKey();
        byte mode = buffer[ISO7816.OFFSET_P1] == (byte)0x00 ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT;
        Cipher cipher = buffer[ISO7816.OFFSET_P2] == (byte)0x00 ? desEcbCipher : desCbcCipher;
        //Initializes the 'cipher' object with the appropriate Key and algorithm specific parameters.
        //DES algorithms in CBC mode expect a 8-byte parameter value for the initial vector(IV)
        if (cipher == desCbcCipher)
        {
            cipher.init(key, mode, desICV, (short)0, (short)8);
        }
        else
        {
            cipher.init(key, mode);
        }
        //This method must be invoked to complete a cipher operation. Generates encrypted/decrypted output from all/last input data.
        cipher.doFinal(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);
        apdu.setOutgoingAndSend((short)0, len);
    }

}

Тестовый сценарий DES выглядит следующим образом:

Code:
//The test script of DES

//DES Select Applet
00A404000B4A617661436172644F530200;
//TDES-CBC Encrypt
//set Key
802002001810E976F89D2561A110E976F89D2561A110E976F89D2561A1;
//set IV
802100000830E91111589CB432;
//CBC Encrypt
//expect:3C9C65A69E27BB0B9000
802200010841E47B250441B4CA;
//set Key
80200200181FC43761574676981FC43761574676981FC4376157467698;
//set IV
8021000008B7B2CE02BFAEDFFF;
//CBC Encrypt
//expect:A22511500C94F0B3AEA0B25F30CB3F839000
8022000110C2EF8033D8D87B5A57C7AE00E6D0AEF5;
//3DEC-CBC Decrypt
// set Key
80200200187CB5F79EC8897C387CB5F79EC8897C387CB5F79EC8897C38;
//set IV
8021000008A25B018DA1AC6A81;
//CBC Decrypt
//expect:7F34DBAA1FA3848D8EF325ED4E291F13D9C6C8A8B10EA21C0ACADF9D8642413B9000
8022010120FD9B328DCC0C86DD36FB6A559E94720D4C4C47D4620C4274119139370C1399A9;
//3DES-ECB Encrypt
//set Key
80200200184CDA838AA42AD02A4CDA838AA42AD02A4CDA838AA42AD02A;
//ECB Encrypt
//expect:0DEAC65F762C8A819000
8022000008869300AFABCF8C8B;
// set Key
8020020018f4d04345e01c68f4f4d04345e01c68f4f4d04345e01c68f4;
//EBC Decrypt
//expect:86104538adf59381f490f78eff7c32f137d3085e2a9d7780de94cecaa6c0f7b29000
8022010020251b7467867536fa8590da6b5bd30266536de9c72c32ec0abfa74a02e25828ce;

Пример кода AES​


Code:
/*
* @file  AESSample.java
* @version v1.0
* Package AID: 4A617661436172644F53
* Applet AID: 4A617661436172644F5301
* @brief The ALgorithm of AES Sample Code in JavaCard API Specification
* @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
*/
package JavaCardOS.Sample.Algorithm;

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

public class AESSample extends Applet
{
    private static final byte INS_SET_AES_KEY              = (byte)0x10;
    private static final byte INS_SET_AES_ICV              = (byte)0x11;
    private static final byte INS_DO_AES_CIPHER            = (byte)0x12;

    private byte aesKeyLen;
    private byte[] aesKey;
    private byte[] aesICV;

    private Cipher aesEcbCipher;
    private Cipher aesCbcCipher;

    private Key tempAesKey1;
    private Key tempAesKey2;
    private Key tempAesKey3;

    public AESSample()
    {
        aesKey = new byte[32];
        aesICV = new byte[16];
        aesKeyLen = 0;
        //Create a AES ECB/CBS object instance of the AES algorithm.
        aesEcbCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_ECB_NOPAD, false);
        aesCbcCipher = Cipher.getInstance(Cipher.ALG_AES_BLOCK_128_CBC_NOPAD, false);
        //Create uninitialized cryptographic keys for AES algorithms
        tempAesKey1 = KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_128, false);
        tempAesKey2 = KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_192, false);
        tempAesKey3 = KeyBuilder.buildKey(KeyBuilder.TYPE_AES_TRANSIENT_DESELECT, KeyBuilder.LENGTH_AES_256, false);

        JCSystem.requestObjectDeletion();
    }

    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new AESSample().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    }

    public void process(APDU apdu)
    {
        if (selectingApplet())
        {
            return;
        }

        byte[] buf = apdu.getBuffer();
        short len = apdu.setIncomingAndReceive();

        switch (buf[ISO7816.OFFSET_INS])
        {
        case INS_SET_AES_KEY:
            // SET_AES_KEY
            setAesKey(apdu, len);
            break;
        case INS_SET_AES_ICV:
            // SET_AES_ICV
            setAesICV(apdu, len);
            break;
        case INS_DO_AES_CIPHER:
            //DO_AES_CIPHER
            doAesCipher(apdu, len);
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    //Set the key of AES Encrypt/Decrypt
    private void setAesKey(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        byte keyLen = 0;
        switch (buffer[ISO7816.OFFSET_P1])
        {
        case (byte)0x01:
            if (len != 16) // The length of key is 16 bytes
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            keyLen = (byte)16;
            break;
        case (byte)0x02:
            if (len != 24) //The length of key is 24 bytes
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            keyLen = (byte)24;
            break;
        case (byte)0x03:
            if (len != 32) //The length of key is 32 bytes
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            keyLen = (byte)32;
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            break;
        }

        JCSystem.beginTransaction();
        //Copy the incoming AES Key value to the global variable 'aesKey'
        Util.arrayCopy(buffer, ISO7816.OFFSET_CDATA, aesKey, (short)0, len);
        aesKeyLen = keyLen;
        JCSystem.commitTransaction();
    }

    //Set AES ICV, ICV is the initial vector
    private void setAesICV(APDU apdu, short len)
    {
        if (len != 16)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        //Copy the incoming ICV value to the global variable 'aesICV'
        Util.arrayCopy(apdu.getBuffer(), ISO7816.OFFSET_CDATA, aesICV, (short)0, (short)16);
    }

    //Sets the Key data, and return the AESKey object. The plaintext length of input key data is 16/24/32 bytes.
    private Key getAesKey()
    {
        Key tempAesKey = null;
        switch (aesKeyLen)
        {
        case (byte)16:
            tempAesKey = tempAesKey1;
            break;
        case (byte)24:
            tempAesKey = tempAesKey2;
            break;
        case (byte)32:
            tempAesKey = tempAesKey3;
            break;
        default:
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
            break;
        }
        //Set the 'aesKey' key data value into the internal representation
        ((AESKey)tempAesKey).setKey(aesKey, (short)0);
        return tempAesKey;
    }

   //AES algorithm encrypt and decrypt
    private void doAesCipher(APDU apdu, short len)
    {
        //The byte length to be encrypted/decrypted must be a multiple of 16
        if (len <= 0 || len % 16 != 0)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        byte[] buffer = apdu.getBuffer();
        Key key = getAesKey();
        byte mode = buffer[ISO7816.OFFSET_P1] == (byte)0x00 ? Cipher.MODE_ENCRYPT : Cipher.MODE_DECRYPT;
        Cipher cipher = buffer[ISO7816.OFFSET_P2] == (byte)0x00 ? aesEcbCipher : aesCbcCipher;
        //Initializes the 'cipher' object with the appropriate Key and algorithm specific parameters.
        //AES algorithms in CBC mode expect a 16-byte parameter value for the initial vector(IV)
        if (cipher == aesCbcCipher)
        {
            cipher.init(key, mode, aesICV, (short)0, (short)16);
        }
        else
        {
            cipher.init(key, mode);
        }
        //This method must be invoked to complete a cipher operation. Generates encrypted/decrypted output from all/last input data.
        cipher.doFinal(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);
        apdu.setOutgoingAndSend((short)0, len);
    }

}

Тестовый сценарий AES выглядит следующим образом:

Code:
//The test script of AES

//AES Select Applet
00A404000B4A617661436172644F530100;
//AES-CBC-256Key
//set Key  CBC-256 Key Length
80100300209AF0BF0D5D711B9E01C59ED55A015C8AB2D3980010B72CBBBA6E2C91F8ADC604;
//set ICV
80110000101C64F340DD29C891B4826509A1FF64E8;
//CBC encrypt
//expect: E2E6C4AB4D212BB52A292B6368137D3E9000
8012000110C9C9332182CFC8AB48908A972D283582;
//AES-CBC-256Key
//set Key  CBC-256 Key Length
8010030020B57260D2B78CF4B37F315000B7720F796A3E379E6934BB21EEB6449C803F3080;
//set ICV
80110000103DCBD02A91EA65D1A2E23A53584AA18A;
//CBC decrypt
//expect:722D19DB28EF9088CB5FE90784C16A3E336156D29CC4421A398B9C22C63E2F074FADA2B9D95AF7BBE2F246000E20AEB03BAFBE61E2768E92FDF537B29ADA75FF93BDBE4DE2A8F053229B6C5062F8F23D71546689B0F48622B59A6BA30EF151D53B3616B9FEF7AE9A95CE56EABB292E9BAF3B380B915BBFD3AB3238AF99F56E4EED4682D146DA18F92902D1A085EE9E609000
80120101902D5D6440C517EBC13EFC8E2471918C3C34620A287D9C5A84CBD77CDCC134E56614A880F0A897F317F6A523BAB1C9FAAEA9A368B3EF0FA7A73AFAC4FA89745B620A07A2D03B47A8A24FABDF1AD39BD90F91CA4FE2B5C667B42ECE36D657E38481D721D0C8C65094CA11B7CB2C1F30AFC7B482C79D16EA21126FFBDD5973A9EB2C42A014C090DA3FF80370EDD9DCB0073E;
//AES-ECB-192Key
//set Key
801002001800CF30D306C95D3851B85D11786917BA3C28F8FB0E349524;
//ECB encrypt
//expect:1108C33BCAB8B43FB229AFDACEBB7859A498371191DEBCD1E40916E2C72835E41B3F536A27D35429FED70B2973862F1C9000
801200003012A4D1CDB906E044B14CC2BC2D6DE6FBAE708568CC248266331195E0ECAEA825DED581F79473A2DE40846DC3003F8CB9;
//AES-ECB-192Key
//set Key
8010020018DCC25F4F162E0F9B5A2617F6341AF37AA41C3EE4C1F27848;
//ECB decrypt
//expect:475161225A00DBBD3CDEB304BB5F8FCCD40B266DB5BC164E23F646EB542D6BA988099087CDC1B98749F61D3EDFFAAAA50564D6BBCF49C9F3267E86877521A18C1897DA808BD356E65261B2F208CE065B9000
801201005006E99C9EBAB3D08F7EE117838078B3C7AF419F797B7672E2DBC2850695695878BAC232736FEE0827F3C4A051DE0BF70EA7ECDFF169A6EC53E78491EACD0D879E397A6E97796DB79B17DFC197125A427B;

Пример кода RSA​


Code:
/*
* @file  RSASample.java
* @version v1.0
* Package AID: 4A617661436172644F53
* Applet AID: 4A617661436172644F5303
* @brief The ALgorithm of RSA Sample Code in JavaCard API Specification
* @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
*/

package JavaCardOS.Sample.Algorithm;

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

public class RSASample extends Applet
{
    private static final byte INS_GEN_RSA_KEYPAIR          = (byte)0x30;
    private static final byte INS_GET_RSA_PUBKEY           = (byte)0x31;
    private static final byte INS_GET_RSA_PRIKEY           = (byte)0x32;
    private static final byte INS_SET_RSA_PUBKEY           = (byte)0x33;
    private static final byte INS_SET_RSA_PRIKEY           = (byte)0x34;
    private static final byte INS_RSA_SIGN                 = (byte)0x35;
    private static final byte INS_RSA_VERIFY               = (byte)0x36;
    private static final byte INS_DO_RSA_CIPHER            = (byte)0x37;

    private byte[] tempBuffer;

    private byte[] flags;
    private static final short OFF_INS    = (short)0;
    private static final short OFF_P1     = (short)1;
    private static final short OFF_P2     = (short)2;
    private static final short OFF_LEN    = (short)3;
    private static final short FLAGS_SIZE = (short)5;

    private static final byte ID_N   = 0;
    private static final byte ID_D   = 1;
    private static final byte ID_P   = 2;
    private static final byte ID_Q   = 3;
    private static final byte ID_PQ  = 4;
    private static final byte ID_DP1 = 5;
    private static final byte ID_DQ1 = 6;

    private byte[] rsaPubKey;
    private short rsaPubKeyLen;
    private byte[] rsaPriKey;
    private short rsaPriKeyLen;
    private boolean isRSAPriKeyCRT;
    private Cipher rsaCipher;  
    private Signature rsaSignature;

    private static final short SW_REFERENCE_DATA_NOT_FOUND = (short)0x6A88;

    public RSASample()
    {
        //Create a transient byte array to store the temporary data
        tempBuffer = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT);
        flags = JCSystem.makeTransientByteArray(FLAGS_SIZE, JCSystem.CLEAR_ON_DESELECT);

        rsaPubKey = new byte[(short)    (256 + 32)];
        rsaPriKey = new byte[(short)(128 * 5)];
        rsaPubKeyLen = 0;
        rsaPriKeyLen = 0;
        isRSAPriKeyCRT = false;
        rsaSignature = null;
        //Create a RSA(not pad) object instance
        rsaCipher = Cipher.getInstance(Cipher.ALG_RSA_NOPAD, false);

        JCSystem.requestObjectDeletion();
    }

    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new RSASample().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    }

    public void process(APDU apdu)
    {
        if (selectingApplet())
        {
            return;
        }

        byte[] buf = apdu.getBuffer();
        short len = apdu.setIncomingAndReceive();
        switch (buf[ISO7816.OFFSET_INS])
        {
        case INS_GEN_RSA_KEYPAIR:
            //GEN_RSA_KEYPAIR
            genRsaKeyPair(apdu, len);
            break;
        case INS_GET_RSA_PUBKEY:
            //GET_RSA_PUBKEY
            getRsaPubKey(apdu, len);
            break;
        case INS_GET_RSA_PRIKEY:
            //GET_RSA_PRIKEY
            getRsaPriKey(apdu, len);
            break;
        case INS_SET_RSA_PUBKEY:
            // SET_RSA_PUBKEY
            setRsaPubKey(apdu, len);
            break;
        case INS_SET_RSA_PRIKEY:
            //SET_RSA_PRIKEY
            setRsaPriKey(apdu, len);
            break;
        case INS_RSA_SIGN:
            //RSA_SIGN
            rsaSign(apdu, len);
            break;
        case INS_RSA_VERIFY:
            //RSA_VERIFY
            rsaVerify(apdu, len);
            break;
        case INS_DO_RSA_CIPHER:  
            //RSA_CIPHER
            doRSACipher(apdu, len);
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    //RSA algorithm encrypt and decrypt
    private void doRSACipher(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        byte p1Tmp = buffer[ISO7816.OFFSET_P1];
        boolean hasMoreCmd = (p1Tmp & 0x80) != 0;
        boolean isEncrypt = (p1Tmp & 0x01) != 1;
        short keyLen = (p1Tmp & 0x08) == (byte)0x00 ? KeyBuilder.LENGTH_RSA_1024 : KeyBuilder.LENGTH_RSA_2048;
        short offset = (p1Tmp & 0x08) == (byte)0x00 ? (short)128 : (short)256;

        if (len  rsaPubKey.length)
        {
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }
        //Copy the value of RSA public key  to the global variable 'rsaPubKey'.
        Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, rsaPubKey, loadedLen, len);
        loadedLen += len;

        if ((buffer[ISO7816.OFFSET_P1] & 0x80) == 0) //last block
        {
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            short modLen = (buffer[ISO7816.OFFSET_P1] & 0x01) == 0 ? (short)128 : (short)256;
            if (loadedLen < modLen + 3 || loadedLen > modLen + 32)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }

            rsaPubKeyLen = loadedLen;
        }
        else
        {
            Util.setShort(flags, OFF_LEN, loadedLen);
        }

    }

    //Set the value of RSA private key
    private void setRsaPriKey(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        if (buffer[ISO7816.OFFSET_P2] == 0) // first block
        {
            rsaPriKeyLen = (short)0;
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3);
            Util.setShort(flags, OFF_LEN, (short)0);
        }
        else
        {
            if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS]
                    || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f)
                    || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1))
            {
                Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }

            flags[OFF_P2] ++;
        }
        short loadedLen = Util.getShort(flags, OFF_LEN);
        if (loadedLen + len > rsaPriKey.length)
        {
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }
        //Copy the value of RSA private key  to the global variable 'rsaPriKey'.
        Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, rsaPriKey, loadedLen, len);
        loadedLen += len;

        if ((buffer[ISO7816.OFFSET_P1] & 0x80) == 0) //last block
        {
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            short modLen = (buffer[ISO7816.OFFSET_P1] & 0x01) == 0 ? (short)128 : (short)256;
            boolean isCRT = (buffer[ISO7816.OFFSET_P1] & 0x40) != 0;
            if ((isCRT && (loadedLen != modLen / 2 * 5)) || (!isCRT && (loadedLen != modLen * 2)))
            {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }

            isRSAPriKeyCRT = isCRT;
            rsaPriKeyLen = loadedLen;
        }
        else
        {
            Util.setShort(flags, OFF_LEN, loadedLen);
        }
    }
    //
    private void genRsaKeyPair(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        short keyLen = buffer[ISO7816.OFFSET_P1] == 0 ? (short)1024 : (short)2048;
        byte alg = buffer[ISO7816.OFFSET_P2] == 0 ? KeyPair.ALG_RSA : KeyPair.ALG_RSA_CRT;
        KeyPair keyPair = new KeyPair(alg, keyLen);
        if (len > 32)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
        if (len > 0)
        {
            ((RSAPublicKey)keyPair.getPublic()).setExponent(buffer, ISO7816.OFFSET_CDATA, len);
        }
        //(Re)Initializes the key objects encapsulated in this KeyPair instance with new key values.
        keyPair.genKeyPair();
        JCSystem.beginTransaction();
        rsaPubKeyLen = 0;
        rsaPriKeyLen = 0;
        JCSystem.commitTransaction();
        //Get a reference to the public key component of this 'keyPair' object.
        RSAPublicKey pubKey = (RSAPublicKey)keyPair.getPublic();
        short pubKeyLen = 0;
        //Store the RSA public key value in the global variable 'rsaPubKey', the public key contains modulo N and Exponent E
        pubKeyLen += pubKey.getModulus(rsaPubKey, pubKeyLen);
        pubKeyLen += pubKey.getExponent(rsaPubKey, pubKeyLen);

        short priKeyLen = 0;
        if (alg == KeyPair.ALG_RSA)
        {
            isRSAPriKeyCRT = false;
            //Returns a reference to the private key component of this KeyPair object.
            RSAPrivateKey priKey = (RSAPrivateKey)keyPair.getPrivate();
            //RSA Algorithm,  the Private Key contains N and D, and store these parameters value in global variable 'rsaPriKey'.
            priKeyLen += priKey.getModulus(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getExponent(rsaPriKey, priKeyLen);
        }
        else //RSA CRT
        {
            isRSAPriKeyCRT =  true;
            //The RSAPrivateCrtKey interface is used to sign data using the RSA algorithm in its Chinese Remainder Theorem form.
            RSAPrivateCrtKey priKey = (RSAPrivateCrtKey)keyPair.getPrivate();
            //RSA CRT Algorithm,  the Private Key contains P Q PQ DP and DQ, and store these parameters value in global variable 'rsaPriKey'.
            priKeyLen += priKey.getP(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getQ(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getPQ(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getDP1(rsaPriKey, priKeyLen);
            priKeyLen += priKey.getDQ1(rsaPriKey, priKeyLen);
        }

        JCSystem.beginTransaction();
        rsaPubKeyLen = pubKeyLen;
        rsaPriKeyLen = priKeyLen;
        JCSystem.commitTransaction();

        JCSystem.requestObjectDeletion();
    }
   //RSA Signature
    private void rsaSign(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        if (rsaPriKeyLen == 0)
        {
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
        }
        boolean hasMoreCmd = (buffer[ISO7816.OFFSET_P1] & 0x80) != 0;
        short resultLen = 0;
        if (buffer[ISO7816.OFFSET_P2] == 0) //first block
        {
            Key key;
            if (!isRSAPriKeyCRT)
            {
                short ret;
                //Creates uninitialized private keys for signature algorithms.
                key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PRIVATE, (short)(rsaPriKeyLen / 2 * 8), false);
                ret = getRsaPriKeyComponent(ID_N, tempBuffer, (short)0);
                ((RSAPrivateKey)key).setModulus(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_D, tempBuffer, (short)0);
                ((RSAPrivateKey)key).setExponent(tempBuffer, (short)0, ret);
            }
            else
            {
                short ret;
                //Creates uninitialized private keys for signature algorithms.
                key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_CRT_PRIVATE, (short)(rsaPriKeyLen / 5 * 16), false);
                ret = getRsaPriKeyComponent(ID_P, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setP(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_Q, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setQ(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_DP1, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setDP1(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_DQ1, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setDQ1(tempBuffer, (short)0, ret);
                ret = getRsaPriKeyComponent(ID_PQ, tempBuffer, (short)0);
                ((RSAPrivateCrtKey)key).setPQ(tempBuffer, (short)0, ret);
            }
            // Creates a Signature object instance of the ALG_RSA_SHA_PKCS1 algorithm.
            rsaSignature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false);
            JCSystem.requestObjectDeletion();
            //Initializ the Signature object.
            rsaSignature.init(key, Signature.MODE_SIGN);

            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3);
            JCSystem.requestObjectDeletion();
        }
        else
        {
            if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS]
                    || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f)
                    || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1))
            {
                Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }

            flags[OFF_P2] ++;
        }

        if (hasMoreCmd)
        {
            // Accumulates a signature of the input data.
            rsaSignature.update(buffer, ISO7816.OFFSET_CDATA, len);
        }
        else
        {
            //Generates the signature of all input data.
            short ret = rsaSignature.sign(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            apdu.setOutgoingAndSend((short)0, ret);
        }
    }
    //RSA Signature and Verify
    private void rsaVerify(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        if (rsaPubKeyLen == 0)
        {
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
        }
        boolean hasMoreCmd = (buffer[ISO7816.OFFSET_P1] & 0x80) != 0;
        short resultLen = 0;
        short offset = ISO7816.OFFSET_CDATA;
        short modLen = rsaPubKeyLen > 256 ? (short)256 : (short)128;
        if (buffer[ISO7816.OFFSET_P2] == 0) //first block
        {
            Key key;
            // Create uninitialized public keys for signature  algorithms.
            key = KeyBuilder.buildKey(KeyBuilder.TYPE_RSA_PUBLIC, (short)(modLen * 8), false);
            //Sets the modulus value of the key.
            ((RSAPublicKey)key).setModulus(rsaPubKey, (short)0, modLen);
            //Sets the public exponent value of the key.
            ((RSAPublicKey)key).setExponent(rsaPubKey, modLen, (short)(rsaPubKeyLen - modLen));

            //Create a ALG_RSA_SHA_PKCS1 object instance.
            rsaSignature = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1, false);
            JCSystem.requestObjectDeletion();
            //Initializes the Signature object with the appropriate Key.
            rsaSignature.init(key, Signature.MODE_VERIFY);
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_INS, flags, OFF_INS, (short)3);
            Util.setShort(flags, OFF_LEN, (short)0);
            JCSystem.requestObjectDeletion();
        }
        else
        {
            if (flags[OFF_INS] != buffer[ISO7816.OFFSET_INS]
                    || (flags[OFF_P1] & 0x7f) != (buffer[ISO7816.OFFSET_P1] & 0x7f)
                    || (short)(flags[OFF_P2] & 0xff) != (short)((buffer[ISO7816.OFFSET_P2] & 0xff) - 1))
            {
                Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }

            flags[OFF_P2] ++;
        }

        short sigLen = Util.getShort(flags, OFF_LEN);
        if (sigLen < modLen)
        {
            short readLen = (short)(modLen - sigLen);
            if (readLen > len)
            {
                readLen = len;
            }
            Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, tempBuffer, sigLen, readLen);
            sigLen += readLen;
            len -= readLen;
            Util.setShort(flags, OFF_LEN, sigLen);
            offset += readLen;
        }
        if (hasMoreCmd)
        {
            if (len > 0)
            {
                //Accumulates a signature of the input data.
                rsaSignature.update(buffer, offset, len);
            }
        }
        else
        {
            if (sigLen != modLen)
            {
                Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }
            //Verify the signature of all/last input data against the passed in signature.
            boolean ret = rsaSignature.verify(buffer, offset, len, tempBuffer, (short)0, sigLen);
            Util.arrayFillNonAtomic(flags, (short)0, (short)flags.length, (byte)0);
            buffer[(short)0] = ret ? (byte)1 : (byte)0;
            apdu.setOutgoingAndSend((short)0, (short)1);
        }
    }

}

Тестовый сценарий RSA выглядит следующим образом:

Code:
//The test script of RSA

//RSA Select Applet
00A404000B4A617661436172644F530300;
//RSA
//generate-keypair-1024 in card
80300000;
//get Publck Key -  N
80310000;

//get Publck Key - E  The data of response APDU command is 4 bytes, such as 01 00 01 90 00
80310100;
//get RSA Private Key - N
80320000;
//get RSA Private Key - D
80320100;

//RSA encrypt - 2048
//set RSA Public key 2048bit

80338100C8C24A7A902FA8983CBBAB3F690528F86D5591496374E6B3B4EC47CA644CB55F204C4D5EEBBD9D236B6F74AC209738CB294A7C26F1251D838EDF8ADAF3E287743A5D7C65BBBCFE4A22BEB06D0D65DAFE1D1217E8AB9E5B7AA0D3883A4D6D2F5BE5B295AE6CD495D45D4452876F573C3EDD402E3BA998EC1078F662027A5F7BCE949C3B3F0309B1BE5EE9AAE720C97C2C2F0CBCD298E3FC049A457513DCCC70BDA06949011BC1F0DB6F499685377DF87B3E66890FB4C0CC09CF12DB338394C44E324D0F1931D623C035;
803301013BD00F518C353243CD22A3239811928163DCDA1352044AE4E15F10FEF648E98AE88B7BBA89F29C7EFAE5EE04E299F90F52FEE263AF2DA885FB010001;
//set RSA Private Key 2048bit
80348100C8C24A7A902FA8983CBBAB3F690528F86D5591496374E6B3B4EC47CA644CB55F204C4D5EEBBD9D236B6F74AC209738CB294A7C26F1251D838EDF8ADAF3E287743A5D7C65BBBCFE4A22BEB06D0D65DAFE1D1217E8AB9E5B7AA0D3883A4D6D2F5BE5B295AE6CD495D45D4452876F573C3EDD402E3BA998EC1078F662027A5F7BCE949C3B3F0309B1BE5EE9AAE720C97C2C2F0CBCD298E3FC049A457513DCCC70BDA06949011BC1F0DB6F499685377DF87B3E66890FB4C0CC09CF12DB338394C44E324D0F1931D623C035;
80348101C8D00F518C353243CD22A3239811928163DCDA1352044AE4E15F10FEF648E98AE88B7BBA89F29C7EFAE5EE04E299F90F52FEE263AF2DA885FB8FFFDD79122995B3A5B0558E03CA0ADE1606596B42505EAEE0549117E796A18B71A202911C76E3B293E7D84F4B65478631F3747553F9DCF0BE93CE95E5B659198D024EF06731DD468528839AE37BFCCD1504ED688D34E5DD5F0A5F93D531BD9DAFCFAA7874D31B9388B8D6325A68877B3A3F49EEF82D364440F001402B96BA533404EB121B0E6604B0678A5AAA100C56;
8034010270B3ECD17EDDCB4F5BC71BBE1E7A405679380E6D9A777AA8452A2DE5F1FECAA09ACEA4A02940A14F28C7CBF7EE0A1A1519B58ED3161A590BC66B82C13CD43C484AD2D77E8301629F9B1EB4C7505C5A7B46C0171668990775FDF2E62BB695DF424130727CD0ACC61943FE8EF513A0AC9BD1;
// RSA Signature  SHA1 &2048bit
//expect:75A78094B3A63715B85327C2839CE1E1831C39B740DDB9F67F27AEBC540DB94BF95C7DEE200AC60A2BF0F64B9F4772A163E036D8DC8E865EFD5B3E7A9442BDF43BA86660D305C15DB2A3A8F5F6E3D1F50E234B193DD787B89E3EDF045E280285474A027E8985F45D883E14593D91CF79017E3AEBCF8A155DD0B5C85BE0A4301D0F80C99A15D154DF54FFE8EB603DA85184386452ABB47C985EF1D5390FF74516A7F0B8A05380DD186AA6FA584287F8AAE6421D98AD84601D734EA008CE0B37FF574BD1C9FE948DABF0A78F4E691FC0A9CAE6DC1288BD2E295CFB31443F09AF16B5D66886BA7AEF2FF272E443ADBA47798F76EF6B4594CEC399526F21236AD3A29000
8035000080C05DECFACFC439CA7AB1EC89F554FF982FB7E8E95FFFC863DFEFE5883EAD5A5591C90D69097BE26ACB2C2EA5FB386FF41AF33AE593EA7418906BC5E912474A4F41D68A04013CACE7C5EBE79EA869397FBA545CB197A3F68E3F2E104C2171C9DD798C4B13DC8FFF0811F5FDBD236EC701B4E2369594B2B48D9341ACF993B33FC5;
//RSA Verify 2048bit
80368000C875A78094B3A63715B85327C2839CE1E1831C39B740DDB9F67F27AEBC540DB94BF95C7DEE200AC60A2BF0F64B9F4772A163E036D8DC8E865EFD5B3E7A9442BDF43BA86660D305C15DB2A3A8F5F6E3D1F50E234B193DD787B89E3EDF045E280285474A027E8985F45D883E14593D91CF79017E3AEBCF8A155DD0B5C85BE0A4301D0F80C99A15D154DF54FFE8EB603DA85184386452ABB47C985EF1D5390FF74516A7F0B8A05380DD186AA6FA584287F8AAE6421D98AD84601D734EA008CE0B37FF574BD1C9FE948DAB;
//expect:019000
80360001B8F0A78F4E691FC0A9CAE6DC1288BD2E295CFB31443F09AF16B5D66886BA7AEF2FF272E443ADBA47798F76EF6B4594CEC399526F21236AD3A2C05DECFACFC439CA7AB1EC89F554FF982FB7E8E95FFFC863DFEFE5883EAD5A5591C90D69097BE26ACB2C2EA5FB386FF41AF33AE593EA7418906BC5E912474A4F41D68A04013CACE7C5EBE79EA869397FBA545CB197A3F68E3F2E104C2171C9DD798C4B13DC8FFF0811F5FDBD236EC701B4E2369594B2B48D9341ACF993B33FC5;
//RSA -2048 encrypt
80378800643E78AA266AA64FED361D907305CD70438AA5F0E674AAD69E5146AD57ACE20DDA79B71C44B4E055B644B4884F25542257C680AFBDB0AF9DC4695E43F998A8226869176A0F33BAC09359773E326EA3BBF99CD04D3746E60D31EC761A174F4AE137D6419B71;
8037880164315A16EB3C0EB90626E3C390D23ED33B7D78AD4D3E78AA266AA64FED361D907305CD70438AA5F0E674AAD69E5146AD57ACE20DDA79B71C44B4E055B644B4884F25542257C680AFBDB0AF9DC4695E43F998A8226869176A0F33BAC09359773E326EA3BBF9;
//expect:50237853BC0EBF1537BACA8022795F75FBCF4DDAF18FB99464F68E2E29D7023159BE25219D4493EADB048811304301507EEECEEC0056665E77960D338B4AB52B00B2235E2CF390B1BFDB77716C82493D719228385B707D56DAB30C06661218F162181E90094E32C5D1879F1401B3B17CE961297977CA7C97B2C10FC0FF104780A360150C797EDFA60677C200AA78F3EDCC99FDA1BCE14961A65C4F41552EE575EFB07F4074C8071F80AE083F1AA2BFDB0007A824A7828BBFB583D96B6D6EAD84F9124CA9B7A41EC522630C605886E8EAD146A6C837ED88BC39D779541B5586B518F20554FF8D1496B9EB17A3954FBCB9F3E7C5B6F01DA8C973E4B41A96B32F5C9000
80370802389CD04D3746E60D31EC761A174F4AE137D6419B71315A16EB3C0EB90626E3C390D23ED33B7D78AD4DA2353B9A1AF1D2AFA2353B9A1AF1D2AF;
//RSA -2048 decrypt
80378900C850237853BC0EBF1537BACA8022795F75FBCF4DDAF18FB99464F68E2E29D7023159BE25219D4493EADB048811304301507EEECEEC0056665E77960D338B4AB52B00B2235E2CF390B1BFDB77716C82493D719228385B707D56DAB30C06661218F162181E90094E32C5D1879F1401B3B17CE961297977CA7C97B2C10FC0FF104780A360150C797EDFA60677C200AA78F3EDCC99FDA1BCE14961A65C4F41552EE575EFB07F4074C8071F80AE083F1AA2BFDB0007A824A7828BBFB583D96B6D6EAD84F9124CA9B7A41EC5;
803709013822630C605886E8EAD146A6C837ED88BC39D779541B5586B518F20554FF8D1496B9EB17A3954FBCB9F3E7C5B6F01DA8C973E4B41A96B32F5C;
//2048-CRT
//set public Key RSA CRT-2048
80338100C8AF536A413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D8;
803301013B95E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC51010001;
//set private Key RSA CRT-2048
8034C100C8E7F037F8E89DF110BA672C16BDE2930EA223E2CF63FC030650DCA03289DD4FBE1056975FCB4566822E18C9A22437FA8685C7978187E1A72860E4BE19BEAA4A88A9C1A64F3186E39E6618039418528006281ADD687842CF8D27198C6D1E16166A4CE5A983263A776A5DCA829FC2F76B1A9369F5B5B2A62382593E8E00B3D36795C183B0BEB5D5171EC3DC28BD4BFE637F76AB6874EB6E7BCDAC5F782C7FD38C3A71394FA503DA1519413D60577AD831257E8C77356952B9F1BDF909FADC609F05002A532D6FFBEBAD;
8034C101C84E68A2FF5914E2A331CFC001586F74ACE4FFD23C2FB584B175070E2C3AC414259DC831536116BA669DB636FA82E65CE1C2D873E2B40552CDCAEDFEE1BCFBF77E31D1F82908A8B54CE471F58FF3B0B79EB00DE1D195033D52EA0DA48401961227A4D48E488081701DF08997D4C29BEAD4BF2F3BD1AB9431AA9775ED5A63958984BA30868AAE23BD2BBB1815764F5896BFD5AEC2FF2B08D23A7EC18D358C3D2E99798E0C9DABDD145A3F7E7FC741097762853E882DFCFEF0165153C60C9D646456FD45980C11611537;
8034C102C8985B04F8BB926E6D14858816B088CDA15391495AE9A7D81DE594037FBB3B75B91DC7B2B454B5272BDD6DD7CAA73487160C903E849E55321324B15EEFDAE772C4B5E355A78023CD2B2D7EA3E2CF1DE7963688813BDF77B8CFAF3B873A05DF43CAF9CDB9BE9079F91187C18B816B8CC151720904B29DBC80EF6443ECCE00665C83D48E95F3B0795F0388BC89B8CF6AFE8BC2051FE6022B159BD8522EDFDE48604DD4113A7E831E78ECF82235BB5AFAA53AF129FFF21AB7BDDE57025A6B57377386EFE7992231D71C4E;
803441032876743A93B519A6A45C6E57EFC081A3CDB6F92DF81092B02DA06AAC635B981CCBFD62488823C5AF51;
//sign  RSA CRT-2048
80358000C8111111413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D8;
//expect: 7008B8ACE976C4024F5148DCCF30DE9CEF6D330FE803B8516A8099CF795C9C57EF9092F1BA7CB75018BF0A7378062FC6D23208CE916F55E0BA471A977CE86FB3E6AAD1282E33E8E5B8FCCF31B2FF689127C292F9B8CC0F07DDDA17A4B870510F6E19187184C3749D1CA957AB2CDE752D459C3D9427A16168BDF1705536E87A97FAAEC1485F90857A0EB2A8DAF5EEDD59F8285D2E65B8D4DEB24EE59A72645B263D02D604EEE03F93EC04EDC8CBC08619E863B2C4A521244A101C6D2EA3E789F1616CE2DFA11190A6C928C0BE4117DF4555DEA280645454CFD755C3B547813FC46667C96223EC5458A9FCB51BBF9524183F0CF3A00A89B812F597CC7285573E7D9000
803500013895E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC51;
//verify RSA CRT-2048
80368000C87008B8ACE976C4024F5148DCCF30DE9CEF6D330FE803B8516A8099CF795C9C57EF9092F1BA7CB75018BF0A7378062FC6D23208CE916F55E0BA471A977CE86FB3E6AAD1282E33E8E5B8FCCF31B2FF689127C292F9B8CC0F07DDDA17A4B870510F6E19187184C3749D1CA957AB2CDE752D459C3D9427A16168BDF1705536E87A97FAAEC1485F90857A0EB2A8DAF5EEDD59F8285D2E65B8D4DEB24EE59A72645B263D02D604EEE03F93EC04EDC8CBC08619E863B2C4A521244A101C6D2EA3E789F1616CE2DFA11190A6;
80368001C8C928C0BE4117DF4555DEA280645454CFD755C3B547813FC46667C96223EC5458A9FCB51BBF9524183F0CF3A00A89B812F597CC7285573E7D111111413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173;
//expect:01 90 00
8036000270F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D895E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC51;
//encrypt RSA CRT-2048
8037C800C8111111413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D8;
//expect:45ACD17EE02228DE45096F1153EF89DBF72933925A17803142A093FD2300CE27CF26A1B38F402E167647035227E0CBB238208A7E166E9DD4F563E04D48C9916C6812AA40AF4715C2D70D32190BC4F9EC2DA0FAD7EFE703AE2808401AA389698BC7428E9172B868E328DA5698CACDBE489EA871225DBEBB238B015828E4B68B274175910D1F72D8D684D24A40077F3A5C75F086A57B733C74CC94C7377A8F555DCB638A4A336344D9B2D53594E7C24BF3FA85705C2E6818B9703EDBBEFDCFA2FC42D3791816025BE4D3045ABF37AEEDF290B90D93E151AFA128E50A271A19AAA7988EBBACF17D26AAF8AAEA0C027186E2715E3A850971F5F16E44DB4FFACE07D09000
803748013895E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC51;
//decrypt  RSA CRT-2048
8037C900C845ACD17EE02228DE45096F1153EF89DBF72933925A17803142A093FD2300CE27CF26A1B38F402E167647035227E0CBB238208A7E166E9DD4F563E04D48C9916C6812AA40AF4715C2D70D32190BC4F9EC2DA0FAD7EFE703AE2808401AA389698BC7428E9172B868E328DA5698CACDBE489EA871225DBEBB238B015828E4B68B274175910D1F72D8D684D24A40077F3A5C75F086A57B733C74CC94C7377A8F555DCB638A4A336344D9B2D53594E7C24BF3FA85705C2E6818B9703EDBBEFDCFA2FC42D3791816025BE4;
//expect:111111413B40AD9D363E2A8192986A4F054C1C4BE30D47EDD76A32D1AA7EE9A9F91E5BA81D20819B5A5293D8C39F8549E3695E13BE12B19405110D2FBED0E393016D231B4201408CDE963377F802579313ECBBB49320B09D8216374EC50A70D70AE1DE5E0E05AD1B7A1F57638674309FB544EB35CBB5535D3C4C727FF633C6CFFF44F0E141B38074B5C92EF26A57B173F3DDE85C5D4F0B2A3F06E4F1961BB07712D9D0B901EDC8CEA67AEDDBBA0C7EA08857B6934168AF893E7F419DE51E45EEF8272274D85F89D895E867318D75FADC8AA35FC053B3E02EABA50B2D7B61F0F3EB7A4BCE1DDB43B6887C93580F8BAED5B5236EC69A7D1C42CCE978A98160AC519000
8037490138D3045ABF37AEEDF290B90D93E151AFA128E50A271A19AAA7988EBBACF17D26AAF8AAEA0C027186E2715E3A850971F5F16E44DB4FFACE07D0;

Пример кода ECC​


Code:
/*
* @file  ECCSample.java
* @version v1.0
* Package AID: 4A617661436172644F53
* Applet AID: 4A617661436172644F5304
* @brief The ALgorithm of ECC Sample Code in JavaCard API Specification
* @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
*/

package JavaCardOS.Sample.Algorithm;

import javacard.framework.*;
import javacard.security.ECPrivateKey;
import javacard.security.ECPublicKey;
import javacard.security.KeyBuilder;
import javacard.security.*;
import javacardx.crypto.*;

public class ECCSample extends Applet
{
    private static final byte INS_ECC_GEN_KEYPAIR         = (byte)0x41;
    private static final byte INS_ECC_GENA                  = (byte)0x42;
    private static final byte INS_ECC_GENP                  = (byte)0x43;
    private static final byte INS_ECC_GENS                  = (byte)0x44;
    private static final byte INS_ECC_GENW                  = (byte)0x45;
    private static final byte INS_ECC_SETS                  = (byte)0x46;
    private static final byte INS_ECC_SETW                  = (byte)0x47;
    private static final byte INS_ECC_SIGN                 = (byte)0x48;
    private static final byte INS_ECC_VERIFY               = (byte)0x49;


    private byte[] tempBuffer;

    private byte[] flags;
    private static final short FLAGS_SIZE = (short)5;

    private short eccKeyLen;
    private Signature ecdsa;
    private KeyPair eccKey;

    public ECCSample()
    {
        //Create a transient byte array to store the temporary data
        tempBuffer = JCSystem.makeTransientByteArray((short)256, JCSystem.CLEAR_ON_DESELECT);
        flags = JCSystem.makeTransientByteArray(FLAGS_SIZE, JCSystem.CLEAR_ON_DESELECT);

        //Create a ECC(ALG_ECDSA_SHA) object instance
        ecdsa = Signature.getInstance(Signature.ALG_ECDSA_SHA, false);

        JCSystem.requestObjectDeletion();
    }

    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new ECCSample().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    }

    public void process(APDU apdu)
    {
        if (selectingApplet())
        {
            return;
        }

        byte[] buf = apdu.getBuffer();
        short len = apdu.setIncomingAndReceive();
        switch (buf[ISO7816.OFFSET_INS])
        {
        case INS_ECC_GEN_KEYPAIR:
            // GEN_KEYPAIR
            GenEccKeyPair(apdu, len);
            break;
        case INS_ECC_GENA:
            // ECC_GENA
            getEccKeyA(apdu, len);
            break;
        case INS_ECC_GENP:
            // ECC_GENP
            getEccKeyP(apdu, len);
            break;
        case INS_ECC_GENS:
            // ECC_GENS
            getEccKeyS(apdu, len);
            break;
        case INS_ECC_GENW:
            // ECC_GENW
            getEccKeyW(apdu, len);
            break;
        case INS_ECC_SETS://PrivateKey
            // ECC_SETS
            setEccKeyS(apdu, len);
            break;
        case INS_ECC_SETW://PublicKey
            // ECC_SETW
            setEccKeyW(apdu, len);
            break;
        case INS_ECC_SIGN:
            // ECC_SIGN
            Ecc_Sign(apdu, len);
            break;
        case INS_ECC_VERIFY:
            //ECC_VERIFY
            Ecc_Verify(apdu, len);
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    //According to the different key length specified in the incoming APDU , generate ECC key pair and store in the  global variable 'eccKey'
    private void GenEccKeyPair(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        short keyLen = (short)0;
        switch (buffer[ISO7816.OFFSET_P1])
        {
        case (byte)0x01: // 192
            //Constructs a KeyPair instance for the specified algorithm and keylength;
            eccKey = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_192);
            keyLen = (short)24;
            break;
        case (byte)0x02:
            //Here, the KeyBuilder.LENGTH_EC_FP_256 only be used in JavaCard API 3.0.4
            eccKey = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
            keyLen = (short)32;
            break;
        case (byte)0x03: // 384
            //Here, the KeyBuilder.LENGTH_EC_FP_384 only be used in JavaCard API 3.0.4
            eccKey = new KeyPair(KeyPair.ALG_EC_FP,KeyBuilder.LENGTH_EC_FP_384);
            keyLen = (short)48;
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            break;
        }
        //(Re)Initializes the key objects encapsulated in this 'eccKey' KeyPair instance with new key values.
        eccKey.genKeyPair();
        eccKeyLen = keyLen;
    }

    //Returns the first coefficient 'A' of the curve of the key.
    private void getEccKeyA(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        ((ECPrivateKey)eccKey.getPrivate()).getA(buffer, (short)0);
        apdu.setOutgoingAndSend((short)0, eccKeyLen);
    }

    //Returns the field specification parameter value of the key.
    private void getEccKeyP(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        ((ECPrivateKey)eccKey.getPrivate()).getField(buffer, (short)0);
        apdu.setOutgoingAndSend((short)0, eccKeyLen);
    }

    //Returns the coefficient 'S' of the curve of the key.
    private void getEccKeyS(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        short length = ((ECPrivateKey)eccKey.getPrivate()).getS(buffer, (short)0);
        apdu.setOutgoingAndSend((short)0, length);
    }

    //Returns the coefficient 'W' of the curve of the key.
    private void getEccKeyW(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        short length = ((ECPublicKey)eccKey.getPublic()).getW(buffer,(short)0);
        apdu.setOutgoingAndSend((short)0, length);
    }

    //Set the value of ECC private key(SetS)
    private void setEccKeyS(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        switch (buffer[ISO7816.OFFSET_P1])
        {        
        case (byte)0x01: // 192 key
            if (len != 24)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            eccKeyLen = 24;
            //Constructs a KeyPai instance for the ALG_EC_FP algorithm and keylength is 192;
            eccKey = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_192);
            break;
        case (byte)0x02:
            if (len != 32)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            eccKeyLen = 32;
            //Constructs a KeyPai instance for the ALG_EC_FP algorithm and keylength is 256;
            //Here, the KeyBuilder.LENGTH_EC_FP_256 only be used in JavaCard API 3.0.4      
            eccKey = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
            break;
        case (byte)0x03: // 384 key
            if (len != 48)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            eccKeyLen = 48;
            //Constructs a KeyPai instance for the ALG_EC_FP algorithm and keylength is 384;
            //Here, the KeyBuilder.LENGTH_EC_FP_384 only be used in JavaCard API 3.0.4
            eccKey = new KeyPair(KeyPair.ALG_EC_FP,KeyBuilder.LENGTH_EC_FP_384);
            break;
        default:
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
            break;
        }
        //In tempBuffer, the offset from 0 to 1 positions stored ECC private key, including 0 to 0 store the private key length, 130 to 255 store the private key data
        Util.setShort(tempBuffer, (short)0, len);
        Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, tempBuffer, (short)2, len);
    }
    //Set the value of ECC public key(SetW)
    private void setEccKeyW(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        switch (buffer[ISO7816.OFFSET_P1])
        {
        case (byte)0x01: // 192 key
            if (len != 24*2+1)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            eccKeyLen = 24;
            //Constructs a KeyPair instance for the ALG_EC_FP algorithm and keylength is 192;
            eccKey = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_192);
            break;
        case (byte)0x02:
            if (len != 32*2+1)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            eccKeyLen = 32;
            //Constructs a KeyPai instance for the ALG_EC_FP algorithm and keylength is 256;
            //Here, the KeyBuilder.LENGTH_EC_FP_256 only be used in JavaCard API 3.0.4
            eccKey = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_256);
            break;
        case (byte)0x03: // 384 key
            if (len != 48*2+1)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            eccKeyLen = 48;
            //Constructs a KeyPai instance for the ALG_EC_FP algorithm and keylength is 384;
            //Here, the KeyBuilder.LENGTH_EC_FP_384 only be used in JavaCard API 3.0.4
            eccKey = new KeyPair(KeyPair.ALG_EC_FP, KeyBuilder.LENGTH_EC_FP_384);
            break;
        default:
            ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
            break;
        }
        //In tempBuffer, the offset from 128 to 255 positions stored ECC public key, including 128 to 129 store the public key length, 130 to 255 store the private key data
        Util.setShort(tempBuffer, (short)128, len);
        Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, tempBuffer, (short)130, len);
    }

    //ECC signature
    private void Ecc_Sign(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        //(Re)Initializes the key objects encapsulated in this KeyPair instance with new key values.
        eccKey.genKeyPair();
        short eccPriKeyLen = Util.getShort(tempBuffer, (short)0);
        //Returns a reference to the private key component of this  ECC KeyPair object.
        ((ECPrivateKey)eccKey.getPrivate()).setS(tempBuffer, (short)2, eccPriKeyLen);
        //Initializes the Signature object with the ecdsa Key
        ecdsa.init(eccKey.getPrivate(), Signature.MODE_SIGN);
        //Generates the signature of all input data.
        short lenTmp = ecdsa.sign(buffer, ISO7816.OFFSET_CDATA, len, buffer, (short)0);

        apdu.setOutgoingAndSend((short)0, lenTmp);
    }

    //Verify the ECC signature, the format of APDU data field is : the signature data and the data to be verified
    private void Ecc_Verify(APDU apdu, short len)
    {
        byte[] buffer = apdu.getBuffer();
        short signLen = buffer[ISO7816.OFFSET_P1];
        //(Re)Initializes the key objects encapsulated in 'eccKey' KeyPair instance with new key values.
        eccKey.genKeyPair();
        short eccPubKeyLen = Util.getShort(tempBuffer, (short)128);
        // Sets the point of the curve comprising the public key.
        ((ECPublicKey)eccKey.getPublic()).setW(tempBuffer, (short)130, eccPubKeyLen);
        short plainLen = (short)(len - signLen);
        short tmpOff = (short)(ISO7816.OFFSET_CDATA + signLen);
        //Initializes the Signature object with the appropriate Key
        ecdsa.init(eccKey.getPublic(), Signature.MODE_VERIFY);
        //Verify the signature of input data against the passed in ECC signature.
        boolean ret = ecdsa.verify(buffer, (short)tmpOff, plainLen, buffer, ISO7816.OFFSET_CDATA, signLen);
        buffer[(short)0] = ret ? (byte)1 : (byte)0;
        apdu.setOutgoingAndSend((short)0, (short)1);
    }

}

Тестовый сценарий ECC выглядит следующим образом:

Code:
//The test script of ECC

//ECC Select Applet
00A404000B4A617661436172644F530400;
//generate ECC 192 key pair
80410100;
//getEccKeyS
80440000;
//getEccKeyW
80450000;
//ECC 192Key
//set private Key S
8046010018D0F9D631D35D30A6E48983131BC6448F15AE7593D4C22F25;
//set public key W
80470100310442A2DE80594BE0318232749834AD2DE6340B16FC3C2B2F77AE97D1F3C08AAA01C7E2645A12EE5CC698BD649183E5CA3E;
//ECC sign
//The ECC signature results are random, even if the private key and the plaintext are the same, the signature result is also different.
804800000101;
//ECC verify
804938003930360219008F079FD3B1CEF3C1F9881C762CF30DCFA563AAE159A5B48C021900D77839556EDAC3C87BEFFDDB426666E57D6A56F45BCC341D01;

Коммуникация​


Code:
/**
* @file  Communication.java
* @brief Communication Sample Code in JavaCard API Specification
* @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
*/
package JavaCardOS.Sample.Communication;

import javacard.framework.*;
import javacardx.apdu.ExtendedLength;

public class Communication extends Applet implements ExtendedLength
{
    public static final byte INS_SEND_RECV_APDU_1   = 0x01;
    public static final byte INS_SEND_RECV_APDU_2   = 0x02;
    public static final byte INS_RECV_EXTEND_APDU   = 0x03;
    public static final byte INS_SEND_EXTEND_APDU   = 0x04;

    private byte[] tmp_memory;
    public static final short MAX_LENGTH = (short)(0x7FFF);

    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new Communication().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    }

    public void process(APDU apdu)
    {
        if (selectingApplet())
        {
            return;
        }
        //Get the apdu buffer datas
        byte[] buf = apdu.getBuffer();
        byte cla= buf[ISO7816.OFFSET_CLA];
        byte ins = buf[ISO7816.OFFSET_INS];
        byte p1 = buf[ISO7816.OFFSET_P1];
        byte p2 = buf[ISO7816.OFFSET_P2];
        short p1p2 = Util.makeShort(p1, p2);

        if (cla != (byte)0x80)
        {
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
        }

        if (p1p2 != 0x00)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
        }

        //Calling this method indicates that this APDU has incoming data.
        short recvLen = apdu.setIncomingAndReceive();

        //Get the incoming data length(Lc).
        short lc = apdu.getIncomingLength();

        if (lc == 0x00)
        {
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }

        switch (ins)
        {
        case (byte)INS_SEND_RECV_APDU_1:
            //Define a byte string
            byte sendStr[] = {'A','P','D','U', ',', 'C','l','a','s','s', ',', 'D','e','m','o'};
            short len = (short) sendStr.length;

            //Copy character to APDU Buffer.
            Util.arrayCopyNonAtomic(sendStr, (short)0, buf, (short)0, (short)len);

            //Send the 'sendStr' string, the hex of JCRE sending data is the ASCII of sendStr.
            apdu.setOutgoingAndSend((short)0, (short)len);
            break;

        case (byte)INS_SEND_RECV_APDU_2:
            //Set the length of received bytes into the 'buf' array,  the offset is 0.
            Util.setShort(buf, (short)0, (short)lc);

            //Set the data transfer direction to outbound.
            short le = apdu.setOutgoing();

            //Set the expected(le) length of response data.
            apdu.setOutgoingLength((short)le);

            //Sends the data of APDU buffer 'buf', the length is 'le' bytes,  the offset is 0.
            apdu.sendBytes((short) 0, (short)le);
            break;

        case (byte) INS_RECV_EXTEND_APDU: //
            short pointer = 0;
            tmp_memory = new byte[MAX_LENGTH];
            short offData = apdu.getOffsetCdata();
            // recvieve data and put them in a byte array 'tmp_memory'
            while (recvLen > (short) 0)
            {
                Util.arrayCopy(buf, offData, tmp_memory, pointer, recvLen);
                pointer += recvLen;
                //Gets as many data bytes as will fit without APDU buffer overflow
                recvLen = apdu.receiveBytes(offData);
            }

            // send the lc length
            apdu.setOutgoing();
            apdu.setOutgoingLength((short)2);
            Util.setShort(buf, (short)0, lc);
            apdu.sendBytesLong(buf, (short) 0, (short)2);
            break;

        case (byte) INS_SEND_EXTEND_APDU: //
            if(buf[ISO7816.OFFSET_LC] != 0x02)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            short sendLen = Util.getShort(buf, ISO7816.OFFSET_CDATA);
            // send the specified length data in byte array 'tmp_memory'
            apdu.setOutgoing();
            apdu.setOutgoingLength(sendLen);
            apdu.sendBytesLong(tmp_memory, (short)0, sendLen);
            //request Object Deletion
            tmp_memory = null;
            JCSystem.requestObjectDeletion();
            break;

        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

}

Место хранения. Класс примера кода JCSystem.​


Code:
/**
 * @file  Storage.java
* @brief The Class of JCSystem Sample Code in JavaCard API Specification
* @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
*/
 
package JavaCardOS.Sample.Storage;
 
import javacard.framework.*;
 
public class Storage extends Applet
{
 
    public static final byte INS_GET_MEMORY_EEPROM   = 0x01;
    public static final byte INS_GET_MEMORY_COR     = 0x02;
    public static final byte INS_GET_MEMORY_COD     = 0x03;
    public static final byte INS_MAKE_TRANSIENT     = 0x04;
 
    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new Storage().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    }
 
    public void process(APDU apdu)
    {
        if (selectingApplet())
        {
            return;
        }
 
        byte[] buf = apdu.getBuffer();
        boolean isDeletionSupported = false;
        switch (buf[ISO7816.OFFSET_INS])
        {
        case INS_GET_MEMORY_EEPROM:
            int memsize_All = 0;
            short memSize_EEP = 0;
            //If the number of available bytes is greater than 32767, then this method returns 32767.
            //It's necessary to apply memory, to allow the remaining the available bytes is less than 32767
            try{
                while(true){
                    //Creates a persistent memory byte array with the specified array length
                    byte[] temp = new byte[(short)0x7FFF];
                    memsize_All += (short)0x7FFF;
                            }
            }catch(Exception e)
            {
                //Obtains the amount of memory of the persistent type that is available to the applet.
                memSize_EEP = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT); 
            }
            memsize_All += memSize_EEP;
            //Splits the int types data 'memsize_All' into 2 short types
            short Tmp1 = (short)((memsize_All >> 16) & 0xFFFF);
            short Tmp2 = (short)(memsize_All & 0xFFFF);
            //Deposits the short value as two successive bytes in the byte array.
            Util.setShort(buf, (short)0, Tmp1); 
            Util.setShort(buf, (short)2, Tmp2); 
            //Request the object deletion service of the Java Card runtime environment.
            apdu.setOutgoingAndSend((short)0, (short)4);
            //Determine if the implementation for the Java Card platform supports the object deletion mechanism
            isDeletionSupported = JCSystem.isObjectDeletionSupported();
            if (isDeletionSupported)
            {
                ////if the Java Card platform supports the object deletion mechanism, request Object Deletion
                JCSystem.requestObjectDeletion();
            }
            break;
        case INS_GET_MEMORY_COR:
            //Obtains the amount of memory of the CLEAR_ON_RESET type that is available to the applet.
            short memSize_COR = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET); 
            //Deposits the short value 'memSize_COR' as two successive bytes in the byte array 'buf'.
            Util.setShort(buf, (short)0, memSize_COR);   
            apdu.setOutgoingAndSend((short)0, (short)2);         
            break;
        case INS_GET_MEMORY_COD:
            //Obtains the amount of memory of the CLEAR_ON_DESELECT type that is available to the applet.
            short memSize_COD = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);   
            //Deposits the short value 'memSize_COD' as two successive bytes in the byte array 'buf'.
            Util.setShort(buf, (short)0, memSize_COD);   
            apdu.setOutgoingAndSend((short)0, (short)2);     
            break;
        case INS_MAKE_TRANSIENT:
            apdu.setIncomingAndReceive();
            short lc = apdu.getIncomingLength();
            if (lc == 0x00)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            //Creates a transient byte array with the specified array length
            byte[] tmpMemory = JCSystem.makeTransientByteArray((short)100, JCSystem.CLEAR_ON_DESELECT);
            //Begins an atomic transaction, to ensure the integrity of data
            JCSystem.beginTransaction();
            //Copies an array from the 'buf' source array, beginning at the ISO7816.OFFSET_CDATA position(non-atomically).
            Util.arrayCopyNonAtomic(buf, ISO7816.OFFSET_CDATA, tmpMemory, (short)0, lc);
            //Copies an array from the 'tmpMemory' source array, beginning at the 0 position
            Util.arrayCopy(tmpMemory, (short)0, buf, (short)0, lc);
            //Commits an atomic transaction. The contents of commit buffer is atomically committed.
            JCSystem.commitTransaction();
            apdu.setOutgoingAndSend((short)0, (short)lc);
            //Determine if the implementation for the Java Card platform supports the object deletion mechanism
            isDeletionSupported = JCSystem.isObjectDeletionSupported();
            if (isDeletionSupported)
            {
                //if the Java Card platform supports the object deletion mechanism, request Object Deletion
                JCSystem.requestObjectDeletion();
            }
            break;
 
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }
}

Пример кода утилиты​


Code:
/*
 * @file  Utility.java
* @brief The Class of Util Sample Code in JavaCard API Specification
* @comment The purpose of this example is only used to show the usage of API functions and there is no practical significance.
*/
package JavaCardOS.Sample.Utility;
 
import javacard.framework.*;
 
public class Utility extends Applet
{
    public static final byte INS_ARRAY_COPY_APDU    = 0x01;
    public static final byte INS_ARRAY_COMPARE_APDU  = 0x02;
    public static final byte INS_SHORT_VALUE_APDU   = 0x03;
    //Redefine the SW1,SW2 error codes
    short SW_DATA_CONVERT_ERROR = 0x6F80;
 
    public static void install(byte[] bArray, short bOffset, byte bLength)
    {
        new Utility().register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    }
 
    public void process(APDU apdu)
    {
        if (selectingApplet())
        {
            return;
        }
        //Get the apdu buffer datas
        byte[] buf = apdu.getBuffer();
        byte ins = buf[ISO7816.OFFSET_INS];
 
        switch (ins)
        {
        case (byte)INS_ARRAY_COPY_APDU:
            apdu.setIncomingAndReceive();
            //Create a transient byte array with the specified array length
            byte[] tmpMemory = JCSystem.makeTransientByteArray((short)10, JCSystem.CLEAR_ON_DESELECT);
            //Fill the byte array 'tmpMemory' (non-atomically) with the value 0x66, beginning from the 0 position, the filling length is 10.
            Util.arrayFillNonAtomic(tmpMemory, (short)0, (short)10, (byte)0x66);
            //Copy an array from the 'tmpMemory' array to APDU Buffer.
            Util.arrayCopy(tmpMemory, (short)0, buf, (short)0, (short)10);
            //Send the length of 10 bytes from the APDU buffer
            apdu.setOutgoingAndSend((short)0, (short)10);
            break;
 
        case INS_ARRAY_COMPARE_APDU:
            //Calling this method indicates that this APDU has incoming data.
            apdu.setIncomingAndReceive();
 
            //Get the incoming data length(Lc).
            short lc = apdu.getIncomingLength();
 
            if (lc != 0x04)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            //Define a byte array named 'cmpArray'
            byte[] cmpArray = {(byte) 0x01, (byte) 0x02, (byte) 0x03, (byte) 0x04};
            //Compare an array from the specified source array,
            byte cmpResult = Util.arrayCompare(cmpArray, (short)0, buf, (short)ISO7816.OFFSET_CDATA, (short)4);
            //if the comparison of the results is same, set the value of 'buf' byte array to "01", if not, set to "02"
            if (cmpResult == (byte)0)
            {
                buf[0] = (byte)1;
            }
            else
            {
                buf[0] = (byte)2;
            }
            apdu.setOutgoingAndSend((short)0, (short)1);
            break;
 
        case INS_SHORT_VALUE_APDU:
            apdu.setIncomingAndReceive();
            //Get the incoming data length(Lc).
            short len = apdu.getIncomingLength();
 
            if (len != 0x02)
            {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
            //Concatenates the two parameter bytes to form a short value.
            short short_value1 = Util.makeShort(buf[ISO7816.OFFSET_CDATA], buf[ISO7816.OFFSET_CDATA+1]);
 
            //Concatenates two bytes in a byte array to form a short value.
            short short_value2 = Util.getShort(buf, ISO7816.OFFSET_CDATA);
            //compare the result value that two methods converted
            if (short_value1 != short_value2)
            {
                ISOException.throwIt(SW_DATA_CONVERT_ERROR);
            }
 
            //Deposits the short value as two successive bytes at the specified offset in the byte array.
            Util.setShort(buf, (short)0, short_value1);
            apdu.setOutgoingAndSend((short)0, (short)2);
            break;
        default:
            ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }
}
 
Top