竹形誠司 ブログ
Java+MySQL+Tomcat    »トピック一覧
掲示板へのスパムが多いため、「ご質問」のコーナーはユーザー登録制とさせていただきました。お手数ですが、上の「新規ユーザーの登録」メニューより登録をお願いします。
帳票Web
アプリケーション

受注開発始めました
詳しくは こちら
竹形 誠司 著/ラトルズ刊
JSP帳票アプリケーション実践開発入門
JSP帳票アプリケーション
実践開発入門

JSP業務アプリケーション短期開発入門
JSP業務アプリケーション
短期開発入門

Java+MySQL+Tomcatで始めるWebアプリケーション構築入門
Java+MySQL+Tomcatで始めるWebアプリケーション構築入門

Java+MySQL+Tomcatで作る掲示板とブログ
Java+MySQL+Tomcatで作る
掲示板とブログ
JavaでFelicaのユニークIDを読む
by 竹形 誠司[takegata]
ICカードの読み書きを試してみようと思って、ACR122というNFC リーダーを買ってみました。

http://www.nfc-reader.com/jp/acr122.php

無地のMifareカード10枚付きで1万円だったので、まぁまぁ安いんじゃないでしょうか。このリーダーはAPDUという方式で通信を行うため「SDKが不要」というのが魅力でした。標準のAPIドキュメントには載っていませんが、J2SE6にはAPDUをサポートするAPIが既に入っているんですよね。

http://java.sun.com/javase/ja/6/docs/ja/jre/api/security/smartcardio/spec/javax/smartcardio/package-summary.html

カードリーダーの技術資料には「FF CA 00 00 04」というバイト列を送ればカードにユニークなIDが取得できると説明されていたので、↑のページにあるサンプルコードを参考に、次のようなコードを書いてみました。
import java.util.List;
import javax.smartcardio.*;

public class SmartCardReadId{
  public static void main(String[] args){
    try{
      // show the list of available terminals
      TerminalFactory factory = TerminalFactory.getDefault();
      List<CardTerminal> terminals = factory.terminals().list();
      // get the first terminal
      CardTerminal terminal = terminals.get(0);
      // establish a connection with the card
      Card card = terminal.connect("T=1");
      CardChannel channel = card.getBasicChannel();
      byte[] c1 = {(byte)0xFF,(byte)0xCA,(byte)0x00,(byte)0x00,(byte)0x04};
      ResponseAPDU r = channel.transmit(new CommandAPDU(c1));
      StringBuilder sb = new StringBuilder();
      for(byte a:r.getData()){
        String hexValue=Integer.toHexString(a & 0xff).toUpperCase();
        if(hexValue.length()==1){
          hexValue="0"+hexValue;
        }
        sb.append(hexValue);
      }
      System.out.println("ID:"+ sb.toString());
      // disconnect
      card.disconnect(false);
    }catch(CardException e){
      e.printStackTrace();
    }
  }
}
CommandAPDUクラスのコンストラクタにコマンドを渡してオブジェクトを作り、channelオブジェクトのtransmitメソッドで送るとResponseAPDUオブジェクトが帰ってきて、getDataメソッドでIDのバイト列が取得できるというわけです。

バイト列を16進数で表示するのって結構メンドクサイですね。上の例では、IntegerクラスのtoHexStringメソッドで16進数に変換していますが、これだと十進数で128から上がマイナスになってしまうので0xffでアンドを取って、更にtoUpperCaseで大文字に揃えて、それぞれのバイトが表す16進数が1桁の場合は頭に0を挿入するなんてことをやっています。

購入したリーダーとカードのセットでは、1Kバイトほどのデータ領域があって、値を自由に書いたり読んだりすることもできます。データの読み書きには認証キーを指定する必要があり、これを知らない人(プログラム)が勝手にデータを書いたり読んだりできないようになっています。

↑のプログラムに読み書き用のコードを追加してtestとかbakaとかtakegataとか書いたり読んだりして遊んでいるだけでも結構楽しいのですが、ふと、その辺にあったSuicaを何気に置いてみたらIDらしきデータが読めるじゃないですか。ちょっとびっくり。じゃぁEdyカードはどうかと思ってリーダーに乗せてみると、やはりIDらしきデータが読み取れます(認証キーが分からないので、データ領域は読めません)。

カードリーダーの仕様を見ると「Felicaカードに支援」と、微妙な日本語で対応を表明しています。調べてみたら、これはIDmと呼ばれるユニークなIDらしく、林優さんという方のウェブで紹介されているプログラムを使ってPaSoRiで確認したら同じデータが読み取れました。

http://yuuhayashi.blogspot.com/2009/01/pasorifelicaidm_30.html

ただ残念なことに、私が書いたプログラムではPaSoRiにアクセスできませんでした。J2SE6の標準APIでは読めないようです。林さんのページで紹介されているプログラムでは、felicalibというライブラリを使っていました。Javaからfelicalib経由でPaSoRiにアクセスする方法は亜細亜大学の先生が↓のページで紹介しています。

http://itasan.mydns.jp/wiki.cgi/ASIA?page=Java%A4%CE%B1%FE%CD%D1%A1%A7Felica%A5%AB%A1%BC%A5%C9%A5%EA%A1%BC%A5%C0#p0

Felica SDKにも興味はありますが、興味だけで買ってみるにはちょっと高い感じですね。
投稿:竹形 誠司[takegata]/2009年 02月 26日 05時 00分 /更新:2011年 05月 25日 10時 15分