2014年6月21日

[felica]相互認証(1) - 内部認証

FeliCa Lite-Sの最大の売り、相互認証。
それを実現するために、内部認証と外部認証を行う。


内部認証

これは、従来のFeliCa Liteにもあった「片側認証」である。
片側認証については、いくつか書いてきた。

リーダライタから上位が、「このカードは自分が発行したものだ」と認証するしくみ。
偽造カードじゃないことを確認するしくみ、といえばよいか。

さて、FeliCa Lite-SになってMAC_Aというレジスタが追加されたが、「MACまたはMAC_Aを使います」ということなので、どちらのレジスタでも同じことができるようだ。

ただ、MACとMAC_Aでは計算方法が異なるそうだ。
以前作った片側認証アプリのレジスタ名だけ変更してみたが、MACの値が一致しなかった。
(前ブログで、MAC_Aが読み込み失敗した、という現象は発生せず。IDブロックと一緒に読み込んだからか。)

違いは、ブロックデータの3DES暗号化でのIVが、RC1なのか、RC1をさらに3DES暗号化したものかどうかだけのようだ。
RC1の3DES暗号化に使うIVが、何か良くわからない(資料の通りにやれば良いのだろうが)。

なんか、暗号化の知識がないから書いてある通りにやっているけど、知っている人からすると関数一発で終わる、みたいなものではないんだろうか、と変な心配をしている。

2-1 基本

 

スターターマニュアルには、MAC_Aと一緒にID, CKV, WCNTを読み出すように書いているが、ユーザーズマニュアルではIDとWCNTになっている。
最低限、IDとWCNTは必要だからってことでいいのかな?

[felica]FeliCa Lite-Sカードを読んでみる

では、さっそくFeliCa Lite-Sカードを読んでみよう。

コマンドとしては、以前と同じく3つをサポートしている。

  • Polling
  • Read without Encryption
  • Write without Encryption

 

では、まずPollingから。
と行きたいところだが、手元にSDK for NFC Starter Kitしかないので、明確に「このコマンドを動かした」という確認ができない。
まずはStarter Kitで作っていたツールを使って、新しく増えたブロックを読むことにする。


WCNT

4B-FE-FF-00-00-00-00-00-00-00-00-00-00-00-00-00

WCNTはライトカウンタ値が入っている。
先頭3byteが有効でエンディアンはリトル。ReadOnly。
デフォルト値は「00 FE FF」だそうなんだけど・・・・???

どういうタイミングでカウントされる勝とうと、S_PAD0~13、REG、ID、SER_C、CKV、CK、MC、STATEブロックへの書き込みでインクリメントとのこと。

デフォルト値、というのは0次発行のときらしいが、出荷試験などで書き込んだと言うことかな?
次は、MC=0x00を書き込んだとき、つまりシステムブロックの書き込み禁止をしたときに、カウント値が0になる。
それ以降はリセットできない。

WCNTが0xfffe00になると、MACつき書き込みができなくなる。
えっ、と思ったが、回数としては16,776,704。1677万回だ。毎秒書き込んだとしても194日かかる。
達する前にWrite withoute Encryptionでエラーになるかもね。

 

MAC_A

エラー

ReadOnlyではないらしいのだが、エラーになった。
なんだろう?
MACブロックと同時に読み込んではいけないとはあるんだけど・・・。
えーっと、ステータスフラグ2が0xB2ってことで「MAC_Aブロック読み出し時にRCブロックへの書き込みがない」と。

では、とりあえずRCブロックに適当な値を書き込んでから・・・同じく0xB2になった。
なんだなんだ?

 

STATE

00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00

意味を持つのは、0番目と8番目。

[0]EXT_AUTH
認証前か後か。
まだやってないけど、新しく追加された認証(片側認証じゃない方)の前か後かだろうかね。

[8]POLL_DIS
Pollingに応答するかどうか。
へー、そんな機能があるんだ。

で、これはReadOnlyではなく、R/Wとのこと。
起動時はどちらも0(認証前、Polling応答する)になるらしいから、Polling未応答にしたまま忘れるという心配はしなくてよさそうだ。

