📄 messcard.java
字号:
Package MessCard;
import javacard.framework.*
public class MessCard extends Applet{
/*常量声明*/
// MessCard应用支持的CLA
final static byte MessCard _CLA=(byte)0x80;
// MessCard应用支持的INS Install指令
final static byte VERIFY=(byte)0x20;
final static byte CREDIT=(byte)0x30;
final static byte DEBIT=(byte)0x40;
final static byte GET_BALANCE=(byte)0x50;
//最大余额 0x7fff是十六进制要运算就要转换为十进制它的十进制是32767
final static short MAX_BALANCE=0x7FFF;
//消费最大值
final static short MAX_TRANSACTION_AMOUNT=0x7F;
//PIN锁定前语序的最大错误尝试次数
final static byte PIN_TRY_LIMIT=(byte)0x03;
//PIN值的最大长度
final static byte MAX_PIN_SIZE=(byte)0x08;
/*MessCard应用返回的错误吗*/
//表明PIN认证错误
final static short SW_VERIFICATION_FAILED=0x6300;
//表明在消费进行之前需要先进行PIN认证
final static short SW_PIN_VERIFICATION_REQUIRED=0x6301;
//表明消费额小于零或大于最大允许值
//amount>MAX_TRANSACTION_AMOUNT or amount<0
final static short SW_INVALID_TRANSACTION_AMOUNT=0x6A83;
//表明余额已超出最大允许值
final static short SW_EXCEED_MAXIMUM_BALANCE=0x6A84;
//表明余额为负值
Final static short SW_NEGATIVE_BALANCE=0x6A85;
/*实例化变量声明*/
//食堂卡应用PIN值
OwnerPIN pin;
//食堂卡应用的余额
short balance;
private MessCard(byte[] bArray,short bOffset,byte bLength){
//MessCard应用构造函数,推荐将应用所需的所有变量,
//同意放到构造函数内进行分配,这样将减少内存泄漏的可能
//以为定的参数创建OwnerPIN 对象实例PIN
pin=new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);
//计算install方法输入参数在输入数组中的偏移量
byte iLen=bArray[bOffset];//AID length
bOffset=(short)(bOffset+iLen+1);
byte cLen=bArray[bOffset];//info length
bOffset=(short)(bOffset+cLen+1);
byte aLen=bArray[bOffset];//applet data length
//去安装参数作为食堂卡的初始PIN
pin.update(bArray,(short)(bOffset+1),aLen);
register();
}
public static void install(byte[] bArray,short bOffset,byte bLength){
new MessCard(bArray,bOffset,bLength);
}
public boolean select(){
if(pin.getTriesRemaining()==0)
return false;
}
public void deselect(){
//当MessCard应用被取消选择时,将PIN的状态清空为初始值
pin.reset();
}
public void process(APDU apdu){
//APDU对象为JCRE临时入口点对象,他可被任何应用所访问,
//负责传递终端发送的APDU命令。通过APDU.getBuffer()命令,
//既可以得到APDU对象的通信缓冲区,即APDU命令数组
byte[] buffer=apdu.getBuffer();
//判断命令头是否正确
buffer[ISO7816.OFFSET_CLA]=(byte)(buffer[ISO7816.OFFSET_CLA]&(byte)0xFC);
//若为SELECT命令,则直接返回,不做其他操作
if((buffer[ISO7816.OFFSET_CLA]==0)&&
(buffer[ISO7816.OFFSET_INS]==(byte)(0xA4)) )
return;
//若为其他命令,则判断命令CLA和INS是否能够为MessCard应用所支持,
//若为支持范围外的其他值,则返回对象的错误状态字
if(buffer[ISO7816.OFFSET_CLA]!=MessCard_CLA)
ISOExecption.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
Switch(buffer[ISO7816.OFFSET_INS]){
case GET_BALANCE:
getBalance(apdu);
retuen;
case DEBIT:
debit(apdu);
return;
case CREDIT:
credit(apdu);
return;
case VERIFY:
verify(apdu);
return;
default:
ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
}
}
private void credit(APDU apdu){
//食堂卡应用鉴权
if(!pin.is Validated())
ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
byte[] buffer=apdu.getBuffer();
//取命令LC,并将之存储在numBytes中
byte numBytes=buffer[ISO7816.OFFSET_LC];
//接收APDU命令数据,并将之存储到APDU通信缓冲区的
//ISO7816.OFFSET_CDATA处,接着5字节的APDU命令头
byte byteRead=(byte)(apdu.setIncomingAndReceive());
//判断LC是否为1否则抛出异常,本应用只支持一个字节长度的存钱消费
if((numBytes!=1)||(byteRead!=1))
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
//取将存入的值
byte creditAmount=buffer[ISO7816.FOFFSET_CDATA];
//判断消费额度是否满足要求
if((creditAmount)>MAX_TRANSACTION_AMOUNT)||(CREDITaMOUNT<0)
)ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
//判断若进行存钱消费,余额是否超出允许最大值
if((short)(balance+creditAmount)>MAX_BALANCE)
ISOException.throwIt(SW_EXCEED_MAXIMUM_BALANCE);
//若以上条件满足,则更新食堂卡余额
blance=(short)(balance+creditAmount);
}
private void debit(APDU apdu){
//食堂卡应用鉴权
if(!pin.isValidated())
ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
byte [] buffer=apdu.getBuffer();
byte numBytes=(byte)(buffer[ISO7816.OFFSET_LC]);
byte byteRead=(byte)(apdu.setIncomingAndReceive());
if((numBytes!=1)||(byteRead!=1))
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
//取即将消费的值
byte debitAmount=buffer[ISO7816.OFFSET_CDATA];
//判断消费消费额度是否满足要求
if((debitAmount>MAX_TRANSACTION_AMOUNT)||(debitAmount<0))
ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
//判断食堂卡余额是否大于消费的数额,即食堂卡是否透支
if((short)(balance-debitAmount)<(short)0)
ISOException.throwIt(SW_NEGATIVE_BALANCE);
//若以上条件全部满足,最后更改食堂卡余额
balance=(short)(balance-debitAmount);
}
private void getBalance(APDU apdu){
byte[] buffer=apdu.getBuffer();
//设置通信传输方向为卡片到终端,同时也表示卡片运行结束,
//准备发送命令响应给终端,其中le为APDU命令中的LE,
//表示终端要求卡片返回的响应数据的长度
short le=apdu.setOutgoing();
if(le<2)
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
//设置卡片发送数据的实际长度
apdu.setOutgoingLength((byte)2);
//复制余额数据岛APDU缓存区中,准备发送给终端
buffer[0]=(byte)(balance>>8);
buffer[1]=(byte)(balance&0xFF);
//调用通信函数发送余额数据
apdu.sendBytes((short)0,(short)2);
}
private void verify(APDU apdu){
byte[] buffer=apdu.getBuffer();
//接收终端发送的PIN数据,并将之存储到APDU通信缓冲区中
byte byteRead=(byte)(apdu.setIncomingAndReceive());
//判断数据终端数据的PIN是否和卡片内的PIN值相符
if(pin.check(buffer,ISO7816.OFFSET_CDATA.byteRead)==false)
ISOException.throwIt(SW_VERIFICATION_FAILED);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -