智能卡。第4部分。JavaCard

你好,Giktayms!

今天我想谈谈JavaCard。本文将重点介绍JavaCard的概念及其架构。如果对此主题感兴趣,那么我可以写一系列单独的文章,其中将详细讨论JavaCard的所有方面。我马上说,我不会教你如何用JavaCard编写第一个应用程序,因为互联网上已经有太多关于此的文章。今天,我们将主要讨论JavaCard的工作原理。

因此,基于JavaCard的智能卡是在所谓的JavaCard Runtime Environment(与Java Runtime Environment几乎没有共同点)中的JavaCard Virtual Machine(适用于智能卡的Java Virtual Machine的受限版本)上运行应用程序的卡。 。

在术语方面,应用程序称为Applet,并包含在Packages中。程序包以CAP文件(而不是Jar文件)分发。程序包和应用程序具有自己的AID(应用程序标识符)。这是必需的,以便可以在诸如SELECT,INSTALL,DELETE等命令中唯一标识它们。 (在ISO7816-4中描述了SELECT,而在Global Platform中描述了JavaCard和其他命令)。

Applet的生命周期与计算机应用程序的通常生命周期略有不同。小程序是从小程序基类继承的任何类。安装应用程序时,将调用其静态安装方法。此方法应创建相应类的对象,然后在其上调用register方法。随后,对象将被保存在系统中并接收其自己的AID,该AID将用于与应用程序的进一步通信。对象及其数据字段存储在NVM(非易失性存储器)中。应用程序使用“ new”运算符创建的每个对象或数组也将位于NVM中。这意味着,与传统的计算机程序不同,JavaCard应用程序的状态是恒定的,即使关闭卡也不会丢失。

与应用程序通信


任何时候,每个打开的逻辑通道都有一个活动的应用程序。活动应用程序是一种接收终端发送的所有APDU的应用程序。收到APDU时,JavaCard会调用活动应用程序的处理方法,该方法将接收到的APDU作为唯一参数。此方法是Applet的核心,因为它处理来自终端的请求。所得的APDU也用于发送响应。

小程序可以通过两种方式激活:

  • 重置卡或打开逻辑通道时,系统通常会激活标记为“默认应用程序”的应用程序
  • 使用P1 = 0x04的SELECT命令和Data中应用程序的AID(全部或部分)

当使用SELECT命令激活应用程序时,激活后立即调用包含该命令的APDU的处理方法。因此,当激活时,Applet能够响应SELECT命令发送信息。 Applet类提供了selectionApplet()方法来确定接收到的命令是否导致应用程序激活。

该应用程序还具有重写select()和deselect()方法的能力,以便分别在激活期间进行初始化和在取消激活期间进行取消初始化。无论如何激活应用程序,都将调用这些方法。

可以使用MANAGE CHANNEL命令打开和关闭逻辑通道。通过开放的逻辑通道,您可以发送任何命令,包括SELECT。SELECT和MANAGE CHANNEL是唯一直接由系统而不是活动应用程序处理的命令。尽管在SELECT命令的情况下,我们可以说它是由系统和活动应用程序都处理的。

调用应用程序和处理SELECT命令的完整规则非常复杂,并且JavaCard和Global Platform之间几乎没有矛盾。但是,我将在下一篇文章中介绍该主题。现在值得一提的是,卡通常遵循全球平台中描述的规则。

内存管理


如上所述,对象和数组默认情况下存储在NVM中。除了NVM,JavaCard还可以使用JCSystem类中的许多方法在RAM中创建阵列。临时存储器有两种类型:重置时清除和取消选择时清除。当卡关闭或重置时,第一个被擦除。当Applet停止活动时(即:当选择另一个应用程序,关闭,重置等时),第二个被删除。应当注意,尽管阵列的内容被擦除(即,所有零或假都写入那里),但是阵列本身仍然保留,并且可以例如存储在对象数据字段中。

NVM中保存了什么:
  • 所有对象及其数据字段。
  • 所有数组。
  • 由new运算符创建的数组的内容。

RAM中存储了什么(CLEAR_ON_RESET或CLEAR_ON_DESELECT):
  • , JCSystem.makeTransient<>Array. , , , JCSystem.makeTransientObjectArray(), NVM. RAM.
  • Global Arrays: (APDU Install Parameters ), Global Arrays, JCSystem.makeGlobalArray().
  • . .


通常,应用程序应创建安装过程中需要的所有对象和数组,而不是动态创建。造成这种情况的原因主要有两个因素:

1)希望确保在成功安装应用程序后,如果某个其他应用程序占用了所有可用内存,它将不会停止工作。
2)垃圾收集器-可选的(尽管很常见)功能。这意味着在动态创建对象时,存在创建的对象永远不会被删除的风险。随着时间的流逝,这将导致缺少可用内存。即使有垃圾收集器,该过程也不会自动发生,而是应应用程序的请求(JCSystem.requestObjectDeletion())。

随后,就面向对象编程而言,很少获得应用程序代码的“干净”。对许多不同的操作使用公共字节[]是一种非常普遍的做法。仅由静态方法组成并在byte []上运行的类也很常见。另外,最小化了类和对象的创建。很少的内存,必须不惜一切代价保护它。

