今日はArduinoでRFIDカードを複製する方法について書いてみようと思う。
一度文章にしておけば忘れないので、復習の意味も込めて残しておく。

1.RFIDカードの内部データ構造
一般的なRFIDカードは MIFARE Classic 1Kカードである。
このカードのメモリ構造は次の通りだ。
- 総容量 1024 bytes (1KB)
- 16個のSector (0~15)
- 各Sectorは4個のBlock (Block 0~3)
- 各Blockは16 bytesそれぞれのセクタは以下のような構造になっている。
Sector n
├── Block 0 (Data or UID block)
├── Block 1 (Data)
├── Block 2 (Data)
└── Block 3 (Sector Trailer: Key A, Access Bits, Key B)こうしたセクタの中で最も重要な意味を持つのは、セクタ0の最初のデータだ。
ここにUIDが入っている。

2.UID
Unique IDentifier(ユニーク・アイデンティファイア)の略で、RFIDカード(例:交通系ICカード、入退室カード、学生証など)ごとに付与された固有識別番号のことを指す。
人に例えると、マイナンバーのような役割だ。
UIDはSector 0のBlock 0内部の先頭4バイトに保存される。
[ UID0 | UID1 | UID2 | UID3 | BCC | Manufacturer Data… ]RFIDリーダーがカードを読むとき、最初に読み出すのがこの部分である。
これをもとにカードの識別が行われる。

3. CUIDカード
重要なのは、MIFARE Classic 1K(純正)のUIDは工場で固定されるという点だ。
NXP純正チップのUIDはROMに保存されており、どんな方法でも書き換えることはできない。
したがって、一般的なカードリーダーやMFRC522ではUIDの改ざんは不可能だ。

しかし市場にはUIDの変更が可能なカードがあり、こうしたカードをCUID(いわゆるマジックカード)と呼ぶ。
先頭のCはChangeable(変更可能)を意味する。
外見はMIFARE Classic 1Kと同じだが、内部チップが次のように異なる。
① Gen1A (UID/Backdoor 対応タイプ)
0x40 / 0x43 バックドアコマンドをサポート
UID変更用のコマンドを別途提供
MFRC522 + ArduinoライブラリのMIFARE_SetUid()で変更可能
② CUID / Gen2 (Block 0 Writable)
バックドアコマンドなし
その代わり、Block 0(UIDが入っているセクタ)を通常の書き込み(WRITE)で上書きできるよう設計
MFRC522がMIFARE_Write(0…)コマンドを受け付ければUID変更が可能
ただし、すべてのCUIDでできるとは限らない。MFRC522が対応していない場合はPN532/ACR122Uが必要
4. ArduinoでRFIDカードを複製する
原理が分かったので、ArduinoでRFIDカードを複製する方法は簡単だ。
UIDをコピーしてやればよい。
まずArduinoを下図のように配線する。

Signal | MFRC522 Pin | Arduino Uno / 101 | Arduino Mega | Arduino Nano v3 | Arduino Leonardo / Micro | Arduino Pro Micro |
|---|---|---|---|---|---|---|
RST / Reset | RST | 9 | 5 | D9 | RESET / ICSP-5 | RST |
SPI SS | SDA (SS) | 10 | 53 | D10 | 10 | 10 |
SPI MOSI | MOSI | 11 / ICSP-4 | 51 | D11 | ICSP-4 | 16 |
SPI MISO | MISO | 12 / ICSP-1 | 50 | D12 | ICSP-1 | 14 |
SPI SCK | SCK | 13 / ICSP-3 | 52 | D13 | ICSP-3 | 15 |
そしてArduino IDEでMFRC522ライブラリを検索してインストールする。

次に、[ファイル] -> [スケッチ例] -> [MFRC522] から ReadNUID を選択する。

そのコードを書き込んだあと、まずUID値を読み取る。
UIDは一般的に16進数4つで構成されている。
F5 5F 36 80もし上のようなUIDを取得したなら、書き込むUIDは次のようになる。
数値の前の0xは、その数が16進数であることを意味する。
0xF5 0x5F 0x36 0x805. 問題点、そして解決
サンプルにあるChangeUIDで手軽に解決したかったが、何度やっても失敗した。
0x40バックドアが毎回タイムアウトしてしまう。
調べてみると、自分のカードはGen2カードで、単に0番セクタにアクセスしてUIDを入れ替えるだけでよかったのだった。
コードは以下の通り。
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9
#define SS_PIN 10
MFRC522 mfrc522(SS_PIN, RST_PIN);
MFRC522::MIFARE_Key key;
// 変更したい新しいUID (4バイト)
byte newUid[4] = { 0xF5, 0x5F, 0x36, 0x80 }; // 例
void setup() {
Serial.begin(9600);
while (!Serial) {}
SPI.begin();
mfrc522.PCD_Init();
Serial.println(F("CUID カード Block 0 に直接 UID 書き込み例"));
// デフォルトキー FF..FF 設定
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
}
void loop() {
// 新しいカード待ち
if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) {
return;
}
Serial.print(F("現在のカード UID: "));
for (byte i = 0; i < mfrc522.uid.size; i++) {
Serial.print(mfrc522.uid.uidByte[i], HEX);
Serial.print(" ");
}
Serial.println();
// === 1. セクタ 0 認証 (Block 0) ===
byte block = 0; // Block 0
MFRC522::StatusCode status;
status = mfrc522.PCD_Authenticate(
MFRC522::PICC_CMD_MF_AUTH_KEY_A,
block,
&key,
&(mfrc522.uid)
);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("認証失敗: "));
Serial.println(mfrc522.GetStatusCodeName(status));
goto HALT;
}
// === 2. 既存の Block 0 内容を読んで manufacturer 部分を保持 ===
byte block0[18]; // 16バイト + サイズ情報
byte size = sizeof(block0);
status = mfrc522.MIFARE_Read(0, block0, &size);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Block 0 読み取り失敗: "));
Serial.println(mfrc522.GetStatusCodeName(status));
goto HALT;
}
// block0[0..3] = 元の UID
// block0[4] = BCC (UID 4バイトの XOR)
// block0[5..15]= メーカー情報など
// === 3. 新しい UID + BCC を計算して上書き ===
byte bcc = newUid[0] ^ newUid[1] ^ newUid[2] ^ newUid[3];
block0[0] = newUid[0];
block0[1] = newUid[1];
block0[2] = newUid[2];
block0[3] = newUid[3];
block0[4] = bcc;
// block0[5..15] はそのままにしておけばメーカー情報は維持される
status = mfrc522.MIFARE_Write(0, block0, 16);
if (status != MFRC522::STATUS_OK) {
Serial.print(F("Block 0 書き込み失敗: "));
Serial.println(mfrc522.GetStatusCodeName(status));
goto HALT;
}
Serial.println(F("新しい UID の書き込み完了。カードを一度離してから再度かざしてください。"));
HALT:
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
delay(1000);
} 6. 感想
今回でRFIDモジュールの正しい使い方をしっかり理解できた。
検索してみるとカードキーでドアを開けるプロジェクトなどがあるが、そういったものも簡単に実装できそうだ。
いろいろと応用してみたい。
ちなみに、この方法でもカードが認識されない場合は、周波数の問題(13.56MHz、125KHz など)の可能性が高い。
もし質問があればコメントしてほしい。
댓글을 불러오는 중...