C#でNFC(Felica/Mifare)の読み取り – 実践編 その5 – Mifare Ultra Light(NTAG21x)への読み書き

本文上広告1



今回やること

前回、Mifare Ultra Light(NTAG21x)の仕様をがっつり読みました。

Mifare Ultra Lightとは? 自分のわかっている範囲でまとめておくと NXP NTAG 213/215/216 ...

今回は、以下のような条件で、

  • 言語 : C#
  • ライブラリ: PCSC-Sharp
  • リーダー : PaSori
  • タグ : NTAG213

次のような項目を実践してみたいと思います。

  • シリアルナンバー部分の読み取りとカードタイプの読み取り(以下のリンクで行った内容と、全体のデータの比較)
  • 今回の到達点 PCSC-SharpとPSCS.ISO7816を使用して、以下のことができるようになる。 Felica(Suica...
  • 未初期化のデータの内容(出荷時のメモリ内容)
  • NDEFライブラリの調査
  • NDEFライブラリの内容に基づいて書き込み
  • ASCIIミラーのテスト(UIDだけでも可)
  • Androidアプリで読み取ってみてどうなるか

ひとまず、以上のようなとこまで、実際にコードを書いて、確かめてみたいと思います。

実際にやってみる

UIDの読み取り

実践編その1とほぼ同じコードです。

var contextFactory = ContextFactory.Instance;

using (var context = contextFactory.Establish(SCardScope.System))
{
    var readerNames = context.GetReaders();
    if (NoReaderFound(readerNames)){
        textBoxForShow.Text += "You need at least one reader in order to run this example. "\r\n";
        return;
    }

    var readerName = ChooseRfidReader(readerNames);
    if (readerName == null)
        return;

    // 'using' statement to make sure the reader will be disposed (disconnected) on exit
    using (var rfidReader = context.ConnectReader(readerName, SCardShareMode.Shared, SCardProtocol.Any))
    {
        var apdu = new CommandApdu(IsoCase.Case2Short, rfidReader.Protocol)
        {
            CLA = 0xFF,
            Instruction = InstructionCode.GetData,
            P1 = 0x00,
            P2 = 0x00,
            Le = 0 // We don't know the ID tag size
        };

        using (rfidReader.Transaction(SCardReaderDisposition.Leave))
        {
             textBoxForShow.Text += "Retrieving the UID .... ";
             textBoxForShow.Text += "\r\n";

            var sendPci = SCardPCI.GetPci(rfidReader.Protocol);
            var receivePci = new SCardPCI(); // IO returned protocol control information.

            var receiveBuffer = new byte[256];
            var command = apdu.ToArray();

            var bytesReceived = rfidReader.Transmit(
                sendPci, // Protocol Control Information (T0, T1 or Raw)
                command, // command APDU
                command.Length,
                receivePci, // returning Protocol Control Information
                receiveBuffer,
                receiveBuffer.Length); // data buffer

            var responseApdu =
                new ResponseApdu(receiveBuffer, bytesReceived, IsoCase.Case2Short, rfidReader.Protocol);

            textBoxForShow.Text +=    "SW1: " + responseApdu.SW1.ToString() 
                                    + ", SW2: " + responseApdu.SW2.ToString() + "\r\n"
                                    + "Uid: ";
            if(responseApdu.HasData) {
                textBoxForShow.Text +=  BitConverter.ToString(responseApdu.GetData());
            } else {
               textBoxForShow.Text += "No uid received";
            }

             textBoxForShow.Text += "\r\n";

        }
    }
}

適当にボタン等を追加して、UID読み取った結果がこちらです。読み取れています。

144バイトの全データの読み取り

List<byte> getBuffer = new List<byte>();

var contextFactory = ContextFactory.Instance;

using (var context = contextFactory.Establish(SCardScope.System))
{
    var readerNames = context.GetReaders();
    if (NoReaderFound(readerNames))
    {
        textBoxForShow.Text += "You need at least one reader in order to run this example.";
        textBoxForShow.Text += "\r\n";
        //Console.ReadKey();
        return;
    }

    var readerName = ChooseRfidReader(readerNames);
    if (readerName == null)
    {
        return;
    }

    // 'using' statement to make sure the reader will be disposed (disconnected) on exit
    using (var rfidReader = context.ConnectReader(readerName, SCardShareMode.Shared, SCardProtocol.Any))
    {
        for(int i= 0; i<9; ++i)
        {
            // Pasori使用の場合はLe=10(16Byte)の場合に限定されるので4ページずつ送ればよい
            var apdu = new CommandApdu(IsoCase.Case2Short, rfidReader.Protocol)
            {
                CLA = 0xFF,
                Instruction = InstructionCode.ReadBinary,
                P1 = 0x00,
                P2 =  (byte)(i*4),
                Le = 0x10 // We don't know the ID tag size
            };

            using (rfidReader.Transaction(SCardReaderDisposition.Leave))
            {
                textBoxForShow.Text += "Read Binary : Page"\r\n";

                var sendPci = SCardPCI.GetPci(rfidReader.Protocol);
                var receivePci = new SCardPCI(); // IO returned protocol control information.

                var receiveBuffer = new byte[256];
                var command = apdu.ToArray();

                var bytesReceived = rfidReader.Transmit(
                    sendPci, // Protocol Control Information (T0, T1 or Raw)
                    command, // command APDU
                    command.Length,
                    receivePci, // returning Protocol Control Information
                    receiveBuffer,
                    receiveBuffer.Length); // data buffer

                var responseApdu =
                    new ResponseApdu(receiveBuffer, bytesReceived, IsoCase.Case2Short, rfidReader.Protocol);

                textBoxForShow.Text += "SW1: " + responseApdu.SW1.ToString()
                                        + ", SW2: " + responseApdu.SW2.ToString()+ "\r\n"
                                        + "Data: ";

                if (responseApdu.HasData){
                    textBoxForShow.Text += BitConverter.ToString(responseApdu.GetData());
                    getBuffer.AddRange(responseApdu.GetData());
                }
                else {
                    textBoxForShow.Text += "No uid received";
                }
            }
        }
    }
}

結果が以下のようになります。

4Byte毎に並べてみると以下のようなかたちになります。

00: 04 3D 8F 3E
01: C2 EC 4C 80
02: E2 48 00 00
03: E1 10 12 00
04: 01 03 A0 0C
05: 34 03 1B D1
06: 01 17 55 00
07: 68 74 74 70
08: 73 3A 2F 2F
09: 6F 66 66 69
10: 63 65 2D 66
11: 75 6E 2E 63
12: 6F 6D FE 00
13: 00 00 00 00
~~~~~~~~~~~~~~~

UIDを読み取ったデータと前回の仕様の読み込みで見た初めのUIDの部分が同じなので、まずは正しく読み取れているかと思います。(3byte目の3Eはチェックバイトなので、UIDには反映されていない。)

Mifare Ultra Lightとは? 自分のわかっている範囲でまとめておくと NXP NTAG 213/215/216 ...

上のコードで肝となるが以下の部分。16*9 = 144分 PaSoriで読み取るようにしています。

for(int i= 0; i<9; ++i)
{
  // Pasori使用の場合はLe=10(16Byte)の場合に限定されるので4ページずつ送ればよい
  var apdu = new CommandApdu(IsoCase.Case2Short, rfidReader.Protocol)
  {
     CLA = 0xFF,
     Instruction = InstructionCode.ReadBinary,
     P1 = 0x00,
     P2 =  (byte)(i*4),
     Le = 0x10 // We don't know the ID tag size
  };
}

ここから書きます。

現在編集中。

次回やること

ここらでいったんNFC関係は休憩します。NFCがらみはしばらくやりませんが、次回やるとしたら、

  • 静的・動的ロックをかけた時の挙動
  • パスワード関係を調べる
  • ACRの調達
  • パスワード・AUTHLIMを設定したときの挙動
  • Excelのアドインで、2つ以上のリーダがあった時の対応
  • Excelのアドインへの落とし込みとその仕様決め
  • Excelのアドインへの落とし込み-書き込み
  • Excelのアドインへの落とし込み-読み込み・解析(シートに解析内容を書き込む)
  • Androidでもっかいコーディングをしてみる。

のようなところで、やってみたいと思います。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする