LoginSignup
15

More than 3 years have passed since last update.

Nfcpy on MacでFeliCaを読む(2021年2月)

Last updated at Posted at 2021-02-15

久しぶりにmacにてnfcpyを利用してFeliCa(WAON)を読む機会があったのでメモ。
以前(2016年)にも同じ趣旨の記事を書いたことがあったのですが、2021年環境で再挑戦。

2016年との同じところ・違うとこ

2016年と同じところもあれば、違うところもある。基本的に簡単になってます。

  • pipはbrewでは(あいかわらず)インストールできない
  • nfcpyはpython3.x(3.5以上)にも対応した(2.xじゃないとダメって記事が多かったけど3.xでOKみたいです)
  • インストールする周辺モジュールは減った(でも0ではない)

やりたいこと

そもそもやりたいことは以下の通り。システムコードやサービスコードがわかっている(わからなくても調べられる)サービスであればいろいろ応用はできると思います。

  • Mac + Pasori(RC-S380)を利用したい
  • あるFeliCa(WAON)のメモリ構造と内容を知りたい
  • WAON番号(16桁)を取り出したい
  • 最終的にはラズパイで利用したのですが、ここではまずnfcpyの利用を検証

インストール

では、環境整備から。

pip

何はなくてもpip。Macにはpython2とpython3がインストールされていますが、python3を明示的に利用してみます。

curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python3 get-pip.py

そもそもget-pip.pyはpython3用のコードらしく2だとエラーになりましたね。

Nfcpy

pip3 install nfcpy

libusb

libusbが無いと実行時にエラーになるみたいなのでbrewでインストールしておきます。

brew install libusb

lsusb(おまけ)

そもそもMacにPasoriが認識されているかを調べたいのでインストールしておきます。

brew install lsusb
lsusb

Bus 020 Device 001: ID 05ac:0267 Apple Inc. Magic Keyboard  Serial: F0T733400FKJ20TAG
Bus 020 Device 000: ID 05ac:8294 Apple Inc. Bluetooth USB Host Controller 
Bus 020 Device 019: ID 05ac:8511 Apple Inc. FaceTime HD Camera (Built-in)  Serial: CCGH17035YH0G1F0
+Bus 020 Device 005: ID 054c:06c3 Sony Corporation RC-S380/P  Serial: 0523593
Bus 000 Device 001: ID 1d6b:ISPT Linux Foundation USB 3.0 Bus 

認識されていますね。

テスト1:メモリタンプ

WAON番号を読むためのシステムコードやサービスコードの情報はネット上にありますが、他のエリアの内容も見たかったのでメモリダンプしてみます。

実装

先人のノウハウがあったので参考にさせていただきました。本当にありがとうございます。
ほぼpython2を3にしているだけです。

waon.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import nfc

def connected(tag):
  # IDm, PMM等を出力
  print(tag)

  if isinstance(tag, nfc.tag.tt3.Type3Tag):
    try:
      # 内容を16進数で出力する
      print(('  ' + '\n  '.join(tag.dump())))
    except Exception as e:
      print("error: %s" % e)
  else:
    print("error: tag isn't Type3Tag")

# タッチ時のハンドラを設定して待機する
clf = nfc.ContactlessFrontend('usb')
clf.connect(rdwr={'on-connect': connected})

実行

実行してみます。
ポイントはNDEF用のSystem 0x12FCと共通領域(0xFF00)の2つのシステムが存在しているということ。

で、WAONの情報は0xFF00の方に書かれています。

python3 waon.py

