起因
小区门禁卡丢了,补办要 50 块还要等一周。我有 PN532 模块和几张空白卡——不如自己来。
硬件准备
- PN532 NFC 模块(约 25 元)
- USB 转 TTL 模块(约 8 元)
- Mifare Classic 1K 空白卡(约 2 元/张)
- 杜邦线若干
接线
PN532 → USB转TTL
VCC → 5V
GND → GND
TX → RX
RX → TX注意 PN532 的拨码开关要切到 UART 模式。
Python 读写代码
import serial
import time
def send_command(ser, cmd):
ser.write(cmd)
time.sleep(0.1)
return ser.read(ser.in_waiting)
def read_card(ser):
# 读取所有 16 个扇区(每扇区 4 个块)
sectors = {}
for sector in range(16):
# 先用默认密钥认证
auth_cmd = build_auth_command(sector, key_type='A')
resp = send_command(ser, auth_cmd)
if b'\x00' not in resp:
print(f'扇区 {sector} 认证失败,尝试其他密钥...')
continue
blocks = []
for block in range(4):
read_cmd = build_read_command(sector * 4 + block)
data = send_command(ser, read_cmd)
blocks.append(data)
sectors[sector] = blocks
return sectors扇区结构分析
Mifare Classic 1K 卡有 16 个扇区,每扇区 4 个块(每块 16 字节):
扇区 0, 块 0: UID + 厂商数据(只读)
扇区 0, 块 1-2: 数据区
扇区 0, 块 3: 密钥A + 控制位 + 密钥B
扇区 1, 块 0-2: 用户数据(通常存卡号)
扇区 1, 块 3: 密钥A + 控制位 + 密钥B
...以此类推大部分门禁系统只用扇区 0 的 UID 做验证——这意味着你只需要复制 UID。但也有系统会读扇区 1 的数据,所以要全部复制。
安全性思考
这次实验让我意识到 Mifare Classic 的安全性有多弱:
- 默认密钥
FFFFFFFFFFFF在大量卡片上依然有效 - CRYPTO-1 加密算法在 2008 年就被完全破解
- 50 元不到的设备就能完整克隆一张卡
如果你的门禁系统还在用 Mifare Classic,尽早升级到 DESFire 或 Ultralight C。安全不是"够用就行"的东西。
完整代码和 GUI 版本(Tkinter 写的,带读写进度条和验证功能)已开源在 GitHub。