求Python代码:用HID OMNIKEY 5321 CL读取Mifare DESFire卡视觉ID
读取Mifare DESFire卡面视觉ID的Python方案
问题背景
我使用HID OMNIKEY 5321 CL读卡器读取Mifare DESFire卡,已通过Python代码成功读取卡片UID(示例UID:04 11 64 FA BC 24 80),但需要读取卡面印刷的视觉ID(示例视觉ID:30307877)。
现有读取UID的代码
from smartcard.System import readers from smartcard.util import toHexString # 建立与读卡器的连接 reader = readers()[0] connection = reader.createConnection() connection.connect() # 发送APDU命令获取卡片数据 command = [0xFF, 0xCA, 0x00, 0x00, 0x00] # 根据需求调整命令 response, sw1, sw2 = connection.transmit(command) # 打印响应数据 if sw1 == 0x90 and sw2 == 0x00: print("成功读取卡片数据:") print(toHexString(response)) else: print("读取卡片数据失败。") # 断开与读卡器的连接 connection.disconnect()
设备及卡片规格
读卡器规格
FW : 5.20 Op Mode : ISO Lib : 200 Por: USB USB Serial No : OKCM007040812072942435634869263 ITEM NO : R53210038-1 REVISION : B VERSION INDEX: ELZ00120
Mifare DESFire卡规格
Smartcard name: MiFare DESFire ATR : 3B 81 80 01 80 80 UID : 04 1A 68 FA BC 24 80 Protocol: ISO 14443A T=CL PICCtoPCD : 424 kbps Frequency : 13.56 Mhz PCDtoPICC
读取视觉ID的Python代码
卡面印刷的视觉ID通常存储在DESFire卡的制造商数据区域或自定义应用文件中,需通过DESFire原生APDU命令读取。以下是通用实现代码:
from smartcard.System import readers from smartcard.util import toHexString def read_desfire_visual_id(): # 连接读卡器 reader = readers()[0] connection = reader.createConnection() connection.connect() try: # 尝试读取制造商数据区域 # PC/SC封装的DESFire读取制造商数据命令 cmd_mfg_data = [0x90, 0x60, 0x00, 0x00, 0x00] response, sw1, sw2 = connection.transmit(cmd_mfg_data) if sw1 == 0x90 and sw2 == 0x00: print("制造商数据读取成功:") print(toHexString(response)) # 解析视觉ID:需根据卡片实际存储位置调整字节切片 # 示例假设视觉ID存储在响应的第4-7字节(大端字节序) visual_id_bytes = response[4:8] visual_id = int.from_bytes(visual_id_bytes, byteorder='big') print(f"卡面视觉ID: {visual_id}") else: # 若制造商区域读取失败,尝试读取自定义应用中的数据 # 替换为卡片实际的应用ID(示例为0x123456) target_app_id = [0x12, 0x34, 0x56] cmd_select_app = [0x90, 0x5A, 0x00, 0x00, 0x03] + target_app_id + [0x00] response, sw1, sw2 = connection.transmit(cmd_select_app) if sw1 == 0x90 and sw2 == 0x00: # 替换为卡片实际的文件ID(示例为0x01) cmd_select_file = [0x90, 0xBD, 0x00, 0x01, 0x00] response, sw1, sw2 = connection.transmit(cmd_select_file) if sw1 == 0x90 and sw2 == 0x00: # 读取文件内容 cmd_read_file = [0x90, 0xBD, 0x00, 0x00, 0x00] response, sw1, sw2 = connection.transmit(cmd_read_file) if sw1 == 0x90 and sw2 == 0x00: print("文件内容读取成功:") print(toHexString(response)) # 调整字节切片匹配视觉ID存储位置 visual_id_bytes = response[:4] visual_id = int.from_bytes(visual_id_bytes, byteorder='big') print(f"卡面视觉ID: {visual_id}") else: print(f"读取文件失败,状态码: {hex(sw1)}{hex(sw2)[2:]}") else: print(f"选择文件失败,状态码: {hex(sw1)}{hex(sw2)[2:]}") else: print(f"制造商区域读取失败,状态码: {hex(sw1)}{hex(sw2)[2:]}") print("请确认视觉ID的存储位置(制造商区域/自定义应用),并调整代码参数") finally: # 断开连接 connection.disconnect() if __name__ == "__main__": read_desfire_visual_id()
注意事项
- 视觉ID的存储位置因制造商而异,需先打印完整的制造商数据或文件内容,定位到对应字节段后调整代码中的切片范围。
- 若卡片启用了认证机制(如DESFire EV1/EV2),需在读取前添加密钥验证命令(如
0x90, 0x0A开头的APDU)。 - 代码中的应用ID、文件ID需替换为卡片的实际参数。
内容的提问来源于stack exchange,提问作者saad patel
相关产品推荐
相关产品推荐

