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上执行其它指令。
|