Android Question B4A and Smart Card reader

Kevin Hartin

Active Member
Licensed User
I have an opportunity to build an app for the Samoan tax authority that is a standalone Simple POS/Register but it needs to interface with a Smart Card reader. This is to be a very low cost solution for village shops where internet connections are less reliable so it will be a standalone device to "fiscalize" invoices for Tax office compliance. Currently there is a Free alternative that communicates with a central server over the internet to do this, but without a reliable internet connection the shop will be non-compliant and face either very expensive alternate solutions or fines.

I have seen another thread that uses the headphone jack to read a Square Card Reader [ https://www.b4x.com/android/forum/threads/read-data-from-headset-jack.10678/#post-143734 ] but I am looking at a Bluetooth unit from Advanced Card Systems that has Android and IOS compatibility [ ACR3901U-S1 ] due to the mechanical issues associated with mounting a device directly to a phone or tablet using a headphone jack or USB connection. [ https://www.acs.com.hk/download-manual/7330/REF-ACR3901U-S1-1.10.pdf ]

The app will need to communicate with the Smart Card using APDU commands using T1 protocol in order to sign the invoice using a stored certificate on the smart card.

Is this something that the various Bluetooth and Serial libraries can handle?

Thanks,
Kev
 

zmrcic

Member
Licensed User
Longtime User
hi...
i'm a little late, i hope not too late :)

only started with CCID, but I think I can put you in the right direction. So, I have managed to read data from the smart card using Omnikey 3x21 reader(+otg cable). Communication is based on APDU commands, posting them here can not help you since every card is different. first, you need to send to reader power_on command or PC_to_RDR_IccPowerOn(search google) like this
62 00000000 00 00 00 0000
msg type(62 power on, 61 power off, 6f read data....)
next is msg length(LSB)
next slot number
next command number(increment for each command....)
next power.....

try this and you will get ATR(hex string explaining your card...protocol, type....), the bold part
response:
801800000000000000003BBF11A28131F2354550B3000000000000000000000000
now, every command and response has special parts, defined in protocol(length, checksum...), to long to elaborate here....
next command, I guess will be 6F - reading data, can be obtained using Wireshark or a similar app.

since you have ACR3901U-S1, I have to admit that I'm stuck there, although they published their protocol. they use T=1, and there is a special way(don't know what) of "packing" APDU in command for T=1. If someone can help us both, now is the time.
 
Upvote 0

Kevin Hartin

Active Member
Licensed User
hi...
i'm a little late, i hope not too late :)

only started with CCID, but I think I can put you in the right direction. So, I have managed to read data from the smart card using Omnikey 3x21 reader(+otg cable). Communication is based on APDU commands, posting them here can not help you since every card is different. first, you need to send to reader power_on command or PC_to_RDR_IccPowerOn(search google) like this
62 00000000 00 00 00 0000
msg type(62 power on, 61 power off, 6f read data....)
next is msg length(LSB)
next slot number
next command number(increment for each command....)
next power.....

try this and you will get ATR(hex string explaining your card...protocol, type....), the bold part
response:
801800000000000000003BBF11A28131F2354550B3000000000000000000000000
now, every command and response has special parts, defined in protocol(length, checksum...), to long to elaborate here....
next command, I guess will be 6F - reading data, can be obtained using Wireshark or a similar app.

since you have ACR3901U-S1, I have to admit that I'm stuck there, although they published their protocol. they use T=1, and there is a special way(don't know what) of "packing" APDU in command for T=1. If someone can help us both, now is the time.
Thanks zmrcic,

