ACR122 - Android / How to get the UID's [duplicate] - android

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);
}

Related

Android BLE: Is it possible to add Service Data and Manufacturer Data at the same time when advertising an iBeacon packet?

I'm currently doing an experiment in order to trigger a beacon detection device. Here is the sample of a detected beacon that can be used to trigger that device.
In my experiment, I'm trying to replicate the beacon like in the above picture by using Android BLE library and using iBeacon protocol, since the detection device claims that it follows iBeacon protocol. First, I try to set the service UUID and service data by using AdvertiseData object, then advertise it. The code roughly looks like this:
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
byte[] experimentData = {0x48, 0x6E, (byte) 0xDD, 0x2A, 0x40, (byte) 0xA6, (byte) 0xF0, 0x07, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
byte[] uuidBytes = {0x10, 0x02}
byte[] advertisingBytes = getAdvertisingBytes();
ParcelUuid parcelUuid = parseUuidFrom(uuidBytes);
dataBuilder.addServiceData(parcelUuid, experimentData);
dataBuilder.addServiceUuid(parcelUuid);
dataBuilder.setIncludeTxPowerLevel(false);
dataBuilder.setIncludeDeviceName(false);
//dataBuilder.addManufacturerData(manufacturerCode, advertisingBytes);
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(0);
settingsBuilder.setTxPowerLevel(3);
settingsBuilder.setConnectable(false);
bluetoothLeAdvertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), null);
I commented the addManufacturerData() part for now. The result looks like this.
Now I modify the code so that instead of using Service UUID and Service Data, I use addManufacturerData to advertise the data. The code looks like this:
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
byte[] experimentData = {0x48, 0x6E, (byte) 0xDD, 0x2A, 0x40, (byte) 0xA6, (byte) 0xF0, 0x07, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
byte[] uuidBytes = {0x10, 0x02}
byte[] advertisingBytes = getAdvertisingBytes();
//ParcelUuid parcelUuid = parseUuidFrom(uuidBytes);
//dataBuilder.addServiceData(parcelUuid, experimentData);
//dataBuilder.addServiceUuid(parcelUuid);
//dataBuilder.setIncludeTxPowerLevel(false);
//dataBuilder.setIncludeDeviceName(false);
dataBuilder.addManufacturerData(manufacturerCode, advertisingBytes);
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(0);
settingsBuilder.setTxPowerLevel(3);
settingsBuilder.setConnectable(false);
bluetoothLeAdvertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), null);
The result is shown below. The "Service Data" part is gone, and it is now recognized as an iBeacon packet:
Now, in the first picture, there are "Service Data" section and "Beacon" section, so I though that by adding Service Data and Manufacturer Data, the two section will be shown. I uncomment all of the code, and now it looks like this:
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
byte[] experimentData = {0x48, 0x6E, (byte) 0xDD, 0x2A, 0x40, (byte) 0xA6, (byte) 0xF0, 0x07, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00};
byte[] uuidBytes = {0x10, 0x02}
byte[] advertisingBytes = getAdvertisingBytes();
ParcelUuid parcelUuid = parseUuidFrom(uuidBytes);
dataBuilder.addServiceData(parcelUuid, experimentData);
dataBuilder.addServiceUuid(parcelUuid);
dataBuilder.setIncludeTxPowerLevel(false);
dataBuilder.setIncludeDeviceName(false);
dataBuilder.addManufacturerData(manufacturerCode, advertisingBytes);
AdvertiseSettings.Builder settingsBuilder = new AdvertiseSettings.Builder();
settingsBuilder.setAdvertiseMode(0);
settingsBuilder.setTxPowerLevel(3);
settingsBuilder.setConnectable(false);
bluetoothLeAdvertiser.startAdvertising(settingsBuilder.build(), dataBuilder.build(), null);
But then the advertising packet does not shown at all in the beacon detection app. No exception either, so I don't know whether the beacon is advertised or not
So, it is possible by using Android BLE library to replicate beacon as shown in the first picture (Service data and beacon/manufacturer data in one packet)?
A single advertisement packet is limited to about 23 data bytes so it does not have room for both manufacturer data and service data of the sizes you have in your example.
Try advertising both at the same time each in its own advertisement. Android devices support transmitting multiple advertisements simultaneously.

