简体   繁体   English

Xamarin/Android、智能卡、BulkTransfer

[英]Xamarin/Android, SmartCard, BulkTransfer

So, I have been tasked with writing code to work with smart cards.因此,我的任务是编写代码来处理智能卡。 The environment is C#.Net, Xamarin. The smart card reader (contact, not NFC) is attached to a Honeywell handheld device.环境是C#.Net,Xamarin。智能卡读卡器(接触式,非NFC)连接到霍尼韦尔手持设备上。 So, with the sparse pieces out there, and I can't just use some third-party library for a variety of reasons, I am tasked with it.因此,由于存在稀疏的部分,并且出于各种原因我不能只使用某些第三方库,因此我承担了它的任务。

Using Android.Hardware.Usb, I can get to the following.

UsbManager - created to context of application.
Scan connected USB devices to the handheld
Properly detecting the specific device.
Getting the configuration object.
Then to the interface
and finally finding the 3 endpoints.. Isochronous, Inbound and Outbound.
Request permission to use the specific device.
and finally Open the device for a UsbConnection handle.

So, now that the door is open to communicate, I need to obviously send a request outbound and get an answer back from the respective out and in endpoints.因此,既然沟通的大门是敞开的,我显然需要向外发送请求并从相应的出站和入站端点获得回复。

I can build the BulkTransfer of an APDU Command and get a response that 2 bytes are available to be received.我可以构建 APDU 命令的 BulkTransfer,并得到一个可以接收 2 个字节的响应。 I then try to do another BulkTransfer on the inbound port with an APDU Response, but it always fails with -1.然后我尝试使用 APDU 响应在入站端口上执行另一个 BulkTransfer,但它总是以 -1 失败。

I have seen other posts that discuss setting communication protocols, baud rates, etc but not sure if that is the issue or not.我看过其他讨论设置通信协议、波特率等的帖子,但不确定这是否是问题所在。 I am totally new to this granular level of serial/usb communications.我对这种细粒度的串行/USB 通信完全陌生。 Unsure of next steps to get the back/forth communication to the device.不确定与设备进行来回通信的后续步骤。

Here is an abbreviated summation of what I am doing to get connected to the device.这是我为连接到设备所做的工作的简要总结。 As for specific equipment, it is a Honeywell CN80 handheld scanner device with an attached CAC reader (also Honeywell).至于具体的设备,是一台Honeywell CN80手持扫描仪设备,附带CAC阅读器(也是Honeywell)。 As for what I am trying to do, just trying to call a verify card exists (or not).至于我想做什么,只是想调用验证卡存在(或不存在)。 I am not trying to actually send data to the device, just a command to inquire against the device and get a proper answer back.我并没有尝试将数据实际发送到设备,只是一个查询设备并获得正确答复的命令。

public void attemptingSmartCommunications()
{
   _myUsbManager = (UsbManager)_myMainActivity.GetSystemService(Context.UsbService);
   foreach (var d in _myUsbManager.DeviceList)
   {  // method checks the device for proper VID/PID
      var dev = d.Value;
      if (isExpectedDevice(dev))
      {
         for (var dc = 0; dc < dev.ConfigurationCount; dc++)
         {
            // SHOULD only be 1 configuration from what I have encountered.
            _myUsbConfiguration = dev.GetConfiguration(dc);

            for (var di = 0; di < _myUsbConfiguration.InterfaceCount; di++)
            {
               _myUsbInterface = _myUsbConfiguration.GetInterface(di);
               // Add on context of each endpoint
               for (var ep = 0; ep < _myUsbInterface.EndpointCount; ep++)
               {
                  var intEndpoint = _myUsbInterface.GetEndpoint(ep);

                  // which one do we need, store into their own respecive properties
                  // for in/out/isochronous
                  switch (intEndpoint.Address.ToString())
                  {
                     case "XferIsochronous":
                        // Control pipe for communication
                        _myIsochronousEndpoint = intEndpoint;
                        break;

                     case "130":
                        // Read IN FROM the USB Device with response
                        _myInEndpoint = intEndpoint;
                        break;

                     case "131":
                        // Write OUT TO the USB Device with command/request
                        _myOutEndpoint = intEndpoint;
                        break;

                  }
               }

               // now, I have the endpoints to request send and read back, make sure permission
               if( _myUsbManager.HasPermission(_myUsbDevice))
               {
                  myConnection = _myUsbManager.OpenDevice(_myUsbDevice);
                  var apdu = MyStaticSmartCardAPDUCommand;
                  // prepares the 4-byte request of CLA, INS, P1, P2 (no data in request)
                  var byteBuffer = apdu.CommandAsBytes(); 
                  var bufferLen = byteBuffer.Length;
                  var resultBytes = _myUsbDeviceConnection.BulkTransfer(_myOutEndpoint, byteBuffer, bufferLen, 2000);
                  // I get indication of 2 byte response
                  if( resultBytes > 0 )
                  {
                     // default buffer prepared with 4 bytes.  SW1, SW2 + 2 expected bytes
                     var apduResp = new APDUResponse(resultBytes);
                     byteBuffer = apduResp.GetResponseBuffer();
                     var responseStatus = _myUsbDeviceConnection.BulkTransfer(_myInEndpoint, byteBuffer, byteBuffer.Length, 3000);

                     // HERE is where it always fails.  
                     // Am I on the right track?  Completely out of it?
                  }
               }
            }
         }
      }
   }
}

