WindowsでOpenSCを使ってMIFARE Standard(Classic)カードデータを読み出す方法

#はじめに
OpenSCを使ってMIFARE Standardカードからデータを読み出します。
・読み出すためのAPDUコマンドを説明します。
・データの更新コマンドを追記しました。(2019/3/30)

#環境
- OS=Windows10
- ICカード= [MIFARE Standard 1K](http://amzn.asia/b85K9jQ)
- カードリーダー=[I-O DATA ぴタッチ](http://www.iodata.jp/product/tsushin/nfc/usb2-nfc2/)
- [PaSoRi RC-S380](http://amzn.asia/fAMY3zi)　の場合、NFC Port Softwareをアンインストールしないと読み出すことができません・・・(最後のメモに記載)

#OpenSCとは
- [OpenSCプロジェクト Home](https://github.com/OpenSC/OpenSC/wiki)
- [WindowsでOpenSCを使ってカードのIDmを確認する方法](https://qiita.com/gebo/items/eb76d2b83041cdb47ec3)

#MIFARE Standardとは
MIFARE(マイフェア)は、非接触型ICカードの国際通信規格(ISO14443)として標準化され、FeliCaに比べ圧倒的に安価であるため、世界的で最も多く採用され普及している。

MIFARE Standard 1kは、約768バイトのユーザーデータメモリを持ち、それが16のセクタに分かれている。これらのセクタは、**AとBと呼ばれる二つの鍵でプロテクトされている**。それぞれのセクタに対して、読み込み、書き込み、値の増減などの操作ができる。
**1セクタは4ブロックで構成され、1ブロック16バイトで構成される。**
※セクタ内の3ブロックはユーザーデータメモリ(DataBlock)で1ブロックは管理用のブロック(
TrailerBlock)。カードの合計メモリサイズは、1block(16byte)×4×16=1,024byte

- 鍵はA、Bともに6Byte。
- デフォルトでは　全てのセクタが鍵A、キーデータ=FF:FF:FF:FF:FF:FF でプロテクトされています。
- したがって何も設定していないカードは鍵に FF:FF:FF:FF:FF:FF を指定することでデータを読み出すことができます。
- ちなみにデータもデフォルト値は全てFFが詰まっています。

#さっそくやってみる
- コマンドプロンプトを立ち上げる。
- opensc-tool.exe のフォルダに移動して以下コマンド実行する。
- opensc-tool.exe -s FF:82:00:00:06:FF:FF:FF:FF:FF:FF
- opensc-tool.exe -s FF:86:00:00:05:01:00:00:60:00
- opensc-tool.exe -s FF:B0:00:00:10
- Received の次の行に出た値（**FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF**）がブロックデータ(最初のセクタの最初のブロック=ブロック00)です。

```console:サンプル-ブロック00のデータを読み出す
C:\Program Files\OpenSC Project\OpenSC\tools>opensc-tool.exe -s FF:82:00:00:06:FF:FF:FF:FF:FF:FF
Using reader with a card: TOPPAN FORMS TR33MUE014 0
Sending: FF 82 00 00 06 FF FF FF FF FF FF
Received (SW1=0x90, SW2=0x00)

C:\Program Files\OpenSC Project\OpenSC\tools>opensc-tool.exe -s FF:86:00:00:05:01:00:00:60:00
Using reader with a card: TOPPAN FORMS TR33MUE014 0
Sending: FF 86 00 00 05 01 00 00 60 00
Received (SW1=0x90, SW2=0x00)

C:\Program Files\OpenSC Project\OpenSC\tools>opensc-tool.exe -s FF:B0:00:00:10
Using reader with a card: TOPPAN FORMS TR33MUE014 0
Sending: FF B0 00 00 10
Received (SW1=0x90, SW2=0x00):
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
```

#概要
1. プロテクトを解除するためのキー情報をメモリにロードする(Load Authentication Keys)
2. セクタに対して認証を実施し、プロテクトを解除する(Authentication)
3. プロテクトが解除されたセクタのブロックデータを読み出す(Read Block Data)

#Load Authentication Keys
- プロテクトを解除するためのキー情報をメモリにロードする
- opensc-tool.exe -s FF:82:00:00:06:FF:FF:FF:FF:FF:FF

##APDUコマンド - Load Authentication Keys
| byte no|項目名|指定値|説明|
|:--|:--|:--|:--|
|0|CLA|FF|命令クラス　FF固定|
|1|INS|82|Load Authentication Keys|
|2|P1|00|00固定|
|3|P2|00|キーナンバー　キーを格納するメモリの番号　※|
|4|Le|06|キーの長さ　6Byte|
|5~11|Data|FF:FF:FF:FF:FF:FF|キーデータ|

※キーナンバー
一時的なメモリのようです。おそらくリーダなどの仕様によって番号の範囲、クリアされるタイミングが異なるのではないかと思います。とりあえず00指定しておけばOK。

#Authentication
- セクタに対して認証を実施し、プロテクトを解除する
- **セクタに対して認証するするのに、指定するのがブロック番号、というところが紛らわしいので注意**
- opensc-tool.exe -s FF:86:00:00:05:01:00:00:60:00

##APDUコマンド - Authentication
| byte no|項目名|指定値|説明|
|:--|:--|:--|:--|
|0|CLA|FF|命令クラス　FF固定|
|1|INS|86|Authentication|
|2|P1|00|00固定|
|3|P2|00|00固定|
|4|Le|05|データ部の長さ 5byte|
|5~10|Data|01:00:00:60:00|データ部(※下参照)|

###※データ部
- データ部には認証の詳細情報をセットします。
- 5バイト

| byte no|項目名|指定値|説明|
|:--|:--|:--|:--|
|0|バージョン番号|01|01固定|
|1||00|00固定|
|2|ブロック番号|00|認証したいブロックの番号(00~)※|
|3|キーのタイプ|60|60h = Aキーとして、認証用に使われる。61h = Bキーとして、認証用に使われます。|
|4|キーナンバー|00|Load Authentication Keysで格納したキーのメモリの番号

※ブロック番号
セクタの先頭のブロック番号を指定します。
つまり、セクタ番号×4を指定します。
例えばセクタ3の場合は3×4=12(0x0c)と指定します。

#Read Block Data
- プロテクトが解除されたセクタのブロックデータを読み出す
- opensc-tool.exe -s FF:B0:00:00:10

##APDUコマンド - Read Block Data
| byte no|項目名|指定値|説明|
|:--|:--|:--|:--|
|0|CLA|FF|命令クラス　FF固定|
|1|INS|B0|Read Block Data|
|2|P1|00|00固定|
|3|P2|00|読み出すブロック番号|
|4|Le|10|読み取りバイト数　10(16byte)固定|

- ブロック番号は00～で指定します。
- 例えば第2ブロックのデータを読み出したい場合は FF:B0:00:**01**:10 と指定します。
- Read Block Dataコマンドにセクタ番号はありません。第2セクタのブロック1を指定する場合はブロック番号に04と指定します。(1セクタ=4ブロックで構成される)

#追記：データ書き込み時
1. プロテクトを解除するためのキー情報をメモリにロードする(Load Authentication Keys)
2. セクタに対して認証を実施し、プロテクトを解除する(Authentication)
3. プロテクトが解除されたセクタのブロックデータを更新する(Update Binary Blocks)

##APDUコマンド - Update Binary Blocks
| byte no|項目名|指定値|説明|
|:--|:--|:--|:--|
|0|CLA|FF|命令クラス　FF固定|
|1|INS|D6|Update Binary|
|2|P1|00|00固定|
|3|P2|00|ブロック番号|
|4|Le|10|更新バイト数　10(16byte)固定|
|5|DATA||データブロック（16byte）|

- ブロック番号は00～で指定します。
- 例えば第2ブロックのデータを更新したい場合は FF:D6:00:**01**:10:11:22:33:44:55:66:77:88:99:00:AA:BB:CC:DD:EE:FF と指定します。
- Update Binary Blocksコマンドにセクタ番号はありません。第2セクタの第1ブロックを指定する場合はブロック番号に04と指定します。(1セクタ=4ブロックで構成される)


#参考
以下サイトを参考にしました。
- [Wiki MIFARE](https://ja.wikipedia.org/wiki/MIFARE)
- [Mifareとは？](http://www.orangetags.co.jp/what_mifare.html)
- [KeyAとKeyB](https://yuki-sato.com/android/nfc4.html)
- [Mifareの基礎知識](http://m-health.u-aizu.ac.jp/~m5101102/SM130/basic_know.html)
- [ACM1252U-Z2 – リファレンスマニュアル 5.5. MIFARE® Classic （1K/4K）メモリカードのPICCコマンド 【P35】](https://www.acs-japan.jp/download-manual/8673/REF-ACM1252U-Z2-JP-1.00.pdf)

#メモ
- PaSoRi RC-S380ではNFC Port Softwareをアンインストールしないとエラーになります。
- 具体的には、Load Authentication Keys⇒Authenticationコマンドは正常終了するが、Read Block Dataで戻り値が SW1=0x69, SW2=0x82 となる。このエラーステータスは[ここ](eternalwindows.jp/security/scard/scard07.html)によると『セキュリティステータスが満足されない。』とのこと。どうやらAuthentication状態がNFC Port Softwareによって勝手にリセットされてしまうようだ。