// ChangeFiles
// Simple program for reading and updating an EF on a smart card
// using the OCF 1.2 with PC/SC to transmit the data.
//
// File: ChangeFiles.java
//
// This program uses the PassThruCardService from OCF opencard.opt.util package.
// Additional informations and reference implementation: www.opencard.org.
// Testet with Towitoko Chipdrive micro on USB port and the appropriate PC/SC drivers
// from Towitoko on Windows 98. Testet with Omnikey CardMan Dongle 6020 on USB port
// and the appropriate PC/SC drivers from Omnikey on Windows 2000. Testet with
// JBuilder 6 and JDK 1.3.1.
//
// This program works with an ISO/IEC 7816-4 smart card with an > 10 byte transparent EF
// with FID=0001 and no read/update access conditions direct under the MF.
//
// Uses OCFPCSC1.DLL, OCFPCSC1.DLL, pcsc-wrapper-src.jar, base-core.jar, base-opt.jar
// from OCF 1.2
// The content of the file "opencard.properties" must be changed to:
// OpenCard.terminals = com.ibm.opencard.terminal.pcsc10.Pcsc10CardTerminalFactory
// For understanding the mechanisms of OCF it is useful to look first into the
// SimpleOCF example.
//
// This source code is under GNU general public license (see www.opensource.org for details).
// Please send corrections and ideas for extensions to Wolfgang Rankl (www.wrankl.de)
// Copyright 2003 by Wolfgang Rankl, Munich
//
// 15. Dez. 2003 - V 7, rw: minor clarifications, add GPL statement
// 5th published version
// 23. Jan. 2003 - V 6, rw: simplifications byte to int conversion, test with new
// card reader, review of the source code, 4th published version
// 9. Oct. 2002 - V 5, rw: improved documentation, 3rd published version
// 4. Okt. 2002 - V 4, rw: bug fixes concerning UI, 2nd published version
// 2. Okt. 2002 - V 3, rw: extended documentation, 1st published version (known bugs
// concerning EXIT button
// 24. Sept. 2002 - V 2, rw: extend command sequence, change UI, add button
// 18. Sept. 2002 - V 1, rw: initial runnable version
//---------------------------------------------------------------------------------------
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import opencard.core.service.*;
import opencard.core.terminal.*;
import opencard.opt.util.*;
public class ChangeFiles implements ActionListener {
static final int IFD_TIMEOUT = 2; // unit: seconds
static final int MAX_APDU_SIZE = 250; // unit: byte
// command SELECT FILE (select MF), according to ISO/IEC 7816-4
// CLA || INS || P1 || P2 || Lc || DATA 1 (= FID high) || DATA 2 (= FID low)
static final byte[] CMD_SELECT_MF = {(byte)0x00, (byte)0xA4,
(byte)0x00, (byte)0x0C, (byte)0x02,
(byte)0x3F, (byte)0x00 };
// command SELECT FILE (select an EF with FID = 0001), according to ISO/IEC 7816-4
// CLA || INS || P1 || P2 || Lc || DATA 1 (= FID high) || DATA 2 (= FID low)
static final byte[] CMD_SELECT_EF0001 = {(byte)0x00, (byte)0xA4,
(byte)0x00, (byte)0x0C, (byte)0x02,
(byte)0x00, (byte)0x01 };
// command READ BINARY, according to ISO/IEC 7816-4
// (read 5 bytes from a selected file with transparent structure)
// CLA || INS || P1 || P2 || Le
static final byte[] CMD_READ_BINARY = {(byte)0x00, (byte)0xB0,
(byte)0x00, (byte)0x0C, (byte)0x05 };
// command UPDATE BINARY, according to ISO/IEC 7816-4
// (update 5 bytes from a selected file with transparent structure)
// CLA || INS || P1 || P2 || Lc || DATA 1 || DATA 2 || ...
static final byte[] CMD_UPDATE_BINARY = {(byte)0x00, (byte)0xD6,
(byte)0x00, (byte)0x0C, (byte)0x05,
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 };
static private int n;
static private byte[] i;
private Frame f;
private Panel p;
private TextArea t;
private Button b;
static private ResponseAPDU response;
static private CommandAPDU command;
public ChangeFiles() {
// build the UI
f = new Frame();
f.setTitle("Smart Card - Terminal Communication");
p = new Panel();
p.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
t = new TextArea(40, 100);
t.setFont(new Font("Monospaced", 0, 12)); // Courier, 12 point size
t.setBackground(new Color(0, 0, 0)); // black
t.setForeground(new Color(200, 255, 100)); // yellowgreen
p.add(t);
b = new Button("Exit");
b.addActionListener(this);
p.add(b);
f.add(p);
f.pack();
f.show();
} // ChangeFiles
public void actionPerformed(ActionEvent evt) {
// exit programm if exit button is pressed
if (evt.getSource() == b) System.exit(0);
} // actionPerformed
public void showText(String Text) {
t.append(Text);
} // showText
public void showATR(byte[] ATR) {
int n, x;
String s = new String();
t.append("ATR: ");
for (n=0; n<i.length; n++) {
x = (int) (0x000000FF & ATR[n]); // byte to int conversion
s = Integer.toHexString(x).toUpperCase();
if (s.length()== 1) s = "0" + s;
t.append(s + " ");
} // for
t.append("\n");
} // showATR
public void showCmdAPDU(byte[] CmdAPDU, int LenCmdAPDU) {
int n, x;
String s = new String();
t.append("IFD->ICC: ");
for (n=0; n<LenCmdAPDU; n++) {
x = (int) (0x000000FF & CmdAPDU[n]); // byte to int conversion
s = Integer.toHexString(x).toUpperCase();
if (s.length() == 1) s = "0" + s;
t.append(s + " ");
} // for
t.append("\n");
} // showCmdAPDU
public void showRspAPDU(byte[] RspAPDU, int LenRspAPDU) {
int n, x;
String s = new String();
t.append("ICC->IFD: ");
for (n=0; n<LenRspAPDU; n++) {
x = (int) (0x000000FF & RspAPDU[n]); // byte to int conversion
s = Integer.toHexString(x).toUpperCase();
if (s.length()== 1) s = "0" + s;
t.append(s + " ");
} // for
t.append("\n");
} // showRspAPDU
public static void main( String [] args ){
ChangeFiles cf = new ChangeFiles();
cf.showText("Start Program: ChangeFiles\n\n");
// get and set system properties for OCF, PC/SC and PassThruCardServce
Properties sysProps = System.getProperties();
sysProps.put ("OpenCard.terminals", "com.ibm.opencard.terminal.pcsc10.Pcsc10CardTerminalFactory");
sysProps.put ("OpenCard.services", "opencard.opt.util.PassThruCardServiceFactory");
try {
SmartCard.start();
CardRequest cr = new CardRequest(CardRequest.ANYCARD, null, PassThruCardService.class);
cr.setTimeout(IFD_TIMEOUT); // set timeout for IFD
SmartCard sc = SmartCard.waitForCard(cr); // wait for ICC in the IFD
cf.showText("INFO: activate smart card\n\n");
if (sc != null) { // no error occur, a smart card is in the terminal
PassThruCardService ptcs = (PassThruCardService) sc.getCardService(PassThruCardService.class, true);
command = new CommandAPDU(MAX_APDU_SIZE); // set APDU buffer size
// get ATR
CardID cardID = sc.getCardID ();
i = cardID.getATR();
cf.showATR(i);
// prepare command APDU
cf.showText("\nINFO: SELECT MF\n");
command.append(CMD_SELECT_MF);
cf.showCmdAPDU(command.getBytes(), command.getLength());
// send command and receive response
response = ptcs.sendCommandAPDU(command);
cf.showRspAPDU(response.getBytes(),response.getLength());
// prepare command APDU
cf.showText("\nINFO: SELECT EF with FID=0001\n");
command.setLength(0);
command.append(CMD_SELECT_EF0001);
cf.showCmdAPDU(command.getBytes(), command.getLength());
// send command and receive response
response = ptcs.sendCommandAPDU(command);
cf.showRspAPDU(response.getBytes(),response.getLength());
// prepare command APDU
cf.showText("\nINFO: READ BINARY\n");
command.setLength(0);
command.append(CMD_READ_BINARY);
cf.showCmdAPDU(command.getBytes(), command.getLength());
// send command and receive response
response = ptcs.sendCommandAPDU(command);
cf.showRspAPDU(response.getBytes(),response.getLength());
// prepare command APDU
cf.showText("\nINFO: UPDATE BINARY\n");
command.setLength(0);
command.append(CMD_UPDATE_BINARY);
cf.showCmdAPDU(command.getBytes(), command.getLength());
// send command and receive response
response = ptcs.sendCommandAPDU(command);
cf.showRspAPDU(response.getBytes(),response.getLength());
// prepare command APDU
cf.showText("\nINFO: READ BINARY\n");
command.setLength(0);
command.append(CMD_READ_BINARY);
cf.showCmdAPDU(command.getBytes(), command.getLength());
// send command and receive response
response = ptcs.sendCommandAPDU(command);
cf.showRspAPDU(response.getBytes(),response.getLength());
// prepare command APDU
cf.showText("\nINFO: UPDATE BINARY\n");
command.setLength(0);
command.append(CMD_UPDATE_BINARY);
for (n=5; n<10; n++) { // count the bytes in the EF
command.setByte(n, (n-4));
} // for
cf.showCmdAPDU(command.getBytes(), command.getLength());
// send command and receive response
response = ptcs.sendCommandAPDU(command);
cf.showRspAPDU(response.getBytes(),response.getLength());
// prepare command APDU
cf.showText("\nINFO: READ BINARY\n");
command.setLength(0);
command.append(CMD_READ_BINARY);
cf.showCmdAPDU(command.getBytes(), command.getLength());
// send command and receive response
response = ptcs.sendCommandAPDU(command);
cf.showRspAPDU(response.getBytes(),response.getLength());
cf.showText("\nINFO: deactivate smart card\n");
SmartCard.shutdown();
} // if
else
cf.showText("\n\ncould not create smart card object (e.g. no ICC in IFD)\n");
} // try
catch (Exception except) {
cf.showText("\n\nCaught exception '" + except.getClass() + "' - " + except.getMessage() );
} // catch