首页 文章

为什么我在CREF JavaCard模拟器的控制台中测试读取和写入APDU时,是否接收输入数据长度!= Lc或SW1 SW2:6700?

提问于
浏览
0

我想知道是否有人可以帮助我,因为我是Java的新手?!我有一个读/写小程序,我从这里的代码开发(基本相同,只是更改了指令代码和小程序名称)(http://www.wrankl.de/Javacard/ReadWriteJava.txt),如下所示:

// @(#)SmartTransfer.java   1.0 07/05/17

//Applet package package smartTransfer;

import javacard.framework.*;

//Transfer class extends the base Applet class
public class Transfer extends Applet {

// Declare constants
// code of instruction class; CLA - First (1 byte) - in the command APDU header
final static byte CLASS = (byte) 0x80;
// codes of INS byte in the command APDU header - for write instruction
final static byte WRITE_USER_INFO_INS = 0x07;
// codes of INS byte in the command APDU header - for read instruction
final static byte READ_USER_INFO_INS = 0x09;
// Size of storage area
final static byte SIZE_MEMORY = (short) 9;
static byte[] memory;

//Member variables - contain values for objects
//OwnerPIN pin;
/************************************/

// Installs the Applet, constructs the transfer object and registers with JCRE
public static void install(byte[] bArray, short bOffset, byte bLength) throws ISOException {
    new Transfer().register();
    memory = new byte[SIZE_MEMORY];
}


/************************************/
// Processing the APDU commands 
@Override
public void process(APDU apdu)
throws ISOException {
    if (selectingApplet()) return;
    byte[] buffer = apdu.getBuffer();
    if (buffer[ISO7816.OFFSET_CLA] !=CLASS) {
        ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
    }
    byte ins = buffer[ISO7816.OFFSET_INS];
    switch (ins) {
    case READ_USER_INFO_INS:
        readUserInfo(apdu);
        break;
    case WRITE_USER_INFO_INS:
        writeUserInfo(apdu);
    default:
        ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);

    }
}

private void writeUserInfo(APDU apdu) {
    byte[] cmd_apdu = apdu.getBuffer();
    // check if P1=0
    if (cmd_apdu[ISO7816.OFFSET_P1] != 0) 
        ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    // check if offset P2 is inside the bound of the memory array
    short offset = (short) (cmd_apdu[ISO7816.OFFSET_P2] & 0x00FF); 
    // calculate offset
    if (offset >= SIZE_MEMORY) 
        ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    // check if expected length is within the memory array
    short lc = (short)(cmd_apdu[ISO7816.OFFSET_LC] & 0x00FF);  
    // check no. off bytes against that in memory object
    if ((offset + lc) > SIZE_MEMORY) 
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    // check there are bytes in the command
    if (lc == 0) 
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    // points to method to get rest of the APDU
    getAPDUBody(apdu);    
    //Data copied to the memory - atomic procedure
    Util.arrayCopy(cmd_apdu, (short)((ISO7816.OFFSET_CDATA) & 0x00FF), memory, offset, lc);  
    // command complete message
    ISOException.throwIt(ISO7816.SW_NO_ERROR);   
}  

//Receive the body of the command APDU method
public void getAPDUBody(APDU apdu) {
    byte[] buffer = apdu.getBuffer();
    // check expected length against actual length in command APDU body
    short lc = (short)(buffer[ISO7816.OFFSET_LC] & 0x00FF);  
    // If not send error message`
    if (lc != apdu.setIncomingAndReceive()) 
        ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
}  

private void readUserInfo(APDU apdu) {
    byte[] cmd_apdu = apdu.getBuffer();
    //----- check the preconditions -----
    // check if P1=0
    if (cmd_apdu[ISO7816.OFFSET_P1] != 0) ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    // check if offset P2 is inside the bound of the memory array
    short offset = (short) (cmd_apdu[ISO7816.OFFSET_P2] & 0x00FF); // calculate offset
    if (offset >= SIZE_MEMORY) ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
    // check if offset P2 and expected length Le is inside the bounds of the memory array
    short le = (short)(cmd_apdu[ISO7816.OFFSET_LC] & 0x00FF); 
    if ((offset + le) > SIZE_MEMORY) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    // check if expected length Le of return bytes is 0
    if (le == 0) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
    // set transmission to outgoing data
    apdu.setOutgoing(); 
    // set the number of bytes to send to the IFD
    apdu.setOutgoingLength((short)le);  
    // send the requested number of bytes to the IFD
    apdu.sendBytesLong(memory, (short)offset, (short)le); 

    }
}

