So lately I have been working with smart cards that hold some information and what I am trying to achieve here is to fetch this data from these smart card using a smart card reader through any Android Smartphone. I have been using a HID OMNIKEY 3021 USB smart card reader which would read these card(And I know this reader works with these cards through windows apps because I have personally tested this)
Now Android provides USB Host that makes it possible to read any USB Host provided the Android Smartphones supports it.
And I am trying to use these classes provided by USB Host to reach out to the data inside this card.
My code to detect any USB Host :
private static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
PendingIntent mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
registerReceiver(mUsbReceiver, filter);
IntentFilter attachedFilter = new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED);
registerReceiver(mUsbAttachedReceiver, attachedFilter);
private final BroadcastReceiver mUsbAttachedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Utils.writeStringToTextFile("\n1 .Get an action : " + action, FileName);
if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
synchronized (this) {
device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
showToast("Plugged In");
mUsbManager.requestPermission(device, mPermissionIntent);
}
}
} else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (device != null) {
showToast("Plugged Out");
// call your method that cleans up and closes communication with the device
}
}
}
};
private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_USB_PERMISSION.equals(action)) {
synchronized (this) {
device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
if (device != null) {
//call method to set up device communication
Utils.writeStringToTextFile("2 .Get an action : " + action + "\nDevice is : " + device, FileName);
showToast("Permission Granted for device");
Handler h = new Handler();
h.postDelayed(run, 1000);
}
} else {
showToast("Permission denied for device" + device);
}
}
}
}
};
Everything works as expected as I get the UsbDevice device
which gives out the info of device, example :
Device is : UsbDevice[mName=/dev/bus/usb/001/002,mVendorId=1899,mProductId=12322,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=OMNIKEY AG,mProductName=Smart Card Reader USB,mVersion=2.0,mSerialNumber=null,mConfigurations=[
UsbConfiguration[mId=1,mName=CCID,mAttributes=160,mMaxPower=50,mInterfaces=[
UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=11,mSubclass=0,mProtocol=0,mEndpoints=[
UsbEndpoint[mAddress=131,mAttributes=3,mMaxPacketSize=8,mInterval=24]
UsbEndpoint[mAddress=132,mAttributes=2,mMaxPacketSize=64,mInterval=0]
UsbEndpoint[mAddress=5,mAttributes=2,mMaxPacketSize=64,mInterval=0]]]]
Now I am trying to use this UsbDevice device
to fetch data and details from the card but I am not successful in doing so and I couldn't find any helpful post regarding this.
I know I have to use UsbInterface
, UsbEndpoint
, UsbDeviceConnection
to get the things I want from the card but I am unable to do so.
Also, I am not able to find any samples or such thing for the same. Can anyone point me to the right direction?
Sorry for the long post also thanks in Advance :)
EDIT : Thanks to Mr. Michael Roland, I was able to read about CCID as reader device speaks CCID over the USB interface.
So I used the following code :
UsbDeviceConnection connection = mUsbManager.openDevice(device);
UsbEndpoint epOut = null, epIn = null;
for (int i = 0; i < device.getInterfaceCount(); i++) {
UsbInterface usbInterface = device.getInterface(i);
connection.claimInterface(usbInterface, true);
for (int j = 0; j < usbInterface.getEndpointCount(); j++) {
UsbEndpoint ep = usbInterface.getEndpoint(j);
showToast("Endpoint is : " + ep.toString() + " endpoint's type : " + ep.getType() + " endpoint's direction : " + ep.getDirection());
Log.d(" ", "EP " + i + ": " + ep.getType());
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
epOut = ep;
} else if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
epIn = ep;
}
}
}
int dataTransferred = 0;
byte[] PC_to_RDR_IccPowerOn = hexStringToByteArray("62" + "00000000" + "00" + "00" + "00" + "0000");
if (epOut != null) {
//Firstly send Power in on Bulk OUT endpoint
dataTransferred = connection.bulkTransfer(epOut, PC_to_RDR_IccPowerOn, PC_to_RDR_IccPowerOn.length, TIMEOUT);
}
StringBuilder result = new StringBuilder();
if (epIn != null) {
final byte[] RDR_to_PC_DataBlock = new byte[epIn.getMaxPacketSize()];
result = new StringBuilder();
//Secondly send Power out on Bulk OUT endpoint
dataTransferred = connection.bulkTransfer(epIn, RDR_to_PC_DataBlock, RDR_to_PC_DataBlock.length, TIMEOUT);
for (byte bb : RDR_to_PC_DataBlock) {
result.append(String.format(" %02X ", bb));
}
if (dataTransferred > 0) {
Utils.writeStringToTextFile("\n2nd buffer received was : " + result.toString(), "Card_communication_data.txt");
String s1 = Arrays.toString(RDR_to_PC_DataBlock);
String s2 = new String(RDR_to_PC_DataBlock);
showToast("received - " + s1 + " - " + s2);
} else {
showToast("received length at 2nd buffer transfer was " + dataTransferred);
}
}
}
And I received 80 13 00 00 00 00 00 00 00 00 3B 9A 96 C0 10 31 FE 5D 00 64 05 7B 01 02 31 80 90 00 76 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
But still I am not sure what to do with Data field: ATR or how to form Command APDU
for PC_to_RDR_XfrBlock
command..
I think I am supposed to
Send command APDU wrapped into PC_to_RDR_XfrBlock command
now; can anyone help me with this?
EDIT 2: I figured out what ATR means and How to form command APDU.
But now I am supposed to switch protocol
The default Protocol is T=0. To set the T=1 protocol, a PTS (also known as PPS) must be sent to the card by the device As both T=0 and T=1 protocols are mandatory for the card, the basic PTS for protocol switching is mandatory for the card. The PTS can be used, as indicated in ISO/IEC 7816-3, to switch to higher baud rates than the default one proposed by the card in the ATR if any (TA(1) byte).
And I am not sure what this means and How to achieve this!!