Java Card A communication error with the smart card has been detected

0

I building a project on Java Card using Java Card 2.1.2 SDK and GPShell as the way of communicating with the device.I tested the helloworld example from GpShell and I managed to send Simple APDU . However when I try to send APDU to a bigger .cap file the device gives me the following error

send_APDU() returns 0x8010002F (A communications error with the smart card has b
een detected. Retry the operation.
)

I attached pieces of code from the applet below.It seems to me a memory problem although Java Card has 80 Kb EEPROM and almost 2 Kb of RAM.In the Eclipse simulator the application works well.

TwineCipher.java

 public class TwineCipher implements IConsts{

    /**
     * The 80 bits of cipher twine
     */

    public static final short MAX_MEMORY_TEMPORARY=32;
    private static  TwineCipher ref_twineCipher_80 = null;
    private static  TwineCipher ref_twineCipher_128 = null;

    public  byte[] temp   =  JCSystem.makeTransientByteArray(MAX_MEMORY_TEMPORARY,JCSystem.CLEAR_ON_DESELECT);
    public  byte[] rk   = JCSystem.makeTransientByteArray((short) ((short)36*8),JCSystem.CLEAR_ON_DESELECT); 

    private static byte  [] roundconst = 
        {
                0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x23, 0x05, 0x0a, 0x14, 0x28, 0x13, 0x26,
                0x0f, 0x1e, 0x3c, 0x3b, 0x35, 0x29, 0x11, 0x22, 0x07, 0x0e, 0x1c, 0x38, 0x33, 0x25, 0x09, 0x12, 0x24, 0x0b,
        };

    private static short [] shufinv = {1, 2, 11, 6, 3, 0, 9, 4, 7, 10, 13, 14, 5, 8, 15, 12};
    private static short [] shuf = { 5, 0, 1, 4, 7, 12, 3, 8, 13, 6, 9, 2, 15, 10, 11, 14};
    private static byte  [] sbox = {0x0C, 0x00, 0x0F, 0x0A, 0x02, 0x0B, 0x09, 0x05, 0x08, 0x03, 0x0D, 0x07, 0x01, 0x0E, 0x06, 0x04};
    private static byte  [] data_enc  = new byte[16];

    public static TwineCipher getInstance(byte type,byte[] key)
    {
        switch(type)
        {
            case TWINE_CIPHER_80:
                if(ref_twineCipher_80 != null)
                    return ref_twineCipher_80;
                ref_twineCipher_80 =  new TwineCipher(key,TWINE_CIPHER_80);
                return ref_twineCipher_80;
            case TWINE_CIPHER_128:
                if(ref_twineCipher_128 != null)
                    return ref_twineCipher_128;
                ref_twineCipher_128 =  new TwineCipher(key,TWINE_CIPHER_128);
                return ref_twineCipher_128;
            default:
                ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
        }
        ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
        return null;
    }

    public static TwineCipher getInstance(byte type)
    {
        switch(type)
        {
            case TWINE_CIPHER_80:
                if(ref_twineCipher_80 != null)
                    return ref_twineCipher_80;
                ref_twineCipher_80 =  new TwineCipher();
                return ref_twineCipher_80;
            case TWINE_CIPHER_128:
                if(ref_twineCipher_128 != null)
                    return ref_twineCipher_128;
                ref_twineCipher_128 =  new TwineCipher();
                return ref_twineCipher_128;
            default:
                ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
        }
        ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
        return null;
    }
    private TwineCipher(byte[] key,byte keySize)
    {
        switch(keySize)
        {
            case TWINE_CIPHER_80:
                expand80Key(key);
                break;
            case TWINE_CIPHER_128:
                expand128Key(key);
                break;
            default:
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        }
    }
    private TwineCipher()
    {

    }

    private void expand80Key(byte[] key)
    {
        short len_x = 20;
        short key_size = 10;
        short iterator = 0,iterator2=0;;
        byte temp_val=-1;
        byte temp_val2=-1,temp_val3=-1,temp_val4=-1;
        short sh=0;
        // reset the array
        Util.arrayFillNonAtomic(temp, (short)0, (short)20, IConsts.UNTOUCHED_VALUE);

        unrowl80ExpandKey(key);

        for ( iterator = 0 ; iterator < 35;iterator ++)
        {
            rk[(short)(iterator * 8 + 0)] = temp[1];
            rk[(short)(iterator * 8 + 1)] = temp[3];
            rk[(short)(iterator * 8 + 2)] = temp[4];
            rk[(short)(iterator * 8 + 3)] = temp[6];
            rk[(short)(iterator * 8 + 4)] = temp[13];
            rk[(short)(iterator * 8 + 5)] = temp[14];
            rk[(short)(iterator * 8 + 6)] = temp[15];
            rk[(short)(iterator * 8 + 7)] = temp[16];

            temp[1] ^= sbox[temp[0]];
            temp[4] ^= sbox[temp[16]];
            temp_val = roundconst[iterator];
            temp[7] ^= temp_val >> 3;
            temp[19] ^= temp_val & 7;

            temp_val  = temp[0];
            temp_val2 = temp[1];
            temp_val3 = temp[2];
            temp_val4 = temp[3];

            for (iterator2 = 0 ; iterator2 < 4;iterator2++)
            {
                sh                  = (short)(iterator2*4);
                temp[sh]            = temp[(short)(sh+4)];
                temp[(short)(sh+1)] = temp[(short)(sh+5)];
                temp[(short)(sh+2)] = temp[(short)(sh+6)];
                temp[(short)(sh+3)] = temp[(short)(sh+7)];
            }

            temp[16]   = temp_val2;
            temp[17]   = temp_val3;
            temp[18]   = temp_val4;
            temp[19]   = temp_val;

        }
        rk[(short)(35 * 8 + 0)] = temp[1];  
        rk[(short)(35 * 8 + 1)] = temp[3];  
        rk[(short)(35 * 8 + 2)] = temp[4];  
        rk[(short)(35 * 8 + 3)] = temp[6];  
        rk[(short)(35 * 8 + 4)] = temp[13]; 
        rk[(short)(35 * 8 + 5)] = temp[14]; 
        rk[(short)(35 * 8 + 6)] = temp[15]; 
        rk[(short)(35 * 8 + 7)] = temp[16]; 

    }
    private void expand128Key(byte[] key)
    {

    }

    public byte[] encrypt(byte[] src,byte[] dest,short len_src)
    {
        Util.arrayFillNonAtomic(temp, (short)0, (short)32, IConsts.UNTOUCHED_VALUE); //reset all values 
                                                   // 16 bytes for first part
                                                  // 16 bytes for next
        short iterator=0,iterator2=0,iterator3=0;
        short START_ITERATOR = 16;
        for( iterator = 0 ; iterator < len_src ; iterator++)
        {
            temp[(short)(2*iterator)] = (byte)((short) (src[iterator] & 0x00FF) >> 4);
            temp[(short)(2*iterator+1)] = (byte)((short) (src[iterator] & 0x00FF) & 0x0F);
        }

        for ( iterator = 0 ; iterator < 35 ; iterator ++)
        {
            for ( iterator2 = 0 ; iterator2 < 8 ; iterator2 ++)
            {
                temp[(short)(2*iterator2+1)] ^= sbox[temp[(short)(2*iterator2)] ^ rk[(short)(iterator*8+iterator2)]]; 

            }

            for (iterator3 = 0 ; iterator3 < 16;iterator3++)
            {
                temp[(short)(shuf[iterator3]+16)] = temp[(short)(iterator3)];
            }
            Util.arrayCopy(temp, (short)16, temp, (short)0, (short)16);
        }
        iterator = 35;
        for (iterator2 = 0; iterator2 < 8 ;iterator2++)
        {
            temp[(short)(2*iterator2+1)] ^= sbox[temp[(short)(2*iterator2)]^ rk[(short)(iterator*8+iterator2)]];        
        }

        for ( iterator = 0 ;iterator < 8 ;iterator++)
        {
            temp[(short)(24+iterator)] = (byte)(temp[(short)(2*iterator)] << 4 | temp[(short)(2*iterator + 1)]);
        }
        Util.arrayCopy(temp, (short)24, dest, (short)(ISO7816.OFFSET_CDATA), (short)8);
        return temp; // returns bytes from 24 to 32
    }
    public byte[] decrypt(byte[] src,byte[] dest,short len_src)
    {
        // for this alg len_src is always 8 
        Util.arrayFillNonAtomic(temp, (short)0, (short)32, IConsts.UNTOUCHED_VALUE); //reset all values 
        short iterator=0,iterator2=0,iterator3=0;
        short START_ITERATOR = 16;
        for( iterator = 0 ; iterator < len_src ; iterator++)
        {
            temp[(short)(2*iterator)] = (byte)((short) (src[iterator] & 0x00FF) >> 4);
            temp[(short)(2*iterator+1)] = (byte)((short) (src[iterator] & 0x00FF) & 0x0F);
        }

        for ( iterator = 35 ; iterator > 0 ; iterator --)
        {
            for ( iterator2 = 0 ; iterator2 < 8 ; iterator2 ++)
            {
                temp[(short)(2*iterator2+1)] ^= sbox[temp[(short)(2*iterator2)]^ rk[(short)(iterator*8+iterator2)]];
            }

            for (iterator3 = 0 ; iterator3 < 16;iterator3++)
            {
                temp[(short)(shufinv[iterator3]+16)] = temp[(short)(iterator3)];
            }
            Util.arrayCopy(temp, (short)16, temp, (short)0, (short)16);
        }
        //FINAL
        iterator = 0;
        for (iterator2 = 0; iterator2 < 8 ;iterator2++)
        {
            temp[(short)(2*iterator2+1)] ^= sbox[temp[(short)(2*iterator2)]^ rk[(short)(iterator*8+iterator2)]];
        }

        for ( iterator = 0 ;iterator < 8 ;iterator++)
        {
            temp[(short)(24+iterator)] = (byte)(temp[(short)(2*iterator)] << 4 | temp[(short)(2*iterator + 1)]);
        }
        Util.arrayCopy(temp, (short)24, dest, (short)(ISO7816.OFFSET_CDATA), (short)8);
        return temp; // returns bytes from 24 to 32 indexes
    }

    public short process(byte type,byte[] data,short start_offset,short len_data)
    {
        Util.arrayCopy(data, start_offset, data_enc, (short) 0, len_data);
        switch(type)
        {
            case OFFSET_P1_ENC:
                encrypt(data_enc, data, len_data);
                return (short)8;
            case OFFSET_P1_DEC:
                decrypt(data_enc, data, len_data);
                return (short)8;
            case OFFSET_P1_GEN:
                expand80Key(data_enc);
                return 10;
            default:
                return (short)-1;
        }

    }

    private void unrowl80ExpandKey(byte[] key)
    {
        temp[(short)(2*0)] = (byte)((short) (key[0] & 0x00FF) >> 4);
        temp[(short)(2*0 + 1)] = (byte)((short) (key[0] & 0x00FF) & 0x0F);  

        temp[(short)(2*1)] = (byte)((short) (key[1] & 0x00FF) >> 4);
        temp[(short)(2*1 + 1)] = (byte)((short) (key[1] & 0x00FF) & 0x0F);  

        temp[(short)(2*2)] = (byte)((short) (key[2] & 0x00FF) >> 4);
        temp[(short)(2*2 + 1)] = (byte)((short) (key[2] & 0x00FF) & 0x0F);  

        temp[(short)(2*3)] = (byte)((short) (key[3] & 0x00FF) >> 4);
        temp[(short)(2*3 + 1)] = (byte)((short) (key[3] & 0x00FF) & 0x0F);  

        temp[(short)(2*4)] = (byte)((short) (key[4] & 0x00FF) >> 4);
        temp[(short)(2*4 + 1)] = (byte)((short) (key[4] & 0x00FF) & 0x0F);  

        temp[(short)(2*5)] = (byte)((short) (key[5] & 0x00FF) >> 4);
        temp[(short)(2*5 + 1)] = (byte)((short) (key[5] & 0x00FF) & 0x0F);  

        temp[(short)(2*6)] = (byte)((short) (key[6] & 0x00FF) >> 4);
        temp[(short)(2*6 + 1)] = (byte)((short) (key[6] & 0x00FF) & 0x0F);  

        temp[(short)(2*7)] = (byte)((short) (key[7] & 0x00FF) >> 4);
        temp[(short)(2*7 + 1)] = (byte)((short) (key[7] & 0x00FF) & 0x0F);  

        temp[(short)(2*8)] = (byte)((short) (key[8] & 0x00FF) >> 4);
        temp[(short)(2*8 + 1)] = (byte)((short) (key[8] & 0x00FF) & 0x0F);  

        temp[(short)(2*9)] = (byte)((short) (key[9] & 0x00FF) >> 4);
        temp[(short)(2*9 + 1)] = (byte)((short) (key[9] & 0x00FF) & 0x0F);  
    }
}

