Java 卡检测到与智能卡的通信错误
Java Card A communication error with the smart card has been detected
我使用 Java Card 2.1.2 SDK 和 GPSshell 在 Java Card 上构建项目作为与 device.I 通信的方式测试了 helloworld
示例GpShell 和我设法发送了 Simple APDU 。但是,当我尝试将 APDU 发送到更大的 .cap
文件时,设备会给我以下错误
send_APDU() returns 0x8010002F (A communications error with the smart card has b
een detected. Retry the operation.
)
我附上了小程序中的代码片段 below.It 在我看来是内存问题,尽管 Java 卡有 80 Kb EEPROM 和将近 2 Kb 的 RAM.In Eclipse 模拟器应用程序效果不错。
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界面
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;
}
}
}
在尝试接收APDU缓冲区数据字段中的数据之前,您必须调用以下方法:
setIncomingAndReceive()
在 APDU 对象上,否则您将收到错误消息。
查看与您的问题相关的 and 。
正在替换:
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 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 TestApplet.java 将解决此命令的问题(仅适用于您在问题下的第一条评论中提到的命令,而不适用于其他命令),但实际上效率不高 :D。因此,找到一个好的行并将此方法调用放在那里。
我使用 Java Card 2.1.2 SDK 和 GPSshell 在 Java Card 上构建项目作为与 device.I 通信的方式测试了 helloworld
示例GpShell 和我设法发送了 Simple APDU 。但是,当我尝试将 APDU 发送到更大的 .cap
文件时,设备会给我以下错误
send_APDU() returns 0x8010002F (A communications error with the smart card has b
een detected. Retry the operation.
)
我附上了小程序中的代码片段 below.It 在我看来是内存问题,尽管 Java 卡有 80 Kb EEPROM 和将近 2 Kb 的 RAM.In Eclipse 模拟器应用程序效果不错。
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界面
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;
}
}
}
在尝试接收APDU缓冲区数据字段中的数据之前,您必须调用以下方法:
setIncomingAndReceive()
在 APDU 对象上,否则您将收到错误消息。
查看与您的问题相关的
正在替换:
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 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 TestApplet.java 将解决此命令的问题(仅适用于您在问题下的第一条评论中提到的命令,而不适用于其他命令),但实际上效率不高 :D。因此,找到一个好的行并将此方法调用放在那里。