如何读取Mifare Classic 1k标签认证阶段的挑战随机数?
可以通过底层通信获取Mifare Classic 1K的认证Challenge Nonce
完全可以绕过javax.smartcardio的抽象封装,直接通过ACR122U发送底层APDU指令,仅执行Mifare Classic认证流程的第一步,获取标签返回的challenge nonce。具体实现方式如下:
核心原理
Mifare Classic的认证流程第一步是:读卡器向标签发送认证指令(指定密钥类型A/B和目标扇区的认证块),标签会直接返回4字节的challenge nonce,这一步不需要提前提供密钥(后续的密钥验证是流程的第二步)。ACR122U支持通过特定格式的APDU封装Mifare原生指令,直接与标签交互。
具体步骤
1. 构造认证请求APDU
ACR122U要求用如下格式的APDU封装Mifare原生指令:
FF 00 00 00 [LEN] [MIFARE_CMD] [PARAMS]
针对认证第一步,构造的APDU为:
- 认证A密钥:
FF 00 00 00 02 60 [BLOCK_ADDR] - 认证B密钥:
FF 00 00 00 02 61 [BLOCK_ADDR]
其中[BLOCK_ADDR]是目标扇区的认证块地址:Mifare Classic 1K共16个扇区,每个扇区包含4个块,扇区n的认证块地址为3 + 4*n(例如扇区0的认证块是块3,对应地址0x03)。
2. 发送APDU并捕获Challenge Nonce
使用支持直接发送原始APDU的库(如Python的pyscard,比javax.smartcardio更灵活)发送上述指令,标签返回的4字节数据即为challenge nonce。
Python示例代码(基于pyscard)
from smartcard.System import readers from smartcard.util import toHexString, toBytes # 初始化读卡器连接 reader = readers()[0] conn = reader.createConnection() conn.connect() # 构造扇区0(认证块3)的A密钥认证请求APDU auth_apdu = [0xFF, 0x00, 0x00, 0x00, 0x02, 0x60, 0x03] response_data, sw1, sw2 = conn.transmit(auth_apdu) # 处理响应 if sw1 == 0x90 and sw2 == 0x00: # response_data即为4字节的challenge nonce print(f"获取到Challenge Nonce: {toHexString(response_data)}") else: print(f"请求失败,状态码: 0x{sw1:02X}{sw2:02X}")
注意事项
- 部分旧公交卡可能对认证指令有限制,如果返回非0x9000的状态码,可尝试更换扇区的认证块地址。
- 若读卡器模式异常,可先发送
FF 00 00 00 01 01切换到Mifare兼容模式。 - 即使不知道标签的密钥,只要标签支持Mifare Classic协议,发送认证指令后就会返回challenge nonce,这正是验证LFSR漏洞所需的前提。
内容的提问来源于stack exchange,提问作者f3ssen
相关产品推荐
相关产品推荐

