I am newbie in Android NFC API.
Currently, I have a NFC tag, I am making an Android app to read data from it. My simple App is launched when my phone get closer enough to the NFC Tag. But I have no idea how to read the data inside the NFC Tag. The tag uses IsoDep technology.
My current code:
#Override
protected void onResume (){
super.onResume();
Intent intent = getIntent();
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
IsoDep isoDep = IsoDep.get(tag);
// How to read data from IsoDep instance?
I googled on internet, I notice people are sending commands to IsoDep to get response from NFC Tag, I suppose from the response, we can parse the data in the tag, I saw people doing this:
//What is the 'command' ? How to define the command?
//e.g.:
byte command = (byte) 0x6A
isoDep.transceive(command)
But, the command is just a byte, as a newbie, it is too difficult to understand what is happening. I have no idea how to define the command to read data? Anyone can explain to me? or is there a document I can learn about the command?
Generally, I need some guidance on how to define commands & how to parse data from response, I would like to read the data stored in the Tag & show the data in String format in UI element (e.g. TextView).
*AND***
I have no problem with those configurations(e.g. AnroidManifest.xml), please don't guide me on how to configure :)
IsoDep allows you to communicate over a ISO-14443-4 connection with the transceive operation. Over this protocol application data units (APDUs) are exchanged. The format is specified, you find a description on Wikipedia.
For exaple, to select an application on a smart card with a particular application identifier (AID) you would execute the following APDU command. The result simply indicates ok (9000) or an error.
byte[] SELECT = {
(byte) 0x00, // CLA Class
(byte) 0xA4, // INS Instruction
(byte) 0x04, // P1 Parameter 1
(byte) 0x00, // P2 Parameter 2
(byte) 0x0A, // Length
0x63,0x64,0x63,0x00,0x00,0x00,0x00,0x32,0x32,0x31 // AID
};
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
IsoDep tag = IsoDep.get(tagFromIntent);
tag.connect();
byte[] result = tag.transceive(SELECT);
if (!(result[0] == (byte) 0x90 && result[1] == (byte) 0x00))
throw new IOException("could not select applet");
After the application has been selected, you can execute application specific commands. The programs are typically written in JavaCard which follows the GlobalPlatorm spec. The following example executes on the above selected application the method 4 (0x04) which returns a byte array of at most 11 bytes. This result is then converted to a string.
byte[] GET_STRING = {
(byte) 0x80, // CLA Class
0x04, // INS Instruction
0x00, // P1 Parameter 1
0x00, // P2 Parameter 2
0x10 // LE maximal number of bytes expected in result
};
result = tag.transceive(GET_STRING);
int len = result.length;
if (!(result[len-2]==(byte)0x90&&result[len-1]==(byte) 0x00))
throw new RuntimeException("could not retrieve msisdn");
byte[] data = new byte[len-2];
System.arraycopy(result, 0, data, 0, len-2);
String str = new String(data).trim();
tag.close();
Related
I am new to Xamarin as well as Android development. I have an NFC tag, specifically a ST M24LR64E, with data on it. I can see the blocks of data using the ST app on Google Play. In my Xamarin app, I cannot send a message to the tag without getting a TagLostException. I can query the tag ID with no issue, but trying to read a single block of data, I get the exception. Any direction would be grateful.
byte[] response = new byte[] { 0x0A };
byte[] cmd = new byte[]
{
(byte) 0x26,
(byte) 0x01,
0x00
};
response = nfcv.Transceive(cmd);
byte[] single = new byte[]
{
(byte) 0x40, // FLAGS
(byte) 0x20, // READ_SINGLE_BLOCK
0, 0, 0, 0, 0, 0, 0, 0,
(byte) (0 & 0x0ff)
};
Array.Copy(id, 0, single, 2, 8);
response = nfcv.Transceive(single);
The first Transceive() is ok and I see 10 bytes coming back. As soon as I try to read a block of data, I get the TagLostException.
With the NfcV tag technology, a TagLostException may indicate that the reader can no longer communicate with the tag or that the command resulted in an error.
According to its manual, the M24LR64E only supports the extended version (Protocol Extension flag set) of the READ_SINGLE_BLOCK command:
The Protocol_extension_flag should be set to 1 for the M24LR64E-R to operate correctly. If the Protocol_extension_flag is at 0, the M24LR64E-R answers with an error code.
Consequently, your version of the READ_SINGLE_BLOCK command is not compatible with the tag. You need to set the Protocol Extension flag and provide a 16 bit block number. A version that should work is:
int blockNumber = 0;
byte[] readSingleBlock = new byte[] {
(byte) 0x28, // Flags: Addressed (bit 5), Protocol Extension (bit 3)
(byte) 0x20, // Command: READ_SINGLE_BLOCK
0, 0, 0, 0, 0, 0, 0, 0, // placeholder for UID
(byte) (blockNumber & 0x0ff),
(byte) ((blockNumber >> 8) & 0x0ff)
};
byte[] id = nfcv.GetTag().GetId();
Array.Copy(id, 0, readSingleBlock, 2, 8);
response = nfcv.Transceive(readSingleBlock);
Since you used the high data rate (Data_rate flag set) with the INVENTORY command, you might also want to use the high data rate with the READ_SINGLE_BLOCK command. You would use the flags value 0x2A (instead of 0x28) in that case.
Finally, you should avoid sending anti-collision/enumeration commands such as the INVENTORY command over any NfcX tag technology object. While this may work, you might confuse the internal state-keeping of the ANdroid NFC stack since it already performs these commands for you and keeps track of the enumerated tag(s). You can get all the information that you would obtain through the INVENTORY request from the Tag object and the NfcV object:
tag.GetId() gives you the UID of the tag.
nfcv.GetDsfId() gives you the DSFID of the tag.
nfcv.GetResponseFlags() gives you the flags byte of the INVENTORY response.
I am developing an application where i have to read information from ITSO smart card. And it supports below three technologies for filter ACTION_TECH_DISCOVERED.
android.nfc.tech.IsoDep, android.nfc.tech.NfcA
android.nfc.tech.NdefFormatable
Now when I using below code
byte[] apduCmd = {
0x00, //CLA
(byte)0xA4, //INS select
0x00, //P1
0x00, //P2
0x02 //LE
};
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
IsoDep isoDep = IsoDep.get(tag);
try {
isoDep.connect();
byte[] result = isoDep.transceive(apduCmd);
Log.i(TAG, "SELECT: " + bytesToHex(result));
if (!(result[0] == (byte) 0x90 && result[1] == (byte) 0x00)) {
Toast.makeText(this, "Exception occurred!", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "Read successfully!", Toast.LENGTH_SHORT).show();
}
} catch (IOException e) {
e.printStackTrace();
}
Above code gives me success bytes i.e. 9000
Now I am not sure what to do next? How to read complete Data/information from this ITSO card. (this card is type of bus ticket).
Any suggestion?
Thanks Michael, i have read the document ITSO specification, and got idea to create command to read the data from the card.
I execute the commands in below sequence.
1) SELECT DIRECTORY- 906A000000
2) SELECT APPLICATION- 905A0000031602A000
3) READ DATA- 90BD0000070400000000000000 (File number- 4)
4) ADDITIONAL FRAME- 90AF000000 (This will execute only if we have Additional frame in response.)
And i am getting response like below for each file ( below response if for file number 4)
Response: 230A00009469FA0798004600002698400100000000000000000000000000000000042C00C0001CDC131089EB4A583BC000000000000000000000000000000000
Now I am not sure how get the information from this?
Can i get all information at once in XML or JSON? Is there any easier way to do this?
Update 10/05/2016
I got the shell information in HEX String, Can you help me to decode the textual information from it. (Reference ITSO specification given above.
I am very new to Android development and NFC in general.
I am trying to build an application to read the content of an NFC card where I don't know anything about this card (bus card), I want to see for example how many tickets I have left.
I have scanned the card with variety of NFC applications and know that this card is of type: IsoDep AND NfcB.
Right now I am trying to read its content using IsoDep with no success (errors 6A82, 91AE, 6E00 and so on).
I have an app that waiting for new intent of type ACTION_NDEF_DISCOVERED || ACTION_TECH_DISCOVERED || ACTION_TAG_DISCOVERED opens a new thread (since it is not possible to read and connect on UI's thread) and I am trying to read the content of the card.
I guess my problem is with the bytes I am passing to isoDep.transceive(NATIVE_SELECT_APP_COMMAND).
Should I keep trying on the IsoDep or should I move to try on the NfcB?
Do you guys have any tips?
here is my code sample:
final byte[] SELECT = {
(byte) 0x00, // CLA Class
(byte) 0xA4, // INS Instruction
(byte) 0x04, // P1 Parameter 1
(byte) 0x00, // P2 Parameter 2
(byte) 0x08, // Length
(byte) 0x31, (byte)0x54, (byte)0x49, (byte)0x43, (byte)0x2e,
(byte) 0x49, (byte)0x43, (byte)0x41, // AID 315449432e494341
};
Tag tagFromIntent = m_intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
IsoDep isoDep = IsoDep.get(tagFromIntent);
try {
isoDep.connect();
byte[] result = isoDep.transceive(SELECT);
String str = bytesToHex(result);
Log.i("test", "SELECT: " + str);
isoDep.close();
} catch (Exception e) {
String error = e.getMessage();
}
my bytes to hex function:
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
=============================================================
Edit:
I have just learned that this card is using Calypso authentication scheme.
In this question's answer helped me a little: Read data from NFC tag (IsoDep)
I found a good SELECT function, i have edited my question to hold the new "SELECT" command which is working- In return i get this string: "6F228408315449432E494341A516BF0C13C70800000000029780A55307060A07062004019000" which i have no idea what it means.
Then I use this command to try and read a string:
byte[] GET_STRING = {
(byte) 0x80, // CLA Class
0x04, // INS Instruction
0x00, // P1 Parameter 1
0x00, // P2 Parameter 2
0x10 // LE maximal number of bytes expected in result
};
But i get error: 6E00, any ideas on how to proceed?
You could communicate with card with IsoDep.
You want to access data on card without specifications of this card, so there's 2 ways:
Get specification of card (how to communicate with it)
Do reverse engineering, it will take lot of time and not sure about the result, and you could "lock" access to the card
UPDATE 1
To read Rav Kav card, threre's an open-source project : http://pannetrat.com/Cardpeek/ code for Rav Kav is here https://code.google.com/p/cardpeek/source/browse/trunk/dot_cardpeek_dir/scripts/calypso/c376n3.lua
You are sending the wrong command to read the application's records. 6E00 means incorrect INS byte.
You can have a look at this github which reads some counters out of a MOBIB card, which is based on the Calypso spec.
https://github.com/flamingokweker/Android-NFC-Mobib-Reader
I have writted some data to NFC tag sucessfully.
Now I would like to read all the blocks for double check.
My codes looks like this and got TAG was lost exception:
byte[] UIDFrame = new byte[] { (byte) 0x26, (byte) 0x01, (byte) 0x00 };
try {
NfcA nfcvTag = NfcA.get(myTag);
nfcvTag.close();
nfcvTag.connect();
response = nfcvTag.transceive(UIDFrame);
...
}
Someone said IsoDep can fix this issue, but if I rewrote the code to
IsoDep aaa = IsoDep.get(myTag);
then I found aaa is null.
Can anyone help me to fix it? Thanks so much
I'm getting a "Tag was lost" exception with the code below. However, data is written successfully despite the exception. Why is the data successfully written eventhough an exception is thrown?
nfc.connect();
byte[] arrByt = new byte[7];
arrByt[0] = 0x01; //Command Flag 0x02 works fine
arrByt[1] = 0x21;
arrByt[2] = 0x06;
arrByt[3] = 0x00;
arrByt[4] = 0x00;
arrByt[5] = 0x00;
arrByt[6] = 0x00;
byte[] response = nfc.transceive(arrByt);
My NFC Chip
Type V (ISO/IEC 15693 / Vicinity), Tag Type SL2 ICS2001 (ICODE SLI), Manufacturer NXP Semiconductors (Germany)
here talked over
But no result :(
When NfcV tag returns non-success code android's NFC stack assumes it is an exception and it throws "Tag was Lost".
To avoid this exception you can use the command 0x02 and the proper byte arrays becomes:
arrByte = {0x02, 0x21, 0x06, 0x00, 0x00, 0x00, 0x00}; where 0x02 is flag command, 0x21 is write single block command, 0x06 is block number and the remaing is 4bytes of data. Hope this will help.