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?

More than 3 years have passed since last update.

Android HCE 調査メモ(その3)

Posted at

目的

C#アプリでもHCEと通信できることを確認します。

環境

今回は以下の機種で動作確認しました。

Android側

  • ビルド環境

  • Android Studio 3.5.3

  • 端末

    • Sony SO-3L
    • Android 9.0 (API level 28)

PC側

  • NFCリーダ
  • ACR1251CL-NTTCom
    (PC/SCモードで使用)
  • OS
    • Windows 10 64bit
  • ビルド環境
  • Visual Studio 2019
  • 言語
    • C#

Android側アプリ

過去の記事を参照ください。
Android HCE 調査メモ(その1)
AIDは「F222222222」となっています。

PC側アプリ

とりあえず、.NET Core コンソールアプリで作成することにします。
(GUI等は後々…)

プロジェクト開始

Visual Studioで新規プロジェクトを作成しておきます。

NuGetパッケージ追加

UWPには標準でライブラリがあるようですが、.NET Core 用の標準ライブラリは無いようです。
そのため、NuGetパッケージの追加を行います。
ツール → NuGetパッケージマネージャー → ソリューションのNuGetパッケージの管理
「PCSC」「PCSC.Iso7816」を追加します。

ソースの作成

エラーチェック等行っていない、あまりキレイではないソースですが、とりあえず動作するソースを以下に書きます。

Program.cs
using System;

namespace HCE_Test
{
    class Program
    {
        static void Main(string[] args)
        {
            var model = new HceModel();
            model.mainProcess();
            Console.ReadKey();
        }
    }
}
HceModel.cs
using PCSC;
using PCSC.Iso7816;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace HCE_Test
{
    class HceModel
    {
        internal ISCardContext SCardContext { get; private set; }
        internal string readerName { get; private set; }

        internal void mainProcess()
        {
            // 初期化
            Initialize();

            // NFCRW接続
            if (!ConnectNFCRW())
            {
                return;
            }
            // GET UID
            getUid();
            // SELECT AID
            var aid = new byte[] { 0xF2, 0x22, 0x22, 0x22, 0x22 };
            selectAID(aid);
        }

        internal void Initialize()
        {
            var contextFactory = ContextFactory.Instance;
            this.SCardContext = contextFactory.Establish(SCardScope.System);
        }

        internal bool ConnectNFCRW()
        {
            string txt = string.Empty;
            bool result = false;
            // Console.WriteLine("カードを置いてください。");
            // Console.ReadKey();
            try
            {
                // 最初に見つけたNFCRWに接続する.
                var readerNames = SCardContext.GetReaders();
                if (IsEmpty(readerNames))
                {
                    return false;
                }
                readerName = readerNames[0];
                using (var rfidReader = SCardContext.ConnectReader(readerName, SCardShareMode.Shared, SCardProtocol.Any))
                {
                    var status = rfidReader.GetStatus();
                    txt += String.Format("Reader {0}\r\n connected with protocol {1}\r\n in state {2}",
                        status.GetReaderNames().FirstOrDefault(),
                        status.Protocol,
                        status.State);
                    var atr = status.GetAtr();
                    if (atr != null || atr.Length > 0)
                    {
                        txt += String.Format("\r\n Card ATR: {0}", BitConverter.ToString(atr));
                    }
                }
                result = true;

            }
            catch (Exception ex)
            {
                txt = ex.Message;
                result = false;
            }
            Console.WriteLine(txt);
            return result;
        }
        internal void getUid()
        {
            string txt = string.Empty;
            try
            {
                using (var rfidReader = SCardContext.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))
                    {
                        // Retrieving the UID .... 

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

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

                        int 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);
                        if ((responseApdu.SW1 == 0x90) && (responseApdu.SW2 == 0x00))
                        {
                            txt = "UID : ";
                            txt += responseApdu.HasData ? BitConverter.ToString(responseApdu.GetData()) : "No uid received";
                        }
                        else
                        {
                            txt = string.Format("SW1: {0:X2}, SW2: {1:X2}\r\n00",
                                responseApdu.SW1,
                                responseApdu.SW2);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                txt = ex.Message;
            }
            Console.WriteLine(txt);
        }

        internal void selectAID(byte[] aid)
        {
            string txt = string.Empty;
            try
            {
                using (var rfidReader = SCardContext.ConnectReader(readerName, SCardShareMode.Shared, SCardProtocol.Any))
                {
                    var apdu = new CommandApdu(IsoCase.Case3Short, rfidReader.Protocol)
                    {
                        CLA = 0x00,
                        Instruction = InstructionCode.SelectFile,
                        P1 = 0x04,
                        P2 = 0x00,
                        Data = aid //AID
                    };
                    var command = apdu.ToArray();
                    txt += string.Format("APDU: {0}\r\n", BitConverter.ToString(command));
                    using (rfidReader.Transaction(SCardReaderDisposition.Leave))
                    {
                        // Retrieving the AID .... 

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

                        var receiveBuffer = new byte[256];
                        int 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);
                        txt += string.Format("SW1: {0:X2}, SW2: {1:X2}\r\n",
                            responseApdu.SW1,
                            responseApdu.SW2);
                        if ((responseApdu.SW1 == 0x90) && (responseApdu.SW2 == 0x00))
                        {
                            txt += "received:";
                            txt += responseApdu.HasData ? BitConverter.ToString(responseApdu.GetData()) : "No data received";
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                txt = ex.Message;
            }
            Console.WriteLine(txt);
        }

        private static bool IsEmpty(ICollection<string> readerNames) => readerNames == null || readerNames.Count < 1;
    }
}

実行結果

リーダーにHCEアプリを起動したAndroidを乗せ、アプリを実行してみます。

Reader ACS ACR1251 CL Reader PICC 0
 connected with protocol T1
 in state Specific
 Card ATR: 3B-88-80-01-00-00-00-00-80-81-71-00-79
UID : B8-65-F7-C4
APDU: 00-A4-04-00-05-F2-22-22-22-22
SW1: 90, SW2: 00
received:30-30-30-30-30-30-30-30

無事受信できました。

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?