RC-S300でMIFARE Classicの読み出し

# やったこと

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

# 必要なライブラリ

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

``` 
dnf install libnfc-devel
``` 

# 実装

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

``` C++
#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;
}
```

## 初期化とか

``` C++
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`はこのカードリーダーでうまく動かないようです。

``` C++
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コマンド解説](https://qiita.com/erik_t/items/835f761792265206ac3f#load-authentication-keys%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E8%A7%A3%E8%AA%AC)にあるように、最初にキー情報のロードを行います。

``` C++
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_sector`と`read_block`は以下のような実装です。

``` C++
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;
}
```

# 参考にした記事

* [WindowsでOpenSCを使う（3.MIFARE Classicブロックデータ読み出し編②）](https://qiita.com/erik_t/items/835f761792265206ac3f)