How to define an APDU for STORE DATA for Host Card Emulation?

I have been looking in the Global Platform Spec on how to define an APDU for my app which will use Host Card Emulation (HCE). My app is supposed to have one phone behaving like an NFC tag through HCE and another phone acting as the NFC reader. The arbitrary data that i am trying to transfer between the phones is just a simple string containing an ID number, but I'm not really sure how to apply it in the code. I have looked at what the different byte commands mean but I'm really not sure how to apply it.
I think I need to use the STORE DATA command but I'm not sure how to intuitively do it and don't really understand. I am currently looking at the HCE side rather than the reader side.
This is my code so far for the HCE side
public class SecondaryActivity extends HostApduService {
#Override
public void onDeactivated(int reason) {
}
#Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
String inboundApduDescription;
byte[] responseApdu;
if (Arrays.equals(AID_SELECT_APDU, commandApdu)) {
inboundApduDescription = "Application selected";
Log.i("HCEDEMO", inboundApduDescription);
byte[] answer = new byte[2];
answer[0] = (byte) 0x90;
answer[1] = (byte) 0x00;
responseApdu = answer;
return responseApdu;
}
return commandApdu;
}
private static final byte[] AID_SELECT_APDU = {
(byte) 0x00,
(byte) 0xA4,
(byte) 0x04,
(byte) 0x00,
(byte) 0x07,
(byte) 0xF0, (byte) 0x39, (byte) 0x41, (byte) 0x48, (byte) 0x14, (byte) 0x81, (byte) 0x00,
(byte) 0x00
};
private static final byte[] STORE_DATA = {
(byte) 0x00,
(byte) 0xA4,
(byte) 0x04,
(byte) 0xA5, // forproprietary data according to the spec
(byte) 0xE2,
(byte) 0x66, (byte) 0x39, (byte) 0x41, (byte) 0x48, (byte) 0x14, (byte) 0x81, (byte) 0x00,
(byte) 0x00
};
private static final byte[] INSTALL = {
(byte) 0x00,
(byte) 0x00,
};
}
How do I send the data from the HCE phone to the reader phone?
What am I missing?
What needs to be done?
You can define virtually any APDU command for HCE. Only the initial SELECT (by AID) command is required. After that, you can create your own command set (or try to follow ISO/IEC 7816-4 commands) as long as you obey the rules of ISO/IEC 7816 for command/response APDU structure, and stick to valid CLA, INS, and status word values.
Since you only want to transfer an ID, you could send this ID directly in response to the SELECT command:
private static final String ID = "1234567890"
#Override
public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
byte[] responseApdu = new byte[] { (byte)0x6F, (byte)0x00 };
if ((commandApdu != null) && (commandApdu.length >= 4)) {
if ((commandApdu[0] == (byte)0x00) && (commandApdu[1] == (byte)0xA4) && (commandApdu[2] == (byte)0x04) && (commandApdu[3] == (byte)0x00)) {
Log.i("HCEDEMO", "Application selected");
byte[] id = ID.getBytes(Charset.forName("UTF-8"));
responseApdu = new byte[id.length + 2];
System.arraycopy(id, 0, responseApdu, 0, id.length);
responseApdu[id.length] = (byte)0x90;
responseApdu[id.length + 1] = (byte)0x00;
}
}
return responseApdu;
}

Control relay over USB from Android

