PCSC sample in Java using intarsys smartcard-io
Here is a new PCSC sample in Java language I promised in PC/SC sample in different languages.
We already saw in a previous article "PCSC sample in Java" that the standard JVM includes javax.smartcardio to access smart cards. We will now see another Java wrapper.
intarsys smartcard-io
The project intarsys smartcard-io is hosted at https://github.com/intarsys/smartcard-io.The licence is 3-Clause BSD.
Installation
Installation is easy. Just get the provided is-smartcard-io.jar files from deploy/ directory and the 3 runtime dependencies from lib/ directory.I have not tried to rebuild the library from source.
Source code
The API is easy to use since it is a direct mapping to the PC/SC WinScard API.package com.company; import de.intarsys.security.smartcard.pcsc.IPCSCCardReader; import de.intarsys.security.smartcard.pcsc.IPCSCConnection; import de.intarsys.security.smartcard.pcsc.IPCSCContext; import de.intarsys.security.smartcard.pcsc.PCSCContextFactory; import de.intarsys.security.smartcard.pcsc.nativec._IPCSC; import java.util.List; public class Blog { public static void main(String[] args) { try { /* Establish context */ IPCSCContext context = PCSCContextFactory.get().establishContext(); /* Display the list of readers */ List<IPCSCCardReader> readers = context.listReaders(); for (IPCSCCardReader reader : readers) { System.out.println("found " + reader + " named " + reader.getName()); } /* Use the first reader */ IPCSCCardReader reader = readers.get(0); /* Connect to the card */ IPCSCConnection connection = context.connect( reader.getName(), _IPCSC.SCARD_SHARE_SHARED, _IPCSC.SCARD_PROTOCOL_Tx); /* Send Select Applet command */ byte[] select = {0x00, (byte)0xA4, 0x04, 0x00, 10, (byte)0xA0, 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01}; byte[] answer; answer = connection.transmit(select, 0, select.length, 256, false); System.out.println("answer: " + answer.length + " bytes"); for (int i=0; i<answer.length; i++) { System.out.print(String.format("%02X ", answer[i])); } System.out.println(); /* Send test command */ byte[] command = {0x00, 0x00, 0x00, 0x00}; answer = connection.transmit(command, 0, command.length, 256, false); System.out.println("answer: " + answer.length + " bytes"); for (int i=0; i<answer.length; i++) { System.out.print(String.format("%02X ", answer[i])); } System.out.println(); for (int i=0; i<answer.length - 2; i++) { System.out.print((char)answer[i]); } System.out.println(); /* Disconnect */ connection.disconnect(_IPCSC.SCARD_LEAVE_CARD); /* Release context */ context.dispose(); } catch(Exception e) { System.out.println("Ouch: " + e.toString()); } } }
Output
found pcscreader 0 named Gemalto PC Twin Reader found pcscreader 1 named Cherry KC 1000 SC Z answer: 2 bytes 90 00 answer: 14 bytes 48 65 6C 6C 6F 20 77 6F 72 6C 64 21 90 00 Hello world!
High level API
Intarsys smartcard-io also provides a higher level API compatible with javax.smartcardio.As documented in the project README:
javax.smartcardio Provider
The library comes with an alternative javax.smartcardio provider. There are a couple of things to consider:
Intended differences
- dedicated PCSC context for terminals, terminal and card
- waitForChange(timeout) semantics improved(?), state change is reset even in case of timeout
- reader insertion is handled, too
- no finalizer for card!
javax.smartcardio bug/limitation
One big problem with the SUN/Oracle implementation of javax.smartcardio is that only one PC/SC context is created.It works fine with a mono-threaded application. But it is very problematic with a multi-threaded application if you want to access different readers at the same time from different threads.
As documented in pcsc-lite SCardEstablishContext():
Each thread of an application shall use its own SCARDCONTEXT
This is because only one thread can use a SCARDCONTEXT at the same time. So 2 SCardTransmit() calls on 2 different cards from 2 threads but using the same SCARDCONTEXT will be serialized by pcsc-lite. This is NOT what you want if you intent to execute the 2 card commands at the same time.
The problem is not present on Windows because the Microsoft WinSCard implement is different.
I don't know how javax.smartcardio behaves on macOS. The WinSCard on macOS has been rewritten using the low level API CryptoTokenKit since macOS Yosemite 10.10 in 2014 (see "OS X Yosemite and smart cards status") and is no more using pcsc-lite.