Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8895

PCSC-sharpでWindowsからNFCタグを読み取ってみた

$
0
0

従業員の入退室管理のため、300枚はあろうかというMifareカードのUIDを読み取る必要があった。
良さげなフリーソフトが見つからなかったので、自分でコード書いてみたという話。

PCSC-sharpとは

Windows7以降に標準添付されているwinscard.dll.NETから簡単に使えるようにするラッパーライブラリ。
:point_right_tone2:【入手元】 https://github.com/danm-de/pcsc-sharp

winscard.dllはスマートカード(ISO7816規格)をWindowsから操作するPC/SCというAPIの実装である。

PCSC-sharpに頼らず自分でDLLを叩きたいんだ!という人は、
@rheneさんの記事 https://qiita.com/rhene/items/725dfe4a6b6307731cbf
がとても参考になると思う。

NFCとは

RFIDと呼ばれる無線通信方式のひとつで、下表の通り複数の規格がある。

規格日本における用途
Type-A (Mifare)Taspoなど
Type-Bマイナンバーカード、住民基本台帳カード、運転免許証など
Type-F (FeliCa)Suica、楽天Edy、nanacoなどの電子マネー
ISO/IEC 15693物流の商品タグなど

Type-AとType-Bは事実上の世界標準で、NFC Pay(クレジットカードのタッチ決済)にも使われている。
日本ではSuicaの自動改札で通信速度が必要だったという背景からFeliCaが採用され、その他電子マネーもこぞって追随したことからFeliCaが普及した。

入退室管理に使うカードではそこまでの性能は必要ないので、安価なMifareが良く使われている。

FeliCaはSONYが開発したものだが、技術力の高さゆえの過剰性能が災いしガラパゴス化した。
4K、8Kテレビは国内メーカーを助けるための開発ではあるが、同じ道を歩まないことを期待する。

ソフトウェアの作成手順

開発環境

ソフトウェア

  • Visual Studio 2019(C#)
  • Windows 10 Pro 1903

ハードウェア

  • SONY ICカードリーダ/ライタ PaSoRi RC-S380(非接触型)
  • DELL ノートパソコン Latitude 7390 内蔵NFCセンサ(非接触型)
  • DELL ノートパソコン Latitude 7390 内蔵スマートカードスロット(接触型)

image.png

NuGetパッケージ

次のNuGetパッケージをプロジェクトに追加する。

画面構成

UIコンポーネントを下図のように配置した。
image.png

C# コード

冒頭にusingディレクティブを追加する。

usingPCSC;usingPCSC.Iso7816;usingPCSC.Exceptions;

アプリケーション起動時、接続されているカードリーダの名前をすべてコンボボックスに追加する。

カードリーダがひとつも接続されていなければアプリケーションを終了する。
PCSC.Exceptions.NoServiceExceptionがスローされたら、ドライバがインストールされていないので、やはり終了する。

FormMain_Load
privatevoidFormMain_Load(objectsender,EventArgse){// リーダーの機器情報を取得try{using(varcontext=ContextFactory.Instance.Establish(SCardScope.System)){varreaderNames=context.GetReaders();if(readerNames==null||readerNames.Length==0){MessageBox.Show("スマートカードリーダが見つかりません","エラー",MessageBoxButtons.OK,MessageBoxIcon.Hand);Application.Exit();// スマートカードリーダが無ければ終了する}foreach(varreaderNameinreaderNames){comboBoxDevice.Items.Add(readerName);// カードリーダの名前をコンボボックスに追加}}}catch(NoServiceException){MessageBox.Show("スマートカードリソースマネージャが稼働していません","エラー",MessageBoxButtons.OK,MessageBoxIcon.Hand);Application.Exit();}comboBoxDevice.SelectedIndex=0;radioButtonNone.Checked=true;// データグリッドビューの初期設定dataGridView.AllowUserToResizeColumns=true;dataGridView.AllowUserToResizeRows=false;dataGridView.RowHeadersVisible=false;dataGridView.ClipboardCopyMode=DataGridViewClipboardCopyMode.EnableWithoutHeaderText;dataGridView.SelectionMode=DataGridViewSelectionMode.FullRowSelect;dataGridView.Columns.Add("seq","連番");dataGridView.Columns.Add("datetime","読み取り日時");dataGridView.Columns.Add("uid","UID/IDm");dataGridView.Columns["seq"].Width=80;dataGridView.Columns["datetime"].Width=200;dataGridView.Columns["uid"].Width=250;}

ボタンがクリックされたら読み取り動作をする。
読み取り用のAPDUコマンドを組み立て、送信し、結果を受信するという手順になる。

pcsc-sharp/Examples/ISO7816-4/Transmit/Program.csを参考にしている。

privatevoidbuttonRead_Click(objectsender,EventArgse){varreaderName=comboBoxDevice.Text;// 選択中のカードリーダ名を得るusing(varcontext=ContextFactory.Instance.Establish(SCardScope.System)){try{using(varrfidReader=context.ConnectReader(readerName,SCardShareMode.Shared,SCardProtocol.Any)){// APDUコマンドの作成varapdu=newCommandApdu(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)){varsendPci=SCardPCI.GetPci(rfidReader.Protocol);varreceivePci=newSCardPCI();// IO returned protocol control information.varreceiveBuffer=newbyte[256];varcommand=apdu.ToArray();varbytesReceived=rfidReader.Transmit(sendPci,// Protocol Control Information (T0, T1 or Raw)command,// command APDUcommand.Length,receivePci,// returning Protocol Control InformationreceiveBuffer,receiveBuffer.Length);// data buffervarresponseApdu=newResponseApdu(receiveBuffer,bytesReceived,IsoCase.Case2Short,rfidReader.Protocol);if(responseApdu.HasData){// バイナリ文字列の整形StringBuilderid=newStringBuilder(BitConverter.ToString(responseApdu.GetData()));if(radioButtonNone.Checked){id.Replace("-",string.Empty);}elseif(radioButtonSpace.Checked){id.Replace("-"," ");}// データグリッドビューに結果を追加し、連番をカウントアップするintseq=(int)numericUpDown.Value;DateTimedt=DateTime.Now;dataGridView.Rows.Add(seq,dt.ToString("yyyy/MM/dd HH:mm:ss"),id.ToString());numericUpDown.Value=++seq;}else{MessageBox.Show("このカードではIDを取得できません","エラー",MessageBoxButtons.OK,MessageBoxIcon.Warning);}}}}catch(RemovedCardException){MessageBox.Show("スマートカードが取り外されたため、通信できません","エラー",MessageBoxButtons.OK,MessageBoxIcon.Hand);}catch(PCSCExceptionex){MessageBox.Show(ex.Message,"スマートカードエラー",MessageBoxButtons.OK,MessageBoxIcon.Hand);}}}

実行結果サンプル

image.png


Viewing all articles
Browse latest Browse all 8895

Trending Articles