【Java Card】Applet升级个性化数据保留方案
·
前言
Applet在使用前通常需要预先写入个性化数据,这些数据作为持久化信息存储,不会因断电而丢失。然而在升级过程中,旧版applet需要先被卸载才能安装新版,这会导致原有的持久化数据丢失。由于新版applet缺乏必要的数据,将无法直接投入使用。因此,applet升级时必须考虑数据保留问题。
本文提出了一套切实可行的applet升级解决方案。
一、基本思路
交付时提供两个applet,一个主applet,一个backup applet。
主applet实现apdu交互的接口以及主要的交互逻辑,而backup applet则仅用来保存个性化数据,不提供对外的apdu交互接口。
由于主要逻辑都在主applet中,因此升级是针对主applet。升级分为3个步骤:
1、将个性化数据从主applet写入到backup applet中。
2、卸载主applet并安装新的主applet。
3、新的主applet从backup applet中获取个性化数据。
二、实现方案
为了实现数据在主applet和backup applet之前的交换,需要用到Java Card的Shareable能力。
Shareable接口
我们仅实现最基本的数据backup和restore接口
public interface DataShareable extends Shareable {
public byte backupInfo(byte[] input, short offset, short length);
public byte restoreInfo(byte[] input, short offset, short length);
}
backup applet
backup applet需要实现DataShareable 接口中的方法。
public byte backupInfo(byte[] input, short offset, short length) {
if(length > info.length) {
return NOT_OK;
}
try {
JCSystem.beginTransaction();
Util.arrayCopy(input, offset, info, (short) 0, length);
JCSystem.commitTransaction();
return OK;
} catch (Exception e) {
try {
JCSystem.abortTransaction();
} catch (Exception ex) {
}
return NOT_OK;
}
}
@Override
public byte restoreInfo(byte[] input, short offset, short length) {
if (length > info.length) {
return NOT_OK;
}
try {
Util.arrayCopyNonAtomic(info, (short) 0, input, offset, length);
return OK;
} catch (Exception e) {
return NOT_OK;
}
}
另外为了安全
1、不要在process中实现方法,因为这个applet不接收外部的apdu指令。
2、在getShareableInterfaceObject中进行主applet的AID的判断,以避免别的applet来访问到这个backup applet。
@Override
public Shareable getShareableInterfaceObject(AID clientAID, byte parameter) {
// only sAIDApplet can call
if (!clientAID.equals(sAIDApplet, (short) 0, (byte) 15)) {
return null;
}
return this;
}
主applet
需要实现以下相关方法
private DataShareable sio = null;
private boolean getSIO() {
if (this.sio == null) {
this.sio = (DataShareable)JCSystem.getAppletShareableInterfaceObject(
JCSystem.lookupAID(BACKUP_APPLET_AID_BYTES,(short)0, (byte)(BACKUP_APPLET_AID_BYTES.length)),
(byte)0);
}
if(this.sio != null) {
return true;
} else {
return false;
}
}
private void backupInfo(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short readCount = apdu.setIncomingAndReceive();
boolean getSIO = getSIO();
if(!getSIO) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
//将个性化数据写入buffer
......
//调用接口
if(NOT_OK == sio.backupInfo(buffer, (short) 0, (short) 48)) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
}
private void restoreInfo(APDU apdu) {
byte[] buffer = apdu.getBuffer();
short readCount = apdu.setIncomingAndReceive();
boolean getSIO = getSIO();
if(!getSIO) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
if(NOT_OK == sio.restoreInfo(buffer, (short) 0, (short) 48)) {
ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
}
JCSystem.beginTransaction();
//保存数据
......
JCSystem.commitTransaction();
}
更多推荐



所有评论(0)