I have this USB Relay and I'd like to control from an Android phone.
(There is a similar post here but it explains how do it from a Linux shell. By looking at that code i figured i'd be able to solve it - apparently not.)
The device lists in lsusb:
Bus 002 Device 011: ID 16c0:05df VOTI
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x16c0 VOTI
idProduct 0x05df
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 34
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 20mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0 No Subclass
bInterfaceProtocol 0 None
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.01
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 22
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 20
I find it strange that the end point is defined as "EP IN". In my mind it should be "EP OUT" since the direction should be "host->device".
Anyway, I use the Android USB manager to create a connection and then initialize the USbRequest for an interrupt based end point. Android permissions and all that is handled so the device is connected successfully.
Snippet for sending data. It runs in a separate thread following the Android guidelines:
UsbRequest request = new UsbRequest();
synchronized (mUsbLock) {
if (mUsbConnection != null && mUsbEndPointIn != null) {
if (!request.initialize(mUsbConnection, mUsbEndPointIn)) {
Log.e(TAG, "Unable to initialize UsbRequest. Thread exits");
return;
} else {
if (DEBUG) {
Log.d(TAG, String.format("Usb request is initialized"));
}
}
} else {
Log.e(TAG, "Usb communication is not up and running. The worker thread should never be started.");
return;
}
}
mRunning.set(true);
while (mRunning.get()) {
if (DEBUG) {
Log.d(TAG, String.format("Waiting for data to be sent to end point"));
}
WorkPackage wp = mWorkQueue.take();
// send the package.
byte[] data = wp.getData();
if (!request.queue(ByteBuffer.wrap(data), data.length)) {
Log.e(TAG, "Unable to queue to send data on UsbRequest.");
continue;
} else {
if (DEBUG) {
Log.d(TAG, String.format("Usb request is queued on end point, ep=%s", printUsbEndpoint(mUsbEndPointIn)));
}
}
}
It seems everything is fine, no errors occur and the request is queued on the end point but then nothing happens at all. I don't get any message back that the request has been handled.
Since the supplier won't release the on/off commands I tried variants based on the Linux post (above). None seem to work though. Supplier only release Windows binary lib.
Sending 8 byte packages (according to max package):
public static byte[] SET_RELAY_ON = {(byte) 0xff, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
public static byte[] SET_RELAY_OFF = {(byte) 0xfd, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
Help appreciated.
So, i figured out how to do this. I will write the solution here in case someone else is having a similar problem.
I had to snoop the USB traffic to understand what to actually send. It turned out that the defined interrupt end point was not used at all. So, the communication with the device was not interrupt based but instead using the control transfer type on end point 0.
So, using the Android USB API this translates into:
Open device (device->host direction):
int r = mUsbConnection.controlTransfer(0xa1, 0x01, 0x0300, 0x00, buffer, buffer.length, 500);
Open relay '1' (host->device direction).
byte[] buffer = {(byte) 0xff, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
int r = mUsbConnection.controlTransfer(0x21, 0x09, 0x0300, 0x00, buffer, buffer.length, 500);
Note, the second parameter in the buffer (0x01) is the relay number (in case you have >1 relay on the board). I only had one.
close relay '1' (host->device direction):
byte[] buffer = {(byte) 0xfd, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
int r = mUsbConnection.controlTransfer(0x21, 0x09, 0x0300, 0x00, buffer, buffer.length, 500);
I have found the project in Github which is similar with this it (for who is looking it)
https://github.com/gigacycle/AndroidHidUsbRelayControl
I have tested this code and I can confirm that it works well with the USB relay board.

How to do authentication for MIFARE Ultralight C on Android

I used an android APP (NFC tag info by NXP) to read my MIFARE Ultraglith C tag and it shows the tag has NXP default key "BREAKMEIFYOUCAN!" on page 0x2C to 0x2F. But I was still failing to authenticate this tag use this key.
// NXP default key: BREAKMEIFYOUCAN! (16 bytes)
byte[] mifareULCDefaultKey = { (byte) 0x49, (byte) 0x45,
(byte) 0x4D, (byte) 0x4B, (byte) 0x41, (byte) 0x45,
(byte) 0x52, (byte) 0x42, (byte) 0x21, (byte) 0x4E,
(byte) 0x41, (byte) 0x43, (byte) 0x55, (byte) 0x4F,
(byte) 0x59, (byte) 0x46 };
In details, I got following result:
1st authentication command: 1A00
response of 1st authentication command: AFCCF489BFB7B98605
ek(RndB): CCF489BFB7B98605
IV 1: 0000000000000000
RndB: 6183511C5B7EF046
RndA: 6E262630E299F94F
RndB': 83511C5B7EF04661
RndA || RndB': 6E262630E299F94F83511C5B7EF04661
IV 2: CCF489BFB7B98605
ek(RndA || RndB'): AB7AF6C6E76675F52B9FF40021A8E2D6
2nd authentication command: AFAB7AF6C6E76675F52B9FF40021A8E2D6
But I still got "Transceive failed" IOException after sending 2nd authentication command. I'm sure the tag is still connected before sending 2nd authentication command.
I have cost 8+ hours on this issue, but still cannot move ahead. Anyone can help?
I had the same problem. The problem is that you are using the wrong Diversified Key for Authentication.

translate C++ function in Android

I'm trying to develop an Android app that does the same as a function written in C++ to communicate between the mobile phone and a remote ethernet interface (I don't know what it exactly is…).
I know that I have to pass to the interface 15 bytes, retrieved from hex values, to pilot some loads connected to the interface.
I've tried a few things, the closest to the correct solution seems to be this one:
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://192.168.2.100:1001");
try {
//String message "AA10A0F0F0FFFF0102FF00010091A5";
byte[] messaggioInBytes={(byte)10101010, //AA
(byte)00010000, //10
(byte)10100000, //A0
(byte)11110000, //F0
(byte)11110000, //F0
(byte)11111111, //FF
(byte)11111111, //FF
(byte)00000001, //01
(byte)00000010, //02
(byte)11111111, //FF
(byte)00000000, //00
(byte)00000001, //01
(byte)00000000, //00
(byte)10010001, //91
(byte)10100101}; //A5
httppost.setEntity(new ByteArrayEntity(messaggioInBytes));
// Execute HTTP Post Request
httpclient.execute(httppost);
} catch(Exception e){
Log.i("ConnectionHandler", "Error", e);
}
With this code the ethernet interface stops blinking and put itself to listening but it doesn't seem to receive the correct command string of bytes.
My doubts are connected to:
1. the format of the command to send
2. the type of connection to use
The only thing I know about the system is that it works well with this C++ function, so I would like to know if there is a way to translate it in Java code for Android instead of using Android NDK to import it.
The C++ function is the following:
void __fastcall TForm1::SendClick(TObject *Sender)
{
unsigned char Buffer[15];
AnsiString Line;
Buffer[0] = 0xAA;
...
Buffer[13] = 0x91;
Buffer[14] = 0xA5;
ClientSocket1->Socket->SendBuf(Buffer,15);
}
Is there anyone who can point me to the right direction?
Not sure if you have other issues but when you are trying to fill the array with bytes you are trying to get the byte value of the wrong numbers.
(byte) 00010000
is trying to stuff 10000 (ten thousand) into a byte.
Try putting in the hex values instead,
(byte)0xAA, (byte)0x10, etc.
Wrote a little test class just to verify that trying to cast a bit representation of a byte was the issue:
public class TestByteArray {
static byte[] myTestArray = {(byte) 0xAA,
(byte) 0x10,
(byte) 0xA0,
(byte) 0xF0,
(byte) 0xF0,
(byte) 0xFF,
(byte) 0xFF,
(byte) 0x01,
(byte) 0x02,
(byte) 0xFF,
(byte) 0x00,
(byte) 0x01,
(byte) 0x00,
(byte) 0x91,
(byte) 0xA5};
static byte[] myBitTestArray = {(byte)10101010, //AA
(byte)00010000, //10
(byte)10100000, //A0
(byte)11110000, //F0
(byte)11110000, //F0
(byte)11111111, //FF
(byte)11111111, //FF
(byte)00000001, //01
(byte)00000010, //02
(byte)11111111, //FF
(byte)00000000, //00
(byte)00000001, //01
(byte)00000000, //00
(byte)10010001, //91
(byte)10100101}; //A5
public static void main(String[] args) {
for(int i = 0;i < myTestArray.length; i++)
{
if(myTestArray[i] != myBitTestArray[i])
{
System.out.println("The value in myTestArray at index " + i + " is " + Integer.toHexString(myTestArray[i] & 0xFF).toUpperCase());
System.out.println("The value in myBitTestArray at index " + i + " is " + Integer.toHexString(myBitTestArray[i] & 0xFF).toUpperCase());
}
else
System.out.println("Arrays are equal at index " + i);
}
}
}

Categories

Resources