懂得Java Card体系结构 API和运行 环境的内部工作原理

了解Java Card体系结构 API和运行 环境的内部工作原理

http://www.cn-java.com/www1/?action-viewnews-itemid-363

摘要

Java Card是能运行Java 程序的智能卡。针对这种新的Java平台,Sun公司的JavaSoft部门已经制订了Java Card 2.0 API技术规范,目前,已有若干授权方正在智能卡上实现这种API。要编写与2.0兼容的Java Card 应用程序,开发人员需要从体系结构上了解Java Card的内涵,其内核类的含义,以及如何针对智能卡开发应用程序。
本文将详细讨论Java Card技术,为您,即开发人员,提供 有关智能卡内 Java平台 的系统体系结构、应用编程接口和运行环境的技术指南。( 4,000字)

作者:Zhiqun Chen,Rinaldo Di Giorgio专稿
本文将首先简单介绍智能卡,并简要回顾智能卡标准ISO 7816。根据Java Developer (开发人员专栏)以前发表的有关智能卡的文章,本文将首先回答这样一个问题:"什么是Java Card?",并简单介绍Java Card系统体系结构。然后,将集中讨论与Java Card相关的若干问题(包括Java Card的生命周期;Java Card 2.0语言子集和API库类;以及Java Card的安全性)。随后还将讨论Java Card运行环境和Java Card工作原理。最后举例说明Java Card的应用:针对Java Card编写的电子钱包应用程序。
本文中凡提到Java Card时均指Java Card 2.0。
什么是智能卡?
智能卡与信用卡大小相同,可通过嵌入到其塑料基体中硅片上的电子电路来存储和处理信息。智能卡主要分为两类:包含有微处理器并具有读、写和计算功能的智能卡(如小型微电脑)。另一类为没有微处理器的内存卡 ,它只能存储信息。内存卡利用安全逻辑算法控制对存储器的存取。
所有智能卡都包括三类存储器:
永久不变存储器(persistent non-mutable memory);永久可变存储器(persistent mutable memory);和非永久可变存储器(non-persistent mutable memory)。ROM、EEPROM和RAM是目前智能卡的三类存储器中使用最普遍的。永久存储器又称非易失性存储器。在本文中我们将交替使用术语永久存储器和非易失性存储器。
国际标准组织规定的ISO 7816第1-7部分包括覆盖智能卡各个方面的一组标准。ISO 7816包括:
  • 物理特性(第1部分)
  • 尺寸和触点位置(第2部分)
  • 电子信号和传输协议(第3部分)
  • 行业间交换指令(第4部分)
  • 应用程序标识符(第5部分)
  • 行业间数据元素(第6部分)
  • 行业间SCQL指令(第7部分)

下图表示智能卡的物理特性,在ISO 7816第1部分中有规定。 懂得Java Card体系结构 API和运行 环境的内部工作原理
Physical Characteristics ---物理特性
Magnetic Stripe ( Back of card ) ---磁条(卡的背面)
Contacts ---触点
Embossing area --- 刻字区
Front of Card ---卡的正面


有关ISO 7816和智能卡的详细情况,请参见"智能卡:入门"。
一般的说,智能卡不包括电源,显示屏,或键盘。它通过其8个触点,利用串行通信接口与外部世界交互。ISO 7816第2部分对智能卡的尺寸和触点位置有详细规定。下图表示智能卡的触点。
懂得Java Card体系结构 API和运行 环境的内部工作原理
Eight Contact Points --- 8个触点
Power Supplier ---电源
Reset ---复位
Check ---检查
Ground ---接地
Optional Contact ---可选触点
Input/Output ---输入/输出
Optional Contacts ---可选触点

智能卡插入可能与另一台计算机相连的卡接收设备(CAD)。卡接收设备又可称作终端、读卡器和IFD (接口设备)。 都具有相同的基本功能,即向智能卡提供电源和建立数据传输连接。

当两台计算机彼此进行通信时,它们交换根据一系列协议构造的数据包。类似地,智能卡也使用自己的数据包---称作APDU (应用协议数据单元)与外部世界对话。APDU包含一条指令或响应信息。在智能卡的世界里 采用的是主 从 模式,而智能卡永远扮演从动的角色。换句话说,智能卡总是在等待来自终端的 命令APDU。随后,它执行APDU规定的动作,并以一个 应答APDU向终端作出回答。智能卡与终端之间互相交换 命令APDU和 应答APDU。

