认证
ultralightEV1.authenticatePwd(passwordBytes);
为了使用 MIFARE Ultralight EV1 标签(或 NTAG21x)的密码进行身份验证,您需要发送 PWD_AUTH (0x1B) 命令(并可能验证 PACK 响应是否符合您的期望):
byte[] pass = { (byte)0x12, (byte)0x34, (byte)0x56, (byte)0x78 };
byte[] pack = { (byte)0x9A, (byte)0xBC };
byte[] response = nfc.transceive(new byte[] {
(byte) 0x1B, // PWD_AUTH
pass[0], pass[1], pass[2], pass[3]
});
if ((response != null) && (response.length >= 2)) {
// success
byte[] packReceived = Arrays.copyOf(response, 2);
if (Arrays.equal(packReceived, pack)) {
// PACK verified, so tag is authentic (not really, but that whole
// PWD_AUTH/PACK authentication mechanism was not really meant to
// bring much security, I hope; same with the NTAG signature btw.)
}
}
设置密码和密码确认
ultralightEV1.programPwd(passwordBytes);
ultralightEV1.programPack(packBytes);
对于 MF0UL11,密码在 0x12 页,密码确认 (PACK) 在 0x13 页(配置页从 0x10 开始)。对于 MF0UL21,密码在 0x27 页,密码确认 (PACK) 在 0x28 页(配置页从 0x25 开始)。
为了动态确定您的标签是 MF0UL11 还是 MF0UL21,您可以发送 GET_VERSION (0x60) 命令:
int cfgOffset = -1;
byte[] response = nfc.transceive(new byte[] {
(byte) 0x60 // GET_VERSION
});
if ((response != null) && (response.length >= 8)) {
// success
if ((response[0] == (byte)0x00) && (response[1] == (byte)0x04)) {
// tag is from NXP
if (response[2] == (byte)0x03) {
// MIFARE Ultralight
if ((response[4] == (byte)0x01) && (response[5] == (byte)0x00) {
// MIFARE Ultralight EV1 (V0)
switch (response[6]) {
case (byte)0x0B:
// MF0UL11
cfgOffset = 0x010;
break;
case (byte)0x0E:
// MF0UL11
cfgOffset = 0x025;
break;
default:
// unknown
break;
}
}
}
}
}
找到配置页面的开头后,您可以使用 WRITE (0xA2) 命令更新这些页面的值(假设您使用当前密码进行身份验证,而配置页面不受保护):
byte[] response = nfc.transceive(new byte[] {
(byte) 0xA2, // WRITE
(byte)((cfgOffset + 2) & 0x0FF), // page address
pass[0], pass[1], pass[2], pass[3] // new page data
});
response = nfc.transceive(new byte[] {
(byte) 0xA2, // WRITE
(byte)((cfgOffset + 3) & 0x0FF), // page address
pack[0], pack[1], (byte)0x00, (byte)0x00 // new page data (always need to write full page)
});
启用密码保护
ultralightEV1.enablePasswordProtection(enabled, fromPageNum);
为了启用密码保护,您需要配置需要密码的第一个页面(AUTH0,MF0UL11 的第 0x10 页上的字节 3/MF0UL21 的第 0x25 页上的字节)并且您需要配置保护模式(PROT,第 7 位) MF0UL11 的第 0x11 页上的字节 0/MF0UL21 的第 0x26 页)。
您通常会首先读取(READ (0x30) 命令)这些页面的旧值,更新受影响的位和字节,然后将新值写入标签:
int fromPageNum = 4;
boolean enableProtection = true;
boolean enableReadProtection = true;
byte[] response = nfc.transceive(new byte[] {
(byte) 0x30, // READ
(byte)(cfgOffset & 0x0FF) // page address
});
if ((response != null) && (response.length >= 16)) {
// success
// NOTE that READ will return *4 pages* starting at page address
byte auth0 = (byte)0xFF;
if (enableProtection || enableReadProtection) {
auth0 = (byte)(fromPageNum & 0x0FF);
}
byte[] writeResponse = nfc.transceive(new byte[] {
(byte) 0xA2, // WRITE
(byte)((cfgOffset + 0) & 0x0FF), // page address
response[0], response[1], response[2], auth0 // new page data
});
byte access = (byte)(response[4] & 0x07F);
if (enableProtection && enableReadProtection) {
access |= (byte)0x80;
}
byte[] writeResponse = nfc.transceive(new byte[] {
(byte) 0xA2, // WRITE
(byte)((cfgOffset + 1) & 0x0FF), // page address
access, response[5], response[6], response[7], // new page data
});
}