如何将数据数组发送到我的Applet并通过Applet进行操作并在响应apdu中返回新数据?

时间:2015-06-14 08:00:01

标签: arrays applet javacard apdu

更新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

我的小程序有问题吗?

1 个答案:

答案 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

<强>解决方案: newData持久性 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[] keybyte[] Data相同。

ii)您不能声明int i,因为只有少数卡支持,请使用byteshort

解决方案:据我了解您在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

干杯!