还值得注意的是APDU对象的作用。在接收每个命令之前,将擦除其位于RAM中的缓冲区。通常不仅使用它来形成答案,而且经常将其用作临时缓冲区。如果卡支持扩展长度,则其大小至少为256个字节或更大。

小程序防火墙


JavaCard的一个重要功能可能会使程序员感到困惑,这就是所谓的Applet防火墙的存在。防火墙的目的是防止任何Applet访问另一个Applet的数据。我必须马上说JavaCard允许使用Shareable Interfaces在应用程序之间进行通信,而且包是可以在不同应用程序中使用的类和函数的库。这就是为什么需要防火墙的原因。Applet防火墙的基本原理如下:

  • 每个应用程序都属于一个上下文。同一包中的所有应用程序都属于同一上下文。
  • 每个对象都属于一个应用程序或系统。
  • 没有应用程序的库(库)没有上下文。来自其类的对象属于创建它们的应用程序。
  • 系统中始终有一个活动上下文。
  • (/ ) , .
  • .
  • . . , , firewall.
  • CLEAR_ON_DESELECT , .

使用共享接口,程序员可以允许一个对象的某些方法可用于来自不同上下文的应用程序。当调用这些方法之一时,系统会将上下文切换到提供可共享接口的对象所属的上下文。这意味着该方法只能访问属于其上下文的对象,例如,如果您将此方法byte []作为原始上下文的参数传递,则访问期间将发生错误。方法执行完成后,上下文将切换回原来的上下文。

该应用程序还可以访问属于系统的某些对象。这些对象称为入口点。有两种类型的入口点:临时入口和永久入口。永久入口点很简单,可以从任何上下文访问它们。一个示例是来自AID类的对象。另一方面,临时入口点有一个限制,可以防止将它们存储在对象的数据字段或类的静态字段中。临时入口点的一个示例是APDU对象。

从JavaCard 3.0.4开始,还可以使用JCSystem.makeGlobalArray()方法创建全局数组。它们的行为与临时入口点的行为完全相同。对于使用Shareable Interface技术调用的方法,它们主要是作为参数使用的。

原子性和交易


更改对象或类的数据字段时,JavaCard保证原子操作。数组上的方法还提供了原子性(名称中带有NonAtomic后缀的方法除外)。这意味着,例如,Util.arrayCopy将复制所有字节(如果成功执行),或者在出现错误或能量损失的情况下保持数组不变。

如果需要在一个原子操作中更改几个常量字段和数组,则JavaCard还提供了JCSystem.beginTransaction()函数来启动事务,并提供JCSystem.commitTransaction()来完成事务。在对JCSystem.beginTransaction()和JCSystem.commitTransaction()的调用之间的数组和常量字段中发生的所有更改将自动成为事务的一部分。如果由于错误,能量损失或对JCSystem.abortTransaction()方法的调用而取消了事务,则系统将恢复原始状态。值得记住的是,交易的技术实现使用了额外的系统缓冲区。如果缓冲区已满,则系统将给出TransactionException错误。

Rmi


JavaCard支持RMI(远程方法调用)技术。在本文中,我不会专门介绍这种技术。我只能说这种功能并不常见,许多卡都不支持它。

API


大多数JavaCard API都专用于加密。有用于加密,创建和验证数字签名,生成密钥和随机数,计算校验和和哈希值以及实现密钥交换方案的类。除了加密之外,JavaCard还提供了用于存储和验证PIN甚至生物识别数据的类。其余的类提供对其他章节中描述的功能的访问,或者是使用字符串,数字,TLV等的辅助类。至于API,它将在另一系列文章中进行解释。

与Java相比的主要JavaCard限制


JavaCard应用程序编程语言是Java。几乎是Java。因此,不支持char,float,double,long和enum类型。卡的int类型是可选的(通常是现代卡支持),如果未通过相应的选项激活,则将其使用,如果将应用程序转换为CAP文件,则会导致错误。忘记了,迭代器和lambda。自版本3.0.0起,转换器支持泛型,静态导入和注释(仅运行时不可见),例如它们不影响代码执行。

要编译代码,请使用普通的JDK编译器。仅当转换为CAP文件或使用Smart IDE for JavaCard时,不兼容错误才会引起注意。

实际上,对于程序员来说最大的问题是默认情况下缺少int。通常,确实不需要它们,所以我不想不必要地激活它们。但是,Java编译器具有将所有算术运算的结果自动转换为int的习惯。为避免这种情况,您必须使用显式类型强制转换为代码中的short或byte,这会使代码的可读性降低。

静态字段的初始化存在另一个限制,即只能使用常量和包含常量的数组初始化对象,而不能使用对象进行初始化。

结论


这就是我对JavaCard的介绍。如果您觉得这篇文章有趣,或者至少引起了您对该主题的兴趣,那么您可以在评论中写下您想进一步了解的内容。因此,我可以决定以什么顺序和多少细节来编写JavaCard的特定功能和应用程序。无论如何,下一篇关于全球平台的文章将结束本系列文章。

Source: https://habr.com/ru/post/zh-CN380543/


All Articles