(Wanted to write a comment, but it got quite long...) (本来想写评论的,但是写的太长了……)

Technically there are two possibilities, without using the drivers from the manufacturer:从技术上讲,有两种可能性,无需使用制造商的驱动程序:

  1. The reader uses standard USB CCID protocol .读写器采用标准的USB CCID协议 Then you need to implement that protocol in your software.然后您需要在您的软件中实现该协议。 The protocol is describedhere .该协议在此处描述。 There is a open source implementation libccid that you could use as a reference.有一个开源实现libccid ,您可以将其用作参考。

  2. Reader uses some proprietary protocol .阅读器使用一些专有协议 Then you need to get the protocol description from the vendor and implement it.然后你需要从供应商那里得到协议描述并实现它。

To differentiate between the two, refer to the reader specifications and/or check it's USB descriptors.要区分两者,请参阅阅读器规格和/或检查它的 USB 描述符。 You may also want to have a look here and here .您可能还想看看这里这里


Some additional (random) notes:一些额外的(随机)注释:

  • Readers using a proprietary protocol usually emulate a USB serial port.使用专有协议的读者通常会模拟一个 USB 串口。 If that is the case then it is meaningless to communicate with the reader over raw USB -- use this serial port instead.如果是这种情况,那么通过原始 USB 与读者通信是没有意义的——改用这个串行端口。

  • I suppose that reader vendor provides some Android drivers for this reader.我想阅读器供应商为此阅读器提供了一些 Android 驱动程序。 I do not know your reasons for not using them but you should.我不知道您不使用它们的原因,但您应该这样做。 Java code should be callable from Xamarin using a bindings library . Java 代码应该可以使用绑定库从 Xamarin 调用。 For native libraries, use P/Invoke (and Xamarin specific documentation ).对于本机库,请使用P/Invoke (和 Xamarin 特定文档)。

  • If some system-level smartcard API is available (eg winscard) then use it (using eg pcsc-sharp if possible).如果某些系统级智能卡 API 可用(例如 winscard),则使用它(如果可能,使用例如pcsc-sharp )。

  • What you do in your code is that you send a raw command-APDU to the USB endpoint and expect a response-APDU as a response.您在代码中所做的是将原始命令 APDU 发送到 USB 端点,并期望响应 APDU 作为响应。 You will definitely need to wrap the command APDU to a protocol specific format (which one depends on the reader).您肯定需要将命令 APDU 包装为特定于协议的格式(具体格式取决于读者)。


Disclaimer: I am no Xamarin expert so please do validate my thoughts.免责声明:我不是 Xamarin 专家所以请验证我的想法。

Good luck with your project!祝你的项目好运!


EDIT> You may also find those posts interesting: 1 , 2编辑> 您可能还会发现这些帖子很有趣: 1 , 2


EDIT2> There is a PoC javascript CCID implementation that you might find easier to follow. EDIT2> 有一个PoC javascript CCID 实现,您可能会发现它更容易理解。

It is also very revealing to see how an official driver communicates with the reader using Wireshark that has a CCID dissector .看看官方驱动程序如何使用具有CCID 解析器Wireshark与读者通信也很有启发性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM