如何获取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。
getAvailableMemorypublic static short getAvailableMemory(byte memoryType) throws SystemException
|
根据接口描述,如果可用字节数超过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
作者:SCPlatform
Email:SCPlatform@outlook.com
本文旨在学习、交流使用,任何对文章内容的出版、印刷,对文章中提到的技术的商业使用时,请注意可能存在的法律风险。