下表分别表示 命令APDU和 应答APDU的格式。ISO 7816第4部分对APDU的结构有专门描述。
命令APDU
标题头(必须) 主体(可选)
CLA INS P1 P2 Lc 数据字段 Le

标题 头对被选指令进行编码。它包括4个字段:类(CLA)、指令(INS)、和参数1和2 (P1和P2)。每个字段包含一个字节:
  • CLA:类字节。在很多智能卡上,这个字节用来表示应用程序。
  • INS:指令字节。这个字节表示指令代码。
  • P1-P2:参数字节。这些字节对 命令APDU提供进一步说明。

Lc表示 命令APDU的数据字段的字节数;Le表示以下 应答APDU 的数据字段希望的字节数。
应答APDU
主体(可选) 尾部(必须)
数据字段 SW1 SW2

状态 字节 SW1和SW2表示 命令APDU在智能卡中的处理状态。

什么是Java Card?

Java Card是能运行Java程序的智能卡。Java Card 2.0技术规范刊登在http://www.javasoft.com/javacard上。它包括有关在智能卡上创建Java Card虚拟机和应用编程接口(API)的详细信息。 最低系统要求为16 kbps只读存储器(ROM)、8 kbps EEPROM和256字节随机存取存储器(RAM)。

Java Card上的系统体系结构如下 页图所示。 其中:
Applet ---小应用程序
Industry Add on Classes ---企业添加类
javacard Framework --- Javacard框架
OS & Native Functions ---操作系统和本地功能

如 图所示,Java Card虚拟机是建立在特定集成电路(IC)和本机操作系统执行程序上的。JVM层利用一般语言和系统接口隐藏了制造商的专利技术。Java Card框架定义了一系列用来开发Java Card应用程序和为这些应用程序提供系统服务的应用程编程接口(API)。某特定 行业或特殊的商务应用可提供添加的库,以提供服务或优化安全性和系统模型。Java Card应用程序 称为applets。一个卡上可驻留多个applets。每个applets均被其AID (应用程序标识符)唯一标识,如ISO 7816第5部分的规定。
懂得Java Card体系结构 API和运行 环境的内部工作原理

应该注意的重要的一点是,智能卡不是个人计算机。它们只有有限的存储器资源和计算功能。用户不应该简单地认为Java Card 2.0是JDK的简化版本。

Java Card的 生命周期

Java Card的 生命周期从本机操作系统、Java Card虚拟机、API类库和可选的applets被 写入ROM时开始。将一个可处理进入 命令的永久性组件 写入芯片的非可变存储器,这一过程又称作掩模(masking)。
在安装入您的钱包之前,Java Card需要经过初始化和个人化。初始化指在卡的非可变存储器内装入一般数据。这种数据对很多智能卡都是相同的,而并非某种卡所特有的;例如发行商或制造商的名称。
下一个步骤,个人化,指将卡分配予某个人。这个过程可通过物理个人化或电子个人化完成。物理个人化指在卡的塑料表面上压印或激光压印您的名字和卡号。电子个人化指在卡的非可变存储器中装载个人数据,例如您的个人密钥、名字和个人身份代码。
各厂家和发行商所采用的初始化和个人化的方法不尽相同。对这两个过程来说,通常都是用EEPROM (一类非可变存储器)存储数据。
现在,Java Card就可以使用了。您可以从发行商 处购买Java Card,也可从零售商 处购买Java Card。零售商销售的卡是通用型的,一般都没有经过个人化。
现在,您可以把您的Java Card插入读卡器,并向驻留在卡上的applet发送 命令APDU,或向卡内下载其它applet或数据。
除非Java Card失效或因某种不可恢复的错误而被闭锁,否则Java Card就能一直使用下去。

Java Card虚拟机的 生命周期

与PC或工作站上的Java虚拟机(JVM)不同,Java Card虚拟机可永远工作。

即使电源断开(即卡从读卡器上取下),存储在卡上的多数信息也必须保存下来。Java Card虚拟机可在EEPROM上创建能保存永久信息的对象。Java Card虚拟机的执行寿命就是卡的寿命。在没有电源的情况下,虚拟机按照无限的时钟周期工作。


