Thursday, September 25, 2008

Getting started with smartcardio

In Java 6, Sun has included a new package called javax.smartcardio. This was obtained from the work done by JSR 268: JavaTM Smart Card I/O API . Compared to previous frameworks (OCF, M.U.S.C.L.E ...) and proprietary libraries, this package is making it it easier for Java applications to access smart card. That's good in itself, and also good because it was a goal of this JSR.

Yet mailing lists are full of members asking what framework to use and how to get started, and unfortunately the example is slightly broken. So here is one that is fixed and show the selection of the Card Manager application on most Java - GlobalPlatform card in use toady.


/**
*
* This example is from http://pierreheuze.blogspot.com/2008/09/getting-started-with-smartcardio.html
*
* Using the javax.smartcardio package, it shows:
* - How to select a terminal
* - Connect to the card using a particular protocol
* - Send Command APDU to the card and process Response APDU.
* The Command APDU selects the CardManager, on a Java - GlobalPlatform card.
* So you need such a card to try this example, but it is easy to adapt the APDU to try
* on another kind of card.
*
* Copyright Pierre Heuze (r)
*
* This example is provided WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, modify, and distribute it for non-commercial and commercial
* purposes, in all cases you must acknowledge the copyright and keep this disclaimer.
*
* This particular example has been successfully compiled and tested using
* Eclipse 3.3.2 and Java 1.6.0_06. It is based on:
* http://java.sun.com/javase/6/docs/jre/api/security/smartcardio/spec/javax/smartcardio/package-summary.html
* But that one doesn't compile and doesn't show a meaningful APDU exchange.
* You should also look at the GlobalPlatform card specification http://www.globalplatform.org
* Comments welcome.
*
*/

import javax.smartcardio.*;
import java.util.*;

/**
* @author PHeuze
*
*/
public class ExSmartCardIO {

/**
* Utility function that converts a byte array into an hexadecimal string.
* @param bytes
*/
public static String toString(byte[] bytes)
{

final String hexChars = "0123456789ABCDEF";
StringBuffer sbTmp = new StringBuffer();
char[] cTmp = new char[2];

for (int i = 0; i <>> 4) & 0x0F);
cTmp[1] = hexChars.charAt(bytes[i] & 0x0F);
sbTmp.append(cTmp);
}

return sbTmp.toString();
}