Type3Tag 'FeliCa Standard (RC-S962)' ID=0114F100A0143000 PMM=0120220427674EFF SYS=12FC
  System 12FC (NDEF)
  Area 0000--FFFE
  System FE00 (Common Area)
  Area 0000--FFFE
    Area 3940--39FF
      Area 3941--39FF
        Random Service 229: write with key & read w/o key (0x3948 0x394B)
         0000: 70 ed 8e aa 14 10 00 70 01 00 00 00 00 00 00 00 |p......p........|
        Random Service 230: write with key & read w/o key (0x3988 0x398B)
         0000: 50 75 bc 5a 48 23 68 c5 dc b6 f5 0c c0 c2 ce 71 |Pu.ZH#h........q|
         0001: 89 ee 71 e6 12 3b be ff 96 b5 2b 69 1a 54 1e f1 |..q..;....+i.T..|
         0002: 47 76 f7 10 bb 9f 3d ec 92 86 53 f1 43 11 07 cc |Gv....=...S.C...|
         0003: fc db 41 9e cd 36 7e 33 1d 4b 69 24 c2 65 a6 36 |..A..6~3.Ki$.e.6|
         0004: d6 34 2c 24 02 0e bf c3 f7 5d 89 32 9f 2c ba 48 |.4,$.....].2.,.H|
         0005: d7 78 f1 50 56 31 d5 84 d8 22 b8 2d 93 1a e9 27 |.x.PV1...".-...'|
         0006: 31 c9 5c f2 46 c8 41 3c 58 77 87 ca 7d 05 69 53 |1.\.F.A<Xw..}.iS|
         0007: a8 3f f1 e9 f4 fb 5b 2d f4 49 a9 47 31 fd a3 fc |.?....[-.I.G1...|
         0008: ae 0e 81 cf bf 1b 37 12 a3 4d 53 f4 25 c8 95 00 |......7..MS.%...|
         0009: 09 88 52 7c 78 07 76 64 66 7c 1f 05 77 16 f9 a1 |..R|x.vdf|..w...|
         000A: fe 1f 3f 59 5b d5 7f 7e 2d 63 7e 8e 9b 99 8f db |..?Y[..~-c~.....|
         000B: 1a 15 f1 9f 5b f3 2b 6a 18 28 97 55 cd b6 ad 66 |....[.+j.(.U...f|
         000C: 84 16 0f 5e fb 4f c6 01 7a 20 35 08 75 b7 30 01 |...^.O..z 5.u.0.|
         000D: 37 56 9a 95 10 90 4f e0 36 82 df 49 80 22 6e 2e |7V....O.6..I."n.|
         000E: 49 58 ab c3 32 92 ee 5d 3b c1 33 e9 4f 59 04 79 |IX..2..];.3.OY.y|
         000F: 1b 5d 05 38 3b 43 7d 9f ff a2 d3 a2 01 11 cf 29 |.].8;C}........)|
         0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         0026: 09 88 52 7c 78 07 76 64 09 88 52 7c 78 07 76 64 |..R|x.vd..R|x.vd|
         0027: 09 88 52 7c 78 07 76 64 32 53 fe 51 a6 0c 7b 31 |..R|x.vd2S.Q..{1|
        Random Service 231: write w/o key (0x39C9)
         0000: 00 00 dd 00 00 2e e0 00 00 2e e0 00 00 c9 00 00 |................|
         0001: 00 1e 00 00 00 1e 00 00 e9 00 00 00 05 00 00 00 |................|
         0002: 05 00 00 e4 00 00 00 00 00 00 00 00 00 00 e8 00 |................|
         0003: 00 00 00 00 00 00 00 00 00 56 00 00 00 01 00 00 |.........V......|
         0004: 00 01 00 00 bb b6 2d 13 b3 b6 3c 55 e8 00 00 f2 |......-...<U....|
         0005: 00 00 00 32 00 00 00 32 00 00 00 00 00 00 00 00 |...2...2........|
         0006: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
         000E: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
        Area 67C0--68FF
        Area 67C1--68FF
          Random Service 415: write with key & read w/o key (0x67C8 0x67CB)
           0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
           0001: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 41 |...............A|
           0002: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
           0003: a9 22 ee a6 a8 e1 0a 89 80 00 00 00 00 00 00 00 |."..............|
          Cyclic Service 415: write with key & read w/o key (0x67CC 0x67CF)
           0000: 00 01 01 01 00 01 01 01 00 01 00 c0 69 00 17 21 |............i..!|
           0001: 31 95 12 43 00 00 00 00 00 00 00 00 00 00 00 00 |1..C............|
           0002: 00 00 00 00 00 00 00 00 50 00 00 00 00 00 00 00 |........P.......|
           0003: 0c 0f e2 92 f5 e1 89 e1 e1 40 28 03 51 19 a9 e0 |.........@(.Q...|
           0004: a4 15 b3 e0 0d a8 d6 d5 f6 fb 60 1c 2a b1 c8 45 |..........`.*..E|
           0005: 47 1c 5d e7 99 49 e0 71 1f 9b f4 6b ac f2 2e 93 |G.]..I.q...k....|
           0006: d4 56 c7 22 87 fc 2b 01 c5 12 28 db bf 49 10 e8 |.V."..+...(..I..|
          Random Service 416: write with key & read w/o key (0x6808 0x680B)
           0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
           *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
           0007: 00 00 00 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
           0008: 00 c9 1b f8 2a 58 ed e0 80 00 00 00 00 00 00 00 |....*X..........|
          Cyclic Service 416: write with key & read w/o key (0x680C 0x680F)
           0000: 39 00 e3 45 0f 46 89 2d 25 8d a5 39 13 e7 a7 35 |9..E.F.-%..9...5|
           0001: 4e 65 9f 1b f5 e1 fe 0f cc d8 a0 84 04 0f c2 99 |Ne..............|
           0002: d9 57 42 1d d0 0b 52 c8 54 90 22 d7 22 2c 21 bf |.WB...R.T.".",!.|
           0003: d0 48 92 89 78 11 08 f2 df ab f7 f3 57 81 c6 74 |.H..x.......W..t|
          Purse Service 416: direct with key & decrement with key & read w/o key (0x6810 0x6814 0x6817)
           0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
          Random Service 417: write with key & read w/o key (0x6848 0x684B)
           0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
           0002: 13 33 ab 4a b3 1b d4 a9 80 00 00 00 00 00 00 00 |.3.J............|
          Cyclic Service 417: write with key & read w/o key (0x684C 0x684F)
           0000: 69 00 17 21 31 95 12 43 01 00 00 00 00 00 00 00 |i..!1..C........|
           0001: ce 92 1a d2 38 dc c6 16 80 00 00 00 00 00 00 00 |....8...........|
          Random Service 418: write with key & read w/o key (0x6888 0x688B)
           0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
           0002: 29 a1 33 1e e3 9d a2 50 80 00 00 00 00 00 00 00 |).3....P........|
          Cyclic Service 418: write with key & read w/o key (0x688C 0x688F)
           0000: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
           0001: 86 a1 a0 e8 21 ad 9d 06 80 00 00 00 00 00 00 00 |....!...........|
          Random Service 419: write with key & read w/o key (0x68C8 0x68CB)
           0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
           0002: ac ea 20 3b c1 52 16 c7 80 00 00 00 00 00 00 00 |.. ;.R..........|
          Cyclic Service 419: write with key & read w/o key (0x68CC 0x68CF)
           0000: 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 |................|
           0001: 82 77 e7 99 2d 9d 7c 92 80 00 00 00 00 00 00 00 |.w..-.|.........|

WAON番号を探す

WAON番号はWAONカードの裏面に刻印されている16桁の番号です。

IMG_0255.jpg

WAON番号の位置が知りたかったのですが、どうやら下記の2箇所にかかれているようです。
変換無し16進数表記なんですよね(苦笑)。

サービスコード0x67CFの
block0の12,13,14,15バイトと(0スタート)
block1の0,1,2,3バイト(0スタート)目の9バイトに書かれてるのと

サービスコード0x684Fの
block0の0,1,2,3,4,5,6,7バイト目までに16進数表記で書かれているようです。

0x684Fのほうが1ブロックにかかれているから利用しやすい感じなので、そちらを利用してみます。

テスト2:WAON番号だけ取り出す

では、上記ダンプ情報を参考に、WAON番号を取り出してみます。

実装

ポイントはシステムコードを指定しているところです。

waonno.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import nfc

#WAONサービスコード
service_code = 0x684F

def connected(tag):

  #システムコード指定(指定しなければ最初に見つかった12FCが読まれる)
  idm, pmm = tag.polling(system_code=0xfe00)
  tag.idm, tag.pmm, tag.sys = idm, pmm, 0xfe00

  if isinstance(tag, nfc.tag.tt3.Type3Tag):
    try:
        #サービスコードの指定
        sc = nfc.tag.tt3.ServiceCode(service_code >> 6 ,service_code & 0x3f)
        #読取りブロックを指定(複数読むときは配列で指定する)
        bc = nfc.tag.tt3.BlockCode(0,service=0)
        data = tag.read_without_encryption([sc],[bc])
        #読む位置を指定:0から8byteまでを読んで16進数表記
        print(data[0:8].hex())
    except Exception as e:
      print(("error: %s" % e))
  else:
    print("error: tag isn't Type3Tag")

# タッチ時のハンドラを設定して待機する
clf = nfc.ContactlessFrontend('usb')
clf.connect(rdwr={'on-connect': connected})

(servc >> 6, servc & 0x3f)は上位10bitをサービスコード、下位6bitをアトリビュート値して抽出して利用している。サービスコードを直接渡したい・・・。

実行

では実行。

python3 waonno.py

6900172131951243

システムコードを指定せずに実行したら error: invalid service code number or attribute ってエラーがでます(それは12FCにはそんなサービスコードは無いから)。

メモ

python2からpython3へのコード変換

python2からpython3へのコード変換は以下のコマンドでできます。

#上書き
2to3 -w test.py

Raspberry Piで利用する場合

原則、同じコード(概念)で動くが、いくつか注意が必要

  • なぜかnfcpy(nfc)モジュールを読み込んでくれないのでPathを指定
  • USBは具体的に指定。'usb'ではなく、'usb:054c:06c3'などとする。

あとは同じで動きました。

~
import sys
sys.path.append('/home/pi/.local/lib/python3.7/site-packages')
import nfc

#HID Keyboard
from Py_Keyboard.HID import Keyboard
kbd = Keyboard()

#WAONサービスコード
service_code = 0x684F

def connected(tag):

  #システムコード指定(指定しなければ最初に見つかった12FCが読まれる)
  idm, pmm = tag.polling(system_code=0xfe00)
  tag.idm, tag.pmm, tag.sys = idm, pmm, 0xfe00

  if isinstance(tag, nfc.tag.tt3.Type3Tag):
    try:
        #サービスコードの指定
        sc = nfc.tag.tt3.ServiceCode(service_code >> 6 ,service_code & 0x3f)
        #読取りブロックを指定(複数読むときは配列で指定する)
        bc = nfc.tag.tt3.BlockCode(0,service=0)
        data = tag.read_without_encryption([sc],[bc])
        #読む位置を指定:0から8byteまでを読んで16進数表記
        no = data[0:8].hex()
        print(no)
        #kbd.write(no+"\n")
    except Exception as e:
      print(("error: %s" % e))
  else:
    print("error: tag isn't Type3Tag")

# タッチ時のハンドラを設定して待機する
clf = nfc.ContactlessFrontend('usb:054c:06c3')
clf.connect(rdwr={'on-connect': connected})

実行時はsudoで。

sudo python3 waonno.py

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
15