POLL_DISは、他にカードがあるかどうかのチェックに使えるそうだ。
複数あるときは、対象以外を応答しないようにするのか?と思ったが、POLL_DISが設定できるということは捕捉したということになるので、意味がないか。 
テクニカルノートには「複数枚のカードがかざされていた場合に1枚のカードを特定するための手段の1つ」とある。
うーむ。

Pollingして応答が返ってきている時点で、カードは捕捉できてると思う。
おそらく、R/Wは最初に返ってきた応答の結果を渡していると思う。
複数枚のカードがあって、異なるタイムスロットで応答を返した場合は、無視された形になる。
しかし、最初に返ってきたカードに対してPOLL_DISすると、次にPollingしたときには別のカードが応答を返すことになる、という考え方で良いのかな。

PaSoRiで複数枚カードはきついような気はするが、試してみたいところではあるな。

 

CRC_CHECK

00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00

0番目だけ有効。
0x00はCRC一致、0xFFはCRC不一致。

これは不正アクセスというよりは、衝撃によるデータ破壊なんかを検出する目的なのかな。


なお、FeliCa Liteで上記レジスタを読もうとしても、ブロックが存在しないのでエラーになる。
LiteとLite-Sの見分けは、とりあえずそれでつければよいのかな。

2014年6月20日

[felica]FeliCa Lite-S来たる!

BLEがんばる、といった矢先、FeliCa Lite-Sカードが届いた。

私「ご、ごめん・・・」
BLE「ううん、いいのよ」

と言ったか言わないかはわからないけど、初めて見るNFCタグが来た以上、調査しないわけにはいかない。


カタログから

まずは、カタログでのスペック違いを見ていこう。
まあ、商品ページを見るとだいたいわかるんだけど。
http://www.sony.co.jp/Products/felica/business/products/RC-S966.html

使用許諾を認めれば、差分ドキュメントもある。
そっちの方がわかりよいか。
http://www.sony.co.jp/Products/felica/business/tech-support/index.html#Lite05S

 

とりあえず覚えておかないといけないのは、上位互換であること。
上位互換という言葉でいいのかわからんが、今までのFeliCa Liteカードとの完全互換があるというのは知っておいた方がよいだろう。
その上で、機能が追加されているのだ。
これを入手できるまで、2年くらいかかった、ということだな。

 

相互認証!

今までのFeliCa Liteは、「片側認証」という認証があった。
何が「片側」かというと、カードリーダ含むカード発行側はFeliCa Liteに対して認証することができる(自分が発行したカードかどうか確認できる)のだけど、FeliCa Lite自身はアクセスされることに対するガードができない。
FeliCa Standardになると相互認証ができるので、「認証がしっかり必要なものはStandardだよねー」という立ち位置だった。

それが、だ。
FeliCa Lite-Sでは相互認証ができるようになったのだ!
やり方はStandardとは違うし、めんどくさそうな感じもするのだが、できないのとできるのとでは雲泥の差がある。
私の調査も、相互認証のやり方を調べることから始めるだろう。

 

その他

私にとっては、それ以外の部分はあまり興味がない。
まあ、212Kbps/424Kbpsの両方に対応したので、もう少し高速化できるかも、というところか。


さて、ついでにIDmのことも書いておこう。
別にこれは、Lite-Sだけのことではないと思う。

FeliCa Standardは、発行側がIDmを決められるらしい。
FeliCa Lite/Lite-Sは、出荷時にIDmが決められているらしい。

この違いが私にはあまりわかっていないのだけれども・・・。
とりあえず、発行されたカードの中では、というところに絞れば、IDmはユニークである。

絞らなければ・・・だと?
IDmってのはなあ、お嬢ちゃん、単なる数字なんだよ、8byteの。
Tg系のコマンド仕様とか見てみるとわかるけど、IDmなんて適当だ。
ソフトで指定することだってできる。