IConst.java interface

  public interface IConsts 
{
    public static final byte UNTOUCHED_VALUE = 0x50;
    public static final byte TRUE = 0x01;
    public static final byte FALSE = 0x00;

    public static final byte OFFSET_CLA_CIPHERS = (byte) 0x00;
    public static final byte OFFSET_INS_LIGHT = (byte) 0x11;


    public static final byte OFFSET_P1_ENC   = (byte) 0x21;
    public static final byte OFFSET_P1_DEC   = (byte) 0x22;
    public static final byte OFFSET_P1_GEN   = (byte) 0x23;

    public static final byte TWINE_CIPHER_80=0x30;
    public static final byte TWINE_CIPHER_128=0x31;
    public static final byte LBLOCK_CIPHER=0x32;
}

LBlockCipher.java 

   public class LBlockCipher implements IConsts {


    public static final byte  LBLOCK_NBROUNDS =  32;
    public static final byte  LBLOCK_KEY_SIZE =  80;
    public static final short MEMORY_OUTPUT=32*4;
    public static final short MEMORY_TEMPORARY=32;  

    static final byte[] S0 = { 14, 9, 15, 0, 13, 4, 10, 11, 1, 2, 8, 3, 7, 6, 12, 5};
    static final byte[] S1 = { 4, 11, 14, 9, 15, 13, 0, 10, 7, 12, 5, 6, 2, 8, 1, 3 };
    static final byte[] S2 = { 1, 14, 7, 12, 15, 13, 0, 6, 11, 5, 9, 3, 2, 4, 8, 10 };
    static final byte[] S3 = { 7, 6, 8, 11, 0, 15, 3, 14, 9, 10, 12, 13, 5, 2, 4, 1 };
    static final byte[] S4 = { 14, 5, 15, 0, 7, 2, 12, 13, 1, 8, 4, 9, 11, 10, 6, 3 };
    static final byte[] S5 = { 2, 13, 11, 12, 15, 14, 0, 9, 7, 10, 6, 3, 1, 8, 4, 5 };
    static final byte[] S6 = { 11, 9, 4, 14, 0, 15, 10, 13, 6, 12, 5, 7, 3, 8, 1, 2 };
    static final byte[] S7 = { 13, 10, 15, 0, 14, 4, 9, 11, 2, 1, 8, 3, 7, 5, 12, 6 };
    static final byte[] S8 = { 8, 7, 14, 5, 15, 13, 0, 6, 11, 12, 9, 10, 2, 4, 1, 3 };
    static final byte[] S9 = { 11, 5, 15, 0, 7, 2, 9, 13, 4, 8, 1, 12, 14, 10, 3, 6 };  

    public  byte[] output    =  JCSystem.makeTransientByteArray(MEMORY_OUTPUT,JCSystem.CLEAR_ON_DESELECT); 
    public  byte[] temp      =  JCSystem.makeTransientByteArray(MEMORY_TEMPORARY,JCSystem.CLEAR_ON_DESELECT); 

    private static LBlockCipher m_instance_Cipher = null;

    public void keySchedule(byte[] key,short start_offset)
    {
        // use for keyR offset temp [0 - 3 ]
        short i = 0 ;
        output[(short)(0*4+3)] = key[(short)(9 + start_offset)];
        output[(short)(0*4+2)] = key[(short)(8 + start_offset)];
        output[(short)(0*4+1)] = key[(short)(7 + start_offset)];
        output[(short)(0*4+0)] = key[(short)(6 + start_offset)];

        for ( i = 1;i<32;i++)
        {
            temp[3] = key[(short)(9 + start_offset)];
            temp[2] = key[(short)(8 + start_offset)];
            temp[1] = key[(short)(7 + start_offset)];
            temp[0] = key[(short)(6 + start_offset)];

            key[(short)(9 + start_offset)] = (byte) ((((key[(short)(6 + start_offset)] & 0x07) << 5) 
                                            & 0xE0) ^ (((key[(short)(5 + start_offset)] & 0xF8) >> 3) & 0x1F));
            key[(short)(8 + start_offset)] = (byte) ((((key[(short)(5 + start_offset)]
                                            & 0x07) << 5) & 0xE0) ^ (((key[(short)(4 + start_offset)] & 0xF8) >> 3) & 0x1F));
            key[(short)(7 + start_offset)] = (byte) ((((key[(short)(4 + start_offset)] 
                                            & 0x07) << 5) & 0xE0) ^ (((key[(short)(3 + start_offset)] & 0xF8) >> 3) & 0x1F));
            key[(short)(6 + start_offset)] = (byte) ((((key[(short)(3 + start_offset)] 
                                            & 0x07) << 5) & 0xE0) ^ (((key[(short)(2 + start_offset)] & 0xF8) >> 3) & 0x1F));
            key[(short)(5 + start_offset)] = (byte) ((((key[(short)(2 + start_offset)] & 0x07) << 5) 
                                            & 0xE0) ^ (((key[(short)(1 + start_offset)] & 0xF8) >> 3) & 0x1F));

            key[(short)(4 + start_offset)] = (byte) ((((key[(short)(1 + start_offset)] & 0x07) << 5) 
                                            & 0xE0) ^ (((key[(short)(0 + start_offset)] & 0xF8) >> 3) & 0x1F));
            key[(short)(3 + start_offset)] = (byte) ((((key[(short)(0 + start_offset)] & 0x07) << 5) 
                                            & 0xE0) ^ (((temp[3] & 0xF8) >> 3) & 0x1F));
            key[(short)(2 + start_offset)] = (byte) ((((temp[3] & 0x07) << 5) & 0xE0) ^ (((temp[2] & 0xF8) >> 3) & 0x1F));
            key[(short)(1 + start_offset)] = (byte) ((((temp[2] & 0x07) << 5) & 0xE0) ^ (((temp[1] & 0xF8) >> 3) & 0x1F));
            key[(short)(0 + start_offset)] = (byte) ((((temp[1] & 0x07) << 5) & 0xE0) ^ (((temp[0] & 0xF8) >> 3) & 0x1F));

            key[(short)(9 + start_offset)] = (byte) ((S9[((key[(short)(9 + start_offset)] >> 4) & 0x0F)] << 4)
                                            ^ S8[(key[(short)(9 + start_offset)] & 0x0F)]);

            key[(short)(6 + start_offset)] = (byte) (key[(short)(6 + start_offset)] ^ ((i >> 2) & 0x07));
            key[(short)(5 + start_offset)] = (byte) (key[(short)(5 + start_offset)] ^ ((i & 0x03) << 6));

            output[(short)(i*4 + 3)] =  key[(short)(9 + start_offset)];
            output[(short)(i*4 + 2)] =  key[(short)(8 + start_offset)];
            output[(short)(i*4 + 1)] =  key[(short)(7 + start_offset)];
            output[(short)(i*4 + 0)] =  key[(short)(6 + start_offset)];;
        }
    }
    public void OneRound(byte[] x,byte[] k,short offset,short offset_x)
    {
        // t  - from 5 - 8 tmp from 9 to 12
        //  u8 t[4], tmp[4];

        temp[9]  = x[(short)(4 + offset_x)];
        temp[10] = x[(short)(5 + offset_x)];
        temp[11] = x[(short)(6 + offset_x)];
        temp[12] = x[(short)(7 + offset_x)];

        x[(short)(4 + offset_x)] ^= k[offset];
        x[(short)(5 + offset_x)] ^= k[(short)(offset+1)];
        x[(short)(6 + offset_x)] ^= k[(short)(offset+2)];
        x[(short)(7 + offset_x)] ^= k[(short)(offset+3)];

        x[(short)(4 + offset_x)] = (byte) (((S1[((x[(short)(4 + offset_x)]) >> 4) & 0x0F]) << 4) 
                                ^ S0[(x[(short)(4 + offset_x)] & 0x0F)]);
        x[(short)(5 + offset_x)] = (byte) (((S3[((x[(short)(5 + offset_x)]) >> 4) & 0x0F]) << 4) 
                                ^ S2[(x[(short)(5 + offset_x)] & 0x0F)]);
        x[(short)(6 + offset_x)] = (byte) (((S5[((x[(short)(6 + offset_x)]) >> 4) & 0x0F]) << 4) 
                                ^ S4[(x[(short)(6 + offset_x)] & 0x0F)]);
        x[(short)(7 + offset_x)]= (byte) (((S7[((x[(short)(7 + offset_x)]) >> 4) & 0x0F]) << 4)
                                ^  S6[(x[(short)(7 + offset_x)] & 0x0F)]);

        temp[5] = (byte) (((x[(short)(4 + offset_x)] >> 4) & 0x0F) ^ (x[(short)(5 + offset_x)] & 0xF0));
        temp[6] = (byte) ((x[(short)(4 + offset_x)] & 0x0F) ^ ((x[(short)(5 + offset_x)] & 0x0F) << 4));
        temp[7] = (byte) (((x[(short)(6 + offset_x)] >> 4) & 0x0F) ^ (x[(short)(7 + offset_x)] & 0xF0));
        temp[8] = (byte) ((x[(short)(6 + offset_x)] & 0x0F) ^ ((x[(short)(7 + offset_x)] & 0x0F) << 4));

        x[(short)(4 + offset_x)] = (byte) (x[(short)(3 + offset_x)] ^ temp[5]);
        x[(short)(5 + offset_x)] = (byte) (x[(short)(0 + offset_x)] ^ temp[6]);
        x[(short)(6 + offset_x)] = (byte) (x[(short)(1 + offset_x)] ^ temp[7]);
        x[(short)(7 + offset_x)] = (byte) (x[(short)(2 + offset_x)] ^ temp[8]);

        x[(short)(0 + offset_x)] = temp[9];
        x[(short)(1 + offset_x)] = temp[10];
        x[(short)(2 + offset_x)] = temp[11];
        x[(short)(3 + offset_x)] = temp[12];


    }
    public void encrypt(byte[] x,short offset_x)
    {
        short i;
        for (i = 0; i<32; i++)
        {
            OneRound(x,output,(short)(4*i),offset_x);
        }
    }
    public void OneRoundInv(byte[] y, byte[] k,short offset,short offset_y)
    {
        // t  - from 5 - 8 tmp from 9 to 12
        //  u8 t[4], tmp[4];

        temp[9]  = y[(short)(0 + offset_y)];
        temp[10] = y[(short)(1 + offset_y)];
        temp[11] = y[(short)(2 + offset_y)];
        temp[12] = y[(short)(3 + offset_y)];

        y[(short)(0 + offset_y)] = (byte) (y[(short)(0 + offset_y)] ^ k[offset]);
        y[(short)(1 + offset_y)] = (byte) (y[(short)(1 + offset_y)] ^ k[(short)(offset+1)]);
        y[(short)(2 + offset_y)] = (byte) (y[(short)(2 + offset_y)] ^ k[(short)(offset+2)]);
        y[(short)(3 + offset_y)] = (byte) (y[(short)(3 + offset_y)] ^ k[(short)(offset+3)]);


        y[(short)(0 + offset_y)] = (byte) (((S1[((y[(short)(0 + offset_y)]) >> 4) & 0x0F]) << 4) ^ S0[(y[(short)(0 + offset_y)] & 0x0F)]);
        y[(short)(1 + offset_y)] = (byte) (((S3[((y[(short)(1 + offset_y)]) >> 4) & 0x0F]) << 4) ^ S2[(y[(short)(1 + offset_y)] & 0x0F)]);
        y[(short)(2 + offset_y)] = (byte) (((S5[((y[(short)(2 + offset_y)]) >> 4) & 0x0F]) << 4) ^ S4[(y[(short)(2 + offset_y)] & 0x0F)]);
        y[(short)(3 + offset_y)] = (byte) (((S7[((y[(short)(3 + offset_y)]) >> 4) & 0x0F]) << 4) ^ S6[(y[(short)(3 + offset_y)] & 0x0F)]);


        temp[5] = (byte) (((y[(short)(0 + offset_y)] >> 4) & 0x0F) ^ (y[(short)(1 + offset_y)] & 0xF0));
        temp[6] = (byte) ((y[(short)(0 + offset_y)] & 0x0F) ^ ((y[(short)(1 + offset_y)] & 0x0F) << 4));
        temp[7] = (byte) (((y[(short)(2 + offset_y)] >> 4) & 0x0F) ^ (y[(short)(3 + offset_y)] & 0xF0));
        temp[8] = (byte) ((y[(short)(2 + offset_y)] & 0x0F) ^ ((y[(short)(3 + offset_y)] & 0x0F) << 4));

        y[(short)(0 + offset_y)] = (byte) (y[(short)(5 + offset_y)] ^ temp[6]);
        y[(short)(1 + offset_y)] = (byte) (y[(short)(6 + offset_y)] ^ temp[7]);
        y[(short)(2 + offset_y)] = (byte) (y[(short)(7 + offset_y)] ^ temp[8]);
        y[(short)(3 + offset_y)] = (byte) (y[(short)(4 + offset_y)] ^ temp[5]);

        // PARTIE GAUCHE
        y[(short)(4 + offset_y)] = temp[9];
        y[(short)(5 + offset_y)] = temp[10];
        y[(short)(6 + offset_y)] = temp[11];
        y[(short)(7 + offset_y)] = temp[12];


    }
    public void decrypt(byte[] x,short offset_x)
    {
        short i;

        for (i = 31; i >= 0; i--)
        {
            OneRoundInv(x,output,(short)(i*4),offset_x);
        }
    }

    private LBlockCipher()
    {

    }
    public short process(byte type,byte[] data,short start_offset,short len_data)
    {
        Util.arrayCopy(data, start_offset, temp, (short) 16, len_data);
        switch(type)
        {
            case OFFSET_P1_ENC:
                encrypt(temp,(short)(16));
                Util.arrayCopy(temp,(short) 16, data, (short) start_offset, len_data);
                return (short)8;
            case OFFSET_P1_DEC:
                decrypt(temp,(short)(16));
                Util.arrayCopy(temp,(short) 16, data, (short) start_offset, len_data);
                return (short)8;
            case OFFSET_P1_GEN:
                keySchedule(temp,(short)(16));
                Util.arrayCopy(temp,(short) 16, data, (short) start_offset, len_data);
                return 10;
            default:
                return (short)-1;
        }

    }
    public static LBlockCipher getInstance()
    {
        if(m_instance_Cipher == null)
            m_instance_Cipher =  new LBlockCipher();
        return m_instance_Cipher;
    }

}

