如何获取JavaCard剩余空间

0x01应用场景

获取JavaCard卡内剩余空间,一方面是在评估一张卡的时候需要用到,另一方面是在应用个人化或者运行时需要用到。

例如:应用提供商为了保证自己的应用在卡内运行期间能够不受空间影响,一般会在个人化(安装应用)的时候先分配好需要用到的空间,以免空间被后来应用占用,导致运行失败。

0x02空间类型

卡内剩余空间包括获取卡内的剩余永久存储器(E2P or Flash),还有获取易失性存储器空间(RAM),这里的RAM分为两部分,一部分是在卡片复位时清零的内存CLEAR_ON_RESET,缩写为COR或者RTR(Clear_on_Reset Transient RAM);另一部分为应用在取消选择的时候清零的内存CLEAR_ON_DESELECT,缩写为COD或者DTR(Clear_on_Deselect Transient RAM)。本文将通过实例获取卡内的这三种存储器剩余空间。

0x03获取接口

对于获取JavaCard内可用空间,API提供了相应的接口JCSystem.getAvaliableMemory(byte memoryType) ,位于javacard.framework包下,如下所示,引用自JCAPI v2.2.2。 

 

getAvailableMemory

public static short getAvailableMemory(byte memoryType)
                                throws SystemException
Obtains the amount of memory of the specified type that is available to the applet. Note that implementation-dependent memory overhead structures may also use the same memory pool.

Notes:

  • The number of bytes returned is only an upper bound on the amount of memory available due to overhead requirements.
  • Allocation of CLEAR_ON_RESET transient objects may affect the amount of CLEAR_ON_DESELECT transient memory available.
  • Allocation of CLEAR_ON_DESELECT transient objects may affect the amount of CLEAR_ON_RESET transient memory available.
  • If the number of available bytes is greater than 32767, then this method returns 32767.
  • The returned count is not an indicator of the size of object which may be created since memory fragmentation is possible.

 

Parameters:
memoryType - the type of memory being queried. One of the MEMORY_TYPE_* constants defined above. See MEMORY_TYPE_PERSISTENT.
Returns:
the upper bound on available bytes of memory for the specified type
Throws:
SystemException - with the following reason codes:
  • SystemException.ILLEGAL_VALUE if memoryType is not a valid memory type.

  根据接口描述,如果可用字节数超过32767(0x3FFF),则只返回32767。那如何返回超过32767的空间,可参考本文后面的代码实例。

0x04代码实例

1.获取DTR剩余空间

 1     /**
 2      * 获取剩余MEMORY_TYPE_TRANSIENT_DESELECT空间
 3      * @return
 4      */
 5     public int getFreeDTR(){
 6         //首先取得剩余空间大小
 7         short memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);
 8         int allmemsize = memsize;
 9         //如果返回值为0x3FFF,则剩余空间大于此值,可继续取得剩余空间
10         while(memsize == (short)32767){
11             JCSystem.makeTransientByteArray(memsize,JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);//不存储返回的数组对象
12             memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);
13             allmemsize += memsize;
14         }
15         return allmemsize;
16     }

 2.获取RTR剩余空间

 1     /**
 2      * 获取剩余的MEMORY_TYPE_TRANSIENT_RESET空间
 3      * @return
 4      */
 5     public int getFreeRTR(){
 6         //首先取得剩余空间大小
 7         short memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
 8         int allmemsize = memsize;
 9         //如果返回值为0x3FFF,则剩余空间大于此值,可继续取得剩余空间
10         while(memsize == (short)32767){
11             JCSystem.makeTransientByteArray(memsize,JCSystem.MEMORY_TYPE_TRANSIENT_RESET);//不存储返回的数组对象
12             memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
13             allmemsize += memsize;
14         }
15         return allmemsize;
16     }

 3.获取E2P/Flash的剩余空间

 1     /**
 2      * 获取剩余的E2P/Flash空间,如果剩余空间大于0x3FFF,则此接口将创建数组,然后再获取新的剩余空间,
 3      * 数组对象头将占用几个字节(根据对象存储结构不一样,可能占用字节数不同,一般数组头为7字节),因此存在误差。
 4      * @return
 5      */
 6     public int getFreePersistent(){
 7         //首先取得剩余空间大小
 8         short memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);
 9         int allmemsize = memsize;
10         //如果返回值为0x3FFF,则剩余空间大于此值,可继续取得剩余空间
11         while(memsize == (short)32767){
12             byte[] tmp=new byte[memsize]; //不存储返回的数组对象
13             memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);
14             allmemsize += memsize;
15         }
16         return allmemsize;
17     }

 注意

1.获取剩余空间的应用自身的代码需要占用部分空间,本例中的应用代码主468字节,存储在卡内空间为 278 字节.

2.DTR与RTR可能使用同一块区域。

