Search code examples
javanfcsmartcardsmartcard-readerpcsc

Pcsc -smartcard get UID


I'm trying to read card UID / HCE android device UID from my pcsc java code. But I'm getting the following error

javax.smartcardio.CardException: sun.security.smartcardio.PCSCException: Unknown error 0x1f

Although I'm able to get ATS bit when I try to get UID I get this error. I have refered my code from here

CODE

import java.io.Console;
import java.util.List;
import java.util.ListIterator;
import java.util.Scanner;

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

public class PCSC {

    private byte[] atr = null;
    private String protocol = null;
    private byte[] historical = null;

    public CardTerminal selectCardTerminal() {
        try {
            // show the list of available terminals
            TerminalFactory factory = TerminalFactory.getDefault();
            List<CardTerminal> terminals = factory.terminals().list();
            ListIterator<CardTerminal> terminalsIterator = terminals
                    .listIterator();
            CardTerminal terminal = null;
            CardTerminal defaultTerminal = null;
            if (terminals.size() > 1) {
                System.out
                        .println("Please choose one of these card terminals (1-"
                                + terminals.size() + "):");
                int i = 1;
                while (terminalsIterator.hasNext()) {
                    terminal = terminalsIterator.next();
                    System.out.print("[" + i + "] - " + terminal
                            + ", card present: " + terminal.isCardPresent());
                    if (i == 1) {
                        defaultTerminal = terminal;
                        System.out.println(" [default terminal]");
                    } else {
                        System.out.println();
                    }
                    i++;
                }
                Scanner in = new Scanner(System.in);
                try {
                    int option = in.nextInt();
                    terminal = terminals.get(option - 1);
                } catch (Exception e2) {
                    // System.err.println("Wrong value, selecting default terminal!");
                    terminal = defaultTerminal;

                }
                System.out.println("Selected: " + terminal.getName());
                // Console console = System.console();
                return terminal;
            }

        } catch (Exception e) {
            System.err.println("Error occured:");
            e.printStackTrace();
        }
        return null;
    }

    public String byteArrayToHexString(byte[] b) {
        StringBuffer sb = new StringBuffer(b.length * 2);
        for (int i = 0; i < b.length; i++) {
            int v = b[i] & 0xff;
            if (v < 16) {
                sb.append('0');
            }
            sb.append(Integer.toHexString(v));
        }
        return sb.toString().toUpperCase();
    }

    public static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character
                    .digit(s.charAt(i + 1), 16));
        }
        return data;
    }

    public Card establishConnection(CardTerminal ct) {
        this.atr = null;
        this.historical = null;
        this.protocol = null;

        System.out
                .println("To establish connection, please choose one of these protocols (1-4):");
        System.out.println("[1] - T=0");
        System.out.println("[2] - T=1");
        System.out.println("[3] - T=CL");
        System.out.println("[4] - * [default]");

        String p = "*";
        Scanner in = new Scanner(System.in);

        try {
            int option = in.nextInt();

            if (option == 1)
                p = "T=0";
            if (option == 2)
                p = "T=1";
            if (option == 3)
                p = "T=CL";
            if (option == 4)
                p = "*";
        } catch (Exception e) {
            // System.err.println("Wrong value, selecting default protocol!");
            p = "*";
        }

        System.out.println("Selected: " + p);

        Card card = null;
        try {
            card = ct.connect(p);
        } catch (CardException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        ATR atr = card.getATR();
        System.out.println("Connected:");
        System.out.println(" - ATR:  " + byteArrayToHexString(atr.getBytes()));
        System.out.println(" - Historical: "
                + byteArrayToHexString(atr.getHistoricalBytes()));
        System.out.println(" - Protocol: " + card.getProtocol());

        this.atr = atr.getBytes();
        this.historical = atr.getHistoricalBytes();
        this.protocol = card.getProtocol();

        return card;

    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        PCSC pcsc = new PCSC();
        CardTerminal ct = pcsc.selectCardTerminal();
        Card c = null;
        if (ct != null) {
            c = pcsc.establishConnection(ct);
            CardChannel cc = c.getBasicChannel();



            try {

                 ResponseAPDU answer = cc.transmit(new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 0x00));

                   System.out.println("answer: " + answer.toString());

            } catch (CardException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

}

OUTPUT

Please choose one of these card terminals (1-3):
[1] - PC/SC terminal ACS ACR1281 1S Dual Reader ICC 0, card present: false [default terminal]
[2] - PC/SC terminal ACS ACR1281 1S Dual Reader PICC 0, card present: true
[3] - PC/SC terminal ACS ACR1281 1S Dual Reader SAM 0, card present: false
2
Selected: ACS ACR1281 1S Dual Reader PICC 0
To establish connection, please choose one of these protocols (1-4):
[1] - T=0
[2] - T=1
[3] - T=CL
[4] - * [default]
4
Selected: *
Connected:
 - ATR:  3B8F8001804F0CA0000003060300030000000068
 - Historical: 804F0CA00000030603000300000000
 - Protocol: T=1
javax.smartcardio.CardException: sun.security.smartcardio.PCSCException: Unknown error 0x1f
    at sun.security.smartcardio.ChannelImpl.doTransmit(Unknown Source)
    at sun.security.smartcardio.ChannelImpl.transmit(Unknown Source)
    at myPcscGoogleCode.PCSC.main(PCSC.java:186)
Caused by: sun.security.smartcardio.PCSCException: Unknown error 0x1f
    at sun.security.smartcardio.PCSC.SCardTransmit(Native Method)
    ... 3 more

Already referred the following Get UID of Mifare Ultralight with SCL010

Please help !

Thanks


Solution

  • I was able to find the solution and get the UID by changing the command APDU. Then I converted the result byte[] to hex UID.

    try {
                    //get UID cmd apdu
                     ResponseAPDU answer = cc.transmit( new CommandAPDU(new byte[] { (byte)0xFF, (byte)0xCA, (byte)0x00, (byte)0x00, (byte)0x00 } ));
    
                       System.out.println("answer: " + answer.toString());
    
                       byte[] reponseBytesArr=answer.getBytes();
    
                       System.out.println("answer byte[]");
                       StringBuilder sb = new StringBuilder();
    
                       for(int i=0;i<reponseBytesArr.length;i++){
                           //print arr
                           byte b =reponseBytesArr[i];
                           System.out.println(b);
                           if(i<=reponseBytesArr.length-3){
                            // append uid
                           sb.append(String.format("%02X ", b));
                           }
                    }    
                        System.out.println("UID: "+sb.toString()); 
    

    Output:

    Please choose one of these card terminals (1-3):
    [1] - PC/SC terminal ACS ACR1281 1S Dual Reader ICC 0, card present: false [default terminal]
    [2] - PC/SC terminal ACS ACR1281 1S Dual Reader PICC 0, card present: true
    [3] - PC/SC terminal ACS ACR1281 1S Dual Reader SAM 0, card present: false
    2
    Selected: ACS ACR1281 1S Dual Reader PICC 0
    To establish connection, please choose one of these protocols (1-4):
    [1] - T=0
    [2] - T=1
    [3] - T=CL
    [4] - * [default]
    4
    Selected: *
    Connected:
    -Card Class class sun.security.smartcardio.CardImpl
     - ATR:  3B8F8001804F0CA0000003060300030000000068
     - Historical: 804F0CA00000030603000300000000
     - Protocol: T=1
    answer: ResponseAPDU: 9 bytes, SW=9000
    answer byte[]
    4
    -28
    -66
    42
    0
    41
    -128
    -112
    0
    UID: 04 E4 BE 2A 00 29 80