Never too late... I took a leap of faith and ordered a sample BT Card Reader and have committed to this project now. I have also ordered a sample of an integrated unit with printer, smartcard reader and a 5 inch Android phone. The manufacturer claims to have a SDK, so hopefully there will be some clues in there too...
[ps.png
 
Upvote 0

zmrcic

Member
Licensed User
Longtime User
following my reply, I have managed to read data using TPDU commands.
but the new problem occurred


B4X:
    msg= b.HexToBytes(("62 00000000 00 00 02 0000").Replace(" ",""))
    SendOutRequest("Msg",  msg,  124)
    SendInRequest(MSG_READ,  124)


    msg= b.HexToBytes(("6F" & somemessage)
    SendOutRequest("Msg",  msg,  124)
    SendInRequest(MSG_READ,  124)
....
'code from USB project, downloaded here from B4A site
Sub SendOutRequest(Name As String, Data() As Byte, Length As Int)
    Dim request As UsbRequest
    request = GetRequest(   True )
    request.Name = Name
    request.Queue(  Data, Data.Length)
End Sub
Sub SendInRequest(Name As String, Length As Int)
    Dim request As UsbRequest
    request = GetRequest(False)
    request.Name = Name
    Dim Data(Length) As Byte
    request.Queue(Data, Data.Length)
End Sub

Sub Connection_NewData (Request As UsbRequest, InDirection As Boolean)
    Dim b As ByteConverter
    Try
       
        Log(b.HexFromBytes(Request.Buffer ))
       
    Catch
        Log(LastException)
    End Try
    If connection.IsInitialized = False Then Return
    If InDirection = False Then
        ReleaseRequest(Request, OutRequests)
        connection.ContinueListening
        Return
    End If

    connection.ContinueListening
End Sub


in connection_newData I get this
'for 62, poweron
801900000000010000003BF0940A0081318A4380318065B0C502C123120FFF8290007900....that is ATR, that is OK
'for 6F, data I get shorten message ending with CRC, not the full message

I have tried connection.BulkTransfer also, but the response for 6F are always shorter than expected(if using APDU(android) or Wireshark(win)
I get "full" response so I know what to expect)

it's like card has some internal buffer, with max size...
how to overcome this? what am I doing wrong?

just analyzed data from T=0 and T=1

780E4F02200000001865564C2D3030317182013C80033132339E3310224FF055 9000
00 20 20
780E4F02200000001865564C2D3030317182013C80033132339E3310224FF055 CRC

now I get this 00 2020 as an extra...
but what to do with it? it's hex so 32 dec....it is just the length of the message without CRC
 
Last edited:
Upvote 0

zmrcic

Member
Licensed User
Longtime User
me again...
it was just my mistake, I followed all commands and get it to work. strange, but after command for setting parameters for T=1, next command is still in APDU, not merged in TPDU, like it is supposed to be.
I noticed that by looking at Wireshark log. why? I don't know. I don't know what that is that command doing since I don't have protocol for card I'm working on.
not much use for anybody else I guess, except for advice to check twice. and then recheck. twice also.
If someone is interested in merging APDU in TPDU and that sort of thing, let them post here and I will publish code...
 
Upvote 0

Kevin Hartin

Active Member
Licensed User
Hey @zmrcic , I am very interested to see any code that manages to talk to the smartcard. I am about to start playing with a wired USB reader ahead of my samples arriving.

Kev
 
Upvote 0

zmrcic

Member
Licensed User
Longtime User
sorry because of my poor knowledge of CCID, but I had to make this in a hury.
OK, communications is based on APDU commands. This are HEX commands dependent of your card and data stored in it.
APDU:
1. first you should start with command POWER_OF
63 00000000 XX YY ZZ0000
00000000is len of data(0 for 63)
XX register(should be 00)
YY global counter(since you strat with power_off is should be 00, but it does not matter)
ZZ power select(00 automatic, but you should check in some sniffer)
0000 future use

2. then POwer_ON
62 00000000 XX YY ZZ0000
same description....
response should be ATR. there are many sites you can parse this data(https://smartcard-atr.apdu.fr/) to see it's specs.


3. DATA
6F XXXXXX ZZ QQ YY WWWW DATA
xxxxxx command length (lsb first)
ZZ register(? should be 00)
QQ counter commands
YY not sure :)
wwww level, for normal length commands should be 0000
DATA hex as is(depends on your card)

response
80 XXXXXX ZZ QQ YY WWWW DATA 9000
params are same as in request(3. DATA) excluding WWWW, that is error if any

that's all.
problem emerges in TPDU

DATA block if T=1 should be
XX YY QQ ZZ CRC
xx node addressing(00)
yy toggle 00 and 40 for every other command, PCB in documentation
QQ len of ZZ
CRC of all data including PCB
so now data request should be
6F XXXXXX ZZ QQ YY WWWW XX YY QQ ZZ CRC

as for code, you should use https://www.b4x.com/android/forum/threads/android-usb-host-tutorial-adbtest.11289/#content
I used bulktransfer, and startlistening, sow no difference.

there are APDU sniffers, I used https://www.mysmartlogon.com/knowledge-base/trace-apdu-on-windows/
 
Upvote 0

Kevin Hartin

Active Member
Licensed User
I have got the Android recognising the Smartcard reader and changed the Class to 11 and SubClass to 0 and seem to start a connection.

I log the following, recognising the in and out Endpoints on address 1 and 130 respectively;
Logs:
USBdevices: (UsbDevice) UsbDevice[mName=/dev/bus/usb/001/004,mVendorId=2278,mProductId=13367,mClass=0,mSubclass=0,mProtocol=0,mManufacturerName=Gemalto,mProductName=USB SmartCard Reader,mVersion=2.0,mSerialNumber=54CC069A,mConfigurations=[
UsbConfiguration[mId=1,mName=null,mAttributes=160,mMaxPower=25,mInterfaces=[
UsbInterface[mId=0,mAlternateSetting=0,mName=null,mClass=11,mSubclass=0,mProtocol=0,mEndpoints=[
UsbEndpoint[mAddress=1,mAttributes=2,mMaxPacketSize=64,mInterval=0]
UsbEndpoint[mAddress=130,mAttributes=2,mMaxPacketSize=64,mInterval=0]
UsbEndpoint[mAddress=131,mAttributes=3,mMaxPacketSize=8,mInterval=16]]]]
Class|SubClass: 11|0
EndPoint Address: 1|Attributes: 2|Direction: 0|EndpointNumber: 1|Interval: 0|MaxPacketSize: 64|Type: 2   'USB_ENDPOINT_XFER_BULK  USB_DIR_OUT'
EndPoint Address: 130|Attributes: 2|Direction: 128|EndpointNumber: 2|Interval: 0|MaxPacketSize: 64|Type: 2   'USB_ENDPOINT_XFER_BULK  USB_DIR_IN'
EndPoint Address: 131|Attributes: 3|Direction: 128|EndpointNumber: 3|Interval: 16|MaxPacketSize: 8|Type: 3   'USB_ENDPOINT_XFER_INT  USB_DIR_IN'
Starting connection
However, I am confused as to how I am supposed to send an APDU command to the Smartcard. I think it is the SendOutRequest sub, but The other Subs such as DispatchMessage, CreateMessage, etc. are clouding my understanding of the process

For instance, my first action is to Verify PIN by sending
APDU Commands:
    Dim APDU_PIN_VERIFY As String = "88 11 04 00 04 01 09 06 03"
    msg = bc.HexToBytes((APDU_PIN_VERIFY).Replace(" ",""))
    SendOutRequest("APDU_PIN_VERIFY", msg, msg.Length)

or to Get the Version of the Secure Element
APDU Commands:
    Dim APDU_GET_SE_VERSION As String = "88 09 04 00 00"
    msg = bc.HexToBytes((APDU_GET_SE_VERSION).Replace(" ",""))
    SendOutRequest("APDU_GET_SE_VERSION", msg, msg.Length)

It seems to send it OK, but what happens then? How can I get hold of the response? I figure it has something to do with Connection_NewData but the presence of SendInRequest makes no sense to me.

Kev
 
Upvote 0

zmrcic

Member
Licensed User
Longtime User
You have to call
B4X:
SendInRequest(MSG_READ,  124)
after sendoutrequest. Then newdata will fire.
also maybe you should do this, I found no difference in performance, although this is not asynch. I have 3 type of cards, and it is working just fine.

B4X:
Dim b As ByteConverter

bytes = b.HexToBytes(("63 00 00 00 00 00 "& iCounterCommands &" 000000").Replace(" ",""))
connection.BulkTransfer(outEndpoint,bytes,bytes.Length,500)
dataTransferred=connection.BulkTransfer(inEndpoint,responseBuffer,responseBuffer.Length,500)
sResponse=b.HexFromBytes(responseBuffer)
 
Upvote 0
Top