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
Related
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 try to integrate an ACR122 to my android app. I'm using the ANDROID Library (http://www.acs.com.hk/en/products/3/acr122u-usb-nfc-reader/) available from ACS.
Everything work, I can detect the presence of a card but I want to extract the UID/ID of the card. Someone know the function to do that?
Do you have an example of this type of integration?
In case of Mifare card you need to send this APDU byte array to the card: (byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00 . I'm not sure about ACR122 API but probably you need to wrap this APDU into specific API method like transmit()
UPDATE
Sample code:
byte[] command = new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
byte[] response = new byte[300];
int responseLength;
responseLength = reader.transmit(slotNum, command, command.length, response,response.length);
System.out.println(new String(response));
Reader is com.acs.smartcard.Reader object
and slotNum is a the slot number. I’m not sure how to find it because I don’t have ACR to test. But if you told that you was able to establish basic communication with reader probably you know slotNum.
In order to prevent this error when trying to read the UID:
com.acs.smartcard.InvalidDeviceStateException: The current state is not equal to specific.
This should rather be:
int slotNum = 0;
byte[] payload = new byte[] { (byte) 0xFF, (byte) 0xCA, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
byte[] response = new byte[7]; // 7 bytes + 90 00 (9 bytes)
try {
reader.power(slotNum, Reader.CARD_WARM_RESET);
reader.setProtocol(slotNum, Reader.PROTOCOL_T0 | Reader.PROTOCOL_T1);
reader.transmit(slotNum, payload, payload.length, response, response.length);
logBuffer(response, response.length);
} catch (ReaderException e) {
Log.e(LOG_TAG, e.getMessage(), e);
}
I am trying to implement IsoDep reading capabilities to chariotsolutions phongap-nfc plugin, so far (even though i am a complete newbie to Java/android and cordova/phonegap) I have managed to make it work with cordova, connect to the card, issue an APDU command and return it back to the web view. (hooray for me right?)
Well the simple problem is that I did not manage to get a 9000 response so far by selecting the application.
I am using LG L Fino#4.4.2.
Additions to NFCplugin.java + import nfc.tech.IsoDep, NFCa, NFCb
.... else if (action.equalsIgnoreCase(ISODEP)) {
registerIsoDep(callbackContext);
} else if (action.equalsIgnoreCase(READISODEP)){
readIsoDep(callbackContext);
} else .....
This should be the tag listener - i think so :-)
private void registerIsoDep(CallbackContext callbackContext) throws JSONException {
addTechList(new String[]{IsoDep.class.getName()});
callbackContext.success();
}
This reads the IsoDep tag, found out that it has to be called within the callback of the previous function (will get back in to that in the Js part)
private void readIsoDep(final CallbackContext callbackContext) throws JSONException {
final Tag tag = savedIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
cordova.getThreadPool().execute(new Runnable() {
#Override
public void run() {
IsoDep isoDep = IsoDep.get(tag);
try {
isoDep.connect();
isoDep.setTimeout(5000);
byte[] SELECT = {
(byte) 0x00, // CLA Class
(byte) 0xA4, // INS Instruction
(byte) 0x04, // P1 Parameter 1
(byte) 0x00, // P2 Parameter 2
(byte) 0x07, // Length
(byte) 0xA0, (byte) 0x00,
(byte) 0x00, (byte) 0x00,
(byte) 0x04, (byte) 0x10,
(byte) 0x10, // AID
(byte) 0x00 // Lenght
};
try {
byte[] result = isoDep.transceive(SELECT);
isoDep.close();
callbackContext.success(result[0] + "|" + result[1]);
}catch (IOException e) {
callbackContext.error("error" + e);
}
} catch (IOException e) {
callbackContext.error("error" + e);
}
}
});
}
Cordova implementation
,addIDDiscoverListener: function(callback, win, fail) {
document.addEventListener("tag", callback, false);
cordova.exec(win, fail, "NfcPlugin", "registerIsoDep", []);
}
};
var isoDep = {
readIsoDep: function(win, fail) {
cordova.exec(win, fail, "NfcPlugin", "readIsoDep", []);
}
}
And lastly "app.js"
nfc.addIDDiscoverListener(function(nfcEvent) {
//listenes for the isodep tag
isoDep.readIsoDep(function(tag) {
console.log(tag); //returns ADPU response codes
}, function(reason) {
console.log('error! ' + reason);
});
},
function() {
console.log('registered reader');
},
function(reason) {
console.log('error! ' + reason);
});
My problem is that no matter what app id I select whether it is MasterCard (A0000000041010) with the above one or PPES (proximity payment system environment), I get this error. Since this is my first attempt to do Java I do not know if it is an implementation issue or command issue (which should be fine) most of this code was written by looking at the chariot solutions code and literally thinking yea this should work, this is here so it should be probably be also here ("cordova execute runnable" - i know sh*t what it does, just assumed it should probably be in my code also).
Also there is probably another small bug - it reads the card only ONCE until I quit the app and start it again.
PS.: I have read a ton of SO post, googled like hell for couple of days and tried a lot of things (learned a couple also) but none of them were able to help me.
PSS.: And yes when it is done I want to merge it the the original project.
Thank for any help and sorry for the long post.
The 6F XX that you are seeing is not the status word. In fact 6F ... is exactly what you should receive when your SELECT (by DF name) command succeeds. 6F is the tag of an FCI template.
When you try to retrieve the status word, you are actually reading the first two bytes of the array that you get from the transceive() method. However, a response APDU looks like
+---------+--------+--------+
| DATA | SW1 | SW2 |
| n bytes | 1 byte | 1 byte |
+---------+--------+--------+
So you would need to check the last two bytes of result for the status word:
result[result.length - 2] + "|" + result[result.length - 1]
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();
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.