2014年7月4日金曜日

PC/SCに潜む謎 その2

前回の(1年以上前ですが)「PC/SCに潜む謎」の続編です。実は何気にこのエントリーが一番アクセスが多いです。前回は PC/SC のコマンドがカードに対して投げるものであって、リーダに投げるものではないというお話でした。

しかしそう、あったんです。リーダに投げる方法がぁ!(騒いでるのは私だけです)

SCardConnect の際に ShareMode というのを指定するんですが、ここに SCARD_SHARE_DIRECT というのがありました。で、これで SCardConnect するとカードが無いのに待望のカードハンドルがもらえるのです!うはー!(激喜

そして、ここからは ACR122 だけの話かもしれませんが、SCardTransmit ではなくて SCardConrtol というコマンド(これもカードハンドルが必要)で投げることで DirectTransmit が可能になります。

というわけで前回の最後の方の「カードが置いてないときにAPDUコマンドは送信できない」という部分は間違いでございましたので訂正してお詫びいたします。

では早速やってみましょう。いつもの ACR122 ちゃんです。


SCardEstablishContext から SCardListReaders してリーダを取得するところまでは前回と同じです。

で、この状態で SCardConnect を SCARD_SHARE_DIRECT モードで実行すると、カードハンドルが取得できます。もちろんカードは置いていません。

そのカードハンドルを使って SCardConrtol コマンドを IOCTL_CCID_ESCAPE_SCARD_CTL_CODE というコントロールコードで実行します(追記:2014/09/19 Raspberry Pi ではこのコントロールコードは 0x42000DAC (0x42000000 | 3500) で動作します)。とりあえず Get Firmware Version というコマンド(FF 00 48 00 00)を投げてみます。

すると 41 43 52 31 32 32 55 32 31 30 (ASCIIで ACR122U210) が返ってきました。動作していますねー。

では DirectTransmit に挑戦です。
ACR122U には PN532 というチップが入っていますので、このチップに直接コマンドを送ることができます。
Direct Transmit についての詳細は「ACRリーダでNTAG固有のコマンドを使う」を参照ください。

今回は InAutoPoll というコマンドを実行してみます。これはポーリングを行うコマンドです。どのタイプのタグをポーリングするとか選んだりできますし、何よりタグが通信圏内に入るとすぐに通知してくれます。

最初にリーダの自動ポーリングをオフにします。これは ACRリーダの Set PICC コマンドを利用します。

で、InAutoPoll コマンドを投げます。ポーリング間隔を一番短い 150ms で実行します。するとプログラムは応答待ちになります。そこでカードを近づけると...おー!おぉー!ぐひひー!  って何やってるかわかんないですね。ACR122UToolで同じことやってみます。

まずはリーダの自動ポーリングをオフに。


そして InAutoPoll コマンドを投げます。すると応答待ちになります。


タグを近づけると...


きたー。NTAGを近づけてみたんですがちゃんとUIDが採れています。
って何か InAutoPoll の話になってきちゃってますが、今回はこれが PC/SC からできたよっていうお話なのでした。
うーん、謎は解決したということでいいんだろうか。関数名は SCardControl だしなぁ。まぁ、どうでもいいか。


2014年4月17日木曜日

ACRリーダでNTAG固有のコマンドを使う

このブログでは毎度おなじみの ACR122U リーダですが、UID取得やデータの書込み・読み込みはAPDUコマンドを使って簡単に行うことができます。
APDUコマンドってなんねー、っていう話はちょっと強敵すぎるので置いておいて、
例えば 0xFF 0xCA 0x00 0x00 0x00 っていうコマンドを投げると置いてあるタグのIDが返ってきます。

ANAのEdyカード

ACR122UToolで実行

で、ここまではいいんですが NTAG 固有の技を使いたいときはどうすればいいんでしょうか。というわけで Direct Transmit というコマンドが用意されています。これはリーダがコマンドをいろいろ解釈せんと、直接コマンドを送りつけるものです。

あー、これ使えばいいんやんとこれまでのほほんと暮らしてきたわけですが、実際使ってみて えー!そうやったん?というような内容があったのでここに書きます。

やりたいことは以前のブログにもありましたが NTAG21x のパスワード機能です。前回のブログでは Android でやってすんなりできたのでまぁ、ACRでも同じやろーと思っていたら全然違ったという話です。プログラムからやると面倒なので ACR122UTool を使って実行します。

認証コマンドは 0x1B です。これに続けて4バイトのパスワードを付けます。パスワードのデフォルトは 0xFF 0xFF 0xFF 0xFF なのでこれでやってみます。


まぁ、ダメですね。0x63 0x00 というのは ACRリーダ的にコマンドに失敗したという意味です。
で、Direct Transmit の出番です。構文は 0xFF 0x00 0x00 0x00 [以降の電文長] [コマンド] となっていますので、これに従って投げます。


やっぱりダメです。
よくよく見ると、Direct Transmit はリーダの中にあるチップ(PN532)に対してダイレクトに投げるコマンドのようです。つまり PN532 のコマンドを利用してその先の NTAG と通信しなければなりません。
というわけで PN532 の InCommunicateThru というコマンドを使います。0xD4 0x42 [投げるコマンド] の構文です。


あ、応答がありました。先頭の 0xD5 0x43 0x00 はコマンド種別とステータスです。後ろの 0x90 0x00 は正常終了のステータス。ということで間の 0x00 0x00 がコマンドの応答内容になります。先のブログの通り、ここは PACK 値というのが返ります。デフォルトは 0x00 0x00 なのでこれが返ってきてるようです。

よっしゃー!行けたか―!ということで読み書きパスワード設定済みのタグを使って読取をしてみます。パスワードが 0x01 0x02 0x03 0x04 に設定してあるのでこれを投げます。


PACK値に設定している 0x12 0x34 が返ってきてます。よしよし。
では読取コマンド 0x30 を使って 4ページ目を読みましょう。


あれ?

ということで結構悩んだんですが、ACRリーダの AutoPolling というのが影響しているそうです。
認証を行う場合、認証後にリードやライトをするわけですが、この間は当然接続が持続されていなければなりません。
しかし AutoPolling だと自動的に Polling をやっちゃって接続が切れてしまうのではないかというのは私の勝手な推測でありこれにより何らかの事故がありましても何の責任も負いませんということでご了承いただきたくよろしくお願い申し上げます。

というわけで AutoPolling をオフにします。


次に現在リーダに乗っているタグをアクティブにします。


で、先ほどと同じように認証コマンドを投げた後で読み取りコマンドを投げると


読めました!あー、結構大変やったなー。

2014年4月10日木曜日

9Solutions で遊ぶ

クレスコIDの大坂さんが遊びに来てくれました~。
簡単にロケーション管理が可能な 9Solutions のデモをマルチメディア館でやります。


セッティング中。9Solutions はBLEを使ってタグがどこにあるのかを検知します。

関係ないですがお昼休みにお弁当食べに行った海ではすでに泳いでる人たちが!


で、こちらが親分の機械。親分はネットに繋ぎます。


こちらが受信機とタグ。


受信機は電源だけあればよく、あとは受信機同士で通信して親分に報告し、親分がクラウドへ送信するとまぁ、そういう感じです。タグにはボタンが付いてたりして、ボタンが押されたら通知することなどもできます。

管理画面がこちら。タグがどの部屋に居るのかがリアルタイムにわかります。


3つの部屋に受信機を設置しました。親分は左上の部屋に置いてあります。受信機同士が話し合って、一番タグに近い受信機のある部屋にそのタグがあるということで親分に報告し、クラウド上のデータが更新されます。
うーん、本当に簡単にできちゃいましたねー。

私「なんで 9Solutions って名前なんですか?」
大坂さん「さぁ~?」

2014年3月28日金曜日

NTAG21xのシグネチャ機能を試す

NTAG21xシリーズのタグにはシグネチャという機能が搭載されています。
これはタグに対して「あんたのシグネチャ教えんね」とコマンドを投げると、「ほげほげ」と32byteのシグネチャを返してくるので、これをゴニョゴニョといじると正しいシグネチャがどうかが確認できるという機能です。
要するに、「あんた本当にNXPのタグね?」というチェックができるわけです。この機能を使えば本当にタグにタッチしたのかどうかが判別できます。

で、上のゴニョゴニョって何ね?何すっとね?ということなんですが、これはNXP社のHPから仕様書がダウンロードできます。(ダウンロードには、NDA的な書類にサインしてNXP社に送ってパスワードをゲットする必要があります)
そんなもんでここにはその詳細を書けないのですが、とりあえずやってみました。

まずはシグネチャをゲットする READ_SIG コマンド(0x3C 0x00)を投げます。
そうすると32byteのデータが返ってきます。



もちろん READ_SIG コマンドに対応していない(NTAG21xシリーズでない)タグはこのコマンドで失敗します。
で、これにゴニョゴニョをかけると...


ほら、確認できました(っていうかメッセージ出してるだけだけど)。

2013年10月9日水曜日

Raspberry Pi で NFC

せっかく Raspberry Pi を入手したので、NFCリーダを取り付けてみましょう。リーダの制御PCの替わりになればいろんなところで使えそうです。リーダはいつもの ACR-122U を使います。


まずはネットで情報収集します。あー、やはり Raspberry Pi に ACR-122U を取り付けてる人いますねー。しかしみんな USB給電では足りないらしく、給電用のハブを利用しているようです。そうすると電源が2個になっちゃいますね。あぁ、早くも暗雲が...

何はともあれやってみましょう。Raspberry Pi を標準でセッティングして、とりあえず ACR-122U を USB に挿します。何も起きませんが、dmesg を見ると ACR122U PICC Interface として認識してます。通常ですとここでリーダの赤LEDが点くんですが点きません。
確か初期化コマンド投げないと点かなかったのでまぁよしとしましょう。

で、どうやって ACR-122U を制御するかが問題です。直接USBにアクセスしてもいいんですがあまりお行儀がよくないのでできれば PC/SC を使いたいところです。ということでパッケージを検索してみます。debian のパッケージサイトから pcsc 関連を見てみます。

おー、pcsc-lite ありますねー、しかも armhf 版の acsccid ドライバまであります。何て素敵な世の中なんでしょう!みんなありがとうぉー!
というわけで acsccid ドライバをインストール

pi@raspberrypi ~ $ sudo apt-get install libacsccid1

で、libpcsc-lite1をインストール

pi@raspberrypi ~ $ sudo apt-get install libpcsclite1

あ、これはすでに入ってるみたい。なんで?まぁいいや。
その後 pcscd を入れてみると、

pi@raspberrypi ~ $ sudo apt-get install pcscd

勝手にデーモンが起動し、


赤LED点きました。
給電は大丈夫なのか?タグを置くと一応反応しています。
うわー、こんな簡単でいいのか?後は PC/SC でコーディングすればよしと。PC/SCかぁ・・・。これが一番面倒だな(笑
開発用のパッケージをインストールします。

pi@raspberrypi ~ $ sudo apt-get install libpcsclite-dev

で、テストプログラムをコーディング

sample.c

#include 
#include 
#include 

#include 

int main(int argc, char *argv[])
{
    SCARDCONTEXT hContext;
    SCARDHANDLE hCard;

    LPSTR lpszReaderName = NULL;    
    LONG lResult;    
    DWORD dwActiveProtocol;    
    DWORD dwAutoAllocate = SCARD_AUTOALLOCATE;    
    int i;    
    
    char UID[24];    
    memset(UID, 0, sizeof(UID));    
    
    lResult = SCardEstablishContext(SCARD_SCOPE_USER, NULL, NULL, &hContext);    
    if (lResult != SCARD_S_SUCCESS) {    
        printf("not service\r\n");    
        return 1;    
    }    
    lResult = SCardListReaders(hContext, NULL, (LPTSTR)&lpszReaderName, &dwAutoAllocate);    
    if (lResult != SCARD_S_SUCCESS) {    
        printf("no reader\r\n");    
        return 1;    
    }    
    printf("%s\r\n", lpszReaderName);    
    
    lResult = SCardConnect(hContext, lpszReaderName, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);    
    if (lResult == SCARD_S_SUCCESS) {    
        SCARD_IO_REQUEST request;    
        request.dwProtocol = dwActiveProtocol;    
        request.cbPciLength = 8;    
        DWORD dwResponseSize;    
        BYTE response[128];    
        BYTE getUID[] = { 0xff, 0xca, 0x00, 0x00, 0x00 };    
    
        dwResponseSize = sizeof(response);    
        lResult = SCardTransmit(hCard, &request, getUID, sizeof(getUID), NULL, response, &dwResponseSize);    
        if (lResult == SCARD_S_SUCCESS && response[dwResponseSize - 2] == 0x90 && response[dwResponseSize - 1] == 0x00) {    
            for (i = 0; i < dwResponseSize - 2; i++)    
                sprintf(UID, "%s%02X", UID, response[i]);    
            printf("%s\r\n", UID);    
        }    
        SCardDisconnect(hCard, SCARD_LEAVE_CARD);    
    }    
    SCardReleaseContext(hContext);    
    
    return 0;    
}

コンパイルして

pi@raspberrypi ~ $ gcc -I/usr/include/PCSC -lpcsclite -o sample sample.c

実行すると

pi@raspberrypi ~ $ ./sample
ACS ACR122U 00 00
04A57EE2613380

おー、読めてるー。ここまでくればあとは大丈夫そうですねー。

2013年10月8日火曜日

NTAG21x のパスワード機能を試す

NATG21xシリーズにはパスワードプロテクションの機能が搭載されています。
単純に書込みのパスワード制限がかかるだけかなーと思って仕様書を見ると読取にもかけられるようです。というわけで試してみます。試すタグは前回登場したNTAG210です。

タグの最後の方の領域に設定情報が書き込まれています。


Page16からPage19の部分です。UIDミラーのときにも少し触れましたが、この部分の構造は以下のようになっています。

Page 16  MIRROR_BYTE  RFUI  MIRROR_PAGE  AUTH0
Page 17  ACCESS  RFUI  RFUI  RFUI
Page 18  PWD(4byte)
Page 19  PACK(2byte)  RFUI  RFUI

この中でパスワードに関連するパラメータは AUTH0、ACCESS、PWD、PACKの4つです。
さらにACCESSがビットごとに設定が決まっていて、PROT、CFGLCK、AUTHLIMの3つの
設定が含まれています。たくさんありますねー。それぞれどんな設定なんでしょうか。

AUTH0
 ページ番号を設定するようです。ここで設定した値以上のページに対してプロテクションがかかるようです。初期値はFFになっていますので、ここを書き換えないとプロテクションが有効になりません。

PWD
 パスワードの実体ですね。4バイトです。初期値は FF FF FF FF のようです。

PACK
 よくわかんないんですが、パスワード認証に成功するとここの値が返り値として戻ってきます。

PWD、PACKの2つは、リードコマンドで読み込もうとしても常にオール00が返ってきます。

PROT
 プロテクションの種別です。1ビットの情報でここが0だと書込みが制限され、1だと読み込みと書込みが制限されます。

CFGLCK
 設定領域のロックフラグのようです。1ビットでここが1になると設定情報が永久に変更できなくなってしまいます。

AUTHLIM
 認証の試行回数のようです。この回数を超えて認証に失敗すると何か起きるようです。

まずは認証コマンドを試します。認証コマンドは 0x1B で、続けてパスワードの4ケタを送信します。
初期値のパスワード FF FF FF FF で投げてみます。


00 00 が返ってきました。ここがPACKの値らしいです。
今度はPACKの値を 01 02 に書き換えてから同じように認証コマンド投げてみます。


確かにPACKの値が返ってきてるようです。
じゃパスワードを別の値にしてみます。


「Tag was lost.」というエラーになりました。まぁ、しっくりいきませんが認証に失敗してるってことらしいです。
では AUTH0 に4を書き込みます。こうすることでユーザ領域の4ページ以降は書込み不可状態になります。


実際に書き込もうとするとエラーになりました。
さらに PROT を1にしてみます。これで読み込みも制限されます。試しにTagInfoで読んでみたらアプリ落ちました(笑
Readコマンドを投げると


00が返ってきました。通常は4ページ分のデータ(16バイト)が返ってくるはずなんですが、コマンド自体はエラーにならずに 00 の1バイトだけ返ってきました。あぁー、プログラマー泣かせですなー。
認証後にReadコマンドを投げると、


きちんと読めてます。

さて、ここで疑問が。AUTH0 に 0 を書いたらどうなるんでしょうか。Page 0 と 1 はタグのUIDが入っています。とするとUIDまで読めなくなってしまうのか!?

というわけでやってみたんですが、UIDは読めました。しかし認証が成功しないようになってしまいました(理由は不明)。というわけで貴重な NTAG210 タグがまた1つ UID しか読めないタグになってしまいました。あーあ、たっちなうには使えるかなー。

2013年10月1日火曜日

UHFは本当に水に弱いのか?

UHF帯のタグを使用する場合、金属に貼りつけると読めなくなるのはHF帯と同じですが、水分があると電波を吸収されてしまうため水分にも弱い特性があります。

じゃーどのくらい弱いんでしょうか。弱いとか言いながら実は結構読めたりするんじゃないでしょうか。ということで試してみました。

用意したのはタッパーです。
これに通常のシールタグ(Alien Squiglette Higgs4)を使います。


タッパーの底にタグを貼ります。


いつものようにMorphicのリーダで読んでみます。
水無しの状態では結構飛びます。


これくらい離れてもまだまだ読んでます。250mWですが十分な距離が出ています。
ここでタッパーにタグが被るくらいの少し水を入れます。


早速読んでみましょう。


これぐらいで限界。やはり弱かった!
下から読むとこんな感じ。


定説通り水に弱いことがわかりました。疑った自分が悔やまれます。まあ、読めただけいいのかもしれませんが(何が?)。

これで終わりは面白くないのでもっと水入れてみます。


これは読めないでしょう。はっはっは。


ピ、ピ、ピ、あれ?

読んでるー。

下からはこんな感じ。


あんまり水の量では変わんないですねー。不思議ー。