I am a newbie in the javacard world. I have a wallet applet successfully running in netbeans (I can credit, debit,check-balance, verify pin etc using APDUs in the device console). I am tasked to write a host application to communicate with this card in netbeans without using the smartcard console. From a little research, I figure that I have to import javax.smartcardio class into my host application, however, as you might know, there is very little documentation on this. Any assistance will be appreciated and of help to many of us who are finding it hard to delve into this world of smartcard programming. Below is my applet code. Pin was passed via parameters as 1122334455667788
via project properties.
package classicapplet1;
//package com.sun.javacard.samples.wallet;
import javacard.framework.*;
public class Wallet extends Applet {
// codes of CLA byte in the command APDUs
final static byte Wallet_CLA = (byte) 0xB0;
// codes of INS byte in the command APDUs
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;
// maximum wallet balance
final static short MAX_BALANCE = 10000;
// maximum transaction amount
final static byte MAX_TRANSACTION_AMOUNT = 100;
// maximum number of incorrect tries before the
// PIN is blocked
final static byte PIN_TRY_LIMIT = (byte) 0x03;
// maximum size PIN
final static byte MAX_PIN_SIZE = (byte) 0x08;
// Applet-specific status words:
final static short SW_VERIFICATION_FAILED = 0x6300;
final static short SW_PIN_VERIFICATION_REQUIRED = 0x6301;
final static short SW_INVALID_TRANSACTION_AMOUNT = 0x6A83;
final static short SW_EXCEED_MAXIMUM_BALANCE = 0x6A84;
final static short SW_NEGATIVE_BALANCE = 0x6A85;
// instance variables declaration
OwnerPIN pin;
short balance;
/**
*
* called by the JCRE to create an applet instance
*/
public static void install(byte[] bArray, short bOffset, byte bLength) {
// create a Wallet applet instance
new Wallet(bArray, bOffset, bLength);
} // end of install method
/**
*
* private constructor — called by the install method to
*
* instantiate a Wallet instance
*/
private Wallet(byte[] bArray, short bOffset, byte bLength) {
pin = new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);
// bArray contains the PIN initialization value
pin.update(bArray, bOffset, bLength);
// register the applet instance with the JCRE
register();
} // end of the constructor
/**
*
* initialize the applet when it is selected
*/
public boolean select() {
// the applet declines to be selected
// if the pin is blocked
if (pin.getTriesRemaining() == 0)
return false;
return true;
} // end of select method
/**
*
* perform any cleanup and bookkeeping tasks before
*
* the applet is deselected
*/
public void deselect() {
// reset the pin
pin.reset();
}
/**
*
* process APDUs
*/
public void process(APDU apdu) {
// APDU object carries a byte array (buffer) to
// transfer incoming and outgoing APDU header
// and data bytes between the card and the host
// at this point, only the first five bytes
// [CLA, INS, P1, P2, P3] are available in
// the APDU buffer
byte[] buffer = apdu.getBuffer();
// return if the APDU is the applet SELECT command
if (selectingApplet())
return;
// verify the CLA byte
if (buffer[ISO7816.OFFSET_CLA] != Wallet_CLA)
ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
// check the INS byte to decide which service method to call
switch (buffer[ISO7816.OFFSET_INS]) {
case GET_BALANCE:
getBalance(apdu);
return;
case DEBIT:
debit(apdu);
return;
case CREDIT:
credit(apdu);
return;
case VERIFY:
verify(apdu);
return;
default:
ISOException.throwIt
(ISO7816.SW_INS_NOT_SUPPORTED);
}
} // end of process method
/**
*
* add money to the wallet
*/
private void credit(APDU apdu) {
// verify authentication
if (!pin.isValidated())
ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
byte[] buffer = apdu.getBuffer();
// get the number of bytes in the
// data field of the command APDU
byte numBytes = buffer[ISO7816.OFFSET_LC];
// recieve data
// data are read into the apdu buffer
// at the offset ISO7816.OFFSET_CDATA
byte byteRead = (byte) (apdu.setIncomingAndReceive());
// error if the number of data bytes
// read does not match the number in the Lc byte
if ((numBytes != 1) || (byteRead != 1))
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
// get the credit amount
byte creditAmount = buffer[ISO7816.OFFSET_CDATA];
// check the credit amount
if ((creditAmount > MAX_TRANSACTION_AMOUNT)
|| (creditAmount < 0))
ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
// check the new balance
if ((short) (balance + creditAmount) > MAX_BALANCE)
ISOException.throwIt(SW_EXCEED_MAXIMUM_BALANCE);
// credit the amount
balance = (short) (balance + creditAmount);
return;
} // end of deposit method
/**
*
* withdraw money from the wallet
*/
private void debit(APDU apdu) {
// verify authentication
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);
// get debit amount
byte debitAmount = buffer[ISO7816.OFFSET_CDATA];
// check debit amount
if ((debitAmount > MAX_TRANSACTION_AMOUNT)
|| (debitAmount < 0))
ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
// check the new balance
if ((short) (balance - debitAmount) < (short) 0)
ISOException.throwIt(SW_NEGATIVE_BALANCE);
balance = (short) (balance - debitAmount);
} // end of debit method
/**
*
* the method returns the wallet’s balance
*/
private void getBalance(APDU apdu) {
byte[] buffer = apdu.getBuffer();
// for(short i=0;i<buffer.length;i++)
// {
// System.out.println((byte)buffer[i]);
// }
// System.out.println((short)0);
// inform the JCRE that the applet has data to return
short le = apdu.setOutgoing();
// set the actual number of the outgoing data bytes
apdu.setOutgoingLength((byte) 2);
// write the balance into the APDU buffer at the offset 0
Util.setShort(buffer, (short) 0, balance);
// send the 2-byte balance at the offset
// 0 in the apdu buffer
apdu.sendBytes((short) 0, (short) 2);
} // end of getBalance method
/**
*
* verify the PIN
*/
private void verify(APDU apdu) {
byte[] buffer = apdu.getBuffer();
// receive the PIN data for validation.
byte byteRead = (byte) (apdu.setIncomingAndReceive());
// check pin
// the PIN data is read into the APDU buffer
// starting at the offset ISO7816.OFFSET_CDATA
// the PIN data length = byteRead
if (pin.check(buffer, ISO7816.OFFSET_CDATA, byteRead) == false)
ISOException.throwIt(SW_VERIFICATION_FAILED);
} // end of verify method
}
How the simulator works?
Netbeans uses Java Card Development kit tools to simulate Java Card. Communication with the simulator requires a little socket programming, but the JCDK provided a library for that already. It is named APDUIO . You can find it and its documentations in the JCDK.
Those ports that Netbeans assign to the simulator is 9025
(for contact) and 9026
(for contactless) by default. But you can change them simply.
How to change Java Card simulator configurations in Netbeans?
1-Go to Services tab, do a right click on Java card Runtime and then select Java Platforms :
2- Select Bundled Java Card and then click on Manage Devices :
3- There, you can change the configured ports:
How to communicate with the simulator via code?
First turn on the simulator in the Netbeans, and then run this program:
package testapduio;
import com.sun.javacard.apduio.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;
public class TestAPDUIO {
public static void main(String[] args) {
CadClientInterface cad;
Socket sock;
Apdu apdu = new Apdu();
apdu.command = new byte[]{(byte) 0x00, (byte) 0xa4, (byte) 0x04, (byte) 0x00, (byte) 0x00};
try {
sock = new Socket("localhost", 9025);
InputStream is = sock.getInputStream();
OutputStream os = sock.getOutputStream();
cad = CadDevice.getCadClientInstance(CadDevice.PROTOCOL_T1, is, os);
byte[] ATR = cad.powerUp();
System.out.println("Answer To Reset:\n");
System.out.println(Arrays.toString(ATR));
byte[] input = apdu.getDataIn();
byte[] output = apdu.getDataOut();
System.out.println("-----------------");
System.out.println(input);
System.out.println("\n");
System.out.println(output);
cad.exchangeApdu(apdu);
System.out.println("-----------------");
System.out.println(input);
System.out.println("\n");
System.out.println(output);
cad.powerDown();
} catch (Exception e) {
System.out.println("Exception Occurred");
}
}
}
Note that, as you see in the import
s above, you need to add the apduio
library from Java Card Development Kit package, to your project'c library in Netbeans .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.