【Python】PaSoRiによるICカードの読み取り
2022/04/16追記:使用したlibusbのVersion記載
2022/10/03追記:Windows11環境での再検証
目的
交通機関などで使われるようなICカードの中身をpythonを使って自宅で閲覧するための検証をします。
とりあえず、読み取るだけまでを目指し、なるべくシンプルなコードで試そうと思います。
2022/10/3追記
上手くいかないというコメントを頂きましたので、Windows11環境にはなってしまいますが、再度検証を行いました。Windows11環境で検証した結果、読み取りはできましたので参考にしていただければと思います。
環境
2022/10/3の最新の検証環境
- Windows11 64bit 21H2
- python 3.8.10
- PaSoRi(RC-S380)
- libusb v1.0.26
以下は過去の検証環境です
- Windows10 64bit
- python3.7(Anaconda3)
- PaSoRi(RC-S380)
方針
pythonにはnfcpyというnfcデバイスの制御ができる、素晴らしいライブラリがあります。今回はこのnfcpyを使用します。
以下のnfcpyの説明サイトで詳しく書かれていますので、これを参考に進めたいと思います。
https://nfcpy.readthedocs.io/en/latest/topics/get-started.html
簡単に言うと、次のような順番で実施します。
- Zadigというツールを使いWinUSBをインストールする。
- libusbをインストールする。
- pythonでnfcpyを使ってコーディングする。
WinUSBとはMicrosoftが提供するUSBドライバらしく、おそらく、PaSoRiなどのリーダのIO制御に必要なのかと思います。そして、ZadigはそのWinUSBを簡単にインストールできるGUIベースのツールのようです。
libusbはUSBデバイスへアクセスするためのCのライブラリで、おそらくnfcpyを使う前提として必要なのだと思います。
ということで、まずはWinUSBとlibusbを準備した上で、pythonのnfcpyを使ってコーディングをしていきたいと思います。
Step1 : WinUSBのインストール
以下のZadigのサイトからZadigの最新版をダウンロードします。
2022/10/3追記
以前はzadig-2.4を使用しましたが、最新の検証環境ではzadig-2.7を使用しました。
旧検証時
今回はzadig-2.4をダウンロードしました。
zadig-2.4.exeをダウンロードして任意の場所に保存した後、右クリック から 管理者として実行を選択します。
すると、GUIが開くので、以下のようにOptions > List All Devicesにチェックを入れます。
次に、PCのUSB端子にPaSoRi(RC-S380)を接続し、下図のようにプルダウンメニューからNFC Port/PaSoRi 100 USBを選択します。PaSoriを接続した状態にしないと選択しとして出てこない場合があります。
2022/10/3再検証
zadig-2.7を使用した場合、以下のようにRC-S380/Pを選ぶと、Driverとしてsonynfcport100c(v1.5.10.0) → WinUSB(v6.1.7600.16385)の組み合わせを選ぶことができました。
この組み合わせでReplace Driver (あるいはInstall Driver)を選択すると、インストールが始まり、完了できました。
以下は旧環境の検証結果
そして、Driverのところで、WinUSB(v6.1.7600.16385)を選択し、Install Driverをボタンを押します。下図は一旦インストールした際に撮ったスクショのため、Replace Driverになってますが、初回はInstall Driverになっているはずです。
Install Driverをクリックすると、インストールが始まりますので、完了するまで待ちます。以上でWinUSBのインストールは完了です。
Step2 : libusbのインストール
以下のサイトからlibusbをダウンロードします。ページのDownloads > Lates Windows Binariesを選択すると、ダウンロードが開始され、7zの拡張子の圧縮ファイルが落ちてきます。
https://libusb.info/
ダウンロードしたファイルを任意の場所へ保存したら、7zipを使って解凍します。
2022/10/3追記
再検証時はlibusb v1.0.26を使用しました。
今回使用したのはlibusb 1.0.22です。
解凍して生成されたフォルダの中から以下の2つのファイルを指定の場所にコピーします。この作業を忘れるとPaSoRiは動きませんので、注意してください。
2022/10/3再検証
- ./VS2015-x64\dll\libusb-1.0.dllを C:\Windows\System32 へコピーする。
- ./VS2015-x64\dll\libusb-1.0.dll を C:\Windows\SysWOW64 へコピーする。
旧環境検証時
- MS64dll\libusb-1.0.dllを C:\Windows\System32 へコピーする。
- MS32\dll\libusb-1.0.dll を C:\Windows\SysWOW64 へコピーする。
以上でlibusbのインストールは完了です。
Step3 : Pythonによる実装
2022/10/3追記
再検証した環境はAnacondaではなく純粋なPythonの環境にて実施しました。以下で作成した環境になります。
旧環境の検証時
まず、Anaconda promptを立ち上げてnfcpyをインストールします。
pip install nfcpy
次に、PaSoRiの上にICカードを載せます。
そして、以下のコードを実行します。
import nfc
#接続定義
clf = nfc.ContactlessFrontend('usb')
print(clf)
#タグの取得
tag = clf.connect(rdwr={'on-connect': lambda tag: False})
#結果表示
print(tag)
print(dir(tag))
SONY RC-S380/P on usb:002:001
Type3Tag ‘FeliCa Standard (RC-S???)’ ID=xxxxxx PMM=xxxxxx SYS=xxxxxx
[‘IC_CODE_MAP’, ‘NDEF’, ‘TYPE’, ‘class‘, ‘delattr‘, ‘dict‘, ‘dir‘, ‘doc‘, ‘eq‘, ‘format‘, ‘ge‘, ‘getattribute‘, ‘gt‘, ‘hash‘, ‘init‘, ‘init_subclass‘, ‘le‘, ‘lt‘, ‘module‘, ‘ne‘, ‘new‘, ‘reduce‘, ‘reduce_ex‘, ‘repr‘, ‘setattr‘, ‘sizeof‘, ‘str‘, ‘subclasshook‘, ‘weakref‘, ‘_authenticated’, ‘_clf’, ‘_format’, ‘_is_present’, ‘_ndef’, ‘_nfcid’, ‘_product’, ‘_target’, ‘authenticate’, ‘clf’, ‘dump’, ‘dump_service’, ‘format’, ‘identifier’, ‘idm’, ‘is_authenticated’, ‘is_present’, ‘ndef’, ‘pmm’, ‘polling’, ‘product’, ‘protect’, ‘read_from_ndef_service’, ‘read_without_encryption’, ‘request_response’, ‘request_service’, ‘request_system_code’, ‘search_service_code’, ‘send_cmd_recv_rsp’, ‘sys’, ‘target’, ‘type’, ‘write_to_ndef_service’, ‘write_without_encryption’]
ICに用意されているタグが簡単にわかりました。
あとは、tag.dumpすると、実際のデータを見ることができます。(途中割愛しています)
tag.dump()
‘System 0003 (Suica)’,
‘Area 00
‘ Cyclic Service 36: write with key & read w/o key…,
‘ 0000: 16 01 00 …
|……..D…….|’,
データを見ることはできましたが、データの意味まで理解するためには、そもそもどんな形でデータが入っているかの予備知識があったり、暗号化されていないことが前提となりそうです。
結果
python nfcpyを使うと、初心者でもデータの中身まで簡単に表示できました。
ただし、中身の意味を知ろうとした場合はICカードがどう運用されているのかの予備知識も必要そう。平文ベタ打ちなら何かしらはわかるかも。
以上
分かりやすい記事で参考にさせていただきました。途中まで順調に進みましたが、
clf = nfc.ContactlessFrontend(‘usb’) でつまずきました。私の環境がWindowsですのでどうも USBの情報がとれないようです。 python -m nfc –search-ttyをしますと、\devの検索しています。Windowsの場合レジストリにその情報があるはずですので、これはLinuxしか動かないのではと思い、あきらめ、winscard.dllを使い C++で作ることにしました。
nfcpyの新しいバージョンを期待します。 今後もpythonの記事を楽しみにしています。
野村 様
記事をご覧くださりありがとうございます。記載が漏れていたのですがこの検証で使用したlibusbのバージョンは1.0.22でした。もし別のバージョンでお試しされてるのであれば、一度1.0.22で試して頂けるとよろしいかと思います。(記事にはバージョンを追記させて頂きました)。見たところ最新バージョンの1.0.26ではMS32とMS64のフォルダが入っておらず、cygwin,Mingw,VS2015用のdllしか内包されていなかったです。ご参考になれば幸いです。
https://github.com/libusb/libusb/releases?page=2
1.0.22でやってみても、何度試してもできません。。。
> こっこ様
コメントありがとうございます。私の検証環境がWindows11になってしまっているため申し訳ございませんが、Windows11で検証した結果を追記しましたので参考にしていただければと思います。
zadig-2.7を使用したのと、libusbをv.1.0.26を使用しております。こちらで一度お試しくださいませ。