Felicaのデータを読む (その4)

先日どこかでNexus SのNFC機能を使ってPASMO(FeliCa)のデータを読むことは、まるでハッキング行為をしているかの如く書かれているのを見たが、自らの、それもFelicaの規格通りのコマンドでセキュリティで保護されていない(暗号化されていない平文の)エリアのデータを読み出すことを果たしてハッキング行為なのだろうか? FeliCaの規格自体NFCの上位に位置する規格であり、仕様通りに動かすことができないほうがおかしいと思うのだ。
 非公開APIを使うことに関しても同様で、いくら非公開だといってもAndroidのようなオープンソースはソースーコードが公開されているのであまり意味は無い(androidの@hideとしている実装はハードウェア依存やベンダー依存のコードなので、いつ変更されるかの保証ができないから非公開という意味合いのほうが強いと思う。本当にベンダーが寡占しているコードはソースコードすら公開されていない)


さて、もう一度整理してみよう。Felicaのデータを読み出す処理に関しては以下のコードで良いはずである。(nfcの機能を使ってFelicaのコマンドを送信する)

  • インテント"android.nfc.action.TAG_DISCOVERED"からタグ情報を取得する
Parcelable nfcTag = intent.getParcelableExtra("android.nfc.extra.TAG"); //FeliCa IDmとタグ情報
byte[] idm = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID); //FeliCa IDm

Field f = nfcTag.getClass().getDeclaredField("mServiceHandle");
f.setAccessible(true);
Object serviceHandle = f.get(nfcTag); //INfcTagインタフェースのメソッドを起動する際に必須のサービスハンドル
Class tagClass = this.tagWrapper.tag.getClass();
Method createRawTagConnection = adapter.getClass().getMethod("createRawTagConnection", tagClass);
Object rawTagConnection = createRawTagConnection.invoke(adapter, nfcTag);
  • android.nfc.RawTagConnection#mTagServiceフィールド(INfcTagリモートインタフェースへの参照)を取得する
Field f = rawTagConnection.getClass().getDeclaredField("mTagService");
f.setAccessible(true);
Object tagService = f.get(rawTagConnection);
  • INfcTag#transceiveメソッドによりnfcリーダーにreadコマンドを送る
Method transceive = tagService.getClass().getMethod("transceive", int.class, byte.class);
byte response = (byte[])transceive.invoke(tagService, serviceHandle, command ); // commandはFeliaコマンドパケット


今まで調べたFeliCaコマンドの仕様と、androidのソースから掘ったAPI(そのほとんどが非公開APIなのでリフレクションを使用してアクセスしている)を使うと大体こんなコードシーケンスになるはずなのだが、昨日書いたようにtransceiveにより送信したコマンドが全く認識されていない。

少し立ち戻ってFeliCaのコマンドパケットの取り扱いを復習してもう最初からやり直そうと思う。


参考 : FeliCaカード ユーザーズマニュアル - SONY