Program used for Java Card Applet Simulation
Be carefull, this program does not run properly with the JDK virtual machine!
Indeed, we suppose that there is no interleaving between threads (master/slave
mode).
So the current executing thread stays executable until it becomes dead (no more
instruction) or suspended (it has called the method suspend())
If you want to know more about our development environment for Java Card,
please click
here
/*********************************************************************
* Root Class
*********************************************************************/
public class Root {
/*********************** Public Method **************************/
public static void main(String[] args) {
User user = new User();
JCRE jcre = new JCRE();
CAD cad = new CAD(jcre, user);
jcre.setCAD(cad);
user.setCAD(cad);
user.resume();
}
}
/*********************************************************************
* User Class
*********************************************************************/
class User extends Thread {
private CAD cad;
/*************************** Constructor *************************/
protected User() {
start();
suspend();
}
/*********************** Public Methods *************************/
public void run() {
cad.installAppli(PurseFr.AID, 1000);
cad.sendAction(PurseFr.AID, PurseFr.PURSE_FR_WITHDRAW, 100);
cad.installAppli(FrequentFlyer.AID, 0);
cad.sendAction(FrequentFlyer.AID, FrequentFlyer.GAIN_MILES, 5000);
// cad.sendAction(PurseFr.AID, PurseFr.PURSE_FR_DEPOSIT, 20);
}
/*********************** Protected Methods **********************/
protected void setCAD(CAD cad1) {
cad = cad1;
}
}
/*********************************************************************
* CAD Class
*********************************************************************/
class CAD extends Thread {
private static byte PROCESS = 1;
private static byte SELECT = 2;
private static byte NOTHING = 0;
protected APDU apdu;
private User user;
private JCRE jcre;
private byte currentAID;
private byte ins;
private byte AID;
private int commandData;
private byte action;
/*************************** Constructor *************************/
protected CAD(JCRE jcre1, User user1) {
apdu = new APDU();
jcre = jcre1;
user = user1;
currentAID = JCRE.NO_SELECTED_APPLET;
start();
suspend();
}
/*********************** Public Methods *************************/
public void run() {
while (true) {
sendActionToCard();
if (action == SELECT) {
if (apdu.sw1 == JCRE.OK) {
currentAID = AID;
apdu.setCommandApdu(JCRE.PROCESS_CLA, ins, NOTHING, commandData);
sendActionToCard();
}
else
currentAID = JCRE.NO_SELECTED_APPLET;
}
user.resume();
suspend();
}
}
public void installAppli(byte AID, int data) {
apdu.setCommandApdu(NOTHING, NOTHING,NOTHING, data);
if (AID == PurseFr.AID)
jcre.install(PurseFr.install(apdu), PurseFr.AID);
else
jcre.install(FrequentFlyer.install(apdu), FrequentFlyer.AID);
}
public void sendAction(byte AID1, byte ins1, int data) {
if ((currentAID == JCRE.NO_SELECTED_APPLET) || (currentAID != AID1)) {
action = SELECT;
ins = ins1;
commandData = data;
AID = AID1;
apdu.setCommandApdu(JCRE.SELECT_CLA, JCRE.SELECT_INS, AID1, NOTHING);
}
else {
action = PROCESS;
apdu.setCommandApdu(JCRE.PROCESS_CLA, ins1, NOTHING, data);
}
resume();
user.suspend();
}
/*********************** Private Methods ************************/
private void sendActionToCard() {
jcre.apdu.copyCommandApdu(apdu);
jcre.resume();
suspend(); // wait the card reply
}
}
/*********************************************************************
* JCRE Class
*********************************************************************/
class JCRE extends Thread {
protected final static byte SELECT_CLA = 0;
protected final static byte PROCESS_CLA = 120;
protected final static byte SELECT_INS = 82;
/*//0xA4 ie -82*/
protected final static byte NO_SELECTED_APPLET = 0;
/*//Possible commands on the applet*/
protected final static byte NO_CODE = 0;
protected final static byte SELECT = 1;
protected final static byte DESELECT = 2;
protected final static byte PROCESS = 3;
protected final static byte OK = 127;
/*//sw1 = 0x90 = -127*/
protected final static byte IMPOSSIBLE = 0;
static JCRE self;
/*//Applets on the Card*/
private final static byte NB_MAX_APPLI_ON_CARD = 5;
private int nbAppletsOnCard;
private Applet appli1, appli2, appli3, appli4, appli5;
private byte appli1AID, appli2AID, appli3AID, appli4AID, appli5AID;
protected byte commandCode;
private byte selectedAppliAID;
private Applet selectedAppli;
protected APDU apdu;
CAD cad;
/*************************** Constructor *************************/
protected JCRE() {
nbAppletsOnCard = 0;
apdu = new APDU();
commandCode = NO_CODE;
selectedAppliAID = NO_SELECTED_APPLET;
self = this;
start();
suspend();
}
/*********************** Public Methods *************************/
public void run() {
while (true) {
/*// Select APDU*/
if (apdu.cla == SELECT_CLA && apdu.ins == SELECT_INS) {
if (selectedAppliAID != NO_SELECTED_APPLET) {
sendCommandToAppletAndWaitResponse(DESELECT, selectedAppliAID);
selectedAppliAID = NO_SELECTED_APPLET;
}
sendCommandToAppletAndWaitResponse(SELECT, apdu.p1);
if (apdu.sw1 == OK)
selectedAppliAID = apdu.p1;
} else {
/*// Process APDU*/
if (selectedAppliAID != NO_SELECTED_APPLET)
sendCommandToAppletAndWaitResponse(PROCESS, selectedAppliAID);
else
apdu.sw1 = IMPOSSIBLE;
}
cad.apdu.copyResponseApdu(apdu);
cad.resume();
/*Wait a CAD action
*/
suspend();
}
}
/*********************** Protected Methods **********************/
protected void install(Applet appli, byte appletAID) {
/*//A mettre un switch qd fait en sem*/
if (nbAppletsOnCard < NB_MAX_APPLI_ON_CARD) {
if (nbAppletsOnCard == 0) {
appli1 = appli;
appli1AID = appletAID;
} else
if (nbAppletsOnCard == 1) {
appli2 = appli;
appli2AID = appletAID;
} else
if (nbAppletsOnCard == 2) {
appli3 = appli;
appli3AID = appletAID;
} else
if (nbAppletsOnCard == 3) {
appli4 = appli;
appli4AID = appletAID;
} else
if (nbAppletsOnCard == 4) {
appli5 = appli;
appli5AID = appletAID;
}
nbAppletsOnCard = nbAppletsOnCard + 1;
appli.start();
appli.suspend();
}
}
protected void setCAD(CAD cad1) {
cad = cad1;
}
/*********************** Private Methods ************************/
private void sendCommandToAppletAndWaitResponse(byte command, byte appletAID)
{
commandCode = command;
if (command == SELECT) {
selectedAppli = searchApplet(appletAID);
}
selectedAppli.resume();
suspend();
}
private Applet searchApplet(byte AID) {
if (AID == appli1AID)
return appli1;
else
if (AID == appli2AID)
return appli2;
else
if (AID == appli3AID)
return appli3;
else
if (AID == appli4AID)
return appli4;
else
/*//if (AID == appli5AID)*/
return appli5;
}
}
/*********************************************************************
* PurseFr Class
*********************************************************************/
class PurseFr extends Applet {
protected final static byte AID = 126;
/*//Possible Instructions*/
protected final static byte PURSE_FR_DEPOSIT = 1;
protected final static byte PURSE_FR_WITHDRAW = 2;
protected final static byte PURSE_FR_BALANCE_CHECK = 3;
private final static int PURSE_FR_MAX = 3000;
private int purseFrTotal;
/*********************** Constructor ********************************/
private PurseFr(APDU apdu) {
purseFrTotal = apdu.commandData;
}
/*********************** Public Methods *****************************/
/**
* Performs only one time at the applet installation
* on the smart card
* A revoir car mauvais renvoi et peut envoyer une exception
*/
public static PurseFr install(APDU apdu) {
return new PurseFr(apdu);
}
/**
* Performs the session ie deal with the APDUs sent by the CAD
*/
public void process(APDU apdu) {
if (apdu.ins == PURSE_FR_DEPOSIT)
purseDeposit(apdu);
else
if (apdu.ins == PURSE_FR_WITHDRAW)
purseWithdraw(apdu);
else
if (apdu.ins == PURSE_FR_BALANCE_CHECK)
purseBalanceCheck(apdu);
}
/*********************** Private Methods ****************************/
private void purseDeposit(APDU apdu) {
int amountOfDeposit = apdu.commandData;
int temporaryPurseFrTotal = amountOfDeposit + purseFrTotal;
if (amountOfDeposit > 0 && temporaryPurseFrTotal <= PURSE_FR_MAX) {
purseFrTotal = temporaryPurseFrTotal;
apdu.setResponseApdu(purseFrTotal, JCRE.OK);
} else
apdu.setResponseApdu(purseFrTotal, JCRE.IMPOSSIBLE);
}
private void purseWithdraw(APDU apdu) {
int amountOfWithdraw = apdu.commandData;
int temporaryPurseFrTotal = purseFrTotal - amountOfWithdraw;
if (amountOfWithdraw > 0 && temporaryPurseFrTotal >= 0) {
purseFrTotal = temporaryPurseFrTotal;
apdu.responseData = purseFrTotal;
} else
apdu.setResponseApdu(purseFrTotal, JCRE.IMPOSSIBLE);
}
private void purseBalanceCheck(APDU apdu) {
apdu.setResponseApdu(purseFrTotal, JCRE.IMPOSSIBLE);
}
}
/*********************************************************************
* Frequent Flyer Class
*********************************************************************/
class FrequentFlyer extends Applet {
protected final static byte AID = 124;
/*//Possible Instructions*/
protected final static byte GAIN_MILES = 1;
protected final static byte REDEEM_MILES = 2;
protected final static byte CHECK_MILES = 3;
private final static int MILES_MAX = 100000;
private int milesTotal;
/************************** Constructor ****************************/
private FrequentFlyer(APDU apdu) {
milesTotal = apdu.commandData;
}
/*********************** Public Methods ****************************/
/**
* Performs only one time at the applet installation
* on the smart card
* A revoir car mauvais renvoi et peut envoyer une exception
*/
public static FrequentFlyer install(APDU apdu) {
return new FrequentFlyer(apdu);
}
/**
* Performs the session ie deal with the APDUs sent by the CAD
*/
public void process(APDU apdu) {
if (apdu.ins == GAIN_MILES)
milesGain(apdu);
else
if (apdu.ins == REDEEM_MILES)
milesRedeem(apdu);
else
if (apdu.ins == CHECK_MILES)
milesCheck(apdu);
}
/*********************** Private Methods ****************************/
private void milesGain(APDU apdu) {
int nbOfMilesGained = apdu.commandData;
int temporaryMilesTotalTempory = nbOfMilesGained + milesTotal;
if (nbOfMilesGained > 0 && temporaryMilesTotalTempory <= MILES_MAX) {
milesTotal = temporaryMilesTotalTempory;
apdu.setResponseApdu(milesTotal, JCRE.OK);
} else
apdu.setResponseApdu(milesTotal, JCRE.IMPOSSIBLE);
}
private void milesRedeem(APDU apdu) {
int nbOfMilesRedeemed = apdu.commandData;
int temporaryMilesTotal = milesTotal - nbOfMilesRedeemed;
if (nbOfMilesRedeemed > 0 && temporaryMilesTotal >= 0) {
milesTotal = temporaryMilesTotal;
apdu.responseData = milesTotal;
} else
apdu.setResponseApdu(milesTotal, JCRE.IMPOSSIBLE);
}
private void milesCheck(APDU apdu) {
apdu.setResponseApdu(milesTotal, JCRE.IMPOSSIBLE);
}
}
/*********************************************************************
* APDU Class
*********************************************************************/
final class APDU extends Object {
/***************** Command APDU Fields*****************************/
// Mandatory Header
byte cla; // Class Byte - Often used to identify an application
byte ins; // Instruction byte - Indicate the instruction code
byte p1; // Parameter bytes
// Conditionnal Body
int commandData; //Data Field
/***************** Response APDU Fields ***************************/
// Conditional
int responseData; //Data field in response
// Mandatory Trailer
byte sw1; // private byte SW1, SW2; command APDU status
/************************** Constructor ***************************/
public APDU() {
}
/************************** Public Methods ************************/
public void setCommandApdu(byte cla1, byte ins1, byte p, int commandData1) {
cla = cla1;
ins = ins1;
p1 = p;
commandData = commandData1;
}
public void setResponseApdu(int responseData1, byte sw) {
responseData = responseData1;
sw1 = sw;
}
public void copyCommandApdu(APDU commandApdu) {
cla = commandApdu.cla;
ins = commandApdu.ins;
p1 = commandApdu.p1;
commandData = commandApdu.commandData;
}
public void copyResponseApdu(APDU responseApdu) {
responseData = responseApdu.responseData;
sw1 = responseApdu.sw1;
}
}
/*********************************************************************
* Applet Class
*********************************************************************/
class Applet extends Thread {
/*//Java Card Applet*/
/************************** Constructor ***************************/
Applet() {
}
/************************** Public Methods ************************/
public void run() {
byte commandCode;
boolean selectOk;
while (true) {
commandCode = JCRE.self.commandCode;
if (commandCode == JCRE.SELECT) {
selectOk = select();
if (selectOk == true)
JCRE.self.apdu.sw1 = JCRE.OK;
else
JCRE.self.apdu.sw1 = JCRE.IMPOSSIBLE;
} else
if (commandCode == JCRE.DESELECT)
deselect();
else
if (commandCode == JCRE.PROCESS) {
process(JCRE.self.apdu);
}
JCRE.self.resume();
suspend();
}
}
public void process(APDU apdu) {
}
/**
* Make this applet selected - a new session has begun
*/
public boolean select() {
return true;
}
/**
* Performs the session finalization - current session end
*/
public void deselect() {
}
}
public class Object {
Object() {
}
}
public class Thread {
Thread() {
}
void start() {
}
}