命令APDU | ||||||
标题头(必须) | 主体(可选) | |||||
CLA | INS | P1 | P2 | Lc | 数据字段 | Le |
应答APDU | ||
主体(可选) | 尾部(必须) | |
数据字段 | SW1 | SW2 |
包名 | 说明 |
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 | 这两个包支持智能卡所要求的密码功能。 |
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上执行其它指令。 |
http://www.blogjava.net/crespochen/archive/2011/05/19/350607.html
四、Java Card硬体需求 |
Java Card有如一部具体而微的电脑,其硬体的规格主要是在於维护Java Card runtime environment的 求,其最小的规格要求为:
五、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之软体架构。
![]() |
图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。