19 August 2010

HelloCard How to Read Java Cards

/**
 *  HelloCard
 * @author ctskinner
 * JavaCard read  ......   not tear-proof.... you can tearaway and halt the program   ..if you're fast
 *
 *  version of  zigosoft    forums.sun
 *
 */

package here.there.and.everywhere;
import java.awt.Toolkit;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;

import javax.smartcardio.ATR;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.CardTerminals;
import javax.smartcardio.CommandAPDU;
import javax.smartcardio.ResponseAPDU;
import javax.smartcardio.TerminalFactory;

public class HelloCard {
    private static final String sSelect    =
            "00A4 04 00  0b 0102030405060708090000  00";
    // Java byte arrays are so ugly... use Strings ...
    private static final String sread_uid  =
            "FFCA 00 00 00";
    private CommandAPDU SELECT_APDU = new CommandAPDU(String2Hex(sSelect));
    private CommandAPDU UID_APDU    = new CommandAPDU(String2Hex(sread_uid));

    private CardTerminal terminal = null;
    private Card card = null;
    private String terminalName;
    private String terminalType;
    private String terminalProtocol;

  
    public static void main(String[] args) {
        try {
            HelloCard hcApp = new HelloCard();
            hcApp.go();
        } catch(Exception e) {
            print(" Error: " + e.getMessage());
        }
    }

    private HelloCard() throws Exception {
        terminalProtocol = "T=0";
        init();
    }

    private static void print (String s) {
        System.out.print(s);
    }
    private void init() throws Exception {
        System.setProperty("sun.security.smartcardio.t0GetResponse", "false");  // ensures 61xx   if T=0 you must handle data returns yourself
        TerminalFactory tf = TerminalFactory.getDefault();
        CardTerminals ct = tf.terminals();
        List<CardTerminal> l = null;
        Card card = null;

        try {
            l = ct.list();
        } catch (Exception e) {
            print (" Error listing Terminals: " + e.toString());
            throw e;
        }

        print (" List of PC/SC Readers connected:\n");
        ListIterator i = l.listIterator();
        while (i.hasNext()) {
            String tn = ((CardTerminal) i.next()).getName();
            print("Reader: " + tn + "\n");
//          pick the first NFRadio contactless
            if (    (tn.contains("-CL"))    && (terminal == null)    )
                terminal = ct.getTerminal(tn);
        }
//      terminalName = l.get(1).getName();
        print ("Terminal fetched: " + terminal.getName() + "\n");
    }

    byte[] UIDstore = {0x00,0x00,0x00,0x00};
    byte[] UID = {0x00,0x00,0x00,0x01};
    public void go() {
        try {
            while (terminal.waitForCardPresent(0)) {

                try {
                    card = terminal.connect("*");
//                    card = terminal.connect(terminalProtocol);
                    print("\nCard on protocol "   + card.getProtocol());
                } catch (Exception e) {
                    print("\nTerminal NOT connected: " + e.toString());
                }
                CardChannel ch = card.getBasicChannel();
                ResponseAPDU ra = ch.transmit(UID_APDU);
                // some cards randomise UID between sessions
                if (check9000(         ra       )) {
                    print("    UID " + Hex2String(ra.getData()));
                    System.arraycopy(ra.getData(),0,UID,0,4);
      
                } else {
                    print("UID NOT OKAY");
                    return;
                }
                if (! (Arrays.equals(UID,UIDstore)) ) {
                     print("    New Card   ATR ");
                    ATR atr = card.getATR();   // dont do this too often!
                    System.arraycopy(UID,0,UIDstore,0,4);
                    print(  Hex2String(  atr.getBytes()  )   );
                }

                // Put here code for sending/receiving APDUs
                // DO SOMETHING WITH Card HERE
               
                //             Toolkit.getDefaultToolkit().beep();  // nogo
                terminal.waitForCardAbsent(0);
                print ("    Card removed    ");
            }// while
        }// try
        catch (CardException e) {
            System.out.println("Error isCardPresent()" + e.toString());
        }
    }
    public static boolean check9000(ResponseAPDU ra) {
        byte[] response = ra.getBytes();
        return (response[response.length - 2] == (byte) 0x90 && response[response.length - 1] == (byte) 0x00);
    }


    public static String  Hex2String(byte[] b) {
        String result="";
        for (byte by:b)
            result+= String.format("%02X", by);
        return result;
}
    public static String stripGarbage(String s) {
    String good =
      "ABCDEF0123456789";
    String result = "";
    for ( int i = 0; i < s.length(); i++ ) {
        if ( good.indexOf(s.charAt(i)) >= 0 )
           result += s.charAt(i);  //stringbuilder might be better
        }
    return result;
    }//______________________________________________

    public static byte[] String2Hex(String sin){
        sin = sin.toUpperCase(); 
        sin = stripGarbage(sin);
        byte[] bout = new byte[sin.length() / 2];  // sz must be even...
        if ((sin.length() & 1) != 0)
            return bout;
        try {
            for (int j = 0; j < sin.length()-1; j+=2) {
                bout[j/2] = (byte)(Integer.parseInt(sin.substring(j,j+2),16));
            } // for
        } // try
        catch (Exception ex) {
            print(" String2Hex " + ex.getMessage() );
        }

        return bout;
    }//_______________________

 
}  //Class____________________________________________________

No comments:

Post a Comment