Android 上的 Mifare Ultralight C 身份验证
Mifare Ultralight C Authentication on Android
我有一些用于测试身份验证的 Mifare Ultralight C 标签。
我第一次使用 NXP TagInfo 应用程序阅读它时,我可以看到以下信息:
(...)
Page 04 - Page 27: FULL OF 0s **(empty tag)**
Page 28: 00 00 -- --
Page 29: 00 00 -- --
Page 2A: 30 -- -- --
Page 2B: 00 -- -- --
Page 2C: 42 52 45 41
PAGE 2D: 4B 4D 45 49
PAGE 2E: 46 59 4F 55
PAGE 2F: 43 41 4E 21
页面 2C - 2F 表示它具有默认密钥 "BREAKMEIFYOUCAN!" (425245414b4d454946594f5543414e21
)。
然后我 运行 我的 Android 应用基本上是这样做的:
写 49454D4B41455242214E4143554F5946
从第 2C 页到第 2F 页(用于验证)。
在页面 2A (42) 写入 0x04;意味着 2A 上的所有页面都需要身份验证。
在第 2B 页写入 0x00 (43);意味着读取和写入都需要身份验证。
//Start authenticating
byte[] result1 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2C, /* PAGE = 44 */
(byte)0x49, (byte)0x45, (byte)0x4D, (byte)0x4B /* 49 45 4D 4B */
});
byte[] result2 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2D, /* PAGE = 45 */
(byte)0x41, (byte)0x45, (byte)0x52, (byte)0x42 /* 41 45 52 42 */
});
byte[] result3 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2E, /* PAGE = 46 */
(byte)0x21, (byte)0x4E, (byte)0X41, (byte)0X43 /* 21 4E 41 43 */
});
byte[] result4 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2F, /* PAGE = 47 */
(byte)0X55, (byte)0X4F, (byte)0X59, (byte)0X46 /* 55 4F 59 46 */
});
//Finish authenticating
//Say the pages the card needs authentication
byte[] result5 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2A, /* PAGE = 42 */
(byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00 /* Message = All pages after 04 needs authentication */
});
byte[] result6 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2B, /* PAGE = 43 */
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 /* Message = authentication is required both for reading and writing */
});
//Finish "card activition"
完成此操作后,我使用 NXP TagInfo 应用程序再次读取标签,正如预期的那样,我再也看不到标签信息了。取而代之的是,它在所有字段(从 04 开始)上指示 .p XX XX XX XX,这表明它需要密码才能读取数据。
在那之后(这里是我看不到我的错误的地方)我尝试再次验证标签(通过写入页面 2C - 2F),但我在验证部分的开头收到此错误:
System.err: java.io.IOException: Transceive failed
System.err: at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:52)
at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:151)
at android.nfc.tech.MifareUltralight.transceive(MifareUltralight.java:215)**
我看不出我做错了什么...
你做错的是你没有真正实现MIFARE Ultralight C认证。在 MIFARE Ultralight C 标签上,写入页面 0x2C..0x2F 完全按照命令所说:它 写入 到该页面,但它 不 执行任何身份验证。
取而代之的是,MIFARE Ultralight C 实现了一种三向相互质询-响应身份验证协议。该协议通过发送 AUTHENTICATE 命令启动:
byte[] result1 = mifare.transceive(new byte[] {
(byte)0xA1, /* CMD = AUTHENTICATE */
(byte)0x00
});
为了响应该命令,您将收到一个挑战,您需要使用身份验证密钥解密、操作、加密并发送回标签以证明您确实拥有身份验证密钥。您可以在Q/A中找到一些实现 MIFARE Ultralight C 身份验证的代码:Android: Authenticating with NXP MiFare Ultralight C.
我有一些用于测试身份验证的 Mifare Ultralight C 标签。
我第一次使用 NXP TagInfo 应用程序阅读它时,我可以看到以下信息:
(...) Page 04 - Page 27: FULL OF 0s **(empty tag)** Page 28: 00 00 -- -- Page 29: 00 00 -- -- Page 2A: 30 -- -- -- Page 2B: 00 -- -- -- Page 2C: 42 52 45 41 PAGE 2D: 4B 4D 45 49 PAGE 2E: 46 59 4F 55 PAGE 2F: 43 41 4E 21
页面 2C - 2F 表示它具有默认密钥 "BREAKMEIFYOUCAN!" (425245414b4d454946594f5543414e21
)。
然后我 运行 我的 Android 应用基本上是这样做的:
写
49454D4B41455242214E4143554F5946
从第 2C 页到第 2F 页(用于验证)。在页面 2A (42) 写入 0x04;意味着 2A 上的所有页面都需要身份验证。
在第 2B 页写入 0x00 (43);意味着读取和写入都需要身份验证。
//Start authenticating
byte[] result1 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2C, /* PAGE = 44 */
(byte)0x49, (byte)0x45, (byte)0x4D, (byte)0x4B /* 49 45 4D 4B */
});
byte[] result2 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2D, /* PAGE = 45 */
(byte)0x41, (byte)0x45, (byte)0x52, (byte)0x42 /* 41 45 52 42 */
});
byte[] result3 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2E, /* PAGE = 46 */
(byte)0x21, (byte)0x4E, (byte)0X41, (byte)0X43 /* 21 4E 41 43 */
});
byte[] result4 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2F, /* PAGE = 47 */
(byte)0X55, (byte)0X4F, (byte)0X59, (byte)0X46 /* 55 4F 59 46 */
});
//Finish authenticating
//Say the pages the card needs authentication
byte[] result5 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2A, /* PAGE = 42 */
(byte)0x04, (byte)0x00, (byte)0x00, (byte)0x00 /* Message = All pages after 04 needs authentication */
});
byte[] result6 = mifare.transceive(new byte[] {
(byte)0xA2, /* CMD = WRITE */
(byte)0x2B, /* PAGE = 43 */
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 /* Message = authentication is required both for reading and writing */
});
//Finish "card activition"
完成此操作后,我使用 NXP TagInfo 应用程序再次读取标签,正如预期的那样,我再也看不到标签信息了。取而代之的是,它在所有字段(从 04 开始)上指示 .p XX XX XX XX,这表明它需要密码才能读取数据。
在那之后(这里是我看不到我的错误的地方)我尝试再次验证标签(通过写入页面 2C - 2F),但我在验证部分的开头收到此错误:
System.err: java.io.IOException: Transceive failed System.err: at android.nfc.TransceiveResult.getResponseOrThrow(TransceiveResult.java:52) at android.nfc.tech.BasicTagTechnology.transceive(BasicTagTechnology.java:151) at android.nfc.tech.MifareUltralight.transceive(MifareUltralight.java:215)**
我看不出我做错了什么...
你做错的是你没有真正实现MIFARE Ultralight C认证。在 MIFARE Ultralight C 标签上,写入页面 0x2C..0x2F 完全按照命令所说:它 写入 到该页面,但它 不 执行任何身份验证。
取而代之的是,MIFARE Ultralight C 实现了一种三向相互质询-响应身份验证协议。该协议通过发送 AUTHENTICATE 命令启动:
byte[] result1 = mifare.transceive(new byte[] {
(byte)0xA1, /* CMD = AUTHENTICATE */
(byte)0x00
});
为了响应该命令,您将收到一个挑战,您需要使用身份验证密钥解密、操作、加密并发送回标签以证明您确实拥有身份验证密钥。您可以在Q/A中找到一些实现 MIFARE Ultralight C 身份验证的代码:Android: Authenticating with NXP MiFare Ultralight C.