2020年6月30日火曜日

NTAG424 DNA で遊ぶ その3(設定編)

いよいよと言うかやっとと言うかようやく設定です。パラメータがたくさんありすぎてきちんと設定できるのか大変心配になる作業です。うっかり設定間違えると設定変更も書き換えもできない何もできなくなってしまうタグが完成してしまいます。恐ろしいですねー。

出荷時にはNDEF部分(FileNo 2)の設定変更には Key0 の Fullモードじゃないとアクセスできないようになっています。というわけで前回面倒な認証作業を実施しました。Fullモードの場合、APDUのデータの部分が暗号化された形で通信を行います。ざっくり言うと CommandHeader + 設定値の暗号化 + チェックサム的な という形式です。

CommandHeader は 02 のようです。コマンドの詳細仕様を見ると先頭に設定を変更する FileNo を記載すると書いてあるので、恐らく FileNo の 2 のことなんだと思いますがよくわかりません。試せばいいんでしょうけど変な風になる恐ろしさがあるのでタグも10枚しかないしそんなにお手軽にできるシチュエーションでもないのですいません。

設定値は FileOption、AccessRights、SDMOptions、SDMAccessRights、UIDOffset、SDMReadCtrOffset、PICCDataOffset、SDMMACInputOffset、SDMENCOffset、SDMENCLength、SDMMACOffset、SDMReadCtrLimit の順に値を並べます。全部説明してると面倒長くなるので、AN12196 の6章で設定してるところだけ書きます。

FileOption(1バイト) は SDM をやるかやらないかと、通信モードを設定します。SDMやる場合は上から2ビット目を1にします。下位2ビットが通信モードです(Plain = 00、MAC = 01、Full = 11)。ということでここは 40h になります。

AccessRights(2バイト)はアクセス権の設定になります。アクセス権は Read、Write、ReadWrite、Change の4つあって、それぞれ 4ビットの値を設定します。0~4を指定すると、そのキー番号での認証を経てアクセス可能になります。 Eh を指定するとフリーアクセス可能です。Changeというのが Write と何が違うねんという感じですがこれは設定の変更の権限になります。AN12196 では Read:Eh、Write:0h、ReadWrite:0h、Change:0h を指定していますが、これだと Read はフリーなんですが Write が認証必要になるので NDEF部分の書き換えが Plainモードでできなくなってしまいます。のでテストするときはやっぱり書き換えたくなったりするのでここは E0EEh にした方がいいと思います。

SDMOptions(1バイト)はSDMの設定になります。先頭1ビット目から、UIDミラーをするかしないか、カウンターミラーをするかしないか、カウンターリミットの機能を使うか使わないか、SDMENCFileDataを使うか使わないか、下位4ビットは 0001 になります。AN12196 では C1h になってますので、UIDミラーとカウンターミラーをONにしています。(SDMENCFileData:1 になってますが間違いです)

SDMAccessRights(2バイト)はSDM関連のアクセス権の設定になります。4ビットずつで F 固定、SDMCtrRet、SDMMetaRead、SDMFileRead の設定です。0~4を指定するとそのキー番号で暗号化されます。この中でSDMMetaReadがUIDとカウンタの暗号化に関わっていて、2を指定していますのでUID+カウンタが Key2 の値で暗号化されることになります。

後は PICCDataOffset(3バイト)、SDMMACInputOffset(3バイト)、SDMMACOffset(3バイト)の順で設定します。PICCDataOffsetがUID+カウンタを暗号化した値をNDEFのURLのどこに挿入するのかを指定します。

設定値は以上になります。ここから Fullモードでアクセスするために電文を組み立てます。

まず暗号化に使用する IV を作ります。IV は A55A + 認証時に取得したTI + コマンドカウンタ + 0000000000000000 を、認証時に作成した Encryption Session Key で暗号化します。コマンドカウンタはコマンドの番号というか順番というかコマンドを発行するたびに+1する値です。

IV = E(Encryption Session Key:1309C877509E5A215007FF0ED19CA564, A55A + 9D00C4DF + 0100 + 0000000000000000 )
 = 3E27082AB2ACC1EF55C57547934E9962

次にこの IV を使って、設定値を暗号化します。

E(Encryption Session Key, IV, 4000E0C1F121200000430000430000 + 80(padding))
= 61B6D97903566E84C3AE5274467E89EA

