使用 SCL010 获取 Mifare Ultralight 的 UID
Posted
技术标签:
【中文标题】使用 SCL010 获取 Mifare Ultralight 的 UID【英文标题】:Get UID of Mifare Ultralight with SCL010 【发布时间】:2014-02-23 18:31:50 【问题描述】:我想获取 Mifare Ultralight NFC 标签的 UID。 在 Java 中我有这个代码:
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 是否正确?
【问题讨论】:
我认为 APDU 不正确。你能告诉你得到的接收字节吗? 这可能是对传递 2 个字节的 REQA 命令的响应(ATQA)吗? 【参考方案1】:您实际使用的命令可能不是您所期望的。
使用此阅读器获取 UID/序列号/枚举标识符的正确命令 APDU 是:
+------+------+------+------+------+
| 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 = 0x00
。 Ne = 0
表示预期响应字节数为零(而 Le = 0 表示预期响应字节数(最多)为 256)。
这会有效地创建以下 Case-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)
【讨论】:
【参考方案2】: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));
【讨论】:
愚蠢的问题,但我怎样才能知道我需要发送哪些数据来读/写?我的意思是我有一个 NXP NTAG216,现在我怎么知道我阅读了哪一页?以上是关于使用 SCL010 获取 Mifare Ultralight 的 UID的主要内容,如果未能解决你的问题,请参考以下文章
如何使用Nexus 5获取Mifare Ultralight 16位UID读数
从 MIFARE DESFire 获取 UID 的 APDU?