这张卡真的有多少内存? (EEPROM和ObjectDeletion游戏!)

时间:2015-04-28 08:53:40

标签: javacard jcop

我写了一个简单的程序来检查requestObjectDeletion()方法功能和我的卡的可用内存。

我的applet响应五种不同类型的APDU命令,如下所示:

  1. SELECT APDU命令:响应:0X9000
  2. 命令:XX 00 XX XX XX [...]响应:以字节为单位返回可用内存。
  3. 命令:XX 01 XX XX XX [...]响应:创建一个2000个元素的本地字节数组(即2000个字节。)
  4. 命令:XX 02 XX XX XX [...]响应:请求对象删除方法
  5. 其他命令:回复:0x9000
  6. 为了返回可用内存,我编写了一个方法,该方法使用无限while循环来创建大量具有100元素的字节数组,并同时增加counter。在捕获Not enough memory异常时,该方法返回counter *100(即在调用此方法之前的空闲内存)

    好的,这是程序:

    public class ObjDeletion extends Applet {
        public static short counter = 0x0000;
    
        private ObjDeletion() {
        }
    
        public static void install(byte bArray[], short bOffset, byte bLength)
                throws ISOException {
            new ObjDeletion().register();
        }
    
        public void process(APDU arg0) throws ISOException {
    
            if (selectingApplet()) {
                return;
            }
    
            byte[] buffer = arg0.getBuffer();
    
            switch (buffer[ISO7816.OFFSET_INS]) {
            case 0x00:
                counter=0;
                ReturnAvailableMem();
                break;
    
            case 0x01:
                genLocalArray();
                break;
    
            case 0x02:
                JCSystem.requestObjectDeletion();
                break;
    
            default:
                return;
    
            }
    
        }
    
        public void genLocalArray() {
            byte[] LocalArray = new byte[2000];
        }
    
        public void ReturnAvailableMem() {
            try {
                while (true) {
                    byte[] dump = new byte[100];
                    counter += 1;
                }
    
            } catch (Exception e) {
    
                ISOException.throwIt((short) (counter * 100));
            }
        }
    }
    

    现在,有一个问题。当我向卡发送一些APDU命令时,这是 OpenSC-Tool 的输出:

    OSC: opensc-tool.exe -s 00a404000b0102030405060708090000 -s 00000000 -s 00020000
     -s 00000000 -s 00020000 -s 00010000 -s 00000000 -s 00020000 -s 00000000 -s 0002
    0000 -s 00010000 -s 00020000 -s 00000000
    
    Using reader with a card: ACS CCID USB Reader 0
    Sending: 00 A4 04 00 0B 01 02 03 04 05 06 07 08 09 00 00
    Received (SW1=0x90, SW2=0x00)
    
    //0::returnAvailableMem()
    Sending: 00 00 00 00 
    Received (SW1=0xE3, SW2=0x58)
    
    //1::returnAvailableMem()
    Sending: 00 00 00 00 
    Received (SW1=0x00, SW2=0x00)
    
    //2::requestObjectDeletion()
    Sending: 00 02 00 00
    Received (SW1=0x90, SW2=0x00)
    
    //3::returnAvailableMem()
    Sending: 00 00 00 00
    Received (SW1=0xE3, SW2=0x58)
    
    //4::requestObjectDeletion()
    Sending: 00 02 00 00
    Received (SW1=0x90, SW2=0x00)
    
    //5::genLocalArray()
    Sending: 00 01 00 00
    Received (SW1=0x90, SW2=0x00)
    
    //6::returnAvailableMem()
    Sending: 00 00 00 00
    Received (SW1=0xDD, SW2=0x18)
    
    //7::requestObjectDeletion()
    Sending: 00 02 00 00
    Received (SW1=0x90, SW2=0x00)
    
    //8::returnAvailableMem()
    Sending: 00 00 00 00
    Received (SW1=0xE3, SW2=0x58)
    
    //9::requestObjectDeletion()
    Sending: 00 02 00 00
    Received (SW1=0x90, SW2=0x00)
    
    //10::genLocalArray()
    Sending: 00 01 00 00
    Received (SW1=0x90, SW2=0x00)
    
    //11::requestObjectDeletion()
    Sending: 00 02 00 00
    Received (SW1=0x90, SW2=0x00)
    
    //12::returnAvailableMem()
    Sending: 00 00 00 00
    Received (SW1=0xE3, SW2=0x58)
    

    命令0返回0xE358(= 58200)。所以调用这个方法之前的内存是58200个字节。

    命令1返回0x0000,这意味着可用内存现在小于100字节。

    命令2返回0x9000,因此requestObjectDeletion成功调用。

    命令3再次返回0xE358,这意味着requestObjectDeletion成功运行。

    命令4返回0x9000,因此requestObjectDeletion成功调用。

    命令5返回0x9000,因此现在会创建一个带有2000元素的字节数组。

    现在我希望该卡的空闲内存等于0xE358 - 2000 = 0xDB88

    但是在下一个命令中:

    命令6返回0xDD18!即我们卡中有0xDD18 + 2000 = 0xE4E8个字节的内存空间!

    这可能是谁?为什么卡在第一个命令中看不到这个400字节(0xE4E8 - 0xE358)?

1 个答案:

答案 0 :(得分:2)

答案很简单,因为每个阵列(以及其他对象)都需要'标题'指出它的类型,大小等。你需要仔细阅读JCRE和JCVM规范。

我还没有检查“标题”的确切大小,但您可以将其设想为(100 + 'header') * X,而不是普通的100 * X

这也解释了优化提示:创建一个大数组可以节省更多内存而不是使用许多小数组 - 但当然存在折衷,例如代码变得不那么可读。