0
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?

nfcpyを使ってFeliCaのIDmを読んだりエミュレートしたり...

Posted at

概要

  • nfcpy を使って簡単にFeliCaのエミュレーションをやれる
  • もちろんSW的なものだけで解決するわけではなく、あくまで対応するFeliCaのカードリーダーが必要になる
    • まぁそんなに高いものでもないし簡単に手に入る
  • これらのアプローチによってFeliCa関連の開発やら検証がだいぶ捗る
    • いちいちたくさんのカードを用意して、わざわざ手動でかざして...とか時間かかるし大変だからね
  • 最後に今回紹介した手法以外のアプローチについても紹介

事前に必要なもの

基本的な使い方

Getting Starged をまず読みましょう。

lsusb とかで色々確認する手順が書かれてるけど、まぁ別にやらんでも Supported devices に載ってる値を使えばOK

超単純に読み取り

以下のコードを実行し、カードをかざす。これでIDmが表示されるはず。

read_tag.py
import nfc

def on_connect(tag):
    # タグ種別やIDなど(FeliCaなら Type3Tag になることが多い)
    print(tag)

    # NDEFがあれば表示(なければ None)
    if tag.ndef is None:
        print("NDEF: (none)")
    else:
        print(f"NDEF length: {tag.ndef.length}")
        for r in tag.ndef.records:
            print(" -", r)

    # False を返すと、presence loop を回さずにすぐ connect() が戻る(=1回読んで終わり)
    return False

def main():
    # 'usb' の部分は 'usb:054c:06c1' のように特定デバイス指定もOK
    with nfc.ContactlessFrontend("usb") as clf:
        tag = clf.connect(rdwr={"on-connect": on_connect})
        # on_connect が False を返すと、ここに tag が返る(必要ならここで追加処理)
        # print("returned:", tag)

if __name__ == "__main__":
    main()
  • 実行例
    • スクリプト実行後、すかさずカードリーダーにカードをかざす
read_tag.py
Type3Tag ID=01234567890ABCDEF PMM=01234567890ABCDEF SYS=0003
NDEF: (none)

超単純にエミュレート

読み取ったカードのIDmを指定してエミュレートさせる。動作確認としてスマホを使えばOK.

emulate.py
import struct
import nfc

# 16バイト=1ブロック。ここでは「16ブロック(=256B)」だけ用意
ndef_data_area = bytearray(16 * 16)

def init_attr_block():
    # Attribute Information Block (block 0) を最低限埋める
    # 公式ドキュメントの例に沿う(RC-S380前提の読み書きブロック数)
    ndef_data_area[0] = 0x10  # NDEF mapping version '1.0'
    ndef_data_area[1] = 12    # 一度に読めるブロック数
    ndef_data_area[2] = 8     # 一度に書けるブロック数
    ndef_data_area[4] = 15    # NDEFデータ用ブロック数(ここでは 16ブロック中 block0 を除く等、用途に合わせて調整)
    ndef_data_area[10] = 1    # 読み書き許可
    # NDEF message length (bytes 11..13) は 0 のまま(空)
    ndef_data_area[14:16] = struct.pack(">H", sum(ndef_data_area[0:14]))  # checksum

def ndef_read(block_number, rb, re):
    if block_number < len(ndef_data_area) // 16:
        i = block_number * 16
        return ndef_data_area[i:i+16]

def ndef_write(block_number, block_data, wb, we):
    if block_number < len(ndef_data_area) // 16:
        i = block_number * 16
        ndef_data_area[i:i+16] = block_data
        return True

def on_startup(target):
    # 例: IDm/PMm/SYS をセット(公式例の値)
    idm, pmm, sys = "03FEFFE011223344", "01E0000000FFFF00", "12FC"
    target.sensf_res = bytearray.fromhex("01" + idm + pmm + sys)
    target.brty = "212F"  # FeliCa 212kbps
    return target

def on_connect(tag):
    print("tag activated")
    # サービスコード 0x0009, 0x000B を NDEF読み書き向けに登録(公式例)
    tag.add_service(0x0009, ndef_read, ndef_write)
    tag.add_service(0x000B, ndef_read, lambda: False)
    return True  # Trueだと「タッチされている間」動作し、離すとループが1回戻る

def main():
    init_attr_block()

    # RC-S380/S: usb:054c:06c1 (環境に合わせて変更)
    with nfc.ContactlessFrontend("usb:054c:06c1") as clf:
        while clf.connect(card={"on-startup": on_startup, "on-connect": on_connect}):
            print("tag released")

if __name__ == "__main__":
    main()
  • 実行例: スクリプト実行後にすかさずスマホをかざす
emulate.py
tag activated
tag released

こんな感じで読み取れた。これはまさに↑でエミュレートさせたやつを読み込ませた。
iOSの NFC Tools アプリを使用

image.png

復合パターン

あとは組み合わせの問題でしかなく、例えば copyモードのように読み取ってそれをすぐにエミュレート... というスクリプトも簡単に書ける。

もっと楽なパターン

ここまでは汎用的なカードリーダーと nfcpy を使った方法を紹介したが、もっと楽なパターンもあるっちゃある。

単一HW的に全部組み込まれたものもあって、例えば Flipper Zero が一番有名だろう。Amazonから買える。

PC持ち歩いてあーだのこーだのやるのは大変。こういった小型デバイスなら、まぁ色んな環境での利用が容易になる。
詳しい言及は避けるが、やろうと思えばやっちゃいけないことにも使えてしまう。

たっけーよ!と思う人向けには、ググれば互換機がいくらか出てくる。
FW書き換えを前提にすれば数千円レベルで買えるものも全然ある。

他のNFCのタイプは??

ここまでくると、あれ? FeliCa以外はどうなるの?と当然思うだろう。
今回紹介したnfcpyを使うアプローチだとFeliCa以外は無理。
が・・・一部限定的ではあるが、上述のHWを使うようなアプローチなら可能。そのうち記事にするかもしれない。

0
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
0
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?