Pregunta

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?

¿Fue útil?

Solución

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)

Otros consejos

import java.nio.ByteBuffer;
import java.util.List;
import javax.smartcardio.Card;
import javax.smartcardio.CardChannel;
import javax.smartcardio.CardException;
import javax.smartcardio.CardTerminal;
import javax.smartcardio.TerminalFactory;

public class Read {

public Read() {

    try {

        CardTerminal terminal = null;

        // show the list of available terminals
        TerminalFactory factory = TerminalFactory.getDefault();
        List<CardTerminal> terminals = factory.terminals().list();
        String readerName = "";

        for (int i = 0; i < terminals.size(); i++) {

            readerName = terminals.get(i).toString()
                    .substring(terminals.get(i).toString().length() - 2);
            //terminal = terminals.get(i);

            if (readerName.equalsIgnoreCase(" 0")) {
                terminal = terminals.get(i);
            }
        }

        // Establish a connection with the card
        System.out.println("Waiting for a card..");

        if(terminal==null)
            return;
        terminal.waitForCardPresent(0);

        Card card = terminal.connect("T=0");
        CardChannel channel = card.getBasicChannel();

        // Start with something simple, read UID, kinda like Hello World!
        byte[] baReadUID = new byte[5];

        baReadUID = new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x00,
                (byte) 0x00, (byte) 0x00 };

        System.out.println("UID: " + send(baReadUID, channel));
        // If successfull, the output will end with 9000

        // OK, now, the real work


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



public String send(byte[] cmd, CardChannel channel) {

    String res = "";

    byte[] baResp = new byte[258];
    ByteBuffer bufCmd = ByteBuffer.wrap(cmd);
    ByteBuffer bufResp = ByteBuffer.wrap(baResp);

    // output = The length of the received response APDU
    int output = 0;

    try {


output = channel.transmit(bufCmd, bufResp);
    }` catch (CardException ex) {
        ex.printStackTrace();
    }`

    for (int i = 0; i < output; i++) {
        res += String.format("%02X", baResp[i]);
        // The result is formatted as a hexadecimal integer
    }

    return res;
}

public static void main(String[] args) {
    new Read();
}
}

After read this code For read and write purpose use bellow commands.

And Read From page : 04 to page : 07 Command is:

read_four_to_seven = new byte[]{(byte) 0xFF, (byte) 0x00, (byte) 0x00,
                         (byte) 0x00, (byte) 0x05, (byte) 0x0D4, (byte) 0x40, (byte) 0x01,
                         (byte) 0x30, (byte) 0x04, (byte) 0x07 };
System.out.println("Read : " + send(read_four_to_seven, channel));

Write into Page 04:

Write_Page_Four = new byte[] { (byte) 0xFF, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x15, (byte) 0xD4, (byte) 0x40,
(byte) 0x01, (byte) 0xA0, (byte) 0x04, (byte) 0x4D,
(byte) 0x65, (byte) 0x73, (byte) 0x75, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00 };
System.out.println("Read : " + send(Write_Page_Four, channel));
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top