新品の無線ICカードを読んでみたら、NDEFフォーマットされたMIFARE Ultralight Cだった

秋葉原で数年前に新品として買ってきた非接触型ICカードPICC: Proximity IC Card)を読んでみました。PICCとは、Suicaや免許のような無線通信できるICカードの総称です。
カードは、MIFARE Ultralight Cで、NDEF(Near field communication Data Exchange Format)タグ用にフォーマットされていました。
本記事は、前の記事を参照しながら書きますので、先ずはそちらからお読みください。

カードの素性がMIFARE Ultralight Cであることが判明

秋葉原で購入したPICC

秋葉原で購入したPICC

これらは、数年前に秋葉原で、「NFC(Near field communication)用のカードを下さい」と言って、棚の奥から出してもらって買った非接触型ICカード(PICC)です。

まず、素性をはっきりさせましょう。

以前、Visual Basic 2019を使い、PC/SCを介してNFCカードにアクセスできるようになったので、そのコードをデバッグモードで動作させながら解析します。

SCardGetStatusChangeを実行すると、rgReaderStates(0).rgbatrに36バイトのATR(Answer to reset)が返ってきます。ATRはカードを初期化したときの初めの応答で、通信情報が含まれています。

16進数で表すと、以下のような値でした。(8バイトずつ切っていますが、連続しています。)

3B-8F-80-01-80-4F-0C-A0
00-00-03-06-03-00-3A-00
00-00-00-51

これを、ACS社の資料を参考に解析してみます。

初めの0~6バイトである3B-8F-80-01-80-4F-0Cは、通信規格のようです。理解するのは難しいのと、PC/SCがよろしく処理してくれるようなので、深入りしないこととします。

7~11バイトの、A0-00-00-03-06は、登録されたアプリケーションプロバイダ識別子(RID)で、PC/SCワークグループを示します。

12バイト目は標準(SS)を意味していて、03hはISO 14443Aパート3を表します。この値が11hだとFeliCaを表します。

13、14バイトの00-3Aは、2バイトでカードネームを表します。

00-01:MIFARE Classic 1K
00-02:MIFARE Classic 4K
00-03:MIFARE Ultralight
00-26:MIFARE Mini
00-3A:MIFARE Ultralight C
00-36:MIFARE Plus SL1 2K
00-37:MIFARE Plus SL1 4K
00-38:MIFARE Plus SL2 2K
00-39:MIFARE Plus SL2 4K
00-30:Topaz/Jewel
00-3B:FeliCa
FF-28:JCOP
FF-[SAK]:定義されていないタグ

こちらにもFeliCaが登場していますね。
まぁ、それはおいておいて、00-3Aですから、カードの素性は、MIFARE Ultralight Cということがめでたくわかりました。

15~18バイトの00-00-00-00はRFU(Reserved for Future Use)で、51hは初めの3Bhを除いたビットごとの排他的論理和です。

APDUによる読み出し命令

新品のカードならロックがかかっておらず、ほとんどの領域が読めるはずですので、読んでみることにします。

カードを読むには、コマンドを送ります。
前の記事で、カードのUIDを読むときには、

Dim pbSendBuffer As Byte() = New Byte() {&HFF, &HCA, &H0, &H0, &H0}

というコマンドを送りました。

このコマンドは、以下に示すような、Application Protocol Data Unit (APDU)という形式でできています。

CLA INS P1 P2 Le
FF CA 00 00 00

CLAは、クラスを示します。FFhは、命令クラスです。
INSは命令を示します。CAhは、データ取得命令です。
P1、P2は、パラメータで、命令の種類や対象を示します。00-00とすると、UIDが対象になります。
Leは、Leの次に続くデータの長さを示します。ここでは00hなので、続くデータはありません。

同様にして、メモリの内容を読み出す命令を考えてみます。

CLA INS P1 P2 Le
FF B0 00 XX 00

CLAは、FFhであり、命令クラスです。
INSのB0hは、バイナリブロックを読む命令です。
P1は固定で00hです。
P2は、ブロック番号を指定します。
Leは00hにすることで、読み出し可能な最大長さを読み出してくれます。

実際にメモリ内容を読み出してみた

カードはMIFARE Ultralight Cということが分かっていますので、製品データシートを参照すると、メモリ領域は、00hから47hページであり、各ページは4バイトのサイズであることが分かりました。

B0コマンドの読み出し単位は16バイトであり、4ページ分を一度に読み込むことができました。
読み出したデータを次に示します。

00h: 04-53-86-59
01h: DA-1B-5C-80
02h: 1D-48-00-00
03h: E1-10-12-00
04h: 01-03-A0-0C
05h: 34-03-00-FE
06h: 00-00-00-00

27h: 00-00-00-00
28h: 00-00-00-BD
29h: 04-00-00-FF
2Ah: 00-05-00-00
2Bh: 00-00-00-00

06h~27hページは、全て00hが入っていたので、省略しました。
2Chページ以降は認証キーが入っていて、読み出せませんでした。

ところで、この結果を最初に見たとき、愕然としました。