最後にチェックサム的なところを計算します。

Cmd(5F) + CmdCounter(0100) + TI(9D00C4DF) + CmdHeader(02) +
E(KSesAuthENC, CmdData)
=5F01009D00C4DF0261B6D97903566E84C3AE5274467E89EA

これの AES-CMAC を計算します。

CMAC = 7BD75F991CB7A2C18DA09EEF047A8D04

さらにこれの偶数バイト目だけを集めたものがチェックサム的な値になります。

MACt = D799B7C1A0EF7A04

ここまできてようやく APDU が完成します。

CLA 90
INS 5F
P1 00
P2 00
Lc 19
Data 02 61B6D97903566E84C3AE5274467E89EA D799B7C1A0EF7A04
Le 00

あー、長かったー。



2020年6月24日水曜日

NTAG424 DNA で遊ぶ その2(認証編)

前回はタグの認証を経ずに、Plainモードでタグに素のNDEFを書き込むところまでをやりました。SUN(Secure Unique NFC) を利用するには UIDミラー、カウンターミラー、SDM(Secure Dynamic Messaging) を利用するように設定をしなくてはなりません。設定コマンドは Fullモードでタグとアクセスしなければならないので、まずは認証という手順を実行する必要があります。

認証を行うには、AuthenticateEVFirst というコマンドを投げます。AN12196 の 6.6 の手順になります。(以下、資料内のデータをそのまま記載します)

CLA 90
INS 71
P1 00
P2 00
Lc 02
Data 0000
Le 00

Dataの1バイト目は使用する Key の番号で 0 を指定しています。すると応答が来ます。

A04C124213C186F22399D33AC2A3021591AF

最後の2バイト(91AF)は応答コードで、AFはコマンドに続きがあることを示します。先頭から16バイトが、タグ側で生成された乱数(16バイト、資料ではRndBと記載)を Key0 で暗号化した値になります。暗号は AES128-CBC(パディング無し)が使用されます。Keyはタグ側で保持している Key0 の値を使用し、IV はオール0(16バイト)が使用されます。

そういうわけで、これを復号するにはタグに保持されている Key0 を知っている必要があります。デフォルトではオール0になっているので、Key=オール0、IV=オール0で復号します。

RndB = B9E2FC789B64BF237CCCAA20EC7E6E48

これでタグ側で生成された乱数が取得できました。
続いてリーダ側で乱数を生成し(RndA)、タグに送ります。

RndA = 13C5DB8A5930439FC3DEF9A4C675360F (乱数なのでなんでもいい)

そのままこの値を送信するのではなく、タグに送信するデータを組み立てます。
RndBを1バイト左にローテーションします。

RndB' = E2FC789B64BF237CCCAA20EC7E6E48B9

RndA と RndB' をくっつけます。

RndA || RndB' = 13C5DB8A5930439FC3DEF9A4C675360FE2FC789B64BF237CCCAA20EC7E6E48B9

先ほどと同じ Key=オール0、IV=オール0で暗号化します。

35C3E05A752E0144BAC0DE51C1F22C56B34408A23D8AEA266CAB947EA8E0118D

これをDataとしてAPDUコマンドを送ります。

CLA 90
INS AF
P1 00
P2 00
Lc 20
Data 上記の値
Le 00

レスポンス
3FA64DB5446D1F34CD6EA311167F5E4985B89690C04A05F17FA7AB2F081206639100

最後の2バイト(9100)は正常応答のコードです。
先頭32バイトを復号します。

9D00C4DFC5DB8A5930439FC3DEF9A4C675360F13000000000000000000000000

先頭から、TI(トランザクション識別子)、RndA'、PDcap2、PCDcap2の値になります。

TI = 9D00C4DF
RndA' = C5DB8A5930439FC3DEF9A4C675360F13

RndA'は、RndAを1バイト左にローテーションした値になっています。これで正常に乱数がやり取りできたことを示します。
PDcap2とPCDcap2の値は使用しません。

ここからこの先のコマンドをやり取りするときに利用する暗号キーを組み立てます。

SV1 = A55A00010080 [RndAの先頭2バイト] [RndAの3バイト目から6バイトとRndBの先頭から6バイトをそれぞれ XOR したもの] [RndBの7バイト目から16バイト目まで] [RndAの9バイト目から16バイト目まで]
=A55A0001008013C56268A548D8FBBF237CCCAA20EC7E6E48C3DEF9A4C675360F

