I'm developing an application in Android for NFC read/write/authentication operations. Here are some code parts you would like.
Android has 3 main types determined for cards, those are Mifare Classic, Mifare Ultralight and Isodep (this is the type of Desfire and Desfire EV1). So, as I get a tag touched, I run this operation:
private String[] getTagInfo(Intent intent) {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String prefix = "android.nfc.tech.";
String[] info = new String[2];
// UID
byte[] uid = tag.getId();
info[0] = "UID In Hex: " + Utils.convertByteArrayToHexString(uid) + "
" +
"UID In Dec: " + Utils.convertByteArrayToDecimal(uid) + "
";
// Tech List
String[] techList = tag.getTechList();
String techListConcat = "Technologies: ";
for(int i = 0; i < techList.length; i++) {
techListConcat += techList[i].substring(prefix.length()) + ",";
}
info[0] += techListConcat.substring(0, techListConcat.length() - 1) + "
";
// Mifare Classic/UltraLight Info
info[0] += "Card Type: ";
String type = "Unknown";
for(int i = 0; i < techList.length; i++) {
if(techList[i].equals(MifareClassic.class.getName())) {
info[1] = "Mifare Classic";
MifareClassic mifareClassicTag = MifareClassic.get(tag);
// Type Info
switch (mifareClassicTag.getType()) {
case MifareClassic.TYPE_CLASSIC:
type = "Classic";
break;
case MifareClassic.TYPE_PLUS:
type = "Plus";
break;
case MifareClassic.TYPE_PRO:
type = "Pro";
break;
}
info[0] += "Mifare " + type + "
";
// Size Info
info[0] += "Size: " + mifareClassicTag.getSize() + " bytes
" +
"Sector Count: " + mifareClassicTag.getSectorCount() + "
" +
"Block Count: " + mifareClassicTag.getBlockCount() + "
";
} else if(techList[i].equals(MifareUltralight.class.getName())) {
info[1] = "Mifare UltraLight";
MifareUltralight mifareUlTag = MifareUltralight.get(tag);
// Type Info
switch (mifareUlTag.getType()) {
case MifareUltralight.TYPE_ULTRALIGHT:
type = "Ultralight";
break;
case MifareUltralight.TYPE_ULTRALIGHT_C:
type = "Ultralight C";
break;
}
info[0] += "Mifare " + type + "
";
} else if(techList[i].equals(IsoDep.class.getName())) {
info[1] = "IsoDep";
IsoDep isoDepTag = IsoDep.get(tag);
info[0] += "IsoDep
";
} else if(techList[i].equals(Ndef.class.getName())) {
Ndef ndefTag = Ndef.get(tag);
info[0] += "Is Writable: " + ndefTag.isWritable() + "
" +
"Can Make ReadOnly: " + ndefTag.canMakeReadOnly() + "
";
} else if(techList[i].equals(NdefFormatable.class.getName())) {
NdefFormatable ndefFormatableTag = NdefFormatable.get(tag);
}
}
return info;
}
However, this doesn't directly get the type of Desfire and Desfire EV1. For that you need to send some bytes to card:
static final byte GET_MANUFACTURING_DATA = (byte) 0x60;
public DesfireManufacturingData getManufacturingData() throws Exception {
byte[] respBuffer = sendRequest(GET_MANUFACTURING_DATA);
if (respBuffer.length != 28)
throw new Exception("Invalid response");
return new DesfireManufacturingData(respBuffer);
}
private byte[] sendRequest (byte command) throws Exception {
return sendRequest(command, null);
}
private byte[] sendRequest (byte command, byte[] parameters) throws Exception {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] recvBuffer = mTagTech.transceive(Utils.wrapMessage(command, parameters));
while (true) {
if (recvBuffer[recvBuffer.length - 2] != (byte) 0x91)
throw new Exception("Invalid response");
output.write(recvBuffer, 0, recvBuffer.length - 2);
byte status = recvBuffer[recvBuffer.length - 1];
if (status == OPERATION_OK) {
break;
} else if (status == ADDITIONAL_FRAME) {
recvBuffer = mTagTech.transceive(Utils.wrapMessage(GET_ADDITIONAL_FRAME, null));
} else if (status == PERMISSION_DENIED) {
throw new Exception("Permission denied");
}else if (status == LENGTH_ERROR) {
throw new Exception("Length Error");
}
else if (status == AUTHENTICATION_ERROR) {
throw new Exception("Authentication error");
}else if (status == PARAMETER_ERROR) {
throw new Exception("Parameter Error");
}else if (status == DUPLICATE_ERROR) {
throw new Exception("Duplicate Error");
}else if (status == NO_SUCH_KEY) {
throw new Exception("No such key");
}else {
throw new Exception("Unknown status code: " + Integer.toHexString(status & 0xFF));
}
}
return output.toByteArray();
}
After you initialize the Manufacturing data, you can easily reach its parts. DesfireManufacturingData class is for evaluating the response from the tag into meaningful parts, but I'll only give link of it: Desfire Manufacturing Data. Also, I must say this is the most all-around project I have found in the Internet with open source, but it only has reading operations for Desfire tags, not write and authenticate. Hope this helps!
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…