2011年9月11日

Type1~Type4 TagとMIFARE Classic Tag

NFC-Aは、Type1とType2とType4をサポートするらしい(4はオプションかな)。
なんじゃそりゃー、と思ったが、棲み分けがあるらしい。

http://www.nfc-forum.org/resources/white_papers/NXP_BV_Type_Tags_White_Paper-Apr_09.pdf

ここの13ページに、Type1~4とそれに対応する商品が書いてあった。

 

Type1は、Topaz。
Type2は、Mifare Ultralight。
Type3は、FeliCa。
Type4は、DESFireやSmartMX。

 

ほほう。
では、今回私が買ったMifare 1Kみたいな「Mifare Classic」はどれにあたるのだろうか?

 

これは、19ページに図があった。
何と、Type MIFARE Classic Tag、という分類があるではないか。。。
http://www.nxp.com/#/pip/pip=[pfp=53424]|pp=[t=pfp,i=53424]

これのAN1304というやつが、MIFARE Classic Tagのことを書いているようだ。

 

Mifare 1KとかはType1とか2なのだろうと思って買ったのだが、まさかの落とし穴であった。
Amazonの商品名には、Ultralightにだけ「Type2」って書いてあった。さすがOrangeTagsさん。

まあ、遊ぶ分にはMifare 1Kで十分だろう。

2011年9月10日

eclipseはSSH2でAESの鍵をわかってくれない

Ubuntuとcygwinとeclipseで、githubにアクセスしようとする。
すると、Ubuntuとcygwinはいけるんだけど、eclipseではpushができない。
まあ、コマンドで打てばいいや、とやっていたのだが、気になって調べてみた。
どうも、AESは見てくれないらしい。
解決方法は、DES3に変換する、みたいなものしかないらしい。
ファイルが2つできるのは嫌だが、鍵を別にするのも嫌なので、変換した。
http://stuvel.eu/blog/161/eclipse-doesnt-support-aes-encrypted-ssh-keys

こそっとはまったのは、EGitが(なのかはわからんが)eclipseで設定したSSH2の内容をすぐには見てくれないこと。
一度eclipseを再起動させんと反映できなかった。
まあ、そんなもんだ。

2011年9月9日

Parcelableは不思議だ

PaSoRiを使って、FeliCa LiteにNDEFのデータを書こうと思った。
データの見方はわかったのだけど、実装するのはめんどくさい。
きっと、Android提供部分にあるはずだ、と探すと、あった。
android.nfc.NdefRecordだ。

 

これが、Parcelableをimplementsしている。
android.os.Parcelableだ。
よく見るんだけど、使ったことがない・・・。
これを機会に、ちょっと見てみようと思ったのが発端だ。

 

どうでもいいことだが、NdefRecordのパケット解析部分はJNIを呼んでいて、そこからlibnfcを呼んでいた。
まあ、そんなもんだ。


Parcelableで検索すると、いっぱい出てくるので、ここに書くことはなかろう。

ソースを見ると、Parcelable自体はシンプルだ。
特に中身があるわけでもない。

 

作業をしているのは、Parcelの方みたいなので、ちょっと見てみよう。
データを書き込むとき、例えばint型であれば、writeInt()というメソッドを呼び出すようだ。
では、writeInt()のソースは・・・JNIか。
JNIのソースファイルは、android_util_Binder.cpp。
そう、Binder関係なのだ。

Binderは、Android用にkernelに手を加えてまで追加したプロセス間も通信できる機能。
らしい。

 

writeInt(jint)は、binderのParcel::writeInt32(int32_t)を呼び出すくらいのことしかしていない。
binderのParcelは、frameworks/base/binderにある。
ここでもwriteAligned(int32_t)しか呼んでない。
writeAligned()は、テンプレートだ。
sizeof(T)が容量内にあることを確認できたら、reinterpret_cast<T*>した左辺値に代入して、sizeof(T)を返している。

いやあ、びっくりだ。
キャストが左辺に置けるんだ。
これって、gcc拡張かなにかか?
あるいは新しいC++ではそんなことが許可されているのか?
最近どっかでそういう記事を見たような気がする。

とまあ、ここまでで見るのはやめだ。
メモリ効率よりも速度効率を優先してるって感じなのがわかったので、よしとしよう。

2011年9月7日