新品なので、ほとんど00hが入っていると思ったのに、結構、データが書き込まれています。
中古品を掴まされたのかな?とまで思いました。
特に、03hページはOTP(One-Time Programmable)エリアであり、書き込んであると、所望のデータを書き込むことができません。どうなっているの?

でも、調べてみると、これは、NDEF(NFC Data Exchange Format)という形式でした。
ということで、「MIFARE Ultralight as Type 2 Tag」のアプリケーションノートも読まないといけなくなりました。(以前は「https://www.nxp.com/docs/en/application-note/AN1303.pdf」でしたが、リンクが切れてしまいました。)

では、内容を解析していきます。

00hページから02hページの0hバイトまで、すなわち04-53-86-59-DA-1B-5C-80-1Dで、7バイトのUIDを表します。すなわち、上位3バイトのシリアル番号は、04-53-86であり、CT(Cascade Tag byte, 88h)とそれらのビット毎の排他的論理和が59hです。また、下位4バイトのシリアル番号はDA-1B-5C-80であり、これらのビット毎の排他的論理和が1Dです。

02hページ1hバイトの48hは、内部使用の変数で、意味は解りません。
続く2h、3hバイトの00-00はロックバイトであり、ロックがかかっていないことを示しています。

03hページは、所望の値を一回だけ書き込むことができる領域(OTP: One Time Programmable)です。CC(Capability Container)とも呼ばれます。
E1hは、NDEFメッセージが存在することを示すマジックナンバです。
10hは、バージョン番号で、Ver.1.0であることを示します。
12hは、8倍した値がデータエリアのサイズになります。12h×8=18d×8=144バイトです。
あれ?MIFARE Ultralight Cは、48ページ×4バイト=192バイトの容量なので、計算が合わないですね?でも、0h~03hのUIDやCCエリア(16バイト)と、28H~2Fhのロックバイト及び認証キーエリア(32バイト)を差し引くと192-16-32=144となって、計算が合います。
CCの最後の00hは、R/Wアクセスで、読み出しと書き込みに制限がないことを示しています。

04hページ0hバイトからの01-03-A0-0C-34は、TVL(Tag, Length, Value)フォーマットによるデータ記載です。
01hは、以下の表でLock Control TLVであり、このTLVがロックバイトのメモリ位置を示すことを意味します。

Tagの値 TLVの用途
00h Null TLV
01h Lock Control TLV
02h Memory Control TLV
03h NDEF Message TLV
FEh Terminate TLV

03hは、Valueの長さを示します。A0-0C-34の3バイトがこのTLVのValueです。各バイトは、Position、Size、Page controlを意味します。

A0hは上位ニブルのAhと下位ニブルの0hに分けて考えます。上位ニブルはページ番号、下位ニブルはオフセットバイト数を意味します。つまり、ロックバイトは10ページ目の0バイトから始まるということです。
0Chは、ロックバイトが12ビットあることを意味します。
34hも上位ニブルと下位ニブルに分けて考えます。上位ニブルはBytesLockedPerLockBitすなわち、1ビットでロックできるバイト数を意味します。2^3=8なので、1ビットで8バイトをロックします。下位ニブルは、BytesPerPage、すなわち、1ページ当たりのバイト数を意味します。2^4=16なので、1ページは16バイトから構成されます。

以上のことから、ロックバイトの開始位置は、10ページ目の0バイトからはじまり、1ページは16バイトなので、160バイト目から始まります。1ページ当たり4バイトで表した先のメモリ構成図では、160÷4=40d=28hです。28hページの00h、01hバイトの値は、00-00であり、ロックビットは12ビット(1.5)バイトですから、ロックはかかっていないことになります。
05hページの01hバイトからの03-00は、次のTLVブロックです。
03hはNDEF Message TLVを表します。しかし、長さは00hなので、データはありません。

05hページの03hバイトのFEhはTerminate TLVなので、タグの終了を意味します。
そこから、データの無い状況が続きます。

28hページにおける0h、1hバイトの00-00は、既述のようにロックバイトです。続く2バイトは、RFUです。
29hページにおける0h、1hバイトの04-00は、カウンタを意味しています。4まで数えている理由は良く分かりません。続く2バイトは、やはりRFUです。

2Ahページと2Bhページの0hバイトは、それぞれAUTH0AUTH1と呼ばれています。
AUTH0にページ番号をセットすると、その値より大きいページ番号には、アクセス制限がかかります。データシートには、03hから30hが有効な値とありますが、ここでは00hになっています。

AUTH1のBit0(LSB)に1をセットすると、読み出しはできるものの、書き込みに認証が必要になります。Bit0に0をセットすると、読み出しと書き込みの双方に認証が必要になります。
現状ではAUTH1も00hになっています。

まとめ

新品のPICCを買ってきて、内部が空であることを確認しようと思ったら、NDEF用の初期値が書き込まれており、図らずも調査する羽目になりました。

次回はタグを実際に書き込んで、その内容を解析したいと思います。

コメント

タイトルとURLをコピーしました