Java 卡中的内存分配

Memory allocation in Java Card

我有一张 Java Card 智能卡,我想评估可用的 EEPROM。

为此,我使用函数 JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT)。 由于这个函数的return语句是一个short,没有分配任何数据,我得到了值0x7FFF。为解决此问题,我以这种方式创建 byte 数组:new byte[(short) 0x7FFF] 以推断可用的持久内存。

如果我创建两个数组:

arr1 = new byte[(short) 0x7FFF];
arr2 = new byte[(short) 0x7FFF];

然后它根据 JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT) 占用 0x1144 字节的可用内存。因此,如果我求和,则意味着有 32767*2 + 4420 = 69954 个字节可用。

但是当我改变数组的大小时:

arr1 = new byte[(short) 0x7FFF];
arr2 = new byte[(short) 0x6FFF];

然后它将占用 0x2244 字节的可用内存。所以如果我求和,这意味着有 70210 个字节可用。

另一个例子: 与

arr1 = new byte[(short) 0x7FFF];
arr2 = new byte[(short) 0x5FFF];

它占用了 0x3344 字节的可用内存。因此,如果我求和,则意味着有 70466 个字节可用。

即使可以忽略不计,为什么会有这些差异?(70210 与 70466 不同)。

同理,我想测试一个小程序可以分配多少个AESKey。因此,我尝试按照我之前的描述找到可用内存,但使用 AESKey 数组。

使用同一张卡,当我以这种方式创建 AESKey 数组时:

arr = new AESKey[(short) 0x03E8];
for (short i = 0x0000; i < 0x03E8; i++) {
  arr[i] = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES,  KeyBuilder.LENGTH_AES_256, false);
}

所以我创建了一个包含一千个 256 位的数组 AESKey。我以为需要 32Ko,但是方法 JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT) 表明有 0x0022 字节可用。为什么是这个结果?

如果我用半键测试(例如 500):

arr = new AESKey[(short) 0x01F4];
for (short i = 0x0000; i < 0x01F4; i++) {
   arr[i] = (AESKey) KeyBuilder.buildKey(KeyBuilder.TYPE_AES,  KeyBuilder.LENGTH_AES_256, false);
}

方法JCSystem.getAvailableMemory(JCSystem.MEMORY_TYPE_PERSISTENT)表明有0x55EE(21998)个字节可用:如果可用EEPROM约为70Ko,我绝对看不到与创建1000个密钥的情况的关系就像我在开头解释的那样...

谁能详细说一下Java卡中内存是怎么分配的,来解释上面引用的结果?

嗯,简短的回答:
Java Card 不能巧妙地存储数组/它需要额外的数据。因此,如果您用 x 字节填充字节数组以达到 0x7FFF 阈值,则该数组内部将需要超过 x 字节来存储数据因此,您注意到了差异。

如果您使用的是 JCOP 卡,则可以使用 UtilX.getAvailableMemory().

来规避此问题

要了解更多知识,请阅读以下内容: http://ruimtools.com/doc.php?doc=jc_best关于减少EEPROM消耗的观点(但是有些部分已经过时)

这有几个原因:

  • 存在对象分配开销;
  • 对齐数据可能会产生开销;
  • 内存碎片可能会产生开销;
  • 对于密钥,可能会有开销来保证它们的安全。

所有这些问题都会减少您可用的内存量。在这方面,您应该将 getAvailableMemory 视为粗略指示 最大数量 可用内存。

需要多少开销取决于 Java 卡片运行时。