2014-02-23 53 views
6

我想獲得Mifare Ultralight NFC標籤的UID。 在Java中我有這樣的代碼:使用SCL010獲取Mifare Ultralight的UID

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

的問題是,我收到兩個字節,而不是UID。 什麼問題? APDU是否正確?

+0

我覺得APDU不correct.Can你告訴接收字節這你得到。 – vikky

+0

這可能是傳遞2字節的REQA命令的響應(ATQA)嗎? – pizzaani

回答

7

您實際使用的命令不是您所期望的。

正確的命令APDU獲得UID /序列號/枚舉與此reader標識符是:

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

但是,你正在使用的構造函數定義:

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

因此,與

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

您正在創建一個具有以下參數的C-APDU CLA = 0xFF,INS = 0xCA,P1 = 0x00, P2 = 0x00。到目前爲止,這與上述APDU相同。但最後一個參數是Ne = 0x00Ne = 0表示預期響應字節數爲零(而Le = 0意味着預期響應字節數爲(高達)256)。

這導致有效地創建以下案例1 APDU:

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

所以頂多你將得到2個字節的狀態字作爲響應(或者指示與0x90 0x00成功或表示有錯誤狀態碼如0x6X 0xXX)。

所以,你可以使用一個字節數組來形成你的APDU:

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

或者你可以指定Ne一個適當的值:

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

閱讀此代碼爲讀取後和寫目的使用下面的命令。

並閱讀頁面:04頁:07的命令是:

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

寫入頁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

愚蠢的問題,但我怎麼才能知道我需要發送讀取/寫入哪些數據? 我的意思是我有一個恩智浦NTAG216,現在我怎麼知道我讀的是哪一頁? –