Posted at

NFC・Felica(Suica, PASMO)でSESAMEを解錠出来るようにする


注意

この記事は nfcpyPython2 にしか対応していなかった頃に実装した記録です。

現在、 nfcpyPython3 に対応しています。


環境変数について

私は環境変数を使う形で書いたのですが、一般ユーザーで環境変数を設定した後

raspbian では sudo すると環境変数がリセットされてしまうので、

sudo 時に環境変数を引き継ぐようにするか sudo 無しで使えるようにする必要がありました。


sudo 無しでRC-S380を使える様にする

参考: Suicaでセサミを解錠 ( with ラズパイ)

参考: 交通系電子マネーカードを 黒PaSori RC-S380 + Raspberry Pi + python で

> lsusb

> sudo sh -c 'echo SUBSYSTEM==\"usb\", ACTION==\"add\", ATTRS{idVendor}==\"054c\", ATTRS{idProduct}==\"06c3\", GROUP=\"plugdev\" >> /etc/udev/rules.d/nfcdev.rules'
> sudo udevadm control --reload-rules
> sudo reboot

ATTRS{idVendor}==\"XXXX\", ATTRS{idProduct}==\"YYYY\" の部分は使っているカードリーダーによって固定の値です。

Sony の PaSori RC-S380 なら上記のコピペで平気なはずです。

参考: USBのベンダーIDとプロダクトIDの話

違うリーダーの場合 lsusb の値を参照しましょう。


sudo 時に環境変数を引き継ぐようにする場合

こちらの記事を参考にしました

参考: sudo時に環境変数PATHが引き継がれない時の対策

上記記事では PATH に限定していますが、 PATH 以外の環境変数を引き継ぎたい場合も visudo で同様にできます

root になってから visudo を実施します

$ su -

# visudo

env_resetsecure_path をコメントアウト(先頭に # を足)します

そして、次の一行を追加します

Defaults    env_keep += "<引き継ぎたい環境変数>"

env_keep に加えることで引き継がせることが出来ます。


実装

これらの記事を参考にしました

参考: Suicaでセサミを解錠 ( with ラズパイ)

参考: PaSoRiでNFCタグとFeliCaを読み込んで出力

参考: Raspberry PiにNFCリーダを接続してSuicaを読み取る


環境変数から情報を取る

Python の話です。

Felica における IDm や NFC の UID 、APIのAuthTokenといった秘匿しておきたい情報についてはコード上に載せず、

環境変数から取ってくるようにしました。

os.environ.get() コマンドで取得出来ます


API

必要なAPIコールはそれぞれ関数として定義しておきます


操作

APIについて


def control_sesame(device_id, command):
url_control = "{0}/sesame/{1}".format(api_endpoint, device_id)
head_control = {"Authorization": auth_token,
"Content-Type": "application/json"}
payload_control = {"command": command}
response_control = requests.post(
url_control, headers=head_control, data=json.dumps(payload_control))
return response_control


結果確認

APIについて


def check_sesame_task(task_id):
url_check = "{0}/action-result?task_id={1}".format(api_endpoint, task_id)
head_check = {"Authorization": auth_token}
response_check = requests.get(url_check, headers=head_check)
return response_check


解錠


def unlock_sesame(device_id, card_id):
response_control = control_sesame(device_id, "unlock")
if response_control == None and not hasattr(response_control, "_content"):
return False

# print vars(response_control)
response_control_content = json.loads(response_control._content)
task_id = response_control_content["task_id"]
print "task_id = {0}".format(task_id)

time.sleep(7.0)
response_check = check_sesame_task(task_id)
if response_check == None and not hasattr(response_check, "_content"):
return False

response_check_content = json.loads(response_check._content)
# print response_check_content
if response_check_content["status"] == "processing":
print "processing"
pass

if response_check_content["status"] == "terminated":
result = response_check_content["successful"]
print "[{0}] card_id: {1} device_id: {2} unlock: {3}".format(datetime.now().strftime("%Y/%m/%d %H:%M:%S"), card_id, device_id, "successful" if result else "failed")
return


メイン

if __name__ == "__main__":

# NFC接続リクエストのための準備
target_req_nfc = nfc.clf.RemoteTarget("106A")
# Suica接続リクエストのための準備
target_req_felica = nfc.clf.RemoteTarget("212F")

print "Waiting for NFC..."
while True:
# USBに接続されたNFCリーダに接続してインスタンス化
clf = nfc.ContactlessFrontend("usb")
# NFC待ち受け開始
# clf.sense( [リモートターゲット], [検索回数], [検索の間隔] )
target_res = clf.sense(target_req_nfc, target_req_felica, iterations=int(
TIME_cycle//TIME_interval) + 1, interval=TIME_interval)

if target_res != None:
print target_res
print vars(target_res)
if not hasattr(target_res, "_brty_send"):
continue

brty = target_res._brty_send
if brty == "106A":
tag = nfc.tag.activate_tt2(clf, target_res)
elif brty == "212F":
tag = nfc.tag.activate_tt3(clf, target_res)
else:
continue

print tag
if tag != None:
print vars(tag)
print tag.type

# Felica
if hasattr(tag, "type") and tag.type == "Type3Tag":
tag.sys = 3
idm = binascii.hexlify(tag.idm)
print "Felica detected. idm = {0}".format(idm)
if idm in key_idms:
unlock_sesame(device_id, idm)

# NFC
else:
if not hasattr(tag, "_nfcid"):
print "Error: tag doesn't have nfcid"
continue

uid = binascii.hexlify(tag._nfcid)
print "NFC detected. uid = {0}".format(uid)
if uid in key_uids:
unlock_sesame(device_id, uid)

# 共通
print "sleep {0} seconds".format(str(TIME_wait))
time.sleep(TIME_wait)

clf.close()

            if brty == "106A":

tag = nfc.tag.activate_tt2(clf, target_res)
elif brty == "212F":
tag = nfc.tag.activate_tt3(clf, target_res)

の部分ですが、Windowsで行っていた際、 nfc.tag.activate(clf, target_res) でどちらも対応できましたが、

raspbian だとそれぞれTypeを指定しないと動きませんでした。

コード全体は GitHub に置いてあります