SV2 = SV1 の先頭2バイトを 5AA5 に変更
=5AA50001008013C56268A548D8FBBF237CCCAA20EC7E6E48C3DEF9A4C675360F

次にSV1とSV2を使って、上記の暗号とは少し違う AES-CMAC という方式で Key0 を使って認証値(ハッシュ値的な?)を計算します。

Encryption Session Key = CMAC(k0, SV1)
 = 1309C877509E5A215007FF0ED19CA564

CMAC Session Key = CMAC(k0, SV2) = 4C6626F5E72EA694202139295C7A7FC7

これで認証の作業は終了です。次はいよいよ設定値の変更になります。



2020年6月22日月曜日

NTAG424 DNA で遊ぶ その1

リリースされてちょっと時間経ってるんですが、NTAG424 DNAというすごい高機能なタグがあります。これまで見て見ぬふり扱ってなかったんですが、触ってみるとえれー大変だったので備忘録もかねて書きたいと思います。

まずこのタグで何ができるのかなんですが、一番大きな機能は Secure Dynamic Messageing(SDM) という機能で、暗号化された電文でタグと通信できる機能です。さらにその機能をNDEFで利用することができて、これまではNDEFにURLを書くとそれがそのままスマホで読み取りできたんですがここにSDMが適用されると Secure Unique NFC (SUN) message となり、URLの一部が暗号化された状態になります。

これまでのNTAGにはUIDミラー(※参照 NTAG210のUIDミラーを試してみる)とカウンターミラーという機能があって、NDEFのURLに自身のUIDとカウンター(タップされた回数)を埋め込むことができました。

例)
書き込まれたURL
https://www.hayato.info/tag?uid=00000000000000&ctr=000000
スマホで読み取ったときのURL
https://www.hayato.info/tag?uid=04C767F2066180&ctr=000010

これが、SDMを使うと UID+カウンタ の値が暗号化されたものが埋め込まれるようになります。そうするとその値がそのままサーバに飛んでいきますので、サーバ側で復号するとタップしたタグのUIDとカウンタ値が取得できます。カウンタ値も取得できるというのがミソで、例えば最後に飛んできたカウンタの値と同じかもしくは低い値であればそれはおそらくタップして取得されたURLではなく、ブックマークやあるいはURLを誰かに送付してそれをそのまま使ってアクセスしてきているのだということが推測できるわけです。

NTAG424 DNA の仕様書はこちらで公開されています。

これがまたこれまでのタグにくらべてボリューミーで読んでいくだけで疲れ楽しめます。さらにAN12196の資料にはエンコードする手順のサンプルが詳細に記載されていますが、これがまた手順が多いのと暗号化を使うので検証しながらやってくので時間かかるのとあとチョイチョイ(たまにがっつり)記載に間違いがあるのでそうすると自分の手順が違うのか仕様書が違うのかこれをまた検証しながらとかやってたのでえらい時間かかり長時間楽しめました。

まず NTAG424 はこれまでのようにメモリのある部分に設定を書き込むのではなく、ISOのどこかで規定されている MF/DF/EF というファイル構造を持っています。最下層のEFを3つ持っていて、それぞれ CC/NDEF/Proprietary という領域になっていて、NDEF領域にNDEFを書き込みます。さらに5つのキーを持てるようになっており、このキーを使って暗号化を行います。

また通信モードというのが3種類(Plain/MAC/Full)あって、Plainだと平文で通信、Fullだと完全に暗号化された通信という感じで、書き込む情報の重要度によって使い分けるようになっています。

今回は Plain モードでできる NDEF の基本URL(埋め込みする前のURL)を書き込むところまでをやります。

AN12196の6章に詳細手順がありますが、これの3番と8番に相当します。ちなみに6番に面倒な認証の手順がありますが、Plainモードで書き込みを行うだけならこの手順は不要です。

はじめに Select File で DF を選択します。DF名は D2760000850101h になっていますのでこれを指定します。

CLA 00
INS A4
P1 04(Select by DF name)
P2 0C(No Response Data)
Lc 07
Data D2760000850101
Le 00

あとはNDEFを書き込みます。

