用Arduino和RC522模块打造智能NFC卡复制工具
周末整理抽屉时翻出一沓旧门禁卡,突然想到能否用手头的电子元件做个卡片复制工具。这个想法让我兴奋不已——毕竟谁不想体验一把"科技魔法"呢?本文将带你用最常见的Arduino开发板和RC522模块,打造一个成本不到百元的NFC卡复制器。无论你是想备份自己的门禁卡,还是单纯对射频技术感兴趣,这个项目都能让你在动手实践中收获满满。
1. 硬件准备与连接
工欲善其事,必先利其器。我们需要准备的硬件非常简单:
- Arduino Uno开发板(约30元)
- RC522 NFC读写模块(约15元)
- 杜邦线若干(公对母)
- 空白M1卡或UID可改写卡(约2元/张)
RC522模块背面通常标注着清晰的引脚定义,我们需要重点关注以下6个接口:
| 模块引脚 | Arduino引脚 | 功能说明 |
|---|---|---|
| SDA | D10 | 片选信号 |
| SCK | D13 | 时钟信号 |
| MOSI | D11 | 主机输出 |
| MISO | D12 | 主机输入 |
| IRQ | 不接 | 中断信号 |
| GND | GND | 地线 |
| RST | D9 | 复位 |
| 3.3V | 3.3V | 电源 |
注意:虽然RC522支持5V供电,但使用3.3V更为安全稳定。连接时建议先断电操作,避免短路风险。
硬件组装只需三步:
- 将RC522的SPI接口对应连接到Arduino
- 接好复位和片选引脚
- 最后连接电源线
检查无误后上电,模块上的红色LED应常亮,表示供电正常。如果使用带天线的版本,注意不要弯折天线线圈,这会影响读写距离。
2. 软件环境配置
在开始编程前,我们需要准备Arduino IDE和必要的库文件。最新版的Arduino IDE(2.3.x)已经内置了不错的库管理功能:
- 打开IDE,点击"工具"->"管理库"
- 搜索并安装"MFRC522"库(作者Miguel Balboa)
- 同时建议安装"SPI"库(Arduino官方)
安装完成后,新建一个空白项目。我们先测试硬件是否正常工作:
#include <SPI.h> #include <MFRC522.h> #define RST_PIN 9 #define SS_PIN 10 MFRC522 mfrc522(SS_PIN, RST_PIN); void setup() { Serial.begin(9600); SPI.begin(); mfrc522.PCD_Init(); Serial.println("Ready to read cards..."); } void loop() { if (!mfrc522.PICC_IsNewCardPresent()) return; if (mfrc522.PICC_ReadCardSerial()) { Serial.print("Card UID:"); for (byte i = 0; i < mfrc522.uid.size; i++) { Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "); Serial.print(mfrc522.uid.uidByte[i], HEX); } Serial.println(); mfrc522.PICC_HaltA(); } }上传代码后打开串口监视器(波特率9600),当用卡片靠近模块时,应该能看到类似这样的输出:
Card UID: 3A 2B 1C 4D这表示我们已经成功读取到卡的UID(唯一标识符)。如果遇到问题,可以检查:
- 接线是否正确,特别是SPI接口
- 库文件是否安装正确
- 卡片是否支持13.56MHz频率
3. NFC卡数据读取详解
成功读取UID只是第一步,M1卡的数据存储结构才是关键所在。标准的M1卡有1KB存储空间,分为16个扇区,每个扇区包含4个块(block),每个块16字节。存储结构如下:
扇区0 ├─ Block 0: 厂商信息(只读) ├─ Block 1: 数据块 ├─ Block 2: 数据块 └─ Block 3: 密钥A(6B)+控制位(4B)+密钥B(6B) ...(扇区1-15结构相同)读取完整卡数据的核心代码如下:
void dumpCardData() { MFRC522::MIFARE_Key key; for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; // 默认密钥 for (byte sector = 1; sector < 16; sector++) { // 跳过扇区0 if (mfrc522.PICC_Authenticate( MFRC522::PICC_CMD_MF_AUTH_KEY_A, sector * 4, &key, &(mfrc522.uid)) != MFRC522::STATUS_OK) { Serial.print("Auth failed for sector "); Serial.println(sector); continue; } for (byte block = 0; block < 3; block++) { // 只读数据块 byte buffer[18]; byte size = sizeof(buffer); if (mfrc522.MIFARE_Read(sector * 4 + block, buffer, &size) != MFRC522::STATUS_OK) { Serial.print("Read failed for block "); Serial.println(sector * 4 + block); continue; } Serial.print("Sector "); Serial.print(sector); Serial.print(" Block "); Serial.print(block); Serial.print(" : "); for (byte i = 0; i < 16; i++) { Serial.print(buffer[i] < 0x10 ? " 0" : " "); Serial.print(buffer[i], HEX); } Serial.println(); } } }这段代码会尝试用默认密钥(FFFFFFFFFFFF)读取所有扇区的数据块。实际应用中可能会遇到:
- 加密扇区:返回认证错误(STATUS_CODE ≠ 0)
- 损坏块:读取超时或返回异常数据
- 特殊格式数据:如门禁系统可能使用特定格式存储用户ID
重要提示:频繁读取卡片可能导致某些系统标记为异常卡。建议在测试时使用空白卡或无关紧要的卡片。
4. 卡片复制实战操作
成功读取原卡数据后,我们需要准备一张UID可改写卡(CUID卡)进行复制。普通M1卡的UID是只读的,而CUID卡允许修改前4/7/10字节的UID。
复制流程分为三个关键步骤:
- UID写入(仅CUID卡需要):
void writeUID(byte* newUID, byte uidSize) { if (mfrc522.PICC_WriteCardSerial(newUID, uidSize)) { Serial.println("UID写入成功"); } else { Serial.println("UID写入失败"); } }- 数据块写入:
bool writeBlock(byte sector, byte block, byte* data) { MFRC522::MIFARE_Key key; for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; if (mfrc522.PICC_Authenticate( MFRC522::PICC_CMD_MF_AUTH_KEY_A, sector * 4 + 3, &key, &(mfrc522.uid)) != MFRC522::STATUS_OK) { return false; } return mfrc522.MIFARE_Write(sector * 4 + block, data, 16) == MFRC522::STATUS_OK; }- 数据验证:
void verifyData(byte sector, byte block, byte* expected) { byte buffer[18]; byte size = sizeof(buffer); if (mfrc522.MIFARE_Read(sector * 4 + block, buffer, &size) == MFRC522::STATUS_OK) { bool match = true; for (byte i = 0; i < 16; i++) { if (buffer[i] != expected[i]) { match = false; break; } } Serial.print("验证结果: "); Serial.println(match ? "成功" : "失败"); } }完整复制流程建议按照以下顺序操作:
- 读取原卡所有可读扇区数据
- 将CUID卡置于读卡区
- 写入UID(与原卡一致)
- 逐个扇区写入数据
- 对每个写入块进行验证
- 测试复制卡是否可用
常见问题处理:
- 写入失败:检查卡片是否支持写入,尝试降低SPI时钟速度
- 部分扇区无法复制:可能是加密扇区,需要获取密钥
- 复制卡无法使用:检查控制位是否复制正确,某些系统会检测卡片类型
5. 安全与伦理考量
在享受技术带来的便利时,我们必须清醒认识到:未经授权复制他人卡片可能涉及法律问题。这里分享几个实际项目中的经验教训:
去年帮小区物业测试门禁系统时发现,他们的卡片居然全部使用默认密钥。虽然我立即报告了这个漏洞,但也意识到如果被别有用心的人利用后果不堪设想。因此建议:
- 仅复制自己拥有权限的卡片
- 企业用户应定期更换密钥
- 重要系统应采用CPU卡等更安全的方案
技术本身无罪,关键在于使用者的意图。这个项目最适合的应用场景其实是:
- 制作备份卡防止原卡丢失
- 开发智能家居门禁系统
- 学习射频识别技术原理
- 创建多功能合一卡(如门禁+公交卡)
对于想深入研究的开发者,可以尝试以下方向:
- 加密破解:通过暴力破解或侧信道攻击获取密钥(仅限合法研究)
- 数据解析:分析不同系统的数据存储格式
- 系统集成:将读卡器接入Home Assistant等智能家居平台
- 安全增强:开发带二次验证的读卡系统
最后提醒:某些新款门禁卡采用动态加密或CPU卡技术,无法用本文方法复制。如果遇到复制后无法使用的情况,很可能就是这类高级卡片。