Flutter应用中MIFARE DESFire卡片AES认证持续失败问题求助
兄弟,我之前踩过DESFire AES认证的大坑,太懂这种卡住的憋屈了!结合我踩过的坑和DESFire EV3的规范,给你列几个最容易出问题的点,你挨个排查试试:
密钥与卡片的匹配细节不能错
首先确认你用的是AES-128还是AES-256?DESFire EV3默认是AES-128,但如果卡片被配置成256位,密钥长度必须严格对应。另外千万注意字节顺序——卡片的密钥是大端字节序,Dart里处理字节数组时很容易搞反,比如卡片密钥是010203...16,你在代码里的字节数组必须完全和这个顺序一致,别搞成小端。认证流程的步骤必须严格遵循双向认证逻辑
DESFire AES是双向认证,步骤比3DES复杂很多,少一步或者顺序错了直接失败:- 先发送
Authenticate AES命令(封装成ISO APDU是90 AA 00 00 01 01 00),卡片会返回16字节的随机数RndB - 用初始密钥(卡片配置的AES密钥)以CBC模式加密RndB(IV全0,无填充)得到SEncRndB,然后生成自己的16字节随机数RndA,把
RndA + SEncRndB打包成APDU发给卡片 - 卡片验证通过后会返回加密后的
RndA' + SEncRndB',你需要解密后验证RndA'是否和你之前发的RndA一致,同时要按照NXP规范里的算法,用RndA和RndB推导出后续通信的会话密钥——这一步很多人会漏掉会话密钥的派生,导致后续读写时加密密钥不对。
- 先发送
PointyCastle的加密配置要精准贴合DESFire要求
- DESFire AES用的是CBC模式+无填充!很多人默认用了PKCS7填充,这会直接导致加密后的字节长度不对,认证失败。初始化AES CBC时,IV必须是16字节的全0数组,这是DESFire的硬性规定,别自己乱设IV。
- CMAC计算也要注意:DESFire用的是AES-CMAC,计算对象是命令的有效数据部分,密钥是当前的会话密钥,一定要严格按照NXP规范里的MAC生成规则来,比如要不要包含APDU的某些字段,别自己瞎改。
flutter_nfc_kit发送命令的格式要正确
DESFire命令必须封装在ISO 7816-4的APDU里,不能直接发裸的DESFire命令。比如CLA字段一般是0x90,INS是DESFire的命令码,P1/P2设为0x00,然后是Lc(命令数据长度)+数据+Le(期望返回的数据长度)。另外处理卡片返回的数据时,要去掉最后的状态字(比如0x9000),只取前面的有效数据部分。调试小技巧
先用PC端的NFC调试工具(比如NXP的TagWriter或者第三方的NFC读写软件)验证卡片的密钥和认证流程是否正常,先排除卡片本身的配置问题。然后在Dart代码里打印每个步骤的发送字节数组和接收字节数组,和NXP规范里的示例数据对比,看哪一步的字节和预期不符——比如加密后的RndB是不是和示例里的一致,会话密钥的派生是不是正确。
备注:内容来源于stack exchange,提问作者DrO