3.以上代码在使用converter转成cap文件时需要加上支持int类型的选项,如果卡片本身不支持int,则代码中相应的地方需要做调整,譬如说如果卡内相应存储器空间大于0x3FFF时,可以将每次取得的值存储在apdubuffer中,一起返回到卡外,然后再计算。 

完整代码

  1 package GetFreeSpacePkg;
  2 
  3 import javacard.framework.APDU;
  4 import javacard.framework.ISO7816;
  5 import javacard.framework.Applet;
  6 import javacard.framework.ISOException;
  7 import javacard.framework.JCSystem;
  8 
  9 /**
 10  * 获取卡内剩余空间,包括E2P/Flash与RAM.
 11  * 对于E2P/Flash来说,如果卡内剩余空间超过0x3FFF,则此应用返回的数据会有较小的误差。
 12  * 测试命令:
 13  * 
 14  * 8000000000 //get DTR
 15  * 8001000000 //get RTR
 16  * 8002000000 //get E2P/Flash
 17  *  
 18  * @author SCPlatform@outlook.com
 19  */
 20 public class GetFreeSpaceApplet extends Applet {
 21     public static void install(byte[] bArray, short bOffset, byte bLength) {
 22         new GetFreeSpaceApplet().register(bArray, (short) (bOffset + 1),bArray[bOffset]);
 23     }
 24 
 25     public void process(APDU apdu) {
 26         if (selectingApplet()) {
 27             return;
 28         }
 29         
 30         byte[] buf = apdu.getBuffer();
 31         int iFreeSpace=0; 
 32         switch (buf[ISO7816.OFFSET_INS]) {
 33         case (byte) 0x00://DTR
 34             iFreeSpace = getFreeDTR();
 35             break;
 36         case (byte) 0x01://RTR
 37             iFreeSpace = getFreeRTR();
 38             break;
 39         case (byte) 0x02://persistent
 40             iFreeSpace = getFreePersistent();
 41             break;
 42         default:
 43             ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
 44         }
 45         JCSystem.requestObjectDeletion();
 46         buf[3]=(byte)(iFreeSpace);
 47         buf[2]=(byte)(iFreeSpace>>8);
 48         buf[1]=(byte)(iFreeSpace>>16);
 49         buf[0]=(byte)(iFreeSpace>>24);
 50         apdu.setOutgoingAndSend((short)0, (short)4);
 51     }
 52     /**
 53      * 获取剩余MEMORY_TYPE_TRANSIENT_DESELECT空间
 54      * @return
 55      */
 56     public int getFreeDTR(){
 57         //首先取得剩余空间大小
 58         short memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);
 59         int allmemsize = memsize;
 60         //如果返回值为0x3FFF,则剩余空间大于此值,可继续取得剩余空间
 61         while(memsize == (short)32767){
 62             JCSystem.makeTransientByteArray(memsize,JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);//不存储返回的数组对象
 63             memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_DESELECT);
 64             allmemsize += memsize;
 65         }
 66         return allmemsize;
 67     }
 68     
 69     /**
 70      * 获取剩余的MEMORY_TYPE_TRANSIENT_RESET空间
 71      * @return
 72      */
 73     public int getFreeRTR(){
 74         //首先取得剩余空间大小
 75         short memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
 76         int allmemsize = memsize;
 77         //如果返回值为0x3FFF,则剩余空间大于此值,可继续取得剩余空间
 78         while(memsize == (short)32767){
 79             JCSystem.makeTransientByteArray(memsize,JCSystem.MEMORY_TYPE_TRANSIENT_RESET);//不存储返回的数组对象
 80             memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_TRANSIENT_RESET);
 81             allmemsize += memsize;
 82         }
 83         return allmemsize;
 84     }
 85     
 86     /**
 87      * 获取剩余的E2P/Flash空间,如果剩余空间大于0x3FFF,则此接口将创建数组,然后再获取新的剩余空间,
 88      * 数组对象头将占用几个字节(根据对象存储结构不一样,可能占用字节数不同,一般数组头为7字节),因此存在误差。
 89      * @return
 90      */
 91     public int getFreePersistent(){
 92         //首先取得剩余空间大小
 93         short memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);
 94         int allmemsize = memsize;
 95         //如果返回值为0x3FFF,则剩余空间大于此值,可继续取得剩余空间
 96         while(memsize == (short)32767){
 97             byte[] tmp=new byte[memsize]; //不存储返回的数组对象
 98             memsize = JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT);
 99             allmemsize += memsize;
100         }
101         return allmemsize;
102     }
103 }

 0x05资料参考

1.Application Programming Interface Java Card™ Platform, Version 2.2.2

posted @ 2012-01-12 18:07  SCPlatform  阅读(1296)  评论(0编辑  收藏  举报