The PWD_AUTH command that you send to the tag does not make much sense.
The idea of the PWD_AUTH command is that you send your password (a 4-byte value) and that the tag responds with its password acknowledge (PACK) value (a 2-byte value) if you authenticated with the correct password. You can then verify the PACK value against the expected password acknowledge to "authenticate" the tag.
So the correct command would be:
byte[] response = nfc.transceive(new byte[] {
(byte) 0x1B, // PWD_AUTH
pass[0], pass[1], pass[2], pass[3]
});
if ((response != null) && (response.length >= 2)) {
byte[] pack = Arrays.copyOf(response, 2);
// TODO: verify PACK to confirm that 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.)
}
What you need in order to enable password protection (on NTAG212):
Set PWD (page 39) to your desired password (default value is 0xFFFFFFFF
).
byte[] response = nfc.transceive(new byte[] {
(byte) 0xA2, // WRITE
(byte) 39, // page address
pass[0], pass[1], pass[2], pass[3]
});
Set PACK (page 40, bytes 0-1) to your desired password acknowledge (default value is 0x0000
).
byte[] response = nfc.transceive(new byte[] {
(byte) 0xA2, // WRITE
(byte) 40, // page address
pack[0], pack[1], // bytes 0-1 are PACK value
(byte) 0, (byte) 0 // other bytes are RFU and must be written as 0
});
Set AUTHLIM (page 38, byte 0, bits 2-0) to the maximum number of failed password verification attempts (setting this value to 0 will permit an unlimited number of PWD_AUTH attempts).
Set PROT (page 38, byte 0, bit 7) to your desired value (0 = PWD_AUTH in needed only for write access, 1 = PWD_AUTH is necessary for read and write access).
byte[] response = nfc.transceive(new byte[] {
(byte) 0x30, // READ
(byte) 38 // page address
});
if ((response != null) && (response.length >= 16)) { // read always returns 4 pages
boolean prot = false; // false = PWD_AUTH for write only, true = PWD_AUTH for read and write
int authlim = 0; // value between 0 and 7
response = nfc.transceive(new byte[] {
(byte) 0xA2, // WRITE
(byte) 38, // page address
(byte) ((response[0] & 0x078) | (prot ? 0x080 : 0x000) | (authlim & 0x007)),
response[1], response[2], response[3] // keep old value for bytes 1-3, you could also simply set them to 0 as they are currently RFU and must always be written as 0 (response[1], response[2], response[3] will contain 0 too as they contain the read RFU value)
});
}
Set AUTH0 (page 37, byte 3) to the first page that should require password authentication.
byte[] response = nfc.transceive(new byte[] {
(byte) 0x30, // READ
(byte) 37 // page address
});
if ((response != null) && (response.length >= 16)) { // read always returns 4 pages
boolean prot = false; // false = PWD_AUTH for write only, true = PWD_AUTH for read and write
int auth0 = 0; // first page to be protected, set to a value between 0 and 37 for NTAG212
response = nfc.transceive(new byte[] {
(byte) 0xA2, // WRITE
(byte) 37, // page address
response[0], // keep old value for byte 0
response[1], // keep old value for byte 1
response[2], // keep old value for byte 2
(byte) (auth0 & 0x0ff)
});
}
If you use MifareUltralight
tag technology, instead of using the transceive
method directly, you could also use the readPages
and writePage
methods:
The READ command
byte[] response = nfc.transceive(new byte[] {
(byte) 0x30, // READ
(byte) (pageAddress & 0x0ff) // page address
});
is equvalent to
byte[] response = nfc.readPages(pageAddress);
The WRITE command
byte[] data = { (byte)..., (byte)..., (byte)..., (byte)... };
byte[] response = nfc.transceive(new byte[] {
(byte) 0xA2, // WRITE
(byte) (pageAddress & 0x0ff), // page address
data[0], data[1], data[2], data[3]
});
is equvalent to
nfc.writePage(pageAddress, data);
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…