Java Card applet和对象的 生命周期

Applet的生命周期始自它正确安装并被注册到系统的注册表中,而当它被从 注册表中删除时其生命周期就结束了。被删除的applet的空间可能被再次使用,也可能不再使用,这取决于卡上是否实现了垃圾收集功能。卡上的applet只有当被终端明确选择后才会 处于激活 状态。

对象是在永久存储器(如EEPROM )中创建的。如果不被其它永久对象所引用,对象就可能丢失或被当做垃圾收集。但向EEPROM写入的速度要比向RAM写入的速度慢1000倍。

某些对象经常被使用,其字段的内容就不必是永久的。Java Card支持RAM中的瞬态(暂时)对象。如果某个对象被宣布为瞬态 ,则其内容就不能 写入永久存储器。


ava Card 2.0语言子集

Java Card程序当然是用Java编写的。它们 可以用一般的Java编译器来编译。因为存储器资源和计算能力有限,所以Java Card并不能支持Java语言技术规范中规定的所有语言功能。特别地,Java Card不支持:

  • 动态类装载
  • 安全管理器
  • 线程和同步
  • 对象复制
  • 对象回收(finalization)
  • 长基本数据类型( float、double、long、和char )
所以支持这些功能的关键词 被省略也就不足为奇了。在有更大存储器的更高级智能卡上,由虚拟机的实现者决定 是否支持32位整数类型及post-issuance applet的native方法。Post-issuance applet即在卡被发放给持卡人后安装在Java Card上的applet。


Java Card 2.0框架

智能卡在市场上已经出现20多年了,多数智能卡一般都可与ISO 7816第1-7部分和/或EMV兼容。我们在前面已经谈到ISO 7816。什么是EMV呢?即EMV,它是由Europay、Mastercard和Visa等公司规定的基于ISO 7816系列的标准,是具有可满足金融业特定要求的附加专利功能的标准。设计Java Card框架的目的是能轻松支持智能卡系统和应用程序。它隐藏了智能卡体系结构的细节,并为Java Card应用程序开发人员提供了相对简单和直接的编程接口。

Java Card框架包括4个包:
包名 说明
javacard.framework 这是JavaCard的内核包。它定义诸如applet和个人身份代码(PIN)等类,这些类是Java Card程序和APDU、系统和Util (为Java Card程序、APDU提供运行时 服务和系统服务等,如APDU处理和对象共享等)的基本构件。
javacardx.framework 这个包可为与ISO 7816-4兼容的文件系统提供面向对象的设计。它支持ISO 7816规定的基本文件(EF)、专用文件(DF)和面向文件的APDU。
javacardx.crypto和javacardx.cryptoEnc 这两个包支持智能卡所要求的密码功能。

Java Cardx包符合Java命名原则,是Java Card框架的延伸。您 并非 必须在智能卡上支持这些包。

Java Card安全性

Java applets受Java安全性的限制,但Java Card系统的安全性模式在很多方面与标准Java有所不同。

Java Card不支持安全管理器类。语言 的安全策略是由虚拟机实施的。

Java applets创建可存储和处理数据的对象。对象由创建该对象的applet所拥有。即使applet 有对某个对象的引用,它也不能调用该对象的方法,除非它拥有该对象,或该对象已确定共享。某个applet可与另一个applet或所有applets共享其对象。

applet是Java Card内的独立实体。其选择、执行和功能不受驻留在同一张卡上的其它applet的影响。

Java Card内部工作原理

在Java Card内部,JCRE ( Java Card运行环境)引用Java Card虚拟机和Java Card框架中的类。Java Card内的每个applet都与JCRE赋予的特定AID关联。

当一个applet 被正确装入卡的永久存储器,并与Java Card框架和卡上的其它库关联后,作为applet安装过程的最后一步,JCRE就调用该applet 的安装方法。install是一种公共静态方法, 它被applet类实现以创建 applet的实例,并 在JCRE中为其注册。因为存储器是有限的,所以 较好的编程方法就是 在此时创建和初始化applet在其生命期内需要的对象。

