对于那些开始使用证卡打印机( Evolis Primacy和Smart-51 )和NFC编码的卡(如Mifare Classic和Mifare DESFire EV2 )的用户,本文将非常有用。 在第一部分中,我们将描述使用证卡打印机的总体印象以及我们必须面对的问题。 在第二部分中,计划显示更多实用的部分:代码,操作技巧。
1.任务如何出现
我们正在开发一种电子票务系统,其中包括使用NFC卡。 每个NFC卡都有一个用户友好的编号和一个单独的ID 。 该号码必须印在卡上,并且ID被写入NFC芯片中。 任务之一是建立稳定的运输卡生产。
在第一阶段,以最简单的方式解决了问题-由NFC卡提供商打印带有数字的打印件,并由我们使用台式机,专用软件和人员记录ID。 从供应商处收到卡后,需要在系统中注册卡并将ID和编号相互关联。 作为台式机阅读器,我们使用了Z-2阅读器[1]。
该过程如下所示:
- 操作员拿起卡。 卡号已经打印在卡上,但是需要在系统中注册卡并在NFC芯片中记录ID
- 操作员将卡放在Z-2读卡器上,并通过手动输入卡号在电子票务系统中注册该卡号。 为了进行绑定和注册,将进行HTTPS API调用
- 操作员取下一张卡,然后再次进行。
一种简单快捷的解决方案,但有一个小缺点。 人为因素的影响会生成幻像卡,其幻影卡上印刷的编号与系统数据库中的链接ID- 编号不对应。
因此,出现了以下有关该问题的陈述:必须自动打印系统号 ,写下ID并在系统中自动注册NFC卡,而无需人工干预。
在本文中,我们将描述我们使用的所有设备以及所有陷阱。 最后,我们将尝试说哪种设备对我们来说更好。
1.1。 NFC卡
我们审查了NFC卡MIFARE Classic 1K和MIFARE DESFire EV2。 MIFARE Classic是最常见且最容易复制的。 但是,它们在大学和公共交通等地方仍然很受欢迎。 处理现金流量时,需要一种更可靠的解决方案。 因此,MIFARE DESFire EV2卡成为了替代方案。 这是最后一种使用DES,TDES(2KTDES,3KTDES),AES加密算法的卡类型[2,3]。 简要介绍每张地图:
MIFARE经典
存储卡是一个扇区并且块。 内存的第一个单位是扇区。 地图上有16个扇区,每个扇区有4个数据块。 每个块的内存为16个字节。 要读取和/或写入数据,读取器必须登录到该扇区。 每个扇区中有一个特殊的块,即拖车块,用于存储密钥。 首先,要与该部门合作,您需要登录到拖车块。 尾部块还存储16个字节:每个密钥类型A 6个字节,每个访问权限4个字节,每个密钥类型B 6个字节。
图1 [4]清楚地显示了扇区,块和键。

图1-Mifare Classic中的存储设备
MIFARE DESFire
卡设备类似于文件系统。 该卡包括应用程序和文件。 在地图上有一个ID为000000(0x00、0x00、0x00)的主应用程序(应用程序)。 在主应用程序内部,您可以创建一个新应用程序并在其中创建数据文件。
DESFire卡的特性如图2所示[5]。 每个应用程序都为应用程序文件分配了自己的访问密钥。

