2014-02-23 11 views
6

Ich möchte die UID des Mifare Ultralight NFC-Tags erhalten. In Java habe ich diesen Code:Erhalten Sie UID von Mifare Ultralight mit SCL010

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(); 

Das Problem ist, dass ich zwei Bytes und nicht die UID erhalten. Was ist das Problem? Ist die APDU korrekt?

+0

Ich denke, die APDU nicht ist correct.Can Sie das Byte empfangen sagen die du erhältst. – vikky

+0

Könnte dies die Antwort (ATQA) auf den REQA-Befehl sein, der 2 Bytes liefert? – pizzaani

Antwort

7

Der Befehl, den Sie tatsächlich verwenden, ist nicht das, was Sie erwartet haben.

Die richtige Kommando APDU die UID/Seriennummer/Enumeration Kennung mit diesem Leser zu bekommen, ist:

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

der Konstruktor Sie verwenden jedoch wie folgt definiert ist:

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

So mit

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

Sie erstellen eine C-APDU mit den folgenden Parametern CLA = 0xFF, INS = 0xCA, P1 = 0x00, P2 = 0x00. Bisher ist dies das gleiche wie die obige APDU. Der letzte Parameter ist . Ne = 0 bedeutet, dass die Anzahl der erwarteten Antwortbytes Null ist (während Le = 0 bedeuten würde, dass die Anzahl der erwarteten Antwortbytes (bis zu) 256 ist).

Daraus ergibt sich effektiv die folgenden Case-1 APDU erstellen:

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

So höchstens Sie das 2-Byte-Statuswort als Antwort (entweder zeigt Erfolg mit 0x90 0x00 oder einen Fehler anzeigt mit einem bekommen Statuscode wie 0x6X 0xXX).

So können Sie entweder ein Byte-Array verwenden, um Ihre APDU zu bilden:

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

Oder Sie können einen richtigen Wert für Ne angeben:

new CommandAPDU(0xFF, 0xCA, 0x00, 0x00, 256) 
5
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(); 
} 
} 

Nach diesen Code lesen Für Lese und schreibe Zweck verwenden, Gebrüll-Befehle.

Und lesen Sie auf Seite: 04 Seite: 07 Befehl ist:

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)); 

schreiben in Seite 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)); 
+0

dumme Frage, aber wie kann ich erfahren, welche Daten ich zum Lesen/Schreiben senden muss? Ich meine, ich habe ein NXP NTAG216 und wie kann ich nun wissen, welche Seite ich gelesen habe? –