驻留在卡上的applet 只有在被明确选择后才会被激活。终端向JCRE发送一个" SELECT APDU " 命令。JCRE暂停当前被选的applet ,并调用该applet的deselect方法进行必要的清理。随后,JCRE把AID已在" SELECT APDU "中规定的applet 标记为当前被选的applet,并调用新被选中的applet 的select方法。select方法使applet 做好接受APDU 命令的准备。JCRE将随后的APDU 命令发送给当前被选的applet,直到它接收到下一个" SELECT APDU " 命令为止。

怎样编写Java Card小应用程序?

演示如何创建Java Card 2.0 applet 的最好方法就是通过范例。下例为可存储电子现金的电子钱包应用程序。该钱包可处理read_balance、deposit和debit等APDU指令。只有知道钱包所有人的个人身份代码(PIN)才能进入钱包。

这个例子被制作成两栏的格式:左栏包括Java代码及Java风格的注解;右栏提供对左栏 代码的详尽解释。
package bank.purse Java Card与标准Java一样也支持包和标识符名称惯例
import javacard.framework.* ;
import javacardx.framework.* ;
 
public class Wallet extends Applet {
/* constants declaration */
一个applet是 javacard.framework.Applet 的继成类的实例
// code of CLA byte in the command APDU header final static byte Wallet_CLA = (byte)0xB0; CLA标识该应用程序
// code of INS byte in the command APDU header
final static byte Deposit = (byte)0x10;
final static byte Debit = (byte)0x20;
final static byte Balance = (byte)0x30;
final static byte Validate = (byte)0x40;
INS标识应用程序指令
// maximum number of incorrect tries before the PIN is blocked
final static byte PinTryLimit = (byte)0x03;
// maximum size PIN
final static byte MaxPinSize = (byte)0x04;
PIN对象参数
// status word (SW1-SW2) to signal that the balance become neagtive;
final static short SW_NEGATIVE_BALANCE = (short)0x6910;
Applet特定静态字
/* instance variables declaration */
OwnerPIN pin;
byte balance;
byte buffer[ ]; // APDU buffer
 
private Wallet( ) {
// It is good programming practice to allocate
// all the memory that an applet need during its
// lifetime inside the constructor
pin = new OwnerPIN(PinTryLimit, MaxPinSize);
balance = 0;
register( );
} // end of the constructor
private构造 方法---类Wallet的实例由其install方法 实例化
applet 通过调用Applet类中所定义的register 方法向JCRE登记注册。现在 对外部 而言,applet 是可见的。
public static void install(APDU apdu) {
// create a Wallet applet instance
new Wallet( );
} // end of install method
在applet安装过程的最后一步,方法install被JCRE调用
public boolean select( ) {
 

// returns true to JCRE to indicate that the applet
// is ready to accept incoming APDUs .
return true;
} // end of select method
这个方法被JCRE调用,表示该applet已被选择。它执行处理以下APDU信息所需要的必要初始化
public void process(APDU apdu) {
// APDU object carries a byte array (buffer) to
// transfer incoming and outgoing APDU header
// and data bytes between card and CAD
buffer = apdu.getBuffer( );
在applet被成功选择之后,JCRE向此方法发送进入的APDU。
APDU对象被JCRE拥有和维护。它封装了底层的基本传输协议 (如ISO7816-3规定的T0或T1 )的细节并提供了通用接口。
// verify that if the applet can accept this
// APDU message
if(buffer[ISO.OFFSET_CLA] !== Wallet_CLA)
ISOException.throwIt
(ISO.SW_CLA_NOT_SUPPORTED);
当发生错误时,applet可能决定中止过程,并抛出一个包含状态字(SW1 SW2)的例外,状态字用于表示卡的处理状态。
switch (buffer[ISO.OFFSET_INS]) {
case Balance: getBalance(apdu); return;
case Debit: debit(apdu); return;
case Deposit: deposit(apdu); return;
case Validate: validate(apdu); return;
default: ISOException.throwIt
(ISO.SW_INS_NOT_SUPPORTED);

}

} // end of process method
process方法的主要功能是执行APDU规定的动作,并向终端返回正确的响应。
INS字节 指定需要执行的动作的类型
private void deposit(APDU apdu) {
// access authentication
if( ! pin.isValidated( ) )
ISOException.throwIt( ISO.SW_PIN_REQUIRED);
// Lc byte denotes the number of bytes in the data
// field of the command APDU
byte numBytes = (byte) (buffer[ISO.OFFSET_LC]);
// indicate that this APDU has incoming data and
// receive data sharing from the offset
// ISO.OFFSET_CDATA
byte byteRead = (byte) (apdu.setIncomingAndReceive( ) );
// It is an error if the number of data bytes read does // not match the number in Lc byte
if(byteRead != 1)
ISOException.throwIt(ISO.SW_WRONG_LENGTH);
// increase the balance by amount specified in the
// data field of the command APDU
balance = (byte)
(balance + buffer[ISO.OFFSET_CDATA]);
// return successfully
return;
} // end of deposit method
参数APDU对象包含一个数据字段,它 指定 存款的金额。
在从JCRE接收到APDU对象后,APDU缓冲器中有前5个字节(CLA、INS、P1、P2、Lc/Le )可用。其在APDU缓冲器中的偏移量在类ISO中规定。因为数据字段是可选的,所以applet需要 显式通知JCRE 获取额外 的数据字节。
卡与CAD之间的通信是在命令APDU和应答APDU对之间交换的。在存钱( deposit ) 例子中, 应答APDU不包含数据字段。JCRE使用状态字0×9000 (正常处理)构成正确的应答APDU。applet开发人员不必关心构造正确的 应答APDU的细节。
当JCRE捕捉到一个exception (表示在处理指令时有错误)时,JCRE会使用Exception中包含的状态字构造 应答APDU 。
private void debit(APDU apdu) {
// access authentication
if( ! pin.isValidated( ) )
ISOException.throwIt(ISO.SW_PIN_REQUIRED);
byte numBytes = (byte) (buffer[ISO.OFFSET_LC]);
byte byteRead = (byte) (apdu.setIncomingAndReceive( ) );
if(byteRead != 1)
ISOException.throwIt(ISO.SW_WRONG_LENGTH);
// balance can not be negative
if(balance - buffer[ISO.OFFSET_CDATA]) <0)
ISOException.throwIt(SW_NEGATIVE_BALANCE);
balance = (byte)
(balance - buffer[ISO.OFFSET_CDATA]);
} // end of debit method
在debit方法中,APDU对象包含一个数据字段, 该数据字段 指定了提款的金额。
private void getBalance(APDU apdu) {
// access authentication
if(! Pin.isValidated( ) )
ISOException.throwIt(ISO.SW_PIN_REQUIRED);
// inform system that the applet has finished processing
// the command and the system should now prepare to
// construct a response APDU which contains data field
apdu.setOutgoing( );
// indicate the number of bytes in the data field
apdu.setOutgoingLength(byte)1);
// move the data into the APDU buffer starting at offset 0
buffer[0] = balance;
// send 1 byte of data at offset 0 in the APDU buffer
} // end of getBalance method
getBalance在 应答APDU的数据字段中返回钱包的余额。
因为应答APDU响应中的数据字段是可选的,所以applet 需要 显式 告诉JCRE 它要返回的数据。JCRE使用APDU对象缓冲器内的数组和正确的状态字构造一个完整的 应答APDU 。
private void validate(APDU apdu) {
// retrieve the PIN data which requires to be validated
// the user interface data is stored in the data field of the
APDU
byte byteRead = (byte) (apdu.setIncomingAnd Receive( ) );
// validate user interface and set the validation falg in the
user interface
// object to be true if the validation succeeds.
// if user interface validation fails, PinException would be
// thrown from pin.check( ) method
pin.check(buffer, ISO.OFFSET_CDATA, byteRead);
} // end of validate method
} // end of class Wallet
PIN是智能卡常用的保护数据免遭越权使用的方法。
PIN中记录自上次正确的PIN确认后不成功的尝试次数。如果不成功的尝试次数超过PIN规定的允许最大尝试次数,则卡就被闭锁。
在成功选择applet后,首先必须使PIN生效,然后才能在applet上执行其它指令。

