1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

株式会社ネオシステムAdvent Calendar 2024

Day 24

RC-S300でMIFARE Classicの読み出し

Last updated at Posted at 2024-12-23

やったこと

RC-S300というカードリーダーを使ってMIFARE Classicの読み込みを行う例です。

必要なライブラリ

libnfcを使用します。Fedoraの場合以下コマンドでインストールできます。

dnf install libnfc-devel

実装

includeとか。マクロはデバッグに役立つので定義してます。

#include <iostream>
#include <string>
#include <sstream>

#include <boost/format.hpp>

#include <nfc/nfc.h>

#define S_ __FILE__ << ":" << __LINE__ << " "

#define MAX_FRAME_LEN 264

std::string hexdump(const uint8_t *p, size_t l) {
    std::stringstream result;
    result << l << "bytes\n";

    while (l != 0) {
        int i;
        result << "   ";
        for (i = 0; i < 16; ++i) {
            uint8_t value = *p++; 
            result << (boost::format("   %02X") % (uint32_t) value);
            if (--l == 0) {
                break;
            }
        }
        result << "\n";
    }
    return result.str();
}   
    
void dump(const uint8_t *buf, std::size_t s) {
    std::cout << hexdump(buf, s);
    return;
}

初期化とか

nfc_context *context;
nfc_device *device;

// NFCコンテキストの初期化
nfc_init(&context);
if (context == nullptr) {
    std::cerr << S_ << "nfc_init error" << std::endl;
    return 1;
}

device = nfc_open(context, NULL);
if (device == NULL) {
    std::cerr << S_ << "nfc_open error" << std::endl;
    nfc_exit(context);
    return 1;
}

if (nfc_initiator_init(device) < 0) {
    std::cerr << S_ << "nfc_initiato_init error" << std::endl;
    nfc_close(device);
    nfc_exit(context);
    return 1;
}

UIDを読み取る

nfc_initiator_select_passive_targetの時点でカードをかざしていないとこの関数はすぐ成功で完了してしまいます。どうもpollingを行うnfc_initiator_poll_targetはこのカードリーダーでうまく動かないようです。

const nfc_modulation nm_mifare = {
    .nmt = NMT_ISO14443A,
    .nbr = NBR_106,
};
nfc_target target;
if (nfc_initiator_select_passive_target(device, nm_mifare, NULL, 0, &target) <= 0) {
    nfc_perror(device, "nfc_initiator_select_passive_target");
    nfc_close(device);
    nfc_exit(context);
    return 1;
}

// UID読み取り
uint8_t abt_rx[MAX_FRAME_LEN];
int res = 0;
const uint8_t read_uid[] = {0xFF, 0xCA, 0x00, 0x00, 0x00};
if ((res = nfc_initiator_transceive_bytes(device, read_uid, sizeof(read_uid), abt_rx, sizeof(abt_rx), 0)) < 0) {
    std::cerr << S_ << "error" << std::endl;
    nfc_close(device);
    nfc_exit(context);
    return 1;
}
dump(abt_rx, res);

セクターのデータ読み出し

Load Authentication Keysコマンド解説にあるように、最初にキー情報のロードを行います。

const uint8_t buf[] = {0xFF, 0x82, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
if ((res = nfc_initiator_transceive_bytes(device, buf, sizeof(buf), abt_rx, sizeof(abt_rx), 0)) < 0) {
    std::cerr << S_ << "error" << std::endl;
    nfc_close(device);
    nfc_exit(context); 
    return 1;
}   
dump(abt_rx, res);

for (uint8_t first_block = 0x0; first_block < 64; first_block += 4) {
    read_sector(device, first_block);
}

read_sectorread_blockは以下のような実装です。

void read_block(nfc_device *device, uint8_t block) {
    uint8_t abt_rx[MAX_FRAME_LEN];
    int res = 0;
    uint8_t read_block[] = {0xFF, 0xB0, 0x00, block, 0x10};
    if ((res = nfc_initiator_transceive_bytes(device, read_block, sizeof(read_block), abt_rx, sizeof(abt_rx), 0)) < 0) {
        std::cerr << S_ << "error" << std::endl;
        return;
    }
    dump(abt_rx, res);
    return;
}

void read_sector(nfc_device *device, const uint8_t first_block) {
    uint8_t abt_rx[MAX_FRAME_LEN];
    int res = 0;
    uint8_t buf[] = {0xFF, 0x86, 0x00, 0x00, 0x05, 0x01, 0x00, first_block, 0x60, 0x00};
    if ((res = nfc_initiator_transceive_bytes(device, buf, sizeof(buf), abt_rx, sizeof(abt_rx), 0)) < 0) {
        std::cerr << S_ << "error" << std::endl;
        return;
    }
    std::cout << "---- first_block: " << (uint32_t) first_block << std::endl;
    dump(abt_rx, res);
    for (uint8_t block = first_block; block < first_block + 4; ++block) {
        read_block(device, block);
    }
    return;
}

参考にした記事

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?