4. 安全元件通信协议:ISO 7816、ISO 14443、SPI/I2C 与 APDU 指令详解

通信协议,说白了就是安全元件(SE)跟外界对话的“语言”。你选错了协议,芯片再强也白搭。我这些年调试过的设备里,至少有三成因协议适配问题导致项目延期。今天咱们就把这几种主流协议掰开揉碎讲清楚。

4.1 接触式通信:ISO 7816

ISO 7816 是接触式智能卡的祖宗协议。你手里的银行卡、SIM 卡,用的就是它。它定义了物理接口、电气特性和传输协议。

4.1.1 物理接口

标准接触式接口有 8 个触点(C1~C8),但实际常用的就几个:

  • C1(VCC):供电,通常 5V、3V 或 1.8V
  • C2(RST):复位信号
  • C3(CLK):时钟信号,频率通常 1~5 MHz
  • C5(GND):地
  • C7(I/O):半双工数据线
经验之谈: 我遇到过不少工程师把 C4 和 C8 当成“没用”的引脚直接悬空。其实有些安全元件用这两个引脚做辅助功能,比如 RFU 或协议协商。建议你设计时至少留出测试点。

4.1.2 传输协议:T=0 与 T=1

ISO 7816-3 定义了两种传输协议:

特性 T=0(字符传输) T=1(块传输)
数据单位 单字节 数据块(含 CRC)
错误检测 奇偶校验 CRC + 重传机制
典型应用 SIM 卡、老式银行卡 Java Card、高端 SE
传输效率 较低 较高

我个人习惯优先选 T=1。为什么?T=0 的奇偶校验在强干扰环境下容易误判。之前有个项目在工业现场用 T=0,数据错得一塌糊涂,换成 T=1 后问题全解决了。

4.2 非接触式通信:ISO 14443

ISO 14443 定义了 13.56 MHz 的非接触式通信标准。你刷公交卡、用手机支付,背后都是它在工作。

4.2.1 四种类型

  • Type A:基于 Miller 编码和 ASK 调制。典型代表:MIFARE Classic。
  • Type B:基于 NRZ 编码和 BPSK 调制。典型代表:二代身份证。
  • Type C:索尼的 FeliCa 方案,日本市场主流。
  • Type D:ISO 15693 衍生,主要用于标签类应用。
关键参数: 通信距离通常 4~10 cm,数据传输速率 106 kbps ~ 848 kbps。别指望它能像 WiFi 一样传几十米,这是物理限制。

4.2.2 防冲突机制

非接触式通信有个麻烦:多张卡同时靠近怎么办?ISO 14443 用“位级防冲突”解决。读卡器发一个请求,所有卡片回复自己的 UID。如果发生冲突(同一比特位有 0 和 1),读卡器就能识别出多张卡的存在,然后逐个选择。

嗯,这里要注意:防冲突算法在 Type A 和 Type B 里实现方式不同。Type A 用“比特掩码”法,Type B 用“时隙”法。我建议你在做多卡共存场景时,优先用 Type B 的时隙法,它在高并发下更稳定。

4.3 直连模式:SPI 与 I2C

物联网设备里,安全元件经常直接焊在 PCB 上,不需要插拔。这时候 SPI 和 I2C 就派上用场了。

4.3.1 SPI 模式

  • 全双工:MOSI 和 MISO 同时传数据
  • 速率高:通常 10~50 MHz,适合大数据量传输
  • 引脚多:至少 4 根线(SCLK、MOSI、MISO、CS)
  • 典型场景:安全固件升级、批量证书写入

4.3.2 I2C 模式

  • 半双工:SDA 线双向传输
  • 速率低:标准 100 kHz,快速 400 kHz
  • 引脚少:只需 2 根线(SCL、SDA)
  • 典型场景:传感器数据签名、密钥协商
对比项 SPI I2C
引脚数 4+ 2
速率 高(10~50 MHz) 低(100~400 kHz)
多设备支持 片选线控制 地址寻址
功耗 较高 较低
避坑指南: 我曾经在一个低功耗项目里选了 SPI 直连 SE,结果发现 SPI 在睡眠模式下漏电严重。后来换成 I2C,待机电流从 50 µA 降到了 2 µA。如果你的设备靠电池供电,优先考虑 I2C。

4.4 APDU 指令格式详解

APDU(Application Protocol Data Unit)是安全元件通信的“通用语言”。不管底层是 7816、14443 还是 SPI,上层指令都是 APDU。

4.4.1 命令 APDU(C-APDU)

主机发给 SE 的指令,结构如下:

| CLA | INS | P1 | P2 | Lc | Data | Le |
| 1B  | 1B  | 1B | 1B | 1B  | Lc B | 1B |
  • CLA:指令类别,比如 0x00 表示 ISO 标准指令
  • INS:指令码,比如 0xA4 表示 SELECT FILE
  • P1/P2:参数,用于指定操作细节
  • Lc:Data 字段的长度(可为 0)
  • Data:要发送的数据
  • Le:期望返回的数据长度(可为 0)

4.4.2 响应 APDU(R-APDU)

SE 返回给主机的应答:

| Data | SW1 | SW2 |
| Le B | 1B  | 1B  |
  • Data:返回的数据(长度由 Le 决定)
  • SW1/SW2:状态字,表示执行结果

4.4.3 常见状态字

SW1 SW2 含义
0x90 0x00 操作成功
0x61 0xXX 还有 XX 字节数据可读
0x6A 0x82 文件未找到
0x69 0x85 安全条件不满足
0x6E 0x00 CLA 不支持
调试技巧: 我习惯在代码里把 SW1/SW2 直接打印成十六进制。比如收到 0x6985,一眼就知道是“安全条件不满足”——八成是没先验证 PIN 就尝试签名了。别问我怎么知道的,调过的坑多了自然就熟了。

4.4.4 一个完整的 APDU 交互示例

假设我们要选择安全元件里的“密钥文件”:

// 命令:SELECT FILE
// CLA=0x00, INS=0xA4, P1=0x00, P2=0x0C
// Lc=0x02, Data=0x3F 0x00 (MF 主文件)
// Le=0x00

发送: 00 A4 00 0C 02 3F 00 00

// 响应:成功
接收: 90 00

你想想看,整个交互就这么简单。但实际项目里,APDU 链式调用、大数据分片传输才是真正的难点。我建议你一开始就封装好 APDU 收发函数,别在业务代码里拼字节流,否则后期维护会想哭。

4.5 本章知识体系总览

下面这张图帮你理清四种通信协议的关系和适用场景:

安全元件通信协议知识体系 安全元件通信协议知识体系 安全元件通信协议 ISO 7816(接触式) ISO 14443(非接触式) SPI 直连模式 I2C 直连模式 T=0 / T=1 传输协议 8 触点物理接口 Type A / B / C / D 防冲突机制 全双工 / 高速 4 线制(SCLK/MOSI/MISO/CS) 半双工 / 低功耗 2 线制(SCL/SDA) APDU 指令(通用上层协议) C-APDU(命令) R-APDU(响应) 提示:APDU 是上层协议,可运行在任何底层传输之上(7816、14443、SPI、I2C)

这张图把四种协议的关系讲得很清楚。底层传输方式不同,但上层都用 APDU 统一交互。你选协议时,先看物理形态(接触/非接触/直连),再看速率和功耗需求,最后用 APDU 封装业务逻辑。这套思路我用了十年,没出过大问题。