/**
* @param args
*/
public static void main(String[] args) {

try
{
// Show the list of available terminals
// On Windows see HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\Readers
TerminalFactory factory = TerminalFactory.getDefault();
List terminals = factory.terminals().list();
System.out.println("Terminals: " + terminals);

// Get the first terminal in the list
CardTerminal terminal = terminals.get(0);

// Establish a connection with the card using
// "T=0", "T=1", "T=CL" or "*"
Card card = terminal.connect("*");
System.out.println("Card: " + card);

// Get ATR
byte[] baATR = card.getATR().getBytes();
System.out.println("ATR: " + ExSmartCardIO.toString(baATR) );

// Select Card Manager
// - Establish channel to exchange APDU
// - Send SELECT Command APDU
// - Show Response APDU
CardChannel channel = card.getBasicChannel();

//SELECT Command
// See GlobalPlatform Card Specification (e.g. 2.2, section 11.9)
// CLA: 00
// INS: A4
// P1: 04 i.e. b3 is set to 1, means select by name
// P2: 00 i.e. first or only occurence
// Lc: 08 i.e. length of AID see below
// Data: A0 00 00 00 03 00 00 00
// AID of the card manager,
// in the future should change to A0 00 00 01 51 00 00

byte[] baCommandAPDU = {(byte) 0x00, (byte) 0xA4, (byte) 0x04, (byte) 0x00, (byte) 0x08, (byte) 0xA0, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x00};
System.out.println("APDU >>>: " + ExSmartCardIO.toString(baCommandAPDU));

ResponseAPDU r = channel.transmit(new CommandAPDU(baCommandAPDU));
System.out.println("APDU <<<: " + ExSmartCardIO.toString(r.getBytes()));

// Disconnect
// true: reset the card after disconnecting card.

disconnect(true);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
}

6 comments:

Shilpa said...

Indeed very thoughtful and good article for newbies !

Thanks a lot for posting this.

But I tried taking this once step ahead and tried writing "hello" after select command and am not able to get hello back in response ? Please help me understand how to write and read back some info from the card (for example say my name, or some hello, etc?). Thanks a lot...

Mr. Thy said...

The posted code does not work. I suppose HTML markup messed with it. I modified it in order to compile:

/**
* UUID 7fd84320-30ca-11de-9830-0002a5d5c51b
*
* This example is from http://pierreheuze.blogspot.com/2008/09/getting-started-with-smartcardio.html
*
* Using the javax.smartcardio package, it shows:
* - How to select a terminal
* - Connect to the card using a particular protocol
* - Send Command APDU to the card and process Response APDU.
* The Command APDU selects the CardManager, on a Java - GlobalPlatform card.
* So you need such a card to try this example, but it is easy to adapt the APDU to try
* on another kind of card.
*
* Copyright Pierre Heuze (r)
* Modified by Thiago Chaves
*
* This example is provided WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, modify, and distribute it for non-commercial and commercial
* purposes, in all cases you must acknowledge the copyright and keep this disclaimer.
*
* This particular example has been successfully compiled and tested using
* Eclipse 3.3.2 and Java 1.6.0_06. It is based on:
* http://java.sun.com/javase/6/docs/jre/api/security/smartcardio/spec/javax/smartcardio/package-summary.html
* But that one doesn't compile and doesn't show a meaningful APDU exchange.
* You should also look at the GlobalPlatform card specification http://www.globalplatform.org
* Comments welcome.
*
*/

import javax.smartcardio.*;
import java.util.*;

/**
* @author PHeuze
*
*/
public class ExSmartCardIO {

/**
* Utility function that converts a byte array into an hexadecimal string.
*
* @param bytes
*/
public static String toString(byte[] bytes) {

final String hexChars = "0123456789ABCDEF";
StringBuffer sbTmp = new StringBuffer();
char[] cTmp = new char[2];

for (int i = 0; i < bytes.length; i++) {
cTmp[1] = hexChars.charAt((bytes[i] & 0xF0) >>> 4);
cTmp[2] = hexChars.charAt(bytes[i] & 0x0F);
sbTmp.append(cTmp);
}

return sbTmp.toString();
}

/**
* @param args
*/
public static void main(String[] args) {

try {
// Show the list of available terminals
// On Windows see
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Calais\Readers
TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
System.out.println("Terminals: " + terminals);
if (terminals.size() == 0) {
System.out.println("No terminals found.");
return;
}
// Get the first terminal in the list
CardTerminal terminal = terminals.get(0);

// Establish a connection with the card using
// "T=0", "T=1", "T=CL" or "*"
Card card = terminal.connect("*");
System.out.println("Card: " + card);

// Get ATR
byte[] baATR = card.getATR().getBytes();
System.out.println("ATR: " + ExSmartCardIO.toString(baATR));

// Select Card Manager
// - Establish channel to exchange APDU
// - Send SELECT Command APDU
// - Show Response APDU
CardChannel channel = card.getBasicChannel();

// SELECT Command
// See GlobalPlatform Card Specification (e.g. 2.2, section 11.9)
// CLA: 00
// INS: A4
// P1: 04 i.e. b3 is set to 1, means select by name
// P2: 00 i.e. first or only occurence
// Lc: 08 i.e. length of AID see below
// Data: A0 00 00 00 03 00 00 00
// AID of the card manager,
// in the future should change to A0 00 00 01 51 00 00

byte[] baCommandAPDU = { (byte) 0x00, (byte) 0xA4, (byte) 0x04,
(byte) 0x00, (byte) 0x08, (byte) 0xA0, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x00,
(byte) 0x00, (byte) 0x00 };
System.out.println("APDU >>>: "
+ ExSmartCardIO.toString(baCommandAPDU));

ResponseAPDU r = channel.transmit(new CommandAPDU(baCommandAPDU));
System.out.println("APDU <<<: "
+ ExSmartCardIO.toString(r.getBytes()));

// Disconnect
// true: reset the card after disconnecting card.
card.disconnect(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}

Unknown said...

I can access to the data of the smart card, when I transmit with all the possible commands I always receive 6E00 => Class not supported or 6D00.
The card is an ISO7816 type card, in the especification I have, it support ISO7816 1/2/3. The chip is SLE66CX320P. I have tried the next code but for all commands I get 6E00 or 6D00, (the code recognize the terminal and the card)


Could anyone help?


for(int i=0;i<256;i++){
for(int j=107;j<256;j++){
CommandAPDU command = new CommandAPDU(i, j, 0, 0, 50);
ResponseAPDU response = channel.transmit(command);
}
}

Mich said...

Hello, i'm trying to use smartcardio i downloaded the api but the ide doesnt't find javax.smartcardio.
What do i have to do to import the api? sorry but i'm a newbe.
Thanks!!

Tri Ngo said...

I'm not sure if you're still tracking this post.
I have a problem with smartcardio.
Even I imported it to my java file. I couldn't use the class inside the package.
May you help me?
Thank you very much.

Vineet Billorey said...

How can I write something to a smart card?