[無駄]Mifareカードを注文する

朝起きて、パソコンを付け、なぜかMifareカードを注文していた。
しかも、1Kを10枚と、ULを1枚。
なんでだ。。。

まあ、いいや。



Mifareのホームページに、UIDは7byteにしますよー、というようなことが書かれていたので、てっきり7byte品しかないと思っていたが、さっき確認すると1Kは4byteだった。
まあ、ULは7byteだからいいか。

何をしたいというわけでもないのだが、FeliCa Liteのことはだいたいわかったと思うので、違うやつもやってみよう、というところだ。
読み込みはできるのだけど、社員証なので書き込みはさすがにやってないのだ。
あとはNFC-Bだけなんだが、これは買えなさそうな気がする。

2011年9月6日

[felica]片側認証でできること

やってみて、わかることがある。
わかっていたはずなのに、つくって、動かしてみて、「ああ、そういえばそうやん」というようなことだ。
片側認証を実装してみて、久しぶりにそういう感触を味わった。


片側認証を文字にすると、だいたいこんなことになる。

  1. カード発行時、発行者がカード鍵をFeliCa Liteに書き込んで、変更できないようにする。
  2. 使うとき、ユーザは発行されたFeliCa LiteをR/Wにかざす。
  3. R/WはFeliCa Liteを捕捉し、RCブロックにランダム値を書き込む。
  4. FeliCa LiteはRCブロックに書き込まれると、内部でセッション鍵を生成する。
  5. R/WはFeliCa LiteのIDブロック、MACブロックをまとめて読み込む。
  6. FeliCa LiteはMACが読み出される前のブロック情報を使ってMACブロックの値を生成するので、5ではIDブロックを使ったMAC値が取得できることになる。
  7. R/WはRCブロックに書き込んだ値と読み取ったIDブロック値から自分でMAC値を計算する。
  8. R/Wは両者のMAC値を比較し、一致したら自分が発行したカードということがわかる。

大切なのは8番。
一致したとわかるのはR/W、すなわち発行者側だけであって、FeliCa Liteは認証などしていないのだ。
これが片側認証の片側たるゆえんである。

 

悪意のある人が、FeliCa Liteを書き換えようとする際はどうしたらよいか?
どうもしない。
なぜなら、FeliCa Liteへの書き込みは認証を必要としないからだ。
Write Without Encryption。
もちろん、読み込む方も同じである。

コマンド名を見れば、そんなことは初めからわかっていたはずなんだけどね-。
片側認証できたので、なにか書き換えられたくない情報を書くようなソフトを考えていて、ようやく思い至ったのだ。


中身を書き換えられることを防ぐことはできないが、書き換えられたことを判断することはできる。
しくみは、MACと同じようにやることだ。
カードのどこかに、ブロック値をカード鍵で暗号化したデータを書き込めば、次に読み込んだときにMACと同じように答え合わせすることで、誰かに書き換えられたかどうかを判断できる。

まあ、防御策にしかならないのだが、そういった用途ができるのであれば十分に有用である。

2011年9月4日

[java]DESede-CBC暗号化

いろいろとネットの情報を参考にしながら、FeliCa LiteのMAC生成アルゴリズムができた。
そのとき、3DES暗号についてなんとなくわかったので、記録を残しておく。


3DESといってもいくつか細かくあるらしく、FeliCa LiteではCBCという方式を使っている。
これは、前ブロックの3DES計算結果を、次のブロックとxorする方式みたいだ。
それは、IVとか初期ベクタとか呼んでいる。

細かい実装は知らないが、1段目でDESエンコード、2段目でそれをDESデコード、3段目でそれをDESエンコードする。
1, 2, 3段目はそれぞれ別の鍵を用いるのが望ましいらしい(FeliCa Liteでは、1と3が同じ)。
鍵が3つとも同じだと、エンコード→デコード→エンコードとなり、DESエンコード1回分と同じになるという。


DESを3回やって、IVを自分でxorしてみたが、ちゃんと同じ結果になった。
xorする実装は好きこのんでやったわけではなく、FeliCa Liteの説明がそうなっていたからだ。
「IVはxorしてつっこむ」という方式であることを知っていたら、やってないですわ。
この辺りが、知識がないなー、と思ったところですな。

