更新1: 我在javacard上安装了我的applet(我在源代码中使用了我已经在问题中接受的答案)。当我通过OpenSc发送generatedKey命令时,它只返回9000作为响应而不是发送XORed数据!我使用Javacard 2.2.1版本创建了我的项目,我确信我的卡可以与该版本兼容。为什么OpenSc没有收到预期的数据?
我想将一个随机字节数组(包括例如24个元素)发送到我的JavaCard applet,然后我的applet应该使用特定方法更改该数组。例如,方法 XOR 每个元素都带有0x05
并在APDU响应中返回结果数组。
为了达到上述目标,我到目前为止编写了以下程序:
package keyGeneratorPackage;
import javacard.framework.*;
public class keyGeneratorPackage extends Applet {
private static final byte HW_CLA = (byte) 0x80;
private static final byte HW_INS = (byte) 0x00;
public static void install(byte[] bArray, short bOffset, byte bLength) {
new keyGeneratorPackage().register(bArray, (short) (bOffset + 1),
bArray[bOffset]);
}
public void process(APDU apdu) {
if (selectingApplet()) {
return;
}
byte[] buffer = apdu.getBuffer();
byte CLA = (byte) (buffer[ISO7816.OFFSET_CLA] & 0xFF);
byte INS = (byte) (buffer[ISO7816.OFFSET_INS] & 0xFF);
byte[] Data = new byte[] { (byte) (buffer[ISO7816.OFFSET_CDATA] & 0xFF) };
if (CLA != HW_CLA) {
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}
switch (INS) {
case HW_INS:
getKey(apdu, Data);
break;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
private void getKey(APDU apdu, byte[] data) {
byte[] buffer = apdu.getBuffer();
byte[] generatedKey = generateKey(data);
short length = (short) generatedKey.length;
Util.arrayCopyNonAtomic(generatedKey, (short) 0, buffer, (short) 0,
(short) length);
apdu.setOutgoingAndSend((short) 0, length);
}
private byte[] generateKey(byte[] Data) {
byte[] key = new byte[] { (byte) 0x00 };
for (int i = 0; i < Data.length; i++) {
key[i] = (byte) (Data[i] ^ 5);
}
return key;
}
}
编译并选择我的applet后,我必须发送以下APDU命令:
>>> 80 00 00 00 18 11 22 33 44 55 66 77 88 99 10 20 30 40 50 60 70 80 90 b1 b2 b3 b4 b5 b6 b7 26
我的小程序有问题吗?
答案 0 :(得分:2)
在方法中,您需要调用private void getKey( APDU apdu , byte[] data)
,
apdu.setIncomingAndReceive();
记住:
这是主要的接收方法。调用此方法表示此APDU具有传入数据。此方法获得尽可能多的字节,而不会在标头后面的APDU缓冲区中发生缓冲区溢出。如果它们适合,它将获取所有传入的字节。
所以更新你的方法:
private void getKey( APDU apdu , byte[] data)
{
apdu.setIncomingAndReceive();
byte[] buffer = apdu.getBuffer();
byte[] generatedKey = generateKey(data);
short length = (short) generatedKey.length;
//short length =1;
Util.arrayCopyNonAtomic(generatedKey, (short)0, buffer, (short)0, (short) length);
apdu.setOutgoingAndSend((short)0, length);
}
注意:setIncomingAndReceive
方法只能在Applet.process()方法中调用一次。有关详细信息,请阅读setIncomingAndReceive。
编辑:您的代码中存在多个问题。我一个接一个地提到它们。
问题1:
byte[] Data =new byte[] {(byte) (buffer[ISO7816.OFFSET_CDATA] & 0xFF)};
它创建长度为1 byte[] Data
且值为0x11
。
<强>解决方案:强>
new
为Data
的持久性 EEP内存创建空间。如果您不再需要Data
,则可以将其设为transient
字节数组。
像这样重写(持久):
// it will create a byte array of length of "lc". Content will be `0x00`.
byte[] Data = new byte[(byte) (buffer[ISO7816.OFFSET_LC] & 0xFF)];
或者这个(瞬态):
byte[] Data = JCSystem.makeTransientByteArray((short) (buffer[ISO7816.OFFSET_LC] & 0x00FF), JCSystem.CLEAR_ON_DESELECT);
问题2:
i)您的generateKey()
方法会崩溃,因为您创建的byte[] key
与byte[] Data
相同。
ii)您不能声明int i
,因为只有少数卡支持,请使用byte
或short
。
解决方案:据我了解您在generateKey()
方法中尝试做什么,我会像这样重写它:
// the byte array preparation of key is the callers duty
private byte[] generateKey(byte[] Data, byte[] key) {
short i;
for (i = 0; i < Data.length; i++) {
key[i] = (byte) (Data[i] ^ (byte)0x05);
}
return key;
}
完整的工作代码是:
JavaCard :v.2.2.2
globalPlatform :v.2.1.1
建议:首先仔细阅读this文档。
package keyGeneratorPackage;
import javacard.framework.APDU;
import javacard.framework.ISO7816;
import javacard.framework.Applet;
import javacard.framework.ISOException;
import javacard.framework.JCSystem;
import javacard.framework.Util;
/**
* KeyGeneratorPackage <br>
*
* @author rakeb.void
*
*/
public class KeyGeneratorPackage extends Applet {
private static final byte HW_CLA = (byte) 0x80;
private static final byte HW_INS = (byte) 0x00;
public static void install(byte[] bArray, short bOffset, byte bLength) {
new keyGeneratorPackage.KeyGeneratorPackage().register(bArray, (short) (bOffset + 1),
bArray[bOffset]);
}
public void process(APDU apdu) {
if (selectingApplet()) {
return;
}
apdu.setIncomingAndReceive();
byte[] buffer = apdu.getBuffer();
byte CLA = (byte) (buffer[ISO7816.OFFSET_CLA] & 0xFF);
byte INS = (byte) (buffer[ISO7816.OFFSET_INS] & 0xFF);
short lc = (short) (buffer[ISO7816.OFFSET_LC] & (short)0x00FF);
// byte[] Data = new byte[(byte) (buffer[ISO7816.OFFSET_LC] & 0xFF)];
byte[] Data = JCSystem.makeTransientByteArray(lc, JCSystem.CLEAR_ON_DESELECT);
if (CLA != HW_CLA) {
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
}
switch (INS) {
case HW_INS: {
// copying the apdu data into byte array Data
Util.arrayCopy(buffer, ISO7816.OFFSET_CDATA, Data, (short) 0, lc);
getKey(apdu, Data);
}
// you forget to put a break here!
break;
default:
// good practice: If you don't know the INStruction, say so:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
private void getKey(APDU apdu, byte[] data) {
byte[] buffer = apdu.getBuffer();
short length = (short) data.length;
//prepareing the key array of same length of Data
byte[] key = JCSystem.makeTransientByteArray(length, JCSystem.CLEAR_ON_DESELECT);
// byte[] generatedKey = generateKey(data, key);
// no need another array generatedKey, as we are passing key as parameter
generateKey(data, key);
// length = (short) generatedKey.length;
Util.arrayCopyNonAtomic(key, (short) 0, buffer, (short) 0, (short) length);
apdu.setOutgoingAndSend((short) 0, length);
}
// .....................................
private byte[] generateKey(byte[] Data, byte[] key) {
short i;
for (i = 0; i < Data.length; i++) {
// i've no idea why you use 0x05 here,
// in the question you mentioned 0x9D
key[i] = (byte) (Data[i] ^ (byte)0x05);
}
return key;
}
}
我发送了APDU:
选择命令:00 A4 04 00 06 A1 A2 A3 A4 A5 00 00
选择命令响应:90 00
generateKey命令:80 00 00 00 18 11 22 33 44 55 66 77 88 99 10 20 30 40 50 60 70 80 90 B1 B2 B3 B4 B5 B6 B7
generateKey命令响应:14 27 36 41 50 63 72 8D 9C 15 25 35 45 55 65 75 85 95 B4 B7 B6 B1 B0 B3 90 00
干杯!