ArduinoでRFIDカードを複製する

힘센캥거루
2025년 11월 26일
9
arduino

今日はArduinoでRFIDカードを複製する方法について書いてみようと思う。

一度文章にしておけば忘れないので、復習の意味も込めて残しておく。

ArduinoでRFIDカードを複製する-1

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が入っている。

ArduinoでRFIDカードを複製する-2

2.UID

Unique IDentifier(ユニーク・アイデンティファイア)の略で、RFIDカード(例:交通系ICカード、入退室カード、学生証など)ごとに付与された固有識別番号のことを指す。

人に例えると、マイナンバーのような役割だ。

UIDはSector 0のBlock 0内部の先頭4バイトに保存される。

[ UID0 | UID1 | UID2 | UID3 | BCC | Manufacturer Data… ]

RFIDリーダーがカードを読むとき、最初に読み出すのがこの部分である。

これをもとにカードの識別が行われる。

ArduinoでRFIDカードを複製する-3

3. CUIDカード

重要なのは、MIFARE Classic 1K(純正)のUIDは工場で固定されるという点だ。

NXP純正チップのUIDはROMに保存されており、どんな方法でも書き換えることはできない。

したがって、一般的なカードリーダーやMFRC522ではUIDの改ざんは不可能だ。

ArduinoでRFIDカードを複製する-4

しかし市場には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を下図のように配線する。

ArduinoでRFIDカードを複製する-5

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ライブラリを検索してインストールする。

ArduinoでRFIDカードを複製する-6

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

ArduinoでRFIDカードを複製する-7

そのコードを書き込んだあと、まずUID値を読み取る。

UIDは一般的に16進数4つで構成されている。

F5 5F 36 80

 もし上のようなUIDを取得したなら、書き込むUIDは次のようになる。

数値の前の0xは、その数が16進数であることを意味する。

0xF5 0x5F 0x36 0x80

5. 問題点、そして解決

サンプルにある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 など)の可能性が高い。

もし質問があればコメントしてほしい。

댓글을 불러오는 중...