あと、24byteの鍵でちょっと迷った。
FeliCa Liteでは2つの鍵しかないので、24byteをどう埋めるのかというところの記述を探したのだが、見つからんかったのだ。
[0-7]に鍵1、[8-15]に鍵2、[16-23]に鍵1をいれると、とりあえずFeliCa Liteと同じ結果になった。
鍵を3つ別にする場合、[0-7]なのか[16-23]なのか気になるが、まあ今のところわからんですな。


できたのは、こんなソース。
8byte固定なのです。

   1: /**
   2:  * Triple-DES暗号化
   3:  * 
   4:  * @param outBuf        暗号化出力バッファ(8byte以上)
   5:  * @param outOffset        暗号化出力バッファへの書き込み開始位置(ここから8byte書く)
   6:  * @param key            秘密鍵(24byte [0-7]KEY1, [8-15]KEY2, [16-23]KEY1)
   7:  * @param inBuf            平文バッファ(8byte以上)
   8:  * @param inOffset        平文バッファの読み込み開始位置(ここから8byte読む)
   9:  * @param ips            初期ベクタ(8byte)
  10:  * @return        true    暗号化成功
  11:  */
  12: private static int enc83(byte[] outBuf, int outOffset, final byte[] key, final byte[] inBuf, int inOffset, IvParameterSpec ips) {
  13:     int sz = 0;
  14:     try {
  15:         // 秘密鍵を準備
  16:         SecretKeyFactory kf = SecretKeyFactory.getInstance("DESede");
  17:         DESedeKeySpec dk = new DESedeKeySpec(key);
  18:         SecretKey sk = kf.generateSecret(dk);
  19:         dk = null;
  20:         kf = null;
  21:  
  22:         // 暗号
  23:         Cipher c = Cipher.getInstance("DESede/CBC/NoPadding");
  24:         c.init(Cipher.ENCRYPT_MODE, sk, ips);
  25:         sz = c.doFinal(inBuf, inOffset, 8, outBuf, outOffset);
  26:         
  27:     } catch (Exception e) {
  28:         Log.e(TAG, "enc83 exception");
  29:     }
  30:     return sz;
  31: }


dkとkfをnullにしているのは、参考にしたソースがそうなっていたから。
セキュリティのために鍵は使ったら0で埋めてから解放する、なんてことまでやっていた。
うーん、このあたりはJavaの知識がないといかんですな。

メモリリーク(Effective Javaで「意図しないオブジェクト保持」と書いてあるやつ)とかも全然気にしていないので、ここ以外の場所が心配である。

[felica]個別化カード鍵のアルゴリズムはなんでもいい

FeliCa Liteのドキュメントに、個別化カード鍵の標準生成アルゴリズムに関するものがある。
ほうほう、と実装して動かしてみてわかった。

これはあくまで「標準」なので、なんでもいいのだ。

 

そもそもなんでこういう資料があるかというと、FeliCa Liteのカード鍵を全発行カードで一緒にしてしまうと、1枚で総当たりしてカード鍵がわかってしまうと、それを使ってカードを自作するとカード運用者は偽造したものとの区別がつかなくなってしまう。

なので「カードごとにカード鍵を変えてください」とアナウンスしている。
それはわかるのだが、カードごとに鍵を変えるというのはなかなか管理が大変である。
IDmは発行カードごとに違ったとしても、運用側がそのカード番号をすべて管理するのは面倒。
そういった番号は管理せず、カードだけでなんとかしてしまえるところに利点があるのだと思う。

 

そこで、個別化マスター鍵というものを用意し、それとカードごとにIDブロック情報からカード鍵を作成しましょう、というのが個別化カード鍵である。
管理者側は、個別化マスター鍵だけ管理しておけばいい(鍵バージョンもあるけど)。
IDブロック情報はカードごとに異なるので、個別化マスター鍵から作られる個別化カード鍵はほぼ一意に決めることができる。
その決めるアルゴリズムが提供されているのである。

 

なので、別にこのアルゴリズムでなくても、カードごとに持っている情報で一意に定まる個別カード鍵が生成できさえすれば何でもいいということになる。

そういうことが、実装してみて、動作確認をしようと考えたときにわかった。
IDが異なれば個別カード鍵も異なることはわかったし、同じIDに対しては同じ個別カード鍵を生成することはわかったけど、それ以上の確認方法が思いつかないのだな。。。

