2014-02-23 56 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,现在我怎么知道我读的是哪一页? –