0
votes

I wrote a simple program to check requestObjectDeletion() method functionality and my card's available memory.

My applet respond to five different kind of APDU commands as follow :

  1. SELECT APDU command : Response : 0X9000
  2. Command : XX 00 XX XX XX [...] Response : Return available memory in byte.
  3. Command : XX 01 XX XX XX [...] Response : Create a local byte array of 2000 elements (i.e. 2000 byte.)
  4. Command : XX 02 XX XX XX [...] Response : request for Object Deletion method
  5. Other commands : Response : 0x9000

To return the available memory I wrote a method that use an infinite while loop to create a lot of byte arrays with 100 elements and increase a counter simultaneously. On catching the Not enough memory exception, the method returns counter *100 (i.e. the free memory before calling this method)

OK, this is the program :

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));
        }
    }
}

Now, there is a problem. This is the output of OpenSC-Tool when I send some APDU commands to the card:

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)

Command 0 returns 0xE358 (=58200). So the memory before calling this method was 58200 bytes.

Command 1 returns 0x0000, and this mean that the free memory is less than 100 byte now.

Command 2 returns 0x9000, so requestObjectDeletion called successfully.

Command 3 returns 0xE358 again, and this mean that requestObjectDeletion run successfully.

Command 4 returns 0x9000, so requestObjectDeletion called successfully.

Command 5 returns 0x9000, so a byte array with 2000 element is created now.

Now I expect the card to have free memory equal with 0xE358 - 2000 = 0xDB88

But in the next command :

Command 6 returns 0xDD18! i.e we have 0xDD18 + 2000 = 0xE4E8 bytes memory space in our card!

Who is this possible? Why the card can't see this 400 bytes (0xE4E8 - 0xE358) in the first command?

1

1 Answers

2
votes

The answer is simply because each array (and other objects as well) requires 'header' to indicate its type, its size, etc. You need to read carefully on JCRE and JCVM specification for this.

I haven't check the precise size of the 'header', but you can imagine it as (100 + 'header') * X, not as plain 100 * X.

This is also explain the optimization tips: creating one big array saves more memory rather than using many small arrays -- but of course there is trade off such as code become less readable.