だから、だ。
だからLite-Sのように相互認証するカードを待ち望んでいたのだ。
今まで、LiteとStandardの間が大きすぎたのだ。
データの保持だけなら、NFC-Aの安いやつでも偽造しづらい(Tg系のコマンドは、NFC-AのIDが一番小さい4byteのものでも、ソフトとしては3byteまでしか指定できないので、少なくとも私レベルでは偽装できない。
7byteのNFCIDだったら、もう何もできないのかもね。

 

そんなわけで、どっちかというとIDmをソフトレベルで全部指定できるというコマンド仕様を変更した方が良いように思うのだが・・・。

2014年6月19日

[ble]nRF51822というチップ

2回のRejectに心を痛めた私は、逃避行動を取ることにした。

BLEを勉強し直そう。
スイッチサイエンスさんからFeSCa(FeliCa Lite-S)が発売されているので気にはなるが、それは注文したものが来るまで待とう。
近距離通信として、BLEはまだ学び始めにすぎない。
もう少し、ちゃんとやらないと。


そんなわけで、注文していたBLE開発キットが今日届いた。
Nordic社のnRF51822というチップが載っている。

https://www.nordicsemi.com/eng/Products/Bluetooth-R-low-energy/nRF51822

nRF51822は、BLEが使えるSoCらしい。
SoC・・・System on Chip、か。
わかるようなわからんような。マイコンとデバイスが一緒になってる、みたいなものか?

この子、ARM Cortex-M0 32bitが載っているそうだ。
こ、こんなに小さいのに・・・。
Cortex-M3のFM3が比較的大きかったので、ちょっと驚きだ。
M0も少しは知らないといかんな。

メモリは、256KB or 128KBのプログラム用FLASHと、16KBのRAM。
そうか・・・16KBもあるのか・・・。まあ、32bitマイコンだから、それなりにないと苦しいのだろうが。

あとは、

  • 温度センサ(センサ目的? マイコン加熱検出用?)
  • SPI
  • I2C互換
  • UART
  • RTC

などか。

まだ開発環境の構築に至っていないので、また後日。

2014年6月12日

[ios]そして再Rejectされる

ふふ、ふふふふふ・・・・・・・。

2.12: Apps that are not very useful, are simply web sites bundled as apps, or do not provide any lasting entertainment value may be rejected

ええ、力強くRejectされましたとも。
予想はしてたんですよ?
きっと通らないだろうなあ、とは思ってたんですよ?

でもね・・・心の奥底では「もしかしたら」って希望を持ってましたよ。
ほら、パンドラの箱の底にだって残ってたじゃないですか。

 

Windows8もブルースクリーンになったし、今日はダメダメだぁ。

2014年6月9日

[android]威嚇!セイバー! 1.0.4

設定画面を追加したので、アップした。
久々にアプリ管理画面を見たけど、あか抜けたねー。

署名付きAPKも久々だったんだけど、2037年に切れるけどいい?って聞かれた。
最初に作ったkeystoreをずっと使ってるんだけど、定期的に更新した方がよいのかな?
でも、最初にアップした署名はずっと管理するだろうし・・・。
期限だけ延ばすとか、できるのか?


AndroidとiOSで同じようなアプリを作ったけど、やっぱりいろいろ違いますな。
めんどくさいので、なんか別の言語で作って、それをAndroid用やiOS用に変換してくれるようなしくみがあるといいのになぁ。
できんよなぁ・・・。

とりあえず、自分にできる技がほとんどないことがわかった・・・。
ちょっとまじめにやらないと、これからの人生が危ないと悟ったのが収穫だったか。

2014年6月8日

[android]ActionBarを表示させたら、onTouchEventの座標がずれる

iOS版の「威嚇!セイバー!」は、設定画面を追加したくらいでReviewに出した。
またリジェクトされる恐怖と戦う日々が始まる・・・。

それまでの間なにもしないのもなんだから、Android版も同じ修正をすることにした。


今まではAndroid1.6から対応してたんだけど、これを機に4.0まで引き上げることにした。
少しずつ新しくしていかんとね。

同じように設定画面を追加しようとしたが、はて、やり方がわからぬ。
どうも最近では、ActionBarを付け、そこから呼べるようにするらしい。
今まではフルスクリーンだったけど、ActionBarを付けることにした。
動的に変化するわけでもないので、AndroidManifestに「@android:style/Theme.WithActionBar」を付けた。

それで表示されるようになったんだけど、onTouchEventで通知される座標がActionBarの分くらい下にずれて通知されている。
威嚇セイバーって、タッチされた座標に向かって歩いて行くんだけど、それが下にずれる結果となっている。
うーむ。

下にずれる、ということは、通知される座標は以前と同じで、表示するViewが下にずれている、ということになる。
たぶん、通知座標は画面左上を原点とした座標系で、ViewはActionBarの下からの座標系なのだろう。
Windowsでいうところのクライアント座標に変換せんといかんのか。

 

しかし、ネットで調べても・・・そんなことをしてる人が見当たらない。
フルスクリーンで作っていたときの残骸が、どこかに残っているのか・・・。

すっきりしないが、getActionBar().getHeight()で座標を差し引くことにした。
うーむ。。。

2014年6月6日

[ios]Xcode6(beta)でAppIDが変わっていた

タイトルがわかりづらくて済まん。
用語がまだよくわかってないのだ。

今朝は7時過ぎに目が覚めたので、そのまま起きて、中途半端になっていた威嚇セイバーを完成させようとした。
といっても、単に絵を増やすだけなので、絵を数枚描いただけなのだが・・・。

で、画像も作り、シミュレータでも動作したので、またRejectされてもいいからアップしようとした。
すると、なんかProvisioningと違うとか、サーバの情報と違うとか、なんかそんな感じのエラーが出た。
(内容は忘れた。すまん。)

うちのiPad miniをiOS8 beta1にしたので、Xcodeもbetaを使っていたからそのせいか、と思いXcode5に戻したけどダメ。
なにがちがうんじゃー、とよくよく見ると、アプリの名前が「com.blogpost.hiro99ma.IKAKU」みたいなので作っていたものが「com.blogpost.hiro99ma.test.IKAKU」になっていたのだ。

このtest付きのって、プロジェクトを新規作成すると自動的にできるTARGETだよなぁ・・・。
なんでそれに切り替わってたんだ・・・。

あと、アプリのバージョン表記も「1.0.0」ってしてたのが、「1.0」になってた。
訳わからんですたい・・・。


そんな艱難を乗り越え、2回目のWaiting For Review状態になった。
来年のDeveloperアカウントの更新もしてしまったので、どうやってもリリースさせないと気が済まない!
これで認めてくれ~~

2014年6月3日

[ios]Static Cellで設定画面を作りたい

Macで、無料のブログエディタ(Blogger対応)があったら教えてくだされ。
画像を貼ることさえできればよいので。。。
なんか設定がうまくできんのよねぇ。。。


さて、それはともかく。
Static Cellで設定画面を作りたい。

まず、UITableViewControllerはこんな。

その中のTableView。
ここがStatic Cellsだ。

そうすると、"Table View Section"というのがセクション数分できる。
Table View Section自体は、特に用が無いみたいで、設定するのはRows。行数だ。



Cellの例。


さて、これを設定として使うときはどうするのか。
今回は、セクションの中身は選択肢で、タップしたものが1つだけ選択されるようなものを考えている。
ラジオボタンみたいなイメージなのだが、iOSではラジオボタンがないからcheckmarkになるんじゃないかと思っている。

ただ、iOSとしてはチェックマークとか、ディスクロージャーとか、そういうのは”Accessory"らしい。
付属物、みたいなものか?
だから、「チェックマーク? 付けたければ付ければいいやん」みたいなスタンスのようだ。
何かというと、タップしたからマークを付ける、とか、他がタップされたからマークを外すとかは、たぶん実装でやってあげないといけない、ということだ。

あ、文句を言っているように聞こえるかもしれないが、どちらかというと「私が文化をわかっていない」の方じゃないかと思っている。
あるいは、やり方をわかっていないだけか。
まあ、文句であることには変わりが無いんだけどね。

そんなわけで、こういう実装をした。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *curCell = [tableView cellForRowAtIndexPath:indexPath];
    
    //同じセクションのチェックを全部外す
    for (NSIndexPath *path in [tableView indexPathsForVisibleRows]) {
        if (path.section == indexPath.section) {
            UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:path];
            cell.accessoryType = UITableViewCellAccessoryNone;
        }
    }
    //自分にチェック

    curCell.accessoryType = UITableViewCellAccessoryCheckmark;
}