图2-Mifare DESFire卡的特性
1.2。 打印机作为解决方案
为了完成此任务,使用了特殊的证卡打印机。 目前,有许多不同的公司提供这些打印机。 例如:Evolis,Smart,Zebra,Datacard等。我们使用了Evolis Primacy和Smart-51打印机。 这些打印机的工作中心有很多共同点:它们都使用盒式磁带进行打印,并且具有类似的清洁原理。 也有区别-不同的NFC编码器。 两种打印机都可以根据客户需要进行补充或更换。
NFC卡的编程器依赖于DESFire的标准ISO / IEC 14443A和ISO / IEC 7816-4,经典标准的ISO / IEC 14443 TypeA。 但是,根据制造商的不同,程序员可以根据标准接受本地命令,也可以将本地命令包装为特定于特定程序员的代码。 我们面临着另一个。
表1-Evolis Primacy和Smart-51的比较
2.实验
通常,使用打印机可以分为几个部分:与技术支持进行通信,研究卡与编码器的交互作用,进行打印。
2.1。 技术支持印象
由于我们需要编写自己的软件,因此与打印机的合作包括与技术支持之间的不断沟通。 在这两种情况下,我们都与我们国家和邻国的公司经销商进行了更多的交谈。
Evolis分销商几乎总是保持联系。 但是,几乎所有问题的具体情况表明有必要与Evolis代表进行沟通。 不幸的是,他们没有给我们他们的联系方式,而不得不通过分销商交换信息。 但是,这仅涉及印刷问题;在编码问题上,我们收到了Elyctis代表的邮件。 与Elyctis的直接通信大大简化了编码过程。 从技术上讲,我们立即相互了解,没有任何误解。 在有关Evolis Primacy的印刷和代码示例的情况下,交流有时陷入停顿。 基本上,负面印象是由于双面打印示例对我们不起作用而花了很长时间来证明的。 我获得了视频打印过程的录音,之后又有了Evolis的更多有用技巧。
Evolis最新的技术支持问题之一是如何通过以太网连接打印机。 目前,我们正在通过USB将打印机连接到笔记本电脑,如果有1-2台打印机,这是可以接受的。 答案还在等待中。 但是,已经从Elyctis收到一个答案,即他们的Evolis Primacy打印机的编码器不提供网络连接。
与Smart-51技术支持进行通信还归结为通过分销商与公司代表进行通信。 在一开始,一切都进行得很顺利。 当对Mifare DESFire之类的卡进行编码时,问题就开始了。 困难是由您在Internet上找不到的特定团队造成的。 因此,您仅需复制制造商提供的工作代码中的某些部分作为示例。 但是,漫不经心的复制并不能带来良好的效果。 结果,花了两个星期的时间向制造商解释该错误,制造商显然是坐在那一边,与系统的复杂程度不是很接近,而是随身携带了常规文档。 留下了不愉快的沉淀物,但是开始得很好。
通过发行商进行的沟通没有任何优点和缺点。 例如:
- 延迟响应,因为分销商方面的负责人可能忙于其他事情或休假。
- 当分销商在另一个国家/地区时,这些是额外的假期,因此不是工作日。 对于Smart-51,在3个国家的人员参与下进行了交流。
- 答复不转发。 响应文本将插入分发者发出的新信件中。 因此,有时附件丢失并且无法立即访问。
- 尚不确定您的消息是否已经到达制造商。
下表是与技术支持联系的字母数量。 基本上,Evolis和Smart的问题大致相同。 例如,“为什么打印不统一的颜色?您有C#或Java代码示例吗?” 以及一些更具体的问题,为什么某些东西无法按预期工作。
表2-具有技术支持的电子邮件数量的比较
2.2。 编码方式
通过APDU命令与阅读器进行通信。 APDU(应用协议数据单元)是用于卡和读取器之间通信的标准格式。 本文将介绍MIFARE Classic和MIFARE DESFire的基本APDU团队。
表3-APDU命令的格式
表4-APDU响应格式
在此处可以找到所有可能的响应代码的说明[6]。 可以在[7]找到一种用于与读卡器通信的设备。
简要的编码算法如下:
- 获取卡的UID。 这是一个唯一编号,由供应商闪烁,并且不会更改。
- 从每个扇区读取数据:
2.1使用默认密钥(0x00或0xFF)登录到扇区
2.2从三个数据块读取数据 - 如果读取的数据为空,则转到数据记录
3.1使用默认密钥(0x00或0xFF)登录到扇区
3.2将数据写入三个扇区数据块
3.3根据卡的UID创建一个新密钥
3.4用新密钥替换拖车块中的授权密钥。
2.2.1。 ly
Evolis打印机使用ELYCTIS CL阅读器 。 使用WinSCard库(C ++和C#)和jnasmartcardio(java),您可以轻松地与阅读器进行交互。 为了使用一个非常简单的界面快速创建软件,决定使用C#编写代码。 大多数情况下,我们的团队使用Java编写代码,这使向C#过渡的痛苦减轻。 Windows更适合使用打印机这一事实也支持C#。
下表显示了Elyctis阅读器接受的本机APDU命令的示例。
表5-Mifare Classic的APDU命令示例
确保像Mifare Classic这样的卡编码成功后,我们切换到DESFire的命令 。 通过参考文献[8],您可以找到带有说明的简单命令示例。 但是,在授权团队中,我们遇到了一种有趣的读者行为。 简而言之,读者本身具有完全授权。 事实证明,Elyctis技术支持为我们提供了一个特殊的固件,其中包括easyDESFire智能 。 仅需要确定阅读器使用哪种加密算法。 在我们的例子中是3DES。
在正常情况下,授权是通过交换多个消息来执行的。
- 我们发送用于授权的APDU命令: 0x90 0x0A 0x00 0x00 0x00 0x00 。
- 根据算法,由卡密钥编码的8个随机字节组成的数组会响应该命令;我们用RandBEnc表示它。
- 我们解密RandBEnc并向左移一个字节。 用RandBLeft表示结果。
- 我们在我们这边生成了一个8个随机字节的数组RandA 。
- 我们将RandA和RandBLeft分组 ,使用卡密钥进行加密,然后发送结果数组16字节。
- 我们得到会话密钥作为响应,从而登录到地图上的应用程序。
有关授权过程的更多详细信息,请参见[9]。 来自github的代码也非常有用[10]。
在编码期间,使用来自源的命令会出现问题[8]。 在Elyctis技术支持的帮助下,我们收到了适用于easyDESFire智能的必要命令。
在Elyctis上进行编码时,发现了读者的一个大问题 - 通信延迟 。 通常,信号不会到达读取器,因此有时需要多次发送同一命令。 此行为不太常见,但在发送打印命令时仍会注意到。 结果,所有命令的发送都会循环执行,直到成功执行为止。
2.2.2。 达利
制造商将其SDK与DUALi编码器一起使用。 在使用Mifare Classic的阶段,可以从分发者提供给我们的模板代码中获取读写命令。 示例包括C ++,Visual Basic,Java。 但是,可以仅在C ++中完全编译代码。 第一次请求C#代码的示例,我们被拒绝了,或者说,分发服务器没有一个。 我们的团队中没有自信的C ++程序员,因此编写所有代码会因为非常简单的事情而变得非常复杂。 例如:
- 处理数组
当将数组作为参数传递给函数时,我们没有传递数组的大小。 为了确定数组的长度,使用了sizeOf()函数。 但是,该函数始终返回大小为4的大小,而不管数组的实际大小如何。 没有立即记录此行为,因为某些数组的大小确实为4。 - 配置所有库
在安装所有必要的环境时,会经历很多痛苦。 我们也已经习惯了maven和apt(在Ubuntu上)。 我们的程序应该通过HTTP请求调用后端API,并在Base64中加密数据。 为此,决定使用libcurl和openssl库。 程序本身的编写在Microsoft Visual Studio环境中进行。 安装libcurl的时间最长。
SDK本身是一个用C ++编写的dll库。 多亏了该代码示例,我们相对较快地编写了一个与Mifare Classic卡进行交互的程序。 如上所述,DUALi的APDU命令非常具体,即前两个字节与Internet上的不匹配。 因此,我必须盲目地复制它们,因为从原则上讲,一切都会按预期进行。 问题始于DESFire卡的测试。
DUALi中用于DESFire的APDU命令的原理至少是可以理解的。 {CLA,INS}有两个字节,它们没有变化,实际上,它们说该命令用于DESFire之类的卡。 参数1和2也不会更改。 传输的数据已包含本机DESFire命令的一部分,即{INS,Data}字节。 大约一个星期以来,我们无法获得对简单命令(例如“选择应用程序”命令)的预期答案。 在代码的开头,我们保留了GetCardStatus命令的APDU执行,这不是DESFire的命令格式。 但是,她工作并发行了UID卡。 事实证明,在执行GetCardStatus之后,DESFire团队停止了工作。 这种疏忽是由我们的部队在与供应商进行了为期一周的对话之后确定的,没有导致任何后果。
在程序稳定运行一个月之后,我们需要用C#重写程序。 主要原因是设置CI。 C ++程序是使用Microsoft Visual Studio编译的。 我们所有的服务器都在Linux上运行,因此无法通过Windows启动docker和必需的Visual Studio ToolKit。 当然,您可以在Windows上构建虚拟机,并且仍然为C ++进行所有配置,但是我并不是真的想要。 反复要求制造商提供示例C#代码后,我们提供了一个示例。 您可以根据C ++接口示例中的方法定义自行编写,但事实证明并非所有功能都已描述。 该示例很有帮助,最后,我们用C#重写了程序并设置了CI。
2.3。 列印
乍看之下,打印似乎不会引起问题,因为首先使用的是打印打印机。 , , .
. , , .
2.3.1. Evolis Primacy
JSON , HTTP . Evolis Services Provider, . 8 :
- : , , . .
- 4-6, . . . . SDK, . .
:
.
.
. , . . , . . . , , , 3.

3 —
3 .
, . . QR-. , QR- . , , 4 6 .
, Evolis , Evolis Print Center, , , . .
2.3.2. Smart-51
, SmartID, . , Evolis. :
- , .
- , .
, . Smart-51. :
- , .
- , QR-
, User Manuals . , , .
2.3.3.
, . , , . . . , .
Evolis Primacy 100 , 0,76 . , 86 . Smart-51 100 , . , .
3.
. . . 17 . .

)

)
4 — : — , —
4.
NFC -. , .. . Smart-51 Evolis Primacy. Evolis , . Smart-51 . Smart-51 Evolis. , . Evolis Primacy , . . Smart-51 . , .
, .. . , .
参考文献
- https://ironlogic.ru/il.nsf/htm/ru_z2usb
- https://www.nxp.com/products/rfid-nfc/mifare-hf/mifare-desfire/mifare-desfire-ev2:MIFARE_DESFIRE_EV2_2K_8K
- https://www.nxp.com/docs/en/data-sheet/MF3DX2_MF3DHX2_SDS.pdf
- https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf
- https://www.nxp.com/docs/en/data-sheet/MF3DX2_MF3DHX2_SDS.pdf
- https://www.eftlab.com/knowledge-base/complete-list-of-apdu-responses/
- Advanced Card Systems Guide http://downloads.acs.com.hk/drivers/en/API-ACR122U-2.02.pdf
- Mifare Desfire communication example https://ridrix.wordpress.com/2009/09/19/mifare-desfire-communication-example/
- Mifare DESFire Data Sheet http://neteril.org/files/M075031_desfire.pdf
- GitHub DESFire https://github.com/EsupPortail/esup-nfc-tag-server/blob/master/src/main/java/nfcjlib/core/DESFireEV1.java