我正在使用Eclipse IDE中的CREF JavaCard模拟器并运行CAP文件以及生成的创建和选择applet脚本,并且一切正常 . 我遇到的问题是当我尝试运行read apdu时 . 下面的写命令示例和我尝试的任何内容(在代码中由writeUserinfo APDU方法设置的边界内)都可以工作,但无论我尝试使用readUserInfo APDU,都无效 . 我要么接收数据输入长度!= Lc或Le = 00 | SW1 SW2:6700 . 我知道这些意思是什么,但我已经尝试了所有我能想到或从现有文献中找到的东西,似乎没有任何效果 . 据我所知,网站上已经说过这个小程序已经过试用和测试,但我还没有收到javacard来测试它是否区分支持,因为我还读到模拟器是基于一个旧的JavaCard .

这是我正在使用的写apdu的一个例子:

//Select Transfer applet
0x00 0xA4 0x04 0x00 0x07 0xFF 0x00 0x20 0x00 0x00 0x00 0x20 0x7F;
APDU|CLA: 00, INS: a4, P1: 04, P2: 00, Lc: 07, ff, 00, 20, 00, 00, 00, 20, Le: 00, SW1: 90, SW2: 00

//Write Ross to memory byte array at offset 2
CMD>0x80 0x07 0x00 0x02 0x04 0x52 0x6f 0x73 0x73 0x7F;
APDU|CLA: 80, INS: 07, P1: 00, P2: 02, Lc: 04, 52, 6f, 73, 73, Le: 00, SW1: 90, SW2: 00

然后这里是所有类型的读APDU我试图从偏移2读取4个字节;

首先我尝试了le = 4字节CMD> 0x80 0x09 0x00 0x02 0x04 0x7F; CREF | C-JCRE已关闭 .

CREF exited with code 0

User input thread exited
ApduTool thread exited
ApduTool process finished with code: 1

APDU|Input data length != Lc around line 50.

我还读到使用CREF是卡级别而不是终端级别所以不需要指定le字段,所以我试过;

CMD>0x80 0x09 0x00 0x02 0x00 0x7F;
APDU|CLA: 80, INS: 09, P1: 00, P2: 02, Lc: 00, Le: 00, SW1: 67, SW2: 00

我还尝试写入许多不同的偏移量,改变内存字节数组的长度 . 我将内存字节数组对象更改为applet install(因为我认为这可能会在applet中创建对象) . 我尝试在读取和写入方法中取出Lc = 0的检查(因为这影响了我读到的Le = 0) . 我尝试将写入和读取命令更改为不包括0x7F,因为这被解释为其他东西);写命令成功的地方; 9000,但是当我运行没有0x7F的读命令时,我得到了这个响应; CMD> 0x80 0x09 0x00 0x02 0x00; CREF | C-JCRE已关闭 .

CREF exited with code 0

User input thread exited
ApduTool thread exited
ApduTool process finished with code: 1

APDU|Invalid Token after "0x00", was expecting one of <INTEGER_LITERAL>  <CHARACTER_LITERAL>  <STRING_LITERAL>

对不起,如果这很长,可能是一个非常简单的问题,但我没有意识到,当我接受这个项目时,这就是它会发生的事情(哈哈哈!我知道!),但我一直在这两个天和尝试了各种各样的事情无济于事所以,如果你们中的任何一个好人可以帮助我,我会非常感激!

2 回答

  • 0

    要返回的最大字节数Ne的值被编码到称为Le的字节表示中 . 可以通过调用 setOutgoing (检查返回值!)从applet中简单地检索Ne的值 . 这也将处理Ne = 256的编码的转换,这是Le设置为 00 .

    因此,您可以检查Ne是否足够大以容纳您的数据 . 如果是这种情况,您可以退货 . 返回的数据少于请求的数据 . 否则,您可能仍需要"throw" 6700 长度的无效状态字 .


    你的命令:

    0x80 0x09 0x00 0x02 0x00 0x7F
    

    当然不正确 . 命令数据大小(Nc)的编码Lc简单地是空字符串,即命令APDU中不存在Lc . 所以你在这里展示的是Le = 0x00 ,它在你的代码中被错误地解释为Ne = 0 . 然后有一个伪字节设置为 0x7F .

    结合我上面的评论,你应该能够发送:

    0x80 0x09 0x00 0x02 0x00
    

    因此,Le = 0x00被解释为Ne的最大大小为256.如果您的数据适合于此,则返回它 . 如果它不适合你必须检查命令链或扩展长度APDU(但根据你的单个APDU写命令它很容易适合 - 这只是未来读者的一个评论) .

  • 0

    谢谢所有有帮助的人...我真的很感激..我总是使用这个网站,并且羡慕所有人利用你的空闲时间来帮助像我这样的人(免费!),谢谢!

    我设法让它工作......基本上我做了这个..

    '你可以尝试改变行if(le == 0)ISOException.throwIt(ISO7816.SW_WRONG_LENGTH); if(le == 0)le =(short)(SIZE_MEMORY - offset);?我从来没有使用过这个模拟器,但是这个0x7F附加到APDU上是什么(对我来说没有任何意义)? - vlp'

    ......然后我把这条线放在线前; 'if((offset le)> SIZE_MEMORY)......它有效! - 再次非常感谢!

相关问题