動いてはいるんだけど、ここまでやってやらんといかんの?とは思う。
あと、indexPathsForVisibleRowsで見えてる部分のindexPathを取得してるけど、じゃあ画面外まで広がってたらどうすんだよ、とか。

まず、didSelectRowAtIndexPathで、タップされたセルの情報が取得できる。
セクション番号とか、行番号とか。
NSIndexPathは、行番号とセクション番号がわかれば取得できる。
ならば、あとはセクション番号から行数がわかれば、indexPathesForVisibleRowsに頼らずに済む。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *curCell = [tableView cellForRowAtIndexPath:indexPath];
    
    //同じセクションのチェックを全部外す
    NSInteger rows = [tableView numberOfRowsInSection:indexPath.section];
    for (NSInteger row=0; row<rows; row++) {
        NSIndexPath *path = [NSIndexPath indexPathForRow:row inSection:indexPath.section];
        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:path];
        cell.accessoryType = UITableViewCellAccessoryNone;
    }
    //自分にチェック

    curCell.accessoryType = UITableViewCellAccessoryCheckmark;
}

どうだ?

2014年6月2日

[ios]設定画面を作ろうとしているが、よくわからん

よくわからんシリーズだ。

iOSで、設定画面を作ろうとしている。
Rejectされたので、なんか設定できるようにしてやろうという考えだ。
iOSの設定アプリに追加するやつじゃなくて、アプリの中に組み込むやつを作る。

