问题读取智能卡

Posted

技术标签:

【中文标题】问题读取智能卡【英文标题】:Issue reading smart card 【发布时间】:2014-05-29 09:51:07 【问题描述】:

我有一个阅读器,它的文档几乎与这个完全相同:http://www.jinmuyu.com/download/JMY680A_EN.pdf 主要区别在于,我的读者声称它还支持 B 型卡。

我有三张 ISO 14443 卡,我连续测试,代码如下:

   byte[] rs = null;

   Thread.Sleep(500);

   // Set module Idle 
   Random r = new Random();
   byte rInt = (byte) r.Next(0, 255);
   rs = send(new byte[]  0x12, rInt );
   if (rs[1] == 0xED)
       throw new Exception("Failed set idle");

   Thread.Sleep(500);

   //// Request B
   //rs = send(new byte[]  0x60, 0x00, 0x00 );
   //if (rs[1] == 0x9F)
   //    throw new Exception("Failed card requestB"); 

   // RequestA
   rs = send(new byte[]  0x20, 0x00 );
   if (rs[1] == 0xDF)
       throw new Exception("Failed card requestA");

    // Reset cardA
    rs = send(new byte[]  0x30 );
    if(rs[1] == 0xCF)
        throw new Exception("Failed card reset");

     // Do other work, Send some APDU to card, etc.
     // ........


     // Exit program

大多数情况下,此代码适用于所有三张卡。 但是,有时,当我将其中一张卡靠近读卡器时,卡请求 A(RequestA 呼叫) 通话失败。然后这张卡总是会失败,直到我给读卡器带来一张新卡。 有谁知道是什么原因造成的?也许我在通话之间需要一些延迟?或者在调用RequestA之前需要调用其他一些(ISO14443相关)函数?

send 是使用SerialPort 类实现的方法。方式如下:

    在每次调用 send 时,都会创建新的 SerialPort 对象 在上面创建的对象上调用Open WriteRead 一些数据 在此方法实例中创建的对象上使用Close 关闭连接

顺便说一句。这是其中一张卡(读卡器失败一次)对 RequestA 命令的成功响应:

ID                 | ATQ     | SAK
0xe1 0x8f 0x68 0xe6 0x04 0x00 0x28

【问题讨论】:

“失败”是什么意思?卡回答错误,或者您根本没有回答,或者您有来自串行的通信错误? @LorenzoDematté:我的意思是失败时抛出异常。根据文档,如果卡返回0xDF作为第二个字节,则表示失败。 我明白了。这可能是很多事情。 0x20 命令似乎特定于您的读卡器,它可能和 ISO / Mifare 命令选择(激活)卡。 Iso 和 desfire 命令有一些不同的错误代码,具体取决于错误,但是......似乎只有你一个人知道读者告诉(或不告诉)你的内容 这是“廉价”阅读器的一个问题:他们实现自己的协议,然后你必须处理你得到的东西。该错误可能是卡错误,通信错误,等等。等等:我看到了你的编辑。这是您从其中一张卡片中得到的“正确”响应吗? 哦,好的。 Mifare 经典是......奇怪的东西。几乎是 A 型,但有自己的一套命令。但通常相当可靠。但我离题了(它们是我所知道的唯一具有 4 字节 UID 的卡)。当你失败后再次尝试时会发生什么?读卡器是否在连续轮询(它会再次尝试选择卡吗?)。您必须考虑到 PICC 中的传输可能非常不可靠,因此在失败前尝试 2/3 次是很正常的。 【参考方案1】:

我无法确定您的代码存在什么问题,但是当连接出错且未打开新连接时,这似乎是一个问题。因为 SerialPort 是您需要处理处置的硬件资源,所以 SerialPort 可能实现 IDisposable,这意味着您可以使用确保连接已关闭和处置。带一张新卡可能会这样做,但是当您使用同一张卡时,您仍然使用处于故障状态的串行端口。

【讨论】:

请在下面查看我对 jhonnash 的评论。通过第二次将卡带到读卡器 - 这发生在我重新启动程序并从头开始运行上面的代码之后 - 你认为在这种情况下 Dispose 仍然是一个问题吗? 是的,它可以,串行端口可能有一些未正确重置的状态。看到它实现了 IDisposable,如果是这样,请使用 using 块。 我对 C# 有点陌生。我发现了这个:msdn.microsoft.com/en-us/library/3cc9y48w.aspx 你建议我在SerialPort.Close() 方法之后调用它? 还要注意如果我在代码中抛出 Failed card requestA 异常 - 到那时端口应该在之前的send 调用中关闭,但我会检查你的建议【参考方案2】:

当您将 cardA 放在读卡器附近时,它会失败。之后,每次将 cardA 靠近读卡器时,它都会失败。

我不确定,但我猜当它失败时,字节数组rs[1] 的第二个位置包含失败代码。因此,此后每次将 cardA 靠近读卡器时,它都会失败,因为字节数组的第 2 位置可能具有先前的值。

所以,请尝试清除字节数组,这可能会解决您的问题。

【讨论】:

第二次将同一张卡带到读卡器,我的意思是当我退出程序并再次运行它时 - 那么 rs 不能有旧值,对吗? (因为你可以看到没有循环 - 所以我只能在重新启动程序时将卡带到读卡器) 它会在之后的 3 到 4 次试验中接受它,还是一旦失败它就永远不会用同一张卡成功的场景......!!! 同一张卡总是一旦被阻塞一次就出问题了,如果我换卡就可以了... 我已经回答了这个问题:) ps。当我 更换 卡时,它会起作用,而且如果我现在使用旧卡 - 它被阻塞,它也会起作用...... 简报文件后;你有没有按照ISO1443去按照5.2.26 ISO14443-4 TYPE-A card reset(RATS)中定义的RATS Process去呢

以上是关于问题读取智能卡的主要内容,如果未能解决你的问题,请参考以下文章

使用 Javascript 读取智能卡证书

读取智能卡上的证书

使用 pkcs#11 从智能卡读取文本文件

智能卡读卡器,无法读取某些卡

从智能卡读取数据 (CNS/CNR)

使用 C# 从 PKI 智能卡读取证书