Raspberry Pi 3にPaSoRiを接続してSuicaカードをダンプする」でSuicaカードの内容をダンプしましたが、同じプログラムでEdyカードをダンプしようとしても、次のように「unable to create a memory dump」のエラーメッセージが表示され、ダンプできませんでした。SuicaカードとEdyカードのデータ構成が違っているのがどうも原因のようです。

$ python suica.py
Type3Tag 'FeliCa Standard (RC-S962)' ID=0114B38F1112E00A PMM=0120220427674EFF SYS=811D
  unable to create a memory dump

このため、nfcpyを使用してPython言語でEdyカードをダンプするプログラムを作成しました。

Edyカードのダンプアプリの作成

Edyカードのダンプアプリ「edy.py」は、Edyカードが持つサービスをすべて列挙し、パスワードなしで読み込めるブロックは、そのブロックをすべてダンプするプログラムです。

  1. サービスコードは 16 ビットの値で、上位 10 ビットがサービス番号、下位 6 ビットが属性値です。 サービスコードは 16 ビット値のため、0 から 0x10000 までを調べれば、すべてのサービスを網羅できます。
  2. nfc.tag.tt3.ServiceCode(i >> 6, i & 0x3f) は、16 ビットの整数 i から ServiceCode オブジェクトを生成します。 i >> 6 で上位 10 ビットの番号、i & 0x3f で下位 6 ビットの属性を取り出します。
  3. tag.request_service は複数のサービスを一度に指定します。check_servicesメソッドで n 個の ServiceCode のリストを作り、request_service メソッドに渡しています。
  4. サービスは、サービス番号「services[i].number」とサービスの属性「services[i].attribute」をパラメータにしたdump_serviceメソッドで取得します。
  5. サービスごとにdump_serviceメソッドを使って、ブロックの内容をダンプします。

edy.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
sys.path.insert(1, os.path.split(sys.path[0])[0])
import nfc


def check_services(tag, start, n):
    services = [nfc.tag.tt3.ServiceCode(i >> 6, i & 0x3f)
                for i in xrange(start, start+n)]
    versions = tag.request_service(services)
    for i in xrange(n):
        if versions[i] == 0xffff: continue
        print services[i], versions[i]
        # ブロック0番の内容を16進数で出力する
        sc = nfc.tag.tt3.ServiceCode(services[i].number, services[i].attribute)
        dumpdata = tag.dump_service(sc)
        print type(dumpdata)
        print len(dumpdata)
        for item in dumpdata:
            print " %s" % item


def connected(tag):
    # タグのIDなどを出力する
    print tag
    if isinstance(tag, nfc.tag.tt3.Type3Tag):
        try:
            n = 32
            for i in xrange(0, 0x10000, n):
                check_services(tag, i, n)
        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})

Edyカードのダンプアプリの実行

次のようにedy.pyを起動し、RC-S380にEdyカードをかざすと、次のようにEdyカードがダンプされます。

$ python edy.py
Type3Tag 'FeliCa Standard (RC-S962)' ID=0114B38F1112E00A PMM=0120220427674EFF SYS=811D
Service Code 0000h (Service 0 Type 000000b) 1

0
Service Code 1000h (Service 64 Type 000000b) 1

0
Service Code 1008h (Service 64 Random RW with key) 1

0
Service Code 100Bh (Service 64 Random RO w/o key) 0

3
 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 |................|
 0005: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Service Code 1108h (Service 68 Random RW with key) 1

0
Service Code 110Bh (Service 68 Random RO w/o key) 0

3
 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 |................|
 0005: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Service Code 1208h (Service 72 Random RW with key) 1

0
Service Code 120Bh (Service 72 Random RO w/o key) 0

3
 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 |................|
 0005: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Service Code 2000h (Service 128 Type 000000b) 1

0
Service Code 2008h (Service 128 Random RW with key) 1

0
Service Code 200Bh (Service 128 Random RO w/o key) 0

3
 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 |................|
 0005: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Service Code 2108h (Service 132 Random RW with key) 1

0
Service Code 210Bh (Service 132 Random RO w/o key) 0

3
 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 |................|
 0005: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Service Code FFFFh (Service 1023 Type 111111b) 1

0