结论

本文首先介绍了智能卡的一些基本概念,然后阐述了Java Card 2.0的技术和开发Java Card应用程序的方法。
Java Card applet是用一般的Java 编译器编译的。 编译器的输出结果(class 文件)被输入Java Card转换器,后者 增强了Java Card 2.0 语言子集的兼容性,可执行名字解析和初始地址链接,并优化Java字节代码 使之更适合 在Java Card虚拟机上运行。转换器的输出结果被下载到Java Card上。本文对转换器和applet 安装协议没有详细说明,因为这些协议尚未标准化。我们 希望在今后的文章中能够阐述这方面的问题。

Java Card为Java世界添加了一种新的平台。Java Card的广泛采用和部署需要市场的推动、更多的应用程序和工具 的开发及时间。同时,在今后几年里,Java Card的使用数量将增加到上百万。也就是说,您不久就会使用随身携带的钱包里的小卡片来存储个人信息和下载应用程序了。

参考资料

  • 有关智能卡Java Developer系列文章的第一篇文章是"智能卡入门"
    http://www.javaworld.com/jw-12-1997/jw-12-javadev.html
  • 有关与Java Card相关的商业机会,请参见"把货币交给Java Card API "
    http://www.javaworld.com/javaworld/jw-02-1998/jw-02-javacard.html
  • 有关在Java Card 1.0 API上开发应用程序的方法,请参见" Java Card速成"
    http: //www.javaworld.com/javaworld/jw-02-1998/jw-02-javadev.html
  • Java Card站点JavaSoft
    http://www.sun.com/products/javacard/
  • Java商业站点
    http://java.sun.com/products/commerce/
  • Javasoft部的Java Card技术总监Joshua Susser对本文进行了审阅并提供了技术指导,谨在此向他表示衷心感谢。