設定画面と言えば、UITableViewController。
Storyboardエディタで、これを貼り付ける。
ついでにUITableViewControllerを継承した新規クラスも作成する。
そしてStoryboardのCustom Classとして指定してやれば、何かあったときに作ったクラスのメソッドが呼ばれるようになる。

UITableViewをStoryboardでやるとき、デフォルトはDynamicなんだけど、Staticという選択もできるとあった。
Staticでやると、実装部分を減らせるらしいので、今回はそうしてみよう。

--------
Static Cellって、あまり情報が見つからない。

設定画面なので、設定した情報を取ってきたり、反映したりしないといかん。
それをどうしていいかが・・・。

最終的には、didSelectRowAtIndexPathで全部やることにした。
セクションがいくつかあって、そのセクションごとにチェックマークが1つあるような設定画面だったのだけど、その「セクションごとに」とかを自動でやれるのかどうかがわからん。
だから、cellForRowAtIndexPathでタップされた位置のセクション番号を取ってきて、indexPathsForVisibleRowsで持っているセルを全部さらい、同じセクションだったらチェックマークをクリアし、最後にタップされたセルにチェックマークする、という泥臭い方法にした。
あー、かっこわるいーー。

設定値はNSUserDefaultsで保持することにした。
設定項目は2つしか作ってなかったんだけど、NSMutableDictionaryで管理させた。
NSUserDefaultsって、NSDictionaryは保持するけど、NSMutableDictionaryがよくわからんかった。
めんどくさいけど、一度NSDictionaryとして取得し、NSMutableDictionaryに変換することにした。保持するときは、setObjectでNSMutableDictionaryすればよかった。

dictionaryForKeyで取得するからNSDictionary形式になったんだけど、objectForKeyで取得すればよいのか?
でも、「オブジェクトを保存する」っていうしくみがどう動いているかわからないので、型が違うとだめそうな気もする。

なんか、こういう基礎的なところがまだ理解できてないよなぁ。。。