I am trying to use the PN532 to read my NFC UID from phone(Samsung Galaxy S10), but i receive just 08 and another 3 digits of random values.I read that a value that start with 08 is a RID(Random ID). Is there any possible way to read just a unique value, or use the PN532 to read something that is unique from my phones NFC?
I want to use that value to compare it with a constant in my code and send an impulse to a relay to open a door.
This code is from da Adafruit_PN532 library.
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_PN532.h>
#define PN532_IRQ (2)
#define PN532_RESET (3) // Not connected by default on the NFC Shield
// Or use this line for a breakout or shield with an I2C connection:
Adafruit_PN532 nfc(PN532_IRQ, PN532_RESET);
void setup(void) {
Serial.begin(115200);
Serial.println("Hello!");
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata) {
Serial.print("Didn't find PN53x board");
while (1); // halt
}
Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC);
// configure board to read RFID tags
nfc.SAMConfig();
Serial.println("Waiting for an ISO14443A Card ...");
}
void loop(void) {
uint8_t success;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID
uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type)
// Wait for an ISO14443A type cards (Mifare, etc.). When one is found
// 'uid' will be populated with the UID, and uidLength will indicate
// if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight)
success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
if (success) {
// Display some basic information about the card
Serial.println("Found an ISO14443A card");
Serial.print(" UID Length: "); Serial.print(uidLength, DEC); Serial.println(" bytes");
Serial.print(" UID Value: ");
nfc.PrintHex(uid, uidLength);
if (uidLength == 4) {
// We probably have a Mifare Classic card ...
uint32_t cardid = uid[0];
cardid <<= 8;
cardid |= uid[1];
cardid <<= 8;
cardid |= uid[2];
cardid <<= 8;
cardid |= uid[3];
Serial.print("Seems to be a Mifare Classic card #");
Serial.println(cardid);
}
delay(2000);
}
}
Do not use the NFC UID for any security purpose, as you can see a phone does give a random one for privacy purposes.
The NFC UID is designed only to help reading hardware deal with handling sending data to the right card when multiple different Tags are in range. There is no guarantee that the UID is actually Unique and that it cannot duplicated (even with Tag that are supposed to have it programmed at the factory you can buy clones from China where they can be programmed by the end user).
It is better to use cryptographic methods with data stored on a tag or emulated Tag if using a phone to provide uniqueness to use a Tag for anything with security implications.
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'm writing an Android application. I'm trying to send NfcA low-level commands (in my case: HALT and WAKE-UP) to my Mifare Plus S card. The NfcA tech is for "low-level" access to ISO 14443 Type A tags (i.e. the
proprietary protocol as mentioned in ISO 14443-3).
This is part of my code:
protected void onNewIntent(Intent intent) {
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
UID = Utils.byteArrayToHexString(intent.getByteArrayExtra(NfcAdapter.EXTRA_ID));
}
NfcA nfca = null;
try {
Log.e(TAG, "WakeUpCMD and HaltCMD");
nfca = NfcA.get(tagFromIntent);
nfca.connect();
Short s = nfca.getSak();
byte[] a = nfca.getAtqa();
byte[] HaltCMD = {0x35, 0x30, 0x30,0x30, 0x00};
byte[] WakeUpCMD = {0x35, 0x32, 0x00};
byte[] data = null;
try {
data = nfca.transceive(HaltCMD);
length = data.length;
}
catch (Exception e){
Log.e(TAG, "HALT complete "+Utils.byteArrayToHexString(data));
}
Log.e(TAG, "Tag is connected: "+nfca.isConnected());
//Log.e(TAG, "Response from tag "+Utils.byteArrayToHexString(data));
nfca.setTimeout(100);
data = nfca.transceive(WakeUpCMD);
Log.e(TAG, "Response from tag"+Utils.byteArrayToHexString(data));
nfca.close();
} catch (Exception e) {
Log.e(TAG, "Error when reading tag");
}
}
WAKE-UP Command is sent by the PCD to put PICCs which have entered the HALT State back into the READY
State. They shall then participate in further anticollision and selection procedures.
|b7| |b6| |b5| |b4| |b3| |b2| |b1|
|1 | | 0 | | 1| | 0| | 0| | 1| | 0| {‘52’} = WAKE-UP
HALT Command consists of four bytes and shall be transmitted using the Standard Frame.
First bit transmitted
S | ‘50’ | ‘00’ | CRC_A | E
If the PICC responds with any modulation during a period of 1 ms after the end of the HALT Frame, this response shall be interpreted as 'not acknowledge'.
This is the descriptions of the two commands from ISO 14443-3 which I try to send to my card.
When I start my app, I get a "Tag Lost" Exception. Can you help me? What's wrong? How can I send these commands?
It seems as if you are converting the command codes into null-terminated ASCII character strings before sending them with NfcA.transceive():
byte[] HaltCMD = {0x35, 0x30, 0x30,0x30, 0x00};
byte[] WakeUpCMD = {0x35, 0x32, 0x00};
0x35 0x30 0x30 0x30 gives "5000"
0x35 0x32 gives "52"
This does not make any sense as the commands (50 00 for HLTA, and 52 for WUPA) are hexadecimal representations of the command values already.
For the HLTA command, you would therefore need to send 50 00:
data = nfca.transceive(new byte[] { (byte)0x50, (byte)0x00 });
Note that S (start of communication), E (end of communication), and CRC_A will be automatically added by the NFC controller (or the NFC stack).
For the WUPA command, you could probably try to send 52:
data = nfca.transceive(new byte[] { (byte)0x52 });
However, it is very likely that the NFC stack does not permit you to send 7-bit commands using the transceive method. Instead, the stack may automatically use this command value as one full byte and add a CRC_A.
General note on sending ISO/IEC 14443-3 initialization and anti-collision commands
Sending such commands may or may not work (depending on the NFC stack implementation and the NFC controller). In general I would strongly recommend that you do not send such commands. Particularly the HLTA command will confuse the internal state keeping of the NFC stack on some devices and will lead to unexpected results. Normally, you don't need to exchange such commands, as anti-collision, initialization and activation are handled automatically by the NFC device.
I'm working on a BLE sensor that is advertising manufacturer specific data. Is there any sample code that demonstrates how to receive an advertisement packet in Android and parse its payload?
This is what I was looking for:
The BLE scan API BluetoothAdapter.startLeScan(ScanCallback) requires a call back function for the scan results. the method needs to look like the following:
private BluetoothAdapter.LeScanCallback ScanCallback =
new BluetoothAdapter.LeScanCallback()onLeScan(final BluetoothDevice device,
int rssi,
final byte[] scanRecord)
{...}
And the scanRecord variable is a byte array which contains the Advertisement packet payload.
Per the BLE specification the structure of the payload is very simple as follows:
The packets can be up to 47 bytes in length and consist of:
1 byte preamble
4 byte access address
2-39 bytes advertising channelPDU
3 bytes CRC
For advertisement communication channels, the access address is always 0x8E89BED6.
The PDU in turn has its own header (2 bytes: size of the payload and its type – whether the device supports connections, etc.) and the actual payload (up to 37 bytes).
Finally, the first 6 bytes of the payload are the MAC address of the device, and the actual information can have up to 31 bytes.
the format of the actual information is as follows:
first byte is length of the data and second byte is type followed by the data.
This is a clever way to allow any application to skip entire data records if they don't care about the contents.
Here is the sample code to determine the contents of the Advertisement packet:
parseAdvertisementPacket(final byte[] scanRecord) {
byte[] advertisedData = Arrays.copyOf(scanRecord, scanRecord.length);
int offset = 0;
while (offset < (advertisedData.length - 2)) {
int len = advertisedData[offset++];
if (len == 0)
break;
int type = advertisedData[offset++];
switch (type) {
case 0x02: // Partial list of 16-bit UUIDs
case 0x03: // Complete list of 16-bit UUIDs
while (len > 1) {
int uuid16 = advertisedData[offset++] & 0xFF;
uuid16 |= (advertisedData[offset++] << 8);
len -= 2;
uuids.add(UUID.fromString(String.format(
"%08x-0000-1000-8000-00805f9b34fb", uuid16)));
}
break;
case 0x06:// Partial list of 128-bit UUIDs
case 0x07:// Complete list of 128-bit UUIDs
// Loop through the advertised 128-bit UUID's.
while (len >= 16) {
try {
// Wrap the advertised bits and order them.
ByteBuffer buffer = ByteBuffer.wrap(advertisedData,
offset++, 16).order(ByteOrder.LITTLE_ENDIAN);
long mostSignificantBit = buffer.getLong();
long leastSignificantBit = buffer.getLong();
uuids.add(new UUID(leastSignificantBit,
mostSignificantBit));
} catch (IndexOutOfBoundsException e) {
// Defensive programming.
Log.e("BlueToothDeviceFilter.parseUUID", e.toString());
continue;
} finally {
// Move the offset to read the next uuid.
offset += 15;
len -= 16;
}
}
break;
case 0xFF: // Manufacturer Specific Data
Log.d(TAG, "Manufacturer Specific Data size:" + len +" bytes" );
while (len > 1) {
if(i < 32) {
MfgData[i++] = advertisedData[offset++];
}
len -= 1;
}
Log.d(TAG, "Manufacturer Specific Data saved." + MfgData.toString());
break;
default:
offset += (len - 1);
break;
}
}
thanks to
how-ibeacons-work
bluetooth org specs
mass for putting me on the right direction!
ADPayloadParser in nv-bluetooth parses the payload of an advertising packet and returns a list of AD structures. The AD structure format is described in "11 ADVERTISING AND SCAN RESPONSE DATA FORMAT" of "Bluetooth Core Specification 4.2".
The following code snippet is an implementation example of onLeScan method.
public void onLeScan(
BluetoothDevice device, int rssi, byte[] scanRecord)
{
// Parse the payload of the advertising packet.
List<ADStructure> structures =
ADPayloadParser.getInstance().parse(scanRecord);
// For each AD structure contained in the advertising packet.
for (ADStructure structure : structures)
{
if (structure instanceof IBeacon)
{
// iBeacon packet was found.
handleIBeacon((IBeacon)structure);
}
......
}
}
You can register a parser of your own for your manufacturer-specific format into ADPayloadParser. Refer to the following links for more information.
Blog: http://darutk-oboegaki.blogspot.jp/2015/03/ibeacon-as-kind-of-ad-structures.html
GitHub: https://github.com/TakahikoKawasaki/nv-bluetooth
JavaDoc: http://takahikokawasaki.github.io/nv-bluetooth/
Maven: http://search.maven.org/#search|ga|1|a%3A%22nv-bluetooth%22
edit 21.02.2016
The library i linked below seems to have been moved;
see https://github.com/AltBeacon/android-beacon-library
You can use Android iBeacon Library for a start.
There is a reference application which you can use for the basics and with simulated data.
~https://github.com/RadiusNetworks/ibeacon-reference-android~
Once you get it up and running you may wish to import the library and use it with your real device, there is also some example code on the site:
http://developer.radiusnetworks.com/ibeacon/android/samples.html
I' currently trying to get HCE running with my arduino uno device mounted with a seeed NFC Shield V 2.0
I'm using the example code from https://github.com/Seeed-Studio/PN532/blob/master/PN532/examples/android_hce/android_hce.ino
#include <SPI.h>
#include <PN532_SPI.h>
#include <PN532Interface.h>
#include <PN532.h>
PN532_SPI pn532spi(SPI, 10);
PN532 nfc(pn532spi);
void setup()
{
Serial.begin(115200);
Serial.println("-------Peer to Peer HCE--------");
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata) {
Serial.print("Didn't find PN53x board");
while (1); // halt
}
// Got ok data, print it out!
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
// Set the max number of retry attempts to read from a card
// This prevents us from waiting forever for a card, which is
// the default behaviour of the PN532.
//nfc.setPassiveActivationRetries(0xFF);
// configure board to read RFID tags
nfc.SAMConfig();
}
void loop()
{
bool success;
uint8_t responseLength = 32;
Serial.println("Waiting for an ISO14443A card");
// set shield to inListPassiveTarget
success = nfc.inListPassiveTarget();
if(success) {
Serial.println("Found something!");
uint8_t selectApdu[] = { 0x00, /* CLA */
0xA4, /* INS */
0x04, /* P1 */
0x00, /* P2 */
0x07, /* Length of AID */
0xF0, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* AID defined on Android App */
0x00 /* Le */ };
uint8_t response[32];
success = nfc.inDataExchange(selectApdu, sizeof(selectApdu), response, &responseLength);
if(success) {
Serial.print("responseLength: "); Serial.println(responseLength);
nfc.PrintHexChar(response, responseLength);
do {
uint8_t apdu[] = "Hello from Arduino";
uint8_t back[32];
uint8_t length = 32;
success = nfc.inDataExchange(apdu, sizeof(apdu), back, &length);
if(success) {
Serial.print("responseLength: "); Serial.println(length);
nfc.PrintHexChar(back, length);
}
else {
Serial.println("Broken connection?");
}
}
while(success);
}
else {
Serial.println("Failed sending SELECT AID");
}
}
else {
Serial.println("Didn't find anything!");
}
delay(1000);
}
void printResponse(uint8_t *response, uint8_t responseLength) {
String respBuffer;
for (int i = 0; i < responseLength; i++) {
if (response[i] < 0x10)
respBuffer = respBuffer + "0"; //Adds leading zeros if hex value is smaller than 0x10
respBuffer = respBuffer + String(response[i], HEX) + " ";
}
Serial.print("response: "); Serial.println(respBuffer);
}
void setupNFC() {
nfc.begin();
uint32_t versiondata = nfc.getFirmwareVersion();
if (! versiondata) {
Serial.print("Didn't find PN53x board");
while (1); // halt
}
// Got ok data, print it out!
Serial.print("Found chip PN5"); Serial.println((versiondata>>24) & 0xFF, HEX);
Serial.print("Firmware ver. "); Serial.print((versiondata>>16) & 0xFF, DEC);
Serial.print('.'); Serial.println((versiondata>>8) & 0xFF, DEC);
// configure board to read RFID tags
nfc.SAMConfig();
}
My android code is taken from the HCE development guide and I also tried the code form https://github.com/grundid/host-card-emulation-sample
My problem is, that the arduino code doesn't even recognize a tag. So all I'm getting is:
Waiting for an ISO14443A card
Didn't find anything!
Waiting for an ISO14443A card
Didn't find anything!
Waiting for an ISO14443A card
As a matter of fact, on the Android side, I do not receive any packet, neither is the fancy NFC sound playing, which usually indicates that at least something is happening.
So my question is, has someone tried to use the Galaxy S3 with cyanogenmod 10 along with HCE support. I'm really out of any ideas, I triplechecked my code, read a lots of question here on SO, but all did at least receive something from the NFC Shield.
I know that the common NFC mode works fine, as I have an application using NFC in "normal" mode. When I run this NFC-protocol on my arduino, all applications receive a packet, (although they can't route them correctly, because they are not adpu packets)
Android 4.4 HCE does not run on Samsung Galaxy S3 with NXP chip.
I had tested for both Galaxy Nexus, Nexus 7(2012) and Galaxy S3. All these 3 devices are not able to run HCE on Kitkat.
You may check the device for HCE support:
boolean isHceSupported =
getPackageManager().hasSystemFeature("android.hardware.nfc.hce");
Android HCE (as provided by the Android 4.4 HCE API) is not supported on CyanogenMod 10.*. That API is only available starting with CyanogenMod 11 and even then I'm not sure that the CyanogenMod implementation of the Android HCE API works on devices with NXP chipset (e.g. Galaxy S3).
CyanogenMod 10.* has a different HCE API. See Nikolay's blog for an example on how to use that API.
Basically, for your Arduino program to work, you would have to implement HCE based on the IsoPcdA technology.
Also note that if you ever switch from CyanogenMod HCE to Android HCE, you have to use ISO 7816-4 compliant APDUs. Thus, an "APDU" like you use it in your code above,
apdu[] = "Hello from Arduino";
would not work. CyanogenMod HCE, however, does not require the use of ISO 7816-4 APDUs on top of the ISO 14443-4 transport protocol and will, therefore, happily accept this string instead of an APDU.
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();