TestApplet.java

  public class TestApplet extends Applet 
            implements IConsts {
    private TestApplet()
    {   

    }

    public static void install(byte bArray[], short bOffset, byte bLength) throws ISOException {
        new TestApplet().register();
    }

    public void process(APDU apdu) throws ISOException {
        if (selectingApplet()) {
            return;
        }
        byte[] buf = apdu.getBuffer();
        if(buf[ISO7816.OFFSET_CLA] != IConsts.OFFSET_CLA_CIPHERS)
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
        switch (buf[ISO7816.OFFSET_INS]) 
        {
            case IConsts.OFFSET_INS_LIGHT:
                processLight(apdu);
                return;
            default:
                break;
        }
    }

    private void processLight(APDU apdu)
    {
         //cla and ins are proccessed
        byte[] buf = apdu.getBuffer();
        byte state = (buf[ISO7816.OFFSET_P1]);
        byte type = (buf[ISO7816.OFFSET_P2]);
        byte count_data = buf[ISO7816.OFFSET_LC];
        if(count_data == 0x00)
            ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
        short len_data = -1;
        switch(state)
        {
            case OFFSET_P1_ENC:
                switch(type)
                {
                    case TWINE_CIPHER_80:
                        TwineCipher m_instance = TwineCipher.getInstance(TwineCipher.TWINE_CIPHER_80);
                        len_data  = m_instance.process(OFFSET_P1_ENC, buf, (short)(ISO7816.OFFSET_CDATA), count_data);
                        apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len_data);
                        return;
                    case TWINE_CIPHER_128:
                        TwineCipher.getInstance(TwineCipher.TWINE_CIPHER_80); //TODO change that
                        return;
                    case LBLOCK_CIPHER:
                        LBlockCipher m_instance_lblock= LBlockCipher.getInstance();
                        len_data  = m_instance_lblock.process(OFFSET_P1_ENC, buf, (short)(ISO7816.OFFSET_CDATA), count_data);
                        apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len_data);
                        return;
                    default:
                        ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
                }
            case OFFSET_P1_DEC:
                switch(type)
                {
                    case TwineCipher.TWINE_CIPHER_80:
                        TwineCipher m_instance = TwineCipher.getInstance(TwineCipher.TWINE_CIPHER_80);
                        len_data  = m_instance.process(TwineCipher.OFFSET_P1_DEC, buf, (short)(ISO7816.OFFSET_CDATA), count_data);
                        apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len_data);
                        return;
                    case TwineCipher.TWINE_CIPHER_128:
                        TwineCipher.getInstance(TwineCipher.TWINE_CIPHER_80); //TODO change that
                        return;
                    case LBLOCK_CIPHER:
                        LBlockCipher m_instance_lblock= LBlockCipher.getInstance();
                        len_data  = m_instance_lblock.process(OFFSET_P1_DEC, buf, (short)(ISO7816.OFFSET_CDATA), count_data);
                        apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len_data);
                        return;
                    default:
                        ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
                }
            case OFFSET_P1_GEN:
                switch(type)
                {
                    case TwineCipher.TWINE_CIPHER_80:
                        TwineCipher m_instance = TwineCipher.getInstance(TwineCipher.TWINE_CIPHER_80);
                        len_data = m_instance.process(TwineCipher.OFFSET_P1_GEN, buf, (short)(ISO7816.OFFSET_CDATA), count_data);
                        apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len_data);
                        return;
                    case TwineCipher.TWINE_CIPHER_128:
                        TwineCipher.getInstance(TwineCipher.TWINE_CIPHER_80); //TODO change that
                        return;
                    case LBLOCK_CIPHER:
                        LBlockCipher m_instance_lblock= LBlockCipher.getInstance();
                        len_data  = m_instance_lblock.process(OFFSET_P1_GEN, buf, (short)(ISO7816.OFFSET_CDATA), count_data);
                        apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len_data);
                        return;
                    default:
                        ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
                }
                default:
                    break;
        }
    }

}
java
eclipse
javacard
apdu
asked on Stack Overflow Apr 9, 2016 by Alberto12 • edited Apr 9, 2016 by Alberto12

