Search code examples
javanfcmifareapdusmartcard-reader

Get UID of Mifare Ultralight with SCL010


I want get the UID of the Mifare Ultralight NFC tag. In Java I have this code:

TerminalFactory factory = TerminalFactory.getDefault();
List<CardTerminal> terminals = factory.terminals().list();
System.out.println("Terminals: " + terminals);

CardTerminal terminal = terminals.get(0);

Card card = terminal.connect("*");
System.out.println("card: " + card);
CardChannel channel = card.getBasicChannel();

ResponseAPDU answer = channel.transmit(new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 0x00));
byte[] uid = answer.getBytes();

The problem is that I receive two bytes and not the UID. What's the problem? Is the APDU correct?


Solution

  • The command you are actually using is not what you might have expected.

    The correct command APDU to get the UID/serial number/enumeration identifier with this reader is:

    +------+------+------+------+------+
    | CLA  | INS  |  P1  |  P2  |  Le  |
    +------+------+------+------+------+
    | 0xFF | 0xCA | 0x00 | 0x00 | 0x00 |
    +------+------+------+------+------+
    

    However, the constructor you are using is defined as:

    public CommandAPDU(int cla, int ins, int p1, int p2, int ne);
    

    So with

    new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 0x00)
    

    you are creating a C-APDU with the following parameters CLA = 0xFF, INS = 0xCA, P1 = 0x00, P2 = 0x00. So far this is the same as the above APDU. But the last parameter is Ne = 0x00. Ne = 0 means that the number of expected response bytes is zero (whereas Le = 0 would mean that the number of expected response bytes is (up to) 256).

    This results in effectively creating the following Case-1 APDU:

    +------+------+------+------+
    | CLA  | INS  |  P1  |  P2  |
    +------+------+------+------+
    | 0xFF | 0xCA | 0x00 | 0x00 |
    +------+------+------+------+
    

    So at most you will get the 2-byte status word as a response (either indicating success with 0x90 0x00 or indicating an error with a status code like 0x6X 0xXX).

    So you can either use a byte array to form your APDU:

    new CommandAPDU(new byte[] { (byte)0xFF, (byte)0xCA, (byte)0x00, (byte)0x00, (byte)0x00 } )
    

    Or you can specify a proper value for Ne:

    new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 256)