[felica]張り巡られた伏線

MACの計算があわんあわんと騒いでいたが、ようやくできた。

いや、FeliCa Liteのユーザーズマニュアルを読んでいるときから、少し違和感があったのだ。
ドキュメントとしては基本的にビッグエンディアンで書かれているのだが、ブロックの説明では「Byte15-8」「Byte7-0」のように、リトルエンディアンで格納されているような記述になっていたのだ。

しかしこちらからすると、メモリ上のデータは1byteずつしか扱わないので、エンディアンもなにもあったもんじゃない。
なので、気にしていなかった。

MACの計算でも「CK1[7:0]」みたいになっていたので、このドキュメントはそういう表し方をしているんだ、と納得させていた。


しかしMACの計算があまりにもうまくいかないので、FeliCa Liteのドキュメントを全部読み直した。
PDF4つくらいで、それほど量は多くない。

読み進めるとテクニカルノートに「DES演算の入出力データの並び(エンディアン)について」という項目がある。
なんでも、FeliCa StandardとFeliCa LiteではDES演算に入れ込むデータの順が異なるという。
これか!!

 

入れ替えしてみると、計算があった。
そうか、あの記述はそういう意味があったのか、と張り巡らされた伏線に気付いた私であった。

[felica]片側認証がうまくいかん

うまくいかんシリーズです。

朝から片側認証というか、MACの計算を実装していた。
FeliCa Liteのユーザーズマニュアルを読んだときは「うわ、こんなの実装できるのか」と思ったのだが、調べていくと実に一般的な手段であることがわかってきた。

つまりまあ、私の知識が少なかったという話だ。

 

ただ困ったことに、計算が合わない。
ユーザーズマニュアルには、FeliCa Liteの動作確認が載っていて、そこにMACもあった。
このRC, ID, CKの組み合わせだとMACはこうなる、というものだ。
これのおかげで、FeliCa Liteに書き込まずにJava上だけで確認ができる。

できるのだが、計算が合わない。
思い違いをしているのか、Java実装で足りていないところがあるのか、そのどちらかだろう。
しかし、そこがまったくわからないのだ。
うーむ・・・。

 

こういうときだな。
「たすけてー」っていいたいのは。

2011年9月3日

[felica]FeliCa LiteのD_IDはどうしたらいいのか

FeliCa Liteのユーザーズマニュアルを読んでいて、理解が難しかったのがD_IDブロック。
何度読んでもわからなかったが、自分なりの解釈を行った。


ユーザーズマニュアルは、こう書いてあると思っている。

  • [15-8]は値を変更することができない
  • [7-0]は値を変更することができない
  • D_IDに書き込みを行うと、IDdとPMmの値は変更できないが、IDmの値を変更できる
  • D_IDの3~4バイト目はR/W

また、IDmを変更しないための注意点として、以下がある。

  • システムブロックを書き換え禁止にする前にD_IDに書き込まないこと
  • 発行したら、システムブロックを書き換え禁止にすること

 

私がわからなかったのは、書き込んでいいのか悪いのか、書き込んでほしくないのかどうか、書き込んだら一体どうなるのか。そのあたりだ。


で、こういう解釈をした。

  • D_IDの3~4バイト目はR/W。ほかはRO。
  • よって、[15-8]のPMmは書き込みもできないし、書き込んでも初期値と同じ値が読める
  • [7-0]のうち、[4-3]は書き込みができる
  • [4-3]に書き込んでも、IDdが変更されるわけではなく、IDmが変更になる。
  • [4-3]に書き込んでも、読み込んだ値は初期値と同じ。
  • システムブロックを書き換え禁止にしないとD_IDへ書き込めてしまうため、IDmが(3,4バイト目だけだが)変更できてしまう。よって、発行時には書き換え禁止にすること。

使えなくなると怖いんで、実機で確かめてないけどね。

特に、[4-3]を書き込んだ後に読み込んだらどうなるのかがわからん。
ドキュメントの「値を変更することができない」は、読み込み値は常に同じということを表していると解釈した。つまり、書き込みと読み込みが非対称というわけだ。

IDブロックには「IDdを書き込む」とあるから、D_IDへの読み書きとは関係なくIDdを書けばよい。
IDdはD_IDを読み込めばいいから、IDmを変更したからといって心配はしなくていいのだろう。