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;
}
}
}
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.
User contributions licensed under CC BY-SA 3.0