How to read a smart card / microprocessor card using a smart card reader in Android software

Recently, I have been working with smart cards that contain some information, and what I'm trying to achieve here is to extract this data from this smart card using a smart card reader using any Android smartphone. I use a HID OMNIKEY 3021 USB smart card reader that will read this card (And I know that this reader works with these cards through Windows applications because I personally checked it)

Now Android provides a USB Host that allows you to read any USB host supported by Android smartphones.

And I'm trying to use these classes provided by the USB host to access 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 when I receive UsbDevice device, which gives information about the device, for 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 one UsbDevice deviceto extract data and data from a map, but I cannot do this, and I have not found a useful message about this.

I know that I need to use UsbInterface, UsbEndpoint, UsbDeviceConnection, to get what I want from the map, but I can not do it.

Also, I cannot find any samples or such things for them. Can someone point me in the right direction?

Sorry for the long post and thanks in Advance :)

: -. , CCID, CCID USB.

, :

        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 type : " + ep.getType() + " endpoint 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);
                }
            }
        }

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 , : ATR Command APDU PC_to_RDR_XfrBlock.

,

APDU, PC_to_RDR_XfrBlock

; - ?

2: , ATR APDU.

T = 0. T = 1, PTS ( PPS) ​​ T = 0 T = 1 , PTS . PTS , ISO/IEC 7816-3, , , ATR, ( (1) ).

, !!

+4
2

- USB USB CCID. , , ( ). . - Android USB ( ) , .

+1

- , , , ( noobs , , , ): -, USB Host API - -.

, , :

    //Allows you to enumerate and communicate with connected USB devices.
    UsbManager mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
    //Explicitly asking for permission
    final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
    PendingIntent mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
    HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();

    UsbDevice device = deviceList.get("//the device you want to work with");
    if (device != null) {
        mUsbManager.requestPermission(device, mPermissionIntent);
    }

, java package javax.smarcard, Android, , , / APDU ( -).

, ,

APDU ( -) APDU .

. :

UsbEndpoint epOut = null, epIn = null;
UsbInterface usbInterface;

UsbDeviceConnection connection = mUsbManager.openDevice(device);

        for (int i = 0; i < device.getInterfaceCount(); i++) {
            usbInterface = device.getInterface(i);
            connection.claimInterface(usbInterface, true);

            for (int j = 0; j < usbInterface.getEndpointCount(); j++) {
                UsbEndpoint ep = usbInterface.getEndpoint(j);

                if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                    if (ep.getDirection() == UsbConstants.USB_DIR_OUT) {
                        // from host to device
                        epOut = ep;

                    } else if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
                        // from device to host
                        epIn = ep;
                    }
                }
            }
        }

APDU APDU:

. :

public void write(UsbDeviceConnection connection, UsbEndpoint epOut, byte[] command) {
    result = new StringBuilder();
    connection.bulkTransfer(epOut, command, command.length, TIMEOUT);
    //For Printing logs you can use result variable
    for (byte bb : command) {
        result.append(String.format(" %02X ", bb));
    }
}

/ . :

public int read(UsbDeviceConnection connection, UsbEndpoint epIn) {
result = new StringBuilder();
final byte[] buffer = new byte[epIn.getMaxPacketSize()];
int byteCount = 0;
byteCount = connection.bulkTransfer(epIn, buffer, buffer.length, TIMEOUT);

    //For Printing logs you can use result variable
    if (byteCount >= 0) {
        for (byte bb : buffer) {
            result.append(String.format(" %02X ", bb));
        }

        //Buffer received was : result.toString()
    } else {
        //Something went wrong as count was : " + byteCount
    }

    return byteCount;
}

, , :

PC_to_RDR_IccPowerOn, .

, 6.1.1 USB- doc .

, : 62000000000000000000 :

write(connection, epOut, "62000000000000000000");

, APDU, , :

read(connection, epIn);

-

80 18000000 00 00 00 00 00 3BBF11008131FE45455041000000000000000000000000F1

, , result read() , Data field: ATR RDR_to_PC_DataBlock

/ , ATR, , , T0 T1, TA (1), FI Index into clock conversion factor table DI Index into Baud rate adjustment factor table ..

ATR.

, T0 - T1, PPS/PTS , PC_to_RDR_SetParameters ( 6.1.7 .

PPS/PTS T0 T1 : "61 00000007 00 00 01 0000 9610005D00FE00".

, : "82 07000000 00 00 00 00 01 96 10 00 5D 00 FE 00". RDR_to_PC_Parameters ( 6.2.3 )

. 6.1.7 CCID. , , ATR, write(), read().

PC_to_RDR_XfrBlock write(), read() . no btyes, read().

, .

0

Source: https://habr.com/ru/post/1681446/


All Articles