1 Answer

2

Before trying to receive the data in the data field of APDU buffer, You must invoke the following method:

setIncomingAndReceive()

on the APDU object otherwise you'll receive an error.

Take a look at this Q&A and this Q&A related to your issue.

Replacing:

case OFFSET_P1_GEN:
                switch(type)
                {
                    case TwineCipher.TWINE_CIPHER_80:
                        TwineCipher m_instance = TwineCipher.getInstance(TwineCipher.TWINE_CIPHER_80);
                        len_data = m_instance.process(TwineCipher.OFFSET_P1_GEN, buf, (short)(ISO7816.OFFSET_CDATA), count_data);
                        apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len_data);
                        return;
// ......

with

case OFFSET_P1_GEN:
                switch(type)
                {
                    case TwineCipher.TWINE_CIPHER_80:
                        TwineCipher m_instance = TwineCipher.getInstance(TwineCipher.TWINE_CIPHER_80);
                        apdu.setIncomingAndReceive();
                        len_data = m_instance.process(TwineCipher.OFFSET_P1_GEN, buf, (short)(ISO7816.OFFSET_CDATA), count_data);
                        apdu.setOutgoingAndSend(ISO7816.OFFSET_CDATA, len_data);
                        return;
//.....

in the TestApplet.java will solve the problem for this command (Only for the command that you mentioned in your first comment under your question, and not for other commands), but it is not efficient actually :D. So find a good line and place this method invocation there.

answered on Stack Overflow Apr 9, 2016 by Abraham • edited May 23, 2017 by Community

User contributions licensed under CC BY-SA 3.0