CLA 00
INS D6
P1 84
P2 00
Lc DataのLength
Data ここにNDEFのデータ
Le 00

仕様書の 6.8.1 では P1=00 になっていますがこれは誤りで、NDEFの領域を示すための値(EFを示す値)を設定する必要あります(それが無いとまだDFまでしか選択してないのでどこに書いていいかわからない)。NDEFのEFは E104h なんですが、ここに設定する値は Short ISO FileID というやつで最後の5ビット(04)になります。先頭1ビット目を1にすることでFileIDを指定することになりますので、84を設定します。

上記2つの APDU を投げることでNDEFの書き込みまでは完了します。
あとは SDM を利用するように設定することで完成しますが、まぁ、そこがまた長い話になるので次回に回します。たぶん。


2020年6月18日木曜日

アンテナとタグの距離を測る

UHFのRFIDタグをリーダで読み取りしたとき、タグがどのへんにあるのかを知りたくなるときがあります。あ、反応してる!してるけどドコ?という感じで。せめてアンテナからの距離がわかれば少しはマシですね。

アンテナからの距離というと最初に思いつくのは電波強度(RSSI)を使うという方法です。確かにタグが近いとRSSIは高くなりますし、タグから離れると低くなります。しかしながらRSSIは結構ざっくりした値でしかも距離に対して線形に変化する値ではないので、正確な距離を求めるにはちょっと物足りません。

そこで位相を利用することが考えられます。位相は昔のリーダでは値採れなかったんですが、最近のリーダはだいたい採れるようになっています。

位相をどう使うかなんですが、イメージとしてはこんな感じです。


1cm単位の精度が出せるというRTK(GPSのごっついみたいな)もこのようなことをしてるんじゃないかと誰かが言っていました。

というわけで計測をやってみます。最近のリーダは位相が採れると言いましたが、リーダによっては値のバラツキが激しかったりします(RSSIもそうですが)。比較的安定して採れている Impinj Revolution を使用しました。

計測風景
結果がこちら

d(cm) RSSI(dBm) 位相(度) 位相の差
5 -37.5 285.47
10 -38.5 206.72 78.75
15 -40.5 126.21 80.51
20 -42.0 46.05 80.16
25 -42.5 318.16 87.89
30 -43.5 228.16 90.00
35 -44.5 136.05 92.11
40 -45.5 42.89 93.16

左からアンテナとタグの距離、RSSI、位相、前の距離のときの位相との差になります。
こうして見ると、RSSIがざっくり下がっていくのに対し、位相は5cmごとに約80度~90度くらいずつ下がってますね。約20cmで一回りしてる感じです。

今回周波数を920.4MHzに固定して行ったので、1波長=c/920.4MHz≒32.6cm くらいですから、30cmくらいで一周すんのかなくらいに思ってましたがそうでもないようです。

とはいえRSSIで何発目の波かをあたりをつけて、位相を使って補正をすることで結構正確に距離がわかるような気がします。

実際はこんなにアンテナと正対することは無いですし、周りに他のタグがあったり電波の反射があったりしますからそううまくいくとはないと思いますが。

2020年6月4日木曜日

氷のタグ読み取り実験

前回、ドライアイスで読み取り実験しましたが、今回は氷で実験してみました。
氷を2つ作り、ドライアイスの時のようにタグを挟み込みます。ただし、氷は縦でないと立たないので、タグも縦になります。

使用したリーダーとタグ

・デンソー BHT-1281
・ALN-9654(Gタグ)



氷の面が平らでないので、ピッタリ重なりませんが。。。

MANICA エクセルツールで、最小出力にして読み取りしました。


【実験結果】
そのままで読み取ると、90cmぐらいでした。
氷ではさむと、70cm~75cmぐらいで、20%前後、読み取り距離が短くなりました。
しかし、時間が経過すると氷が溶けるためか、35%ぐらいまで読み取り距離が短くなりました。
ドライアイスと同様、表面の水が影響しているように思います。
極寒地や冷凍倉庫のような、氷が溶けない環境でないと、なかなか正確な実験は難しそうです。

【おまけ】
ガリガリ君で読み取りしてみました。
試す前から短くなることは想定できましたが、読み取り距離が30cmとなり、1/3ぐらいになりました。
氷の塊(固体)と違い、水分量が多いからだと思われます。