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 <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <winscard.h>

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ですが十分な距離が出ています。
ここでタッパーにタグが被るくらいの少し水を入れます。


早速読んでみましょう。


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


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

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


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


ピ、ピ、ピ、あれ?

読んでるー。

下からはこんな感じ。


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