作者简介

Rinaldo Di Giorgio是Sun Microsystems公司研究部的在职工程师。他在该公司从事数字经济的试验。他的电子邮件地址是rinaldo.digiorgio@javaworld.com。

Zhiqun Chen是Javasoft商业交易集团的Java Card工程师。她负责设计和开发Java Card API和应用程序。她在为Java Electronic Commerce Framework ( Java电子商务框架)开发Visa Open Platform卡应用程序及MasterCard MondexTM终端和应用程序方面积累了丰富的经验。Zhiqun Chen的电子邮件地址是zhiqun.chen@javaworld.com。

 

 

 

----------------------------

 

http://www.blogjava.net/crespochen/archive/2011/05/19/350607.html

四、Java Card硬体需求

Java Card有如一部具体而微的电脑,其硬体的规格主要是在於维护Java Card runtime environment的 求,其最小的规格要求为:

  • 512 bytes RAM:主要用於存放程式执行时的 stack、暂存资料以及做为I/O的缓冲区。
  • 24 KB ROM :主要用於存放系统的程式以及 Runtime Environment,如 JVM、applets、 native functions 等。
  • 8 KB EEPROM:用於储存我们所下载至 Java Card的 applets,并且做为 object heap存放之处。
  • 8-bit processor: Java Card必须至少支援8位元的处理器。
五、Java Card软体架构

在上述的硬体架构中,基本上我们可以将Java Card想像为一部PC的缩影,而Java Card的软体架构则具有OS、 native functions 、JCRE(Java Card Runtime Environment)以及架构在此JCRE上的应用程式(Java Card applets),事实上Java Card的软体架构也是与今日的软体架构相仿,图5-1即为Java Card之软体架构。

懂得Java Card体系结构 API和运行 环境的内部工作原理
图5-1 Java Card之软体架构图

在此软体架构中,最底层的OS and Native Functions 是负责低阶的处理工作,如同今日的作业系统。而在上面两层Java Card Interpreter与Java Card APIs and Framework就是我们所谓的JCRE,主要负责执行Java Card applets以及提供 applet执行所 要的环境。而 Industry Add-on Classes则是 service provider 所提供的classes,使得企业与公司能够提供属於自己的服务程式。

Java Card的最上层就是所谓的Java Card applets,就如图5-1所示,一个 Java Card可以执行多个Java Card applets,但是要特别注意,Java Card 的执行环境并无支援Multi-thread,所以一次只能执行一个applet,并且 applet与applet之间也有firewall的阻隔。尽管如此,在Java Card的设计之中亦有让不同的 applets相互沟通的机制,我们只 要让applet implement javacard.framewor k.Shareable interface就能够分享applet 的 resource。

因为受限於体积与 resource,所以 Java Card在执行环境上的支援是相当有限的,表5-1即 Java Card执行环境的支援现况,其他详细内容请参考 references。