如何将数据数组发送到我的 Applet 并由 Applet 和 return 响应 apdu 的新数据进行操作?

How to send a data array to my Applet and manipulation it by Applet and return new data in response apdu?

更新 1: 我在 javacard 上安装了我的小程序(我使用源代码作为我已经接受的问题的答案)。当我通过 OpenSc 发送 generatedKey 命令时,它只是 returns 9000 作为响应而不是发送异或数据!我用 Javacard 2.2.1 版创建了我的项目,我确定我的卡与该版本兼容。为什么 OpenSc 没有收到预期的数据?


我想向我的 JavaCard applet 发送一个包含例如 24 个元素的随机字节数组,然后我的 applet 应该使用特定方法更改该数组。例如,方法 XOR 每个元素与 0x05 和 returns 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;
    }

}

我必须在编译并选择我的小程序后发送以下 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

我的小程序有问题吗?

方法中,private void getKey( APDU apdu , byte[] data)需要调用,

apdu.setIncomingAndReceive();

记住:

This is the primary receive method. Calling this method indicates that this APDU has incoming data. This method gets as many bytes as will fit without buffer overflow in the APDU buffer following the header. It gets all the incoming bytes if they fit.

所以像这样更新你的方法:

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

编辑: 您的代码中有几个问题。我一一提到。

问题一:

byte[] Data =new byte[] {(byte) (buffer[ISO7816.OFFSET_CDATA] & 0xFF)};

它创建一个 byte[] Data,长度为 1,值为 0x11

解法: newData 持久性 EEP 内存中创建 space。如果你不再需要 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);

问题二:

i) 您的 generateKey() 方法将崩溃,因为您正在创建 byte[] key 与创建 byte[] 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 :

Select Command : 00 A4 04 00 06 A1 A2 A3 A4 A5 00 00

Select Command Response : 90 00

generateKey Command : 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 Command Response : 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

干杯!