2017/05/28

[c/c++]lmdb

以前、Caffeを見ていたときにlmdbのデータを見る方法を調べたことがある。
http://hiro99ma.blogspot.com/2015/10/caffelmdb.html

このときは、mdb_dumpというツールでデータを見るだけだった。


そして、Cで書かれているKey-Value StoreなDBがないか探していると、lightning memory-mapped databaseなるものが出てきた。
OpenLDAPプロジェクトで作ってるようなのだが、これがlmdbだったのだ。

Symas Lightning Memory-mapped Database | Symas Corporation

世の中、狭いねぇ。


github(ぎっとはぶ、と読むのだね。私は、じっとはぶ、と読んでて怪訝な顔をされたよ)はこちら。
https://github.com/LMDB/lmdb


makeすると、ライブラリなどが生成されていた。
単独でビルドできるか、別の場所に「lmdb.h, liblmdb.a, mtest.c」だけをコピーした。

$ gcc -o tst mtest.c -L. -llmdb -pthread

うん、ビルドできた。

$ ./tst

あ、あれ、死んでしまう。。。
なんだ、dbを置くディレクトリは自分で作らんといかんのか。

$ mkdir testdb
$ ./tst

結果は分からないが、動いた。



lmdbを見つけるより前に、FineDBというものを見つけていた。
FineDB

これがlmdbをベースにしている、と書いていて、そういえばlmdbって記事にしたことあるな、という経緯でたどり着いたのだった。


FineDBはまだ動かしていないが、フォルダ構成がserver/cliとなっていて、これはこれで面白そうだ。
ただ、4年前が最後のcommitなので、lmdbを参照にしている部分は古いのかもね。

2017/05/27

[c/c++]leveldbをcで使いたかったが、libstdc++が必要だった

いつもsqliteを使っていたので、たまには違うものを使っておこうと思い、leveldbを使ってみることにした。

google/leveldb: LevelDB is a fast key-value storage library written at Google that provides an ordered mapping from string keys to string values.


configureなどがないので、makeして、includeディレクトリと、out-staticに入っていたlibleveldb.aを別の場所にコピーして、emnl/leveldb-c-exampleからleveldb_example.cを持ってきた。

$ gcc -I./include -o tst leveldb_example.c -L. -lleveldb -pthread

・・・大量にリンクエラーが出てきた。
deleteがどうのこうのと出ているので、C++のライブラリがいるようだ。
まあ、もとがC++だから、仕方ないか。。。


しかし、snappyとかいうエラーも出ている。
データを圧縮するライブラリらしいが、必須なのか?

Makefileを見ていくと、どうやらbuild_detect_platformというスクリプトで環境をチェックして、設定をbuild_config.mkに作り、それをMakefileが読込んでいるようだ。
どうやら、私が使っている環境ではsnappyをapt-getか何かでインストール済みのようだ(実を言えば、leveldbもインストール済みだった)。
今回は最小構成にしたいので、スクリプトでsnappy検出のところをコメントアウトさせた。


これでもlibstdc++.aみたいなものはいるので、あきらめよう。

$ gcc -I./include -c leveldb_example.c
$ gcc -o tst leveldb_example.o -L. -lleveldb -pthread -lstdc++

動くようだ。


サンプルが、leveldb_put()するときに"value"という文字を書き込んでいるのだが、きっちり5byte分しか書込んでいないので、その後でleveldb_get()したあとにprintf()したときの文字が化けて出力されることがあるようなので、気になる人は\0まで書込むなり、get後に\0を足すなりするとよかろう。

Cだけで書かれたNoSQLというかKVSのライブラリがあると、小さそうでよいのだけどね。

2017/05/26

[linux]msgsnd()のサイズを計算したい

まだやっている、Linuxのメッセージキューの調査。

前回で終わりの予定だったが、msgsnd()のmsgszを自動で計算したくなったのだ。
mtext[SZ_BUF]みたいにサイズが決まっているならやりやすいけど、メッセージキューってデータ構造を問わないので、せっかくなら使うデータをずらずら並べたいところだ。
そうすると、msgszがよくわからなくなってしまう。


試しに、msgszを8192にしたまま、構造体のサイズを小さくしてみた。
うん、やっぱりcoreを吐いてしまう。
msgrcv()だけが死ぬときもあれば、msgsnd()が死んでしまうこともある。
アラインメントによっては、死なないこともありそうだから、サイズはやはり気をつけておきたい。


あれこれ考えたが、これくらいしか思いつかない。

  • 構造体のsizeofから、mtypeの次のメンバーをoffsetof()した値を引く
  • mtypeの次のメンバーを構造体にしてしまう

後者の方がスマートかな?

2017/05/25

[linux]msgsnd()のサイズ確認

前々回の記事だが、タイトルは間違っていないものの、検討結果が間違っていた。
修正したので、以前読まれた方は申し訳ないが、一番下だけでも再確認していただきたい。

[linux]メッセージキューのmsgszは8192を超えてはいかん

msgsnd()のサイズ指定を構造体全体のsizeofでやっていたのだけど、指定するのはmtextの部分だけのようだ、ということだ。



が、すっきりしないので検証を行った。
Xubuntu16.04だ。

https://gist.github.com/hirokuma/5916e918f40bbf82dc5723e42789007c

まず、構造体としてはmtextを8192より256くらい多めに確保する。
送信側はmtextをすべて0x77で初期化し、受信側は0xccで初期化しておく。
そしてmsgsnd()では8192を指定し、受信側のmtextが0x77以外になるポイントを探す。


結果としては、8192、と出力された。
0から始まるので、0~8191までの8192バイトは0x77であることが確認できた。

sizeof(構造体) - sizeof(long)としているサイトがあったので、8192がどこからどこまでなのかが気になっていたのだ。
もしsizeof(long)が開始地点だったら、8188バイトまでしかコピーされていなかったはずだ。
一応offsetof()で調べたが、mtextは8バイト目だった。


よし、これでもう間違えないぞ。

[clang]BUFSIZ

マクロにBUFSIZというものがあったのだが、なんだろうか?
stdio.hに入っていることは分かったのだが・・・。



これは、ファイルが使用するI/Oバッファサイズに関係するようだ。
Man page of SETBUF
setbuf()がBUFSIZを使い、setbuffer()はそのサイズ指定可能版ということか。


printfさせると、BUFSIZは8192だった。
環境や時代で変わる値だと思うが、8KBまではバッファリングされることになる。


Man pageの説明を読むと、意識していないことが書かれていた。

  • バッファリングの種類は3種類ある
    • unbuffered
      • 出力をすぐ書込む
    • block buffered
      • 文字の読み書きはブロック単位で行われる
      • 吐き出すにはfflushなどを使う
    • line buffered
      • 新しい行が出力されるか、新しい行が入力されるまでためられる
  • ファイルはすべてblock buffered
    • 初めて入出力するときにmallocが呼ばれる
  • stderrはunbuffered


printf()とfprintf(stderr)を混ぜていると、出力されるタイミングが違うなあ、と思っていたのだ。
出力先が違うからだと思っていたが、バッファリングの種類が違っていたからなのか。


引数がFILE*だから、システムコールレベルではなく、stdioとしてサポートしていることになるのだな。
open()した場合は、OSの動作を見ておかねばなるまい。

[linux]メッセージキューのmsgszは8192を超えてはいかん

※2017/05/25 22:25 修正あり

Linuxのメッセージキューは、まずはサンプルを動かすことにした。
いつものように、LinuxといいつつWindows10のBash on Ubuntu on Windows(以下 BoW)だ。

が・・・コンパイルは通るものの、msgget()でエラーになる。

Function not implemented


嫌な予感は的中した。
System V IPC is missing · Issue #1016 · Microsoft/BashOnWindows

Creators Updateでセマフォと共有メモリは対応したけど、メッセージキューはbacklogと書いてあるから、まだ残ってるという意味なのかな。


まあ、何でもかんでも期待しちゃいかんだろう。


VMに入っているUbuntu環境に持っていくと、進んだ。

が、msgsnd()でInvalid argumentが出てしまう。
Man page of MSGOP
msgsnd()がEINVALを返すのは、以下のどれか。

  1. msqid が不適切な値
  2. mtype が正の値でない
  3. msgsz が不適切な値 (0 以下か、システムで決まる値 MSGMAX よりも大きい値)

msqidはチェックしているし、mtypeも正の値を代入している。
ということは、3番のmsgszだ。

サンプルでは、こういう構造体になっていた。

struct {
    long mtype
    char mtext[BUFSIZ];
};

このBUFSIZは、8192だった。
だから、sizeofすると、たぶん8196・・・違った、8200だった。
8byteアラインなのね。


ではMSGMAXは?
これはマクロ値にはなっていないようだったが、Man pageの下の方に書いてあった。

MSGMAX

メッセージのテキストの最大サイズ: 8192 バイト (Linux では、この制限値は /proc/sys/kernel/msgmax 経由で読み出したり変更したりできる)。

うーん、ここだけ読むとメッセージのテキストの最大サイズだから使ってもよさそうなのだけど、msgszのが超えたらいかんと書いてある方が強いのだろう。


というわけで、うちの環境ではmtextが8184までOKで、8185からInvalid argumentになった。

sizeofはマクロに入れられないので、

struct {
  long mtype;
  char mtext[SZ_BUF];
};

#if 8 + SZ_BUF > 8182
#error !!!
#endif

みたいにして判定させるのが良いかも。


※追記

あれからいくつか見てみたが、msgsnd()に指定するサイズとして、sizeof(構造体)ではなく、sizeof(構造体) - sizeof(long)、としているサイトが見られた。
ま、まさか・・・。

もう一度説明を見直すと、msgsnd()のサイズとして指定するのは、struct msgbufではなく、mtextに相当するサイズ(msgsz)と書いてあるではないか!

私はmsgsnd()で構造体のサイズを指定していたのだが、それではダメだ。
そして、アラインメントもあるので、sizeof(long)を引くのも正しくなさそうな感じがする。
ここは、mtextに相当するサイズをマクロで指定するのがよいのかもしれん。


ふっ、まだまだ私も青いのぅ。。。
タイトルは間違っていないものの、動作検証をしていないから、後日やろう。

2017/05/24

[c/c++][linux]プロセス間でのメッセージキューに似たものはあるのか?

久々に、Linuxでネットワーク関係のアプリを書こうとしている。

やりたいのは、裏で通信してくれるアプリと、そのアプリに指示を出すアプリだ。
うまく作れば1つのアプリにまとめてもよさそうだが、いかんせん、コンソールから指示を入力させたりする実装をしたくないので、別アプリにして引数で指示を与えようと考えたのだ。
これもRPCの一種になるのかな?


そこまで考えて、悩むことになった。
どうやって指示アプリと通信アプリを接続すればよいのだろうか?
確かローカル環境では、socketpairでファイルみたいなのを作ってやっていたような気がする。。
まあ、今回は指示を出すだけなので、pairは作らなくてよいか。


指示を出すだけなので排他処理はいらないように見えるが、裏で通信していて、受信したメッセージによっては送信を行うことがある。
その送信も、指示するのと同じ経路でやってしまおうと考えている。
つまり、送信処理をキューでためられるようにして、そのキューには指示アプリか受信メッセージが追加を行う。
それぞれプロセスが違うので、ここに排他処理を入れようというわけだ。


なんとなく、共有メモリを作って、セマフォで排他するんじゃなかろうか、と思ったのだが、メッセージキューがあるらしい。
msegrcv, msgsndには排他がいるとか書いていないから、排他は不要なのかな?


しかし、メッセージキューに関して検索しても、あまり新しい記事が出てこない。
実はもっと便利なライブラリがあったりするのでは?と探すが、うまく探し出せない。
関連する語彙がわからん。。。


わからんので、ここら辺を見ながら作ってみよう。
IPC: Message Queues | Shinta's Site

[c/c++]accept数を制限したい

珍しくsocketで作っている。
serverという程のものではないのだが、socketをいくつか受け入れるしくみを作ろうとしている。

Man page of LISTEN

socket()して、bind()して、listen()して、あとはaccept()でやってくるのを待つ。
教科書通りにやると、accept()で処理がブロックされて、clientからのconnect()を待つことになる。

 

今回は、同時にN個まで接続できる、というようなことをやりたい。

socketって、同じポートで接続できないんじゃなかったっけ?と思ったが、connect()する方が適当にポート番号を振って接続しに来るためか、あまり気にしなくてよかった。
まあ、次々accept()したいから、スレッド起動させたりはせんといかんが、そのくらいのようだ。

では、あとは数を制限するだけだ。
・・・・あれ、どうやって?


今回も、Windows10のBash on Ubuntu on Windowsでやっている。

まずは、一番それっぽいように見えた、listen()のbacklogを変更した。
接続キューの上限みたいだから、それでいけると思ったのだが・・・ダメだ。
よく読むと「保留中の接続のキューの最大長」とのことだ。
だから、手でconnectするアプリを次々起動させるようなことでは、保留させる必要がないということだろう。

 

linux - Is it possible to unlisten on a socket? - Stack Overflow
これを読むと、accept()してすぐclose()!らしい。

int delsock = accept(sock, NULL, NULL);
close(delsock);

まあ、確かにやりたいことは満たすのだけど、connect()でエラーが返るわけでは無いので、ちょっとなぁ。

 

しかし、connect()のエラー値を見ても、あまりふさわしいのがないな。
ECONNREFUSEDが近いけど、ちょっと意味が違う。
一時的にリソースが使えない、みたいなのはなさそうだから、あんまりがんばっても仕方ないのか。

2017/05/23

[win]WinMerge

Windows10で、ファイルの比較をするのにWinMergeを使っている。
version 2.14.0.99+-jp-99となっているから、日本語版なのかな。

image

 

シェル連携させていて、Explorerのファイルを選択してコンテキストメニューから「比較」とすると、比較した画面が表示されるので便利だ。

image

 

何気なくファイルを選択してしまうと、左右のどちらにどのファイルがいるのかわからなくなってしまうのだが、選択の仕方を意識的に行うだけで、どちらにどのファイルが来るのか確定できそうな気配だ。

「気配」としたのは、今のところ私の環境はそうなっているけど、何でそうなるのか知らないからで、他の環境だとそうならないかもしれん。

 

私の環境では、2ファイルを選択する場合、ExplorerからCtrlキーを押したままファイル選択を1つずつ行うと、比較ウィンドウの右側に1番目に選んだファイルが、左側に2番目に選んだファイルが出てくるようだった。
ファイルがソートされている順に左→右と出したいのであれば、Explorerでは並んだファイルの下からCtrlキーでクリックしていくと期待通りに出てくれている。

 

技というほどではないし、確定しているものでも無いけど、私の場合はこれでずいぶんと手間が省けるようになった。

2017/05/21

Diffie-Hellmanの25519や448とは?

前回、まったく内容を理解しないまま、noise-cのサンプルアプリだけ動かした。
あとは、これをプロジェクトに組み込めばよい・・・と思っていたのだが、そうではなかった。
まだわかっていないが、サンプルも引数で設定が変更できたように、何か使用方法を決めるというもののようだった。

 

たとえば、Noise_NN_25519_AESGCM_SHA256、などという名前が、何か意味を持っているらしい。

Prefix : Noise
Pattern : NN
Diffie-Hellman : 25519
Cipher : AESGCM
Hash : SHA256

ということのようだ。
もはや呪文ですな。。。

 

noise-cがサポートしているアルゴリズムは、ドキュメントに書かれている。
http://rweather.github.io/noise-c/index.html#algorithms

これが仕様を満たしているのかどうか、満たしていなかったら改造できるのかどうか、改造できなかったら他のライブラリがあるのかどうか、その辺を見ていくことになりそうだ。
うう、つらい・・・。

つらいのだが、誰か調べてくれるわけでもないので、基礎知識に相当するものくらいは記事にしてもよかろう。


知りたいのは、Diffie-Hellmanだ。
サンプルのechoでも、25519と448という数字しか出てきていない。
そもそも、Diffie-Hellmanって鍵交換とかそういうはなしじゃなかっただろうか?
それの数字って、何なのだろう。

 

RFC 7748 - Elliptic Curves for Security
検索すると、すぐに出てきた。
RFCで推奨している楕円曲線の種類が、25519と448という名前のようだ。
RFC 7748だけじゃなくて、8031や8037などにも出てくるな。

2^255 - 19をつなげて、25519。
448はちょっと違って、2^448 - 2^224 - 1となっている。
そういえば、前調べたChaCha20-Poly1305も、2^130 - 5だったからそういう名前だった。


Diffie-Hellmanは、安全に鍵を交換するための方式だ。
鍵といっても物理的な鍵ではなく、データとしての鍵だ。
検索すると、たくさん出てくる。

また、CipherやHashも暗号関係の技術だ。
これらをどう組み合わせてもよいようにできているのだろう。

だから・・・noise-cが対応していないパラメータを使うようになっているという可能性もあるということだ。
嫌な予感はするのだが、これ以上は触れるのを止めておこう。

[c/c++]noise-c ?

仕様書で「プロトコルはnoise-cで」みたいなことが書かれていた。

noise-c ???

どうやら、Noiseプロトコル、というものがあるらしく、そのC言語実装がnoise-cだそうな。
rweather/noise-c: Noise-C, a plain C implementation of the Noise protocol

プロトコルに興味は無いのだが、githubに上がってるくらいだから、ブログのネタにしても悪くはなかろう。


プロトコル仕様は、これらしい。

The Noise Protocol Framework

いやー、見る気にならんわー。
最初の方に"crypto"と出てくるので、何か暗号化するようなプロトコルなのだろう。

こういうのって、作っている人は改良しながらやっていくから中身が分かるのだろうけど、外側から見ている人、特に私みたいに成果だけ使おうとしている人にとっては、なかなかつらい。

私もgithubにときどき上げているが、使いやすくがんばっているわけではないし、そもそも「誰にでも使えるように」などと考えているわけではないから、同類だ。
それに、ドキュメントを整備しているわけではないから、同類とすることすらためらわれるレベルである。。。

 

まあ、いいのだ。
使おうと思う人が増えると、自然とドキュメントも整備したくなってくるものだから、それだけの違いなのである。


話を戻そう。

noise-cの使い方はまだわからないが、examplesはある。
Noise-C: Using Noise-C: Client/Server Echo Example

ただ、これを読んだまま実行してもなんだかわからなかったので、手順を残しておこう。
動かしたのは、bash on ubuntu on windows(16.04)だ。

 

 

githubから落とす

cloneでも何でもよいので、持ってこよう。

 

makeする

autogen.shがあるから、まずはそれを実行するとよかろう。
Build手順が載っているので、その順番でよいのではなかろうか。
Noise-C: Main Page

 

exam:key生成

いま、noise-cのディレクトリにいるとしよう。

$ cd examples/echo
$ mkdir keys
$ cd keys
$ ../echo-keygen/echo-keygen 25519 client_key_25519 client_key_25519.pub
$ ../echo-keygen/echo-keygen 25519 server_key_25519 server_key_25519.pub
$ ../echo-keygen/echo-keygen 448 client_key_448 client_key_448.pub
$ ../echo-keygen/echo-keygen 448 server_key_448 server_key_448.pub

パスをちゃんと書けよ!と思った。

実際は、*.pubの方を公開するのだけど、今回は同じPC内で実行するから、面倒を省くために keys/に全部置いているだけだ。
psk(pre-shared key)もいるらしいが、読んでもよくわからんので、こういうスクリプトを作った。

#!/bin/bash
rm -rf keys
mkdir keys
./echo-keygen/echo-keygen 25519 keys/client_key_25519 keys/client_key_25519.pub
./echo-keygen/echo-keygen 25519 keys/server_key_25519 keys/server_key_25519.pub
./echo-keygen/echo-keygen 448 keys/client_key_448 keys/client_key_448.pub
./echo-keygen/echo-keygen 448 keys/server_key_448 keys/server_key_448.pub

echo -en '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f' > keys/psk.bin
base64 keys/psk.bin > keys/psk

 

exam:server起動

待ち受ける方。

$ cd examples/echo/echo-server
$ ./echo-server --key-dir=../keys 7000

これで、待ち状態になった。

 

exam:client起動

serverに接続をお願いする方。

$ cd examples/echo/echo-client
$ ./echo-client Noise_NN_25519_AESGCM_SHA256 localhost 7000
Noise_NN_25519_AESGCM_SHA256 handshake complete.  Enter text to be echoed ...

これで待ち状態になった。
なにかテキストを打ち込むと、そのまま返ってきた。

hiro99ma
Received: hiro99ma

うーん。。。動いているような気はするが、そもそもなんだかわかっていないので、そこから先に進めないな。
こうやって、詳細を調べていく間に世の中が進んでいくのだけど、まあ仕方ないわね。。。


examplesには続きがあった。
上記の動かし方は、static keyが不要な動かし方らしい。
確かに、作ったkeyを指定してない。

$ ./echo-client --client-private-key=../keys/client_key_448 \
            --server-public-key=../keys/server_key_448.pub \
            Noise_KK_448_ChaChaPoly_BLAKE2b hostname 7000

これを実行すると、echo-server側にエラーが表示される。

set client public key: Unknown identifier

ソースでいえば、ここのはず。
コメントからすると、client用のpubkeyを設定しているのだろう。

 

・・・ここのif文って、どっちもNOISE_DH_CURVE25519しかチェックしてないじゃないか。。。
NOISE_DH_CURVE448に変更すると動いた。

修正されたので、もう大丈夫だ。

2017/05/19

[win]Bash on Ubuntu on Windows起動

2017年4月のCreators Updateを当てたWindows10を使っている。
Bash on Ubuntu on Windows(な、長い。。。)の安定度が増したので、非常にありがたい。
デフォルトがこっちになって、コマンドプロンプトエミュレーション機能、みたいな形になっても困らないくらいだ。

起動するときは、メニューからショートカット選択している。
プロパティは、こう。

image

テキストエディタで編集しているディレクトリで開いてくれるとありがたいのだが、このbash.exeは特殊なためか、私が使っているEmEditorでは起動に失敗してしまう。

image


話が少し変わるが、最近テキストエディタとしてVisual Studio Codeを使うようになってきた。
自分で書いたくらいのC言語だったらテキストエディタでも追えるのだが、あまり使わない言語だったり大きいプロジェクトだったりすると関数を探すだけで疲れてしまう。

Windows上でVisual Studio Codeを起動しているのだが、Ctrl+@で「端末の切り替え」というキーに割り当てられているようだった。
なんとなく押すと、PowerShellが起動した。
「もしかしたら、bashが起動できるのでは?」と見てみると、できるようになっていた。
VSCodeをフォルダで開いているためか、bashもそのディレクトリで起動している。

 

さすがMicrosoft製だけあって、自分のところからは起動できるのか、と設定を見てみると、こういうのが追加されていた。

"terminal.integrated.shell.windows": "C:\\WINDOWS\\Sysnative\\bash.exe"

\WINDOWS\Sysnative?

image

ないよなぁ。。。

が、このパスをEmEditorに指定すると、bashが起動した。
へー。
もう試す環境が無いのだが、Anniversary Updateでも使えたのかもしれん。


おまけ

VSCode ver.1.12.2を使ってるけど、検索のデフォルト設定方法がわからん。
起動すると「大文字小文字の区別無し」「単語検索ではない」になっているのだけど、私は通常がその逆なので、毎回設定し直さないといけない。
設定方法があったら教えてくだされ。

 

大文字小文字を区別しなかったら、思ってもないものが検索されて困りそうだけど、他のエディタでもデフォルトがそうなっているから、少数派なのか。。。

2017/05/18

[c/c++]leveldb ?

ちょっとしたデータを読み書きして保持するとき、SQLiteと使うことが多かった。
別に検索したいとか、そういう要望があるわけではなく、他にそういうものはないのだろうと思い込んでいたのだ。

 

最近、またそういうデータを保持するしくみがいるので、どうしたものか悩んでいたら、leveldbというものがあることを教えてもらった。

グーグルがNoSQL軽量ライブラリ「LevelDB」をオープンソース化。SQLiteとの比較ベンチマークも公開 - Publickey

NoSQLですか。。。
まずはその用語からですな。


NoSQL - Wikipedia

"RDBMS以外のデータベース管理システム"くらいの言葉らしい。
リレーショナルデータベースマネージメントシステム、かな。
テーブル書いて、線でつなげていた気がする。

 

leveldbは、リレーショナルじゃなくて、キーバリュー型。
キーとそれに対するバリューをストアするので、キーバリューストアとか、KVSとか呼ばれるようだ。
そういえばAndroidのプリファレンスもそのくらいの機能しか使わなかったな。


google/leveldb - github

C++か。。。
c.hという、Cのインターフェースがあるので、ライブラリを作ってしまえばCからもアクセスできそうだ。

ただ、APIが思ったよりも多いので、ROMが多少心配だ。
また、できればファイルシステムを使わないようなところでも使えるとよいのだが・・・さすがに無理か。

2017/05/17

[c/c++]またMakefileの名前一致で失敗していた

以前、こういう記事を書いた。
hiro99ma blog: [c/c++]Makefileのdependは名前一致なのか

依存ファイルのオブジェクトファイル部分に相対のパス名が入っていると、うまくいかないようだった、という話だ。
相対というのは、

obj/./test.o

みたいに、間違ってないけど不要な相対パスなのかもしれん。
そこまでは調べていないのだ。

 

そのあと、依存ファイルの作り方を変更することで対応できそうだったという記事を書いた。
hiro99ma blog: [c/c++][make]dependの解決

そのMakefileを使っていたのだが、またうまくいっていなかった。
オブジェクトファイル名をソースファイル名から作っているところで、単にフォルダ名と拡張子だけを変更していたのだが、ソースファイルをさらに別ディレクトリを作っているとダメだったのだ。

 

こんなディレクトリ構成になっている。

_build/
   hello.o
   hello2.o

src/
  hello.c
  hello2/
    hello2.c

だが、ソースファイルをそのままオブジェクト名にしてしまうと、

_build/hello.o
_build/hello2/hello2.o

になっていたのだ。
まあ、単なる考慮漏れだ。

 

あれこれ考えたが、このMakefileはオブジェクトファイルを同じディレクトリに放り込むので、$(notdir)でパスを取り除けばよかろう、という結論に至った。
https://github.com/hirokuma/makefile_hello

オブジェクトファイルを同じディレクトリに置くことの弱点は、同じ名前のソースファイルがあるとダメだ、ということだろう。
一人でやっていると起きないけど、複数人でやっているとやらないとも限らない。
関数名はファイル名に関連したプレフィクスを付けるルールにしておけば対応できると思うが、名前が長くなるのが悩みどころだ。

2017/05/15

[ble]BLE NanoでnRF Snifferを動かす

nRF Snifferという、nRF51 DKなどで動かせるスニファがある。
ファームウェアもあるし、COMポート経由でWindowsとアクセスするようだから、別にnRF51 DKじゃなくても動かせそうな気がする。

 

対応しているハードウェアは、こうなっていた。
nRF-Sniffer-UG

• nRF51822 Evaluation Kit (PCA10001) and a mini USB cable
• nRF51422 Evaluation Kit (PCA10003) v3.0.0 or later and a mini USB cable
• nRF51822 Development Kit dongle (PCA10000)
• nRF51-DK (PCA10028) v1.0.0 or later and a micro USB cable
• nRF51 Dongle (PCA10031)

nRF51822とnRF51422が混ざっているが、使うのはBLEだけだからどっちでもよいのだろう。


nRFgo Studioでファームを焼く。
ちゃんと動いているかどうかは、PCA10001かPCA10003ならAdvertisingの検出でLED1がトグルするらしい。

PCA10001の図面を見ると、LED1はP0.19につながっている。
BLE nanoのP0.19もLEDにつながっている。
が、PCA10001はHで点灯、BLE nanoはLで点灯になっている。。。

あ、これは気にしなくていいか。
逆になっているだけだ。
AdvertisingするPeripheralを動かすと・・・点滅した!


次はUARTだ。

nRF51 DKやPCA10001はUSBでPCとつなぐので、ぱっと見てnRF51のどのポートかわからん。。。
nRF51 DKのUsers Guideに「4.2 Virtual COM port」という章があり、以下の表が載っていた。

image2

P0.09がTXD、P0.11がRXD、でよいのか?
それなら、BLE nanoもそうなっている。

あとは、問題になるとすれば通信速度だろうか?
よくわからんので、Snifferに入っていたexeファイルを実行した。
・・・とりあえず、ダメなようだ。

AppDataの下にログが入っているので確認すると、

Cannot configure port, some setting was wrong

などといわれている。
エラーは87番になっていて、検索すると

ERROR_INVALID_PARAMETER
87 (0x57)
The parameter is incorrect.

らしい。
Prolificのではダメなのかも。

何も考えず、BLE nano用のUSB-I/Fに挿してからexeを起動させると動いた。
考えすぎだ。。。


操作できるようなコンソール画面が出てきたものの、Advertisingしている機器の一覧が表示されない。

ログファイルを見てみると、Firmware versionは取得できているが、Invalid packetというエラーがたくさん出ている。
ここまでくると、もうよくわからんな。。。

 

ロジアナでUARTを計測した。
何か送信し続けているようなので、TXDを見てみる。

image3

これは10MHzサンプリングだから、まあ足りてないことはないだろう。
1bitが2.1usくらいだから、1/(2.1*10^-6)=476190.4762。
465kbpsくらいか?
460kbpsでよいかもしれん。

 

うちにあるBLE NanoのUSB I/F(MK20)がその速度に対応できないだけじゃなかろうか。
以前購入した、aitendoのUSB-UART変換モジュールをつなげた。
ああ、動くじゃないか。。。
CTS/RTSがないので、そこはGNDに落とさないといかんようだ。

 

image9

 

Wiresharkも、1.12.13をインストールし、スニファアプリが動いている状態で起動させ、Users Guide PDFのTroubeleshootingを読みながらpipe(\\.\pipe\wireshark_nordic_ble)を設定すれば、アタッチしてBLEパケットを読み取ることができた。
(うちはWireshark2も使いたいのだが、そっちをインストールするとスニファがレジストリを見てしまうせいか、2の方を起動しようとしてしまうのだ。)

あまり深く触っていないが、ここまで動けば他も動くんじゃなかろうか。

 

スニファのHEXファイルも、mbedっぽくD&Dして書込めば済んだような気がする。
USB-I/Fが誤算だったが、今は新しいタイプになっているようなので、もしかしたらそっちだと普通にいけるのかもしれない。

2017/05/14

[win10]MS17-010 の適用

なんだか世間では、ランサムウェアのWannaCryptなるものが流行っているらしい。
あらやだわ、ということで、うちのWindows10(Creators Update後)がちゃんと対策されているかどうか確認したい。

 

ランサムウェア WannaCrypt 攻撃に関するお客様ガイダンス

  • MS17-010をインストール
  • マルウェア対策製品を最新にしておく
  • SMBv1を無効にしておくと、さらに安心かも

 

対策製品を最新にしておくのは、このPCはWindows Defenderしか使っていないので、Windows Updateしておけばよいだろう。

SMBv1はここで無効にできる。

image

が、さて、これを無効にしても大丈夫だったっけ?
Sambaで使われていなければ大丈夫な気がするが、はてさて。

ファイル共有で利用されている SMB のバージョンを確認する方法 | Hebikuzure's Tech Memo
DEPENDENCIESは「MRxSmb20」になっていたから、SMBv2を使っているのか?
でも、このSMB 1.0のサポートにはチェックが入っているのだが。。。

とりあえずチェックを外して、アクセスできなかったら戻そう。
再起動がいるようなので、後で確認する。


そして、対策であるMS17-010だ。

マイクロソフト セキュリティ情報 MS17-010

緊急なのは分かるのだが、Windows10だけでこんだけ書いてあるのだ。

image

どれだよ!
まあ、半分は32bit/64bitの違いなので、3つしかないとはいえ、どれが自分用なのかわからん。

Versionは、Windowsのバージョンだろうとは思うが、今使っているPCはこうなっている。

image

そう、該当するバージョンがないのだ。。。
だから、既に対応されていると考えることもできるし、この記事が2017年3月15日だから、まだこのバージョンは正式になっていなかったと考えることもできてしまう(うちがv.1703にしたのは2017/4/18のようだ)。

とりあえず、一番上のバージョン無しを試してみたが、これはインストールできなかった。
バージョンはこういう関係のようだ。

  • バージョン無し: 2015年7月にリリースされた初期バージョン
  • 1511: 2015年11月
  • 1607: Anniversary Update
  • 1703: Creators Update


PSA: Massive ransomware campaign (WCry) is currently being conducted. SMB v1 (MS17-010) is the primary attack surface. All desktop and server versions of Windows from Vista to 10 are affected. Make sure your machines are patched to avoid infection. : pcma
こちらでは、1703ではKB4016871で対応されている、と書かれている。
うん、そのKBならうちのPCもインストールされている。

 

2017年 5月マイクロソフトセキュリティ更新プログラムに関する注意喚起(JPCERT)
ここで「リモートからの攻撃によって任意のコードが実行される恐れがあります」と書いてあるので、2017年5月のアップデートが入っていれば大丈夫なのかな。

 
大丈夫かどうかって、実際に攻撃を受けるまでわからないから怖いのだな。。。
 

2017/05/13

[ble]BLE NanoとJ-Link LITEをつなぐ

過去の私もやっているが、やはりBLE NanoとJ-Link LITEをつなぎたい。

hiro99ma blog: [ble]BLE nanoを使う

1.27mmのところをどうするかだけが問題なのだが、前回もかなり無理やりつなげている。
そろそろ、何か治具を作った方が良いんじゃなかろうか。

 

1.27mm--2.54mm変換基板が余っているので、ぜいたくに使うことにした。

image

 

内側はこうなっている。
4本が上の方に集まっていてよかった。

image

 

BLE Nanoに挿す方は、前回と同じだ。

image

 

簡素な作りだが、動けばよかろうなのだ。

2017/05/12

[ble]BLE NanoとUSB-IFでKeilにつなぐ

過去の私は、BLE Nano(ノーマル)に、USB-I/FだけでKeilを使ったデバッグができていたらしい。
hiro99ma blog: [ble]BLE nanoを使う

が、疲れていたのか、酒飲みながらだったのか知らないが、どうやってつなげていたのか書いていない。
私のばか。。。


まず、USB-I/FをDAPLINKにしなくてはならないだろう。
これは、上記リンク先だったり、数日前の記事だったり、その辺を読んでUSB-I/Fのファームウェアを書き換えればよいだろう。

 

USB-I/Fをつないでない状態で、nRF5 SDKのKeilプロジェクトサンプルを立ち上げる。
ちょっと古いが、nRF5 SDK v11.0.0を使うことにする。
PCA10028用プロジェクトを開き、デバッグ設定を"CMSIS-DAP"にして見てみる。
   examples\ble_peripheral\ble_app_hrs\pca10028\s130\arm5_no_packs

image

まあ、未接続だからな。
では、つないで、開き直してみよう。

image

あ、見えてる。
では、とKeilツールバーにある「d」っぽいアイコンをクリック。
・・・失敗した。

Build Outputに「No Algorithm found」と出ているので、先ほどのDebug設定の反対側のタブを開いてみた。

image

ああ、ないね。
nRF51xxxがそれっぽいので、Addした。

image

これで「d」をクリックすると、デバッガが起動してmainで止まってくれた。


そういうわけで、前回は特に書くことがなかったので、書かなかっただけと思われる。

[clang]uint64_tのprintf

最近、64bit型を使うことが増えてきた。
その場合は、uint64_tにしている。

デバッグで値を標準出力に出したい場合、printf()を使っている。
そのとき、"%d"なんか使うと、warningが出てしまう。

今使っている環境では、

printf("%llu\n", (unsigned long long)value);

などとしている。

 

これでも困りはしないのだが、キャストが長すぎる。
確か、uintXX_t系の書式が定義されていたはずだ。。。


困ったときは、オライリーのCクイックリファレンスだ。
さすがにここは、古い本には載っていない。

目次で見つけたのは、「第18章 標準ライブラリ関数」のprintfだ。
持っている本では、p.520の表18-9に載っていた。stdint.hで定義されているらしい。
ふむふむ、uint64_tで16進数だったら「PRIx64」でよいようだ。

#include <stdio.h>
#include <stdint.h>


int main(int argc, char *argv[])
{
    uint64_t val = 0x123456789abcdef0ULL;

    printf("val = %" PRIx64 "\n", val);
    return 0;
}

しかし・・・コンパイルエラーが出る。。。

 

なぜだ。。。
他のページを見直すと、「16.3 標準ヘッダの内容」にも同じような内容が書かれていた。
しかし、p.287を見ると「<inttypes.h>」となっている。

#include <stdio.h> #include <inttypes.h> int main(int argc, char *argv[]) { uint64_t val = 0x123456789abcdef0ULL; printf("val = %" PRIx64 "\n", val); return 0; }

コンパイルが通るではないか!

というわけで、p.520の表18-9は、stdint.hにあるのは整数型の型だけで、変換して石マクロはinttypes.hにあるのを覚えておきましょう。


ちなみに、今回使った「PRIx64」がどういうマクロなのか、printf("%s\n", PRIx64)で見てみました。

lx

えー、そうなの。。。

ちなみに、

PRIu64 : "lu"
PRIi64 : "li"

でした(Bash on Windows)。

2017/05/08

BLE-Nano+USBでHEXファイルが焼けない (2)

昨日の続きだ。
久しぶりにBLE-Nanoを出してみたが、HEXファイルがうまく焼けなかったので、なんとかしたい。

 

まず、MK20の方から。
うちにあるのは、こちら。

image

こちらの写真と見比べると、MK20 USB V1.0だということがわかる。
そのファームウェアは、こちら。
BLENano/USB-IF/MK20-USB/board_v1.0 at master · RedBearLab/BLENano

これをダウンロードして、MK20はRSTボタンを押したままUSBポートに挿し、Windowsが認識するのを待つ。
そうすると「BOOTLOADER」というラベル名のドライブとして見えるので、ダウンロードしたファイルをD&Dで書込む。
LEDが高速点滅したら終わりらしいので、USBポートから外す。

 

もう一度USBポートに挿すと、「DAPLINK」というラベル名のドライブとして見えた。
では、何か焼いてみよう。

RedBearLab BLE Nano | mbed
ここに、LED点滅のHEXがあるから、それをドライブにD&Dしてみる。。。

image

あれ、点滅しない??
何か間違っているのか・・・。

あ、LEDはこっちじゃなくて、BLE-Nanoにも載ってるんだ。

image

こちらは無事に点滅していた。

 

・・・もしかしたら、昨日焼けないと思っていたのは、単に見ているLEDが違っていただけかも、と思ったが、いやいや、HEXファイルをドライブにD&DしたらUSBから取り外された動作をしていたので、それ以前の問題だったのだ。

 

そんなわけで、Windows10でうまくいかなかった人は、firmwareを書き換えてみるとよいかもしれん。

BLE-Nano+USBでHEXファイルが焼けない (1)

机の片付けをしていると、TIのBLEドングルが見つかった。
懐かしいのでノートPC(Windows10)に挿してみたところ、ドライバが認識されなかった。。。
デスクトップPCのWindows10は認識した。

ノートPCは何も設定していなかったので、おそらく今回が初回の接続だったはずで、Creators Update。
デスクトップPCは以前から使用できていて、Anniversary Updateだ。

どの違いが影響しているか分からないので、これはデスクトップPCにCreators Updateがインストールされたときに確認しよう。


ついでに、近くにあったBLE-Nanoも使ってみることにした。
mbedにできるMK20-USBもあるので、挿してHEXファイルをドライブに置いてみた。

しかし・・・焼けない。
途中でUSBを抜いたような音がして、また接続される。
これは、デスクトップPCもノートPCも同じ動作だった。
少なくとも、以前はデスクトップPCでは使えていた形跡があるのだが。。。

DAPLink firmwareなら'DAPLink'、CMSIS-DAP firmwareなら'MBED'というラベル名になるらしい。
そして、うちではMBEDという名前だったから、CMSIS-DAP firmwareが焼かれていたのだろう。

 

RedBearLab BLE Nano | mbed
こっちでは、firmwareとして20140912という日付だから、githubにある方が新しいな。

実は、なんとなくMK20のボタンを押したままUSBに挿してしまい、何か焼くモードになったので、mbedのサイトにある方を焼いてしまったのだ。

 

次回は、githubにある方を焼いてから試すとしよう。
今日やってしまえばよいのだが、もう眠たいのだ。。。

2017/05/07

[bc]segwitのTXID

連休にもかかわらず、書けるような記事が何もない。。。
これではまずいので、困ったときのBitcoinネタを出そう。

 

ビットコイン分裂騒動は「レイヤー2」への反動か | TechCrunch Japan

SegWitを前提としないLightning Network実装は理論的には可能だが、開発者にとって「やりたくない仕事」なのだそうだ

あははは、うまい表現だ。
最初に「segwitなしでLN(LightNing)」という話を聞いたときは、おお!そんなことが!、と思ったけど、どうやって実現するのかを読んでいく途中で「あー、私にはむりー」となってしまった。
(2017/05/10:Lightning Network、の方がふさわしいな。)

 

基本的に、Bitcoinのやりとりは、誰も信用しない、というところを重視していると思っている。
trustless、というやつだ。
現金をBitcoinに替えたりする場合は知らんが、Bitcoinの中だけでもそうなるように苦慮している。
ときどき「そこまでするの??」というような内容もあるのだけど、理論的にツッコミできないので、そういうものかとあきらめている。

雰囲気としては、Bitcoinは秘密鍵とデジタル署名で成り立っている。
もちろん、ブロックチェーンというだけに、ブロックのもつ役割は大きいのだけど、ブロックは何からできているかというとBitcoinの価値を移動させるトランザクションで、トランザクションは秘密鍵でデジタル署名することになっているのだ。

 

トランザクションは、それぞれを識別するIDが付いている。
これが「トランザクションID」(TXID)というやつだ。
どこか中央のサーバがあれば、そこが一意になる値を付ければよいのだが、Bitcoinでは中央がいないので、一意になるような値をがんばって付けなくてはならない。
連番にしてしまうと、ネットワークの転送時間などもあって、同時に同じ番号を付けられてしまうこともあるだろう。
だからだと思うが、トランザクションIDはトランザクションの中身を使って算出するようになっている。
ハッシュ値、というやつですな。

 

そのトランザクションIDの計算をする方法が、非segwitとsegwitで異なる。
非segwitの場合は、トランザクションの中身だけで計算できた・・・と思う。
しかしsegwitの場合、従来の計算方法を使ったIDの算出方法と、新しい計算でのID算出方法がある。
そして、非segwitのトランザクションIDと同じ位置にいるのは、新しい計算でのIDの方である。

 

新しい計算方法の特徴は、

  • そのトランザクションのINPUTがいくらのBitcoin量(amount)だったかを計算に含める
  • そのトランザクションのデジタル署名は計算に含めない

だと思う。
前者は、確かトランザクション展性という脆弱性に対応するため(だったと思う)。
最初の記事に出てくる「レイヤー2」にとっては、後者の方が欲しい。

2017/05/10追記
この計算方法は、署名についてだった。。。
TXIDについてはトランザクションの中身だけで計算できるが、計算に含める部位と演算方法が違う。
その部位に署名(witness)が入らないため、TXIDは署名をする前に計算できる。

なお、WTXIDというものもあり、これは従来と同じ計算方法のため、署名もひっくるめてハッシュ計算している。

記事を読んでいると「チャネル」という言葉がしばしば出てくると思う。
これは「私とあなただけがやりとりする口座」みたいな意味だ。
テレビやラジオのチャンネルよりも、Amazonなどのログインアカウントみたいな意味合いの方が強いかな。

Bitcoinで口座に相当するものといえばBitcoinアドレスになるが、ここは「私とあなた」なので、2-of-2のmultisigアカウントを作ることになる。
Bitcoinのアカウントを作るだけなら何とでもできるが、それをBlockchain上に見えるようにするには、既にあるトランザクションからそのアカウントに送金してもらうことになる。
だから、レイヤー2のアカウントを作る=そこに入金する、ということになる。

が、2-of-2のmultisigに入金するということは、2人ともデジタル署名をしないとお金を取り出せないということでもある。
もし相手が偽物だったり、入金した後に逃げられて取り戻せなくなったりするのでは・・・・という心配が残る。
これが、「trustless」が重視される理由だ。
相手が悪いことをしても、少なくとも自分は損をしない、下手をしたら悪いことをした人が損をする、というくらいのことを、計算上で実現させるようにしている。
計算上というか、Bitcoinの支払いスクリプトで、そうなるようにがんばっているのだ。

相手から署名してもらわなくてもTXIDが計算できるということは、multisigへ入金したとして、そこから自分に取り戻すトランザクションを署名無しで作ることができるという意味でもある。
そこまで保険を掛けておけば、取り戻すトランザクションが手元にあるので、相手が逃げるかどうかはわからないけどチャネルを開いても少なくとも損はしない、という安心感が得られる。

 

こういう、異常系というか純正常系というか、そういう部分がレイヤー2の大半を占めるので、けっこう大変なのだよ。。。

2017/05/02

[golang]値を複数返す関数があるが、片方しかいらない

久々にgoで書かれたソースを見ている。
相変わらずわからんが、動かすことはできるので、fmt.Printf()を埋め込んで動きを見ている。

 

A1という関数を使っている箇所があり、それと似たA2という関数を使った場合の違いを見ようとした。
そのA2という関数は、値を2つ返すようになっているのだが、私は1つしか使わない。
まあよかろう、と適当な変数に代入させたのだが、エラーになってしまった。
どうも、未使用の変数があるとエラー扱いになるようなのだ。

じゃあもう片方も無理やり使ってやればよいのだろうが、使い道が思いつかない。。。
試しに、いる戻り値しか取得しないようにしたがエラーになるし、コンマだけで数をごまかそうとしてもエラーになった。
うーん。。。

 

未使用の変数/インポートに対するエラーを抑止できますか?
変数として「_」を使えばよいということか?
試しにやってみると、エラーが消えた。
Pythonもそういえば、「_」を使って回避できたような気がする(deleteで消した方がよいかもしれんが)。

2017/05/01

「ChaCha20 and Poly1305」は「ChaCha20-Poly1305」でよい気がしてきた

数学が専門ではないと逃げようとしたが、理論的な導出はわからないだろうし、導かれた結果が正しいかどうかは分からないかもしれないが、結果を利用するのは常套手段でなくてはならない。

前回、ChaCah20が出てくるRFCで、私が知りたかったのは「RFC-7539」、TLS/SSLに出てくるRFCは「RFC-7905」で、数字が違うのだから、きっと中身も違うはずだ、と何も考えずに結論してしまった。

 

しかし、そうなのだろうか?
RFCの番号が違うとか、RFC-7539の中に「7905」という数字が出てこないとか、そんな見た目だけのことで思考を止めてはいけないのではなかろうか、と考え始めた。

内容は分からないにしても、思考停止するのはよくないだろう。
せめて、自分なりに調べてみて、わからなければあきらめる、くらいのことをしてもよいはずだ。


RFC 7905 - ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)

一番簡単なところから始める。
さっきは、RFC-7539の中に「7905がない」というだけで済ませてしまったが、その逆を考えてなかったのだ。

果たして、RFC-7905の中には、RFC-7539への参照が書かれていた。
無関係ではないのだ。
しかも、文中で4回も参照されている。

RFC-7905を眺めたが、ここにはアルゴリズムのことは書かれておらず、TLSの暗号suiteとしてのChaCha20 and Poly1305のことが書かれているだけのようだ。
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256など、どの組み合わせを使うかということだけが書かれているのか。

では、方向性は間違ってなかったのかも。


AEAD_CHACHA20_POLY1305の要求がどうのこうの書かれているが、そういうのはここを読んでいくのがよさそうだ。

新しいTLSの暗号方式ChaCha20-Poly1305 - ぼちぼち日記

上の方しか読んでなかったけど、ちゃんとChaCha20の説明とPoly1305の説明が出ているじゃないか。。。

ChaCha20-Poly1305は「認証付き暗号」という種類で、認証付き暗号はAEADという略称らしい。
Poly1305は16byteのMAC値を生成するようで、計算したときも16byte増えていたから、暗号化した結果にMACを付けることを認証付き暗号と呼ぶのだろうか。

 

アルゴリズムは分かっていないが、なんとなく雰囲気は分かった気がするので、ChaCha20関連はこれで終わりにしよう。

2017/04/30

「ChaCha20 and Poly1305」は「ChaCha20-Poly1305」ではないだろう

ChaCha20を調べ始めたとき、私はリンク先を載せていた。
それは、RFC-7539だ。

こちらを読んでいたのだが、出てきたのはRFC-7905だった。
新しいTLSの暗号方式ChaCha20-Poly1305 - ぼちぼち日記

RFC-7539 : ChaCha20 and Poly1305 for IETF Protocols
RFC-7905 : ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS)

えっ、別物???
私が調べないといけなかったのは「ChaCha20 and Poly1305」で、「ChaCh20-Poly1305」ではなかったということか。
最初に正しいリンク先を示しておきながら、どんどん違った方向にミスリードさせていくとは、なんたるトリックよ。。。

もちろん、ブログに書いているのは氷山の一角で、あれこれ調べたり悩んだりし続けていたのでした。


あまりにガックリしたので、今回はこれまで。

[clang]よくわからずchacha20する

「よくわからず」は、まだ甘い表現だ。
「まったくわからず」と言った方がよいのだが、取りあえずchacha20で何かしてみよう。

今回は、libsodumを使う。


[gist]libsodium1

よくわからないまま、chacha20という名前が入っていたAPIを使う。
。。。使おうとしたが、xchachaやchacha_ieftなどの種類があった。
結果も異なる。。。

ChaCha20-Poly1305のサンプルがあったので、少しだけ変更した。
MESSAGEに入れたデータは、encryptしてdecryptするとちゃんと復元される。

enc= 8eb13143515e31c709aabdb474a9f910a929b6389c4abaac90c62e5511bdb0ab1186

dec= 64(d) 69(i) 67(g) 69(i) 74(t) 61(a) 6c(l) 20( ) 74(t) 65(e) 6c(l) 65(e) 76(v) 69(i) 73(s) 69(i) 6f(o) 6e(n)

"digital television"が18文字で、encryptすると34byteだから、+16byte。
"test"は4文字で、encryptすると20byteなので、+16byte。
crypto_aead_chacha20poly1305_ABYTESが16byteだった。

 

いやあ、さっぱりわからんね。。。
ストリーム暗号だから、暗号にする単位ごとに16byteあればよいということだろうか。

2017/04/29

Poly1305

前回、Chacha20が使えるライブラリを調べた。
しかし、何か忘れている気がする・・・と思ったら、RFCではChacha20-Poly1305となっている。

Poly1305とはなんだろうか?


メッセージ認証符号とのこと。
Poly1305 - Wikipedia

メッセージ認証符号ってなんだ?と調べると、「メッセージを認証するための短い情報」ということだ。
メッセージ認証符号 - Wikipedia

MACは、FeliCaでも出てきたな。

INPUT1: 共通鍵
INPUT2: メッセージ
OUTPUT: MAC値

メッセージが変わると、MAC値も変わるので、書き換わってないことが確認できるということらしい。
デジタル署名と似たような感じがするが、あっちは秘密鍵で符号化して公開鍵で復号するタイプだった。
そして、秘密鍵で署名する場合は「秘密鍵を知っている=持ち主」という図式になっているので、署名を作った人はメッセージを符号化した人と同じと見なせるが、MACは共通鍵なのでそれができない(というのが、否認不可性をもたない、ということだろう)。

じゃあ、デジタル署名の方が優れているじゃないか、ということになってしまうが、MACの方が処理が軽いのかな?
デジタル署名ほどの機能は求めていないシーンもあるだろうから、そういう場合によいのかも。
この辺は、とても疎いので逃げておこう。。。

 

Poly1305の「1305」は、2130-5が素数だからら・・・って、いきなり素数のこと出てきてもわからん。

poly1305.dvi - poly1305-20050329.pdf

The Poly1305-AES formula is a straightforward polynomial evaluation modulo 2130-5;

うーん、moduloに関係していることは分かるのだが、まあ専門家じゃないので、ここも見なかったことにしておこう。

 

WikipediaのPoly1305には、オリジナルは「Poly1305-AES」と書かれている。
TLSでは、AESではなくChaCha20を使うと書かれているが、こっちは「ChaCha20-Poly1305」と順番が逆だ。
AESはブロック暗号で、ChaCha20はストリーム暗号だから、それを取り替えただけだろうと思うのだが、計算順序が違ったりするのだろうか?

 

まあいい。
既に自分で実装する気がないので、ライブラリさえあればよいのだ。
ともかく、ChaCha20だけではダメで、Poly1305も一緒にやらないとダメということはわかった。

前回調べた、ライブラリになっていないソースは、ChaCha20だけだ。。。というか、この人、ChaCha20自体の考案者やん!
Salsa20ときて、ChaCha20ときているから、ダンスの名称(だっけ)からとった名前のようだ。
そのうち、ジルバなんかも出てくるのだろうか。

ごにょごにょ調べていたが、ここを読んだ方がわかりやすいと思う。
新しいTLSの暗号方式ChaCha20-Poly1305 - ぼちぼち日記


libsodiumやwolfSSLはChaCha20-Poly1305と書いてあるから大丈夫だろう。
mbedTLSが対応するまで、それでしのぐしかないが、configureで移植できない環境に持っていくのは大変そうだ。

2017/04/28

ChaCha20が入っているライブラリ

お仕事で、ChaCha20というものが出てきた。
茶々?

リンクはここになっていた。
RFC 7539 - ChaCha20 and Poly1305 for IETF Protocols

stream cipherと書いてあるので、連続するデータをどんどん暗号化できるというものなのだろうか?

ストリーム暗号 - Wikipedia

ああ、AESなどはデータの塊を暗号化するからブロック暗号で、そういう制限がないのがストリーム暗号なのか。

 

残念ながら私は専門家じゃないので、難しいことは分からない。
知りたいのは、自分で実装できるようなものなのか、ライブラリを使った方がよさそうかということなのだが、こういう暗号関係は自分で実装しない方がよいだろう。
間違うと、ひどい目にあうし。

というわけで、ライブラリを探したい。


まず出てきたのが、libsodium。
ChaCha20-Poly1305 · libsodium

wolfSSLにもあった。
wolfSSL - Docs | wolfCrypt Manual - Chapter 18.7 (ChaCha20-Poly1305)

 

では、私がよく使っているmbedTLSにも・・・無かった。。。
Will ChaCha20 and Poly1305 be supported in mbedtls? · Issue #346 · ARMmbed/mbedtls

実装が進んでいる気配はあるが、もう1年前か。
Implement Chacha20 and Poly1305 by damaki · Pull Request #485 · ARMmbed/mbedtls

 

Cortex-Mくらいしか使わないから、小さいのがいいんだけどなぁ、と思ったら、こういうのがあった。
joostrijneveld/chacha-arm-cortex-m: Optimized assembly implementation of ChaCha8/12/20 permutation for ARM Cortex-M3 and Cortex-M4

Cortex-M3とかM4に最適化してあるらしい。
ほうほう、と中身を探したが、chacha20.hはあるが、本体がなさそうだ。
chacha20_perm_asm()をexternしているので、これが本体なのだとは思うが、Googleで検索しても出てこん。
本体は、libopencm3というARM cortex-M用のオープンソースライブラリなのかと思ったけど、うまく探せない。。。

 

ライブラリになっていると、各プラットフォームに移植するときに面倒だったりするから、数ファイルだけでできていて組み込めるのがよいのだけどなぁ。
Chachaだけだったらここにリファレンス実装があった。
The ChaCha family of stream ciphers

ref, regs, mergedって、なんの違いなんだ。。。
使い方がわからんので、同じソースを使っているこちらを読んでみるか。
circulosmeos/triops: triops: a multiplatform command-line encryption tool using CHACHA + KECCAK

2017/04/25

[et]EthereumはJavaScriptがわからないとつらかった

仕事ではほとんどBitcoinしか見ていないのだが、それじゃあんまりだということでEthereumも少し見てみることになった。

環境の作り方はいくつかあると思うが、私がやったのは、

という組み合わせだった。
これも自分で作ったわけではなく、作ってもらったのを使っただけだ。

geth(たぶん、go言語で書かれたethereumエンジンという意味だろう)を動かし、それにJavaScriptのAPIでアクセスするというやり方だ。

 

ethereumは、私から見ると、JavaScriptっぽい言語で動く仮想マシンだ。
EVM、EVMとよく出てくるけど、仮想マシンがEVMね。
JavaScriptのAPIでアクセスするから「JavaScriptっぽい言語」というわけではない。
Solidityという言語でプログラムを書いて、それをブロックチェーンに載せると、燃料(gas)を与えればプログラムが動く、というイメージだ。

JavaScriptからはAPIを経由してSolidityで書いた関数を呼び出す。
関数ではブロックチェーンに書込んだり読込んだりができる。
なんとなく、DBアクセスしている気分だ。

ただ、DBじゃないので、書込んだ値は「自分のノードでそう思っている」というだけで、マイニングされてブロックに組み込まれないと値が確定しない(のだと思う)。
この辺りは、しくみがよくわからんかった。
ライトキャッシュみたいに、自分が書込んだ値を読込めば本体にアクセスせずに読み込めるけど、書込んでない人は本体を読みに行くので、キャッシュが吐き出されるまでは値が変わらない、みたいなことじゃないかなぁ。

 

ドキュメントの更新はそんなに頻繁ではないようで、APIを使ってみたらもう搭載されていなかった、ということがときどきあった。

私が触っていた頃は、ちょうどtestenetのRopstenが攻撃を受けたところで、Parityという別実装のエンジンだと対処法があったのだけど、Gethではどうしようもなさそうだったので、プライベートチェーンを作って試して終わった。


とにかくつらかったのが、Solidityとかじゃなくて、JavaScriptそのもの。
使い慣れていない上に、スクリプト言語自体に不慣れなので、毎日荒れていた(私が)。

また、便利なはずのmeteorも、私にとっては「JavaScriptがよくわからないのに、さらによくわからないものが載っている」ということになり、いろいろつらかった。

つまり、そういう言語に使い慣れている人であれば、敷居はそんなに高くないのかもしれない。
JavaScriptが書ける人であれば、ブロックチェーンのところはSolidityを使える少数の人にやってもらって、周りのアクセスするところは普通のJavaScriptが書ける人で対応できる。

ネットニュースでブロックチェーンを使った実験とかあるけど、多少複雑なことをブロックチェーンだけで完結させたいと思ったら、何かしらブロックチェーンでプログラムが動いてくれる方が便利で、そうなるとEthereumか、という選択になるのだろう。
技術者を集めやすいし、JavaScriptで書ける人はブラウザを使ったサービスなんかをよく作りそうな気がするので、画面の見栄えもよさそうだ。

 

Ethereumはホワイトペーパーとイエローペーパーというものがある。
ホワイトペーパーは日本語訳もあるので、ちょっと読みづらいけど中身としては興味深かった。
Bitcoinを分析しているところなんかも面白い。
[Japanese] White Paper · ethereum/wiki Wiki

イエローペーパーは、いやあ、さっぱりわからなかった。。
http://yellowpaper.io/

このくらいできないと、ブロックチェーン技術者になれないのだろうか・・・。

Windows10 Creators Updateの様子

うちで動いているPCのうち、1台だけCreators Updateになった。

今のところ、特に困ったことはない。
IMEがATOKを使っていたのに切り替えられていたり、高速スタートアップが有効に戻されていたり、システムフォントが元に戻っていたりと、いくつか元に戻されていた。

得に便利になったというものはないのだが、Bash on Ubuntu on Windowsの動作がいろいろLinuxのUbuntuに近くなったので、それが一番ありがたい。
今のところ、valgrindも動いている。

 

さっき気付いたが「ディスプレイ」の設定に「夜間モード」というものがあった。
ブルーライト軽減というやつかな。
眠たくなりそうな色なので、ちょうどよいかも。

では、おやすみなさい。。。

2017/04/17

Windows10の更新(2017年春)

2017/04/17 23時半

風呂から上がってくると、画面が薄暗くなっていて、中央にこんなダイアログが出ていた。。。

image

「設定の確認」をクリックすると、プライバシー設定の項目が5つくらい表示されて、ON/OFFできるようになっていた。
とりあえず、全部OFFにして承諾すると、バックグラウンドで何かするようなことをごにょごにょ言って、また元の画面に戻った。

 

Windows Updateの画面を見ても、タスクトレイを見ても、何かしているようには見えない。
タスクマネージャーを起動しても、何かダウンロードしている感じでもない。

うーん、なんだったのだろうか?


2017/04/18 8時半

Windows Update画面の更新ボタンを押すと、ダウンロードが始まったようだ。。。

image

日曜日にバックアップを取っているので、このまま進めてみよう。
今回のPCは、Windows標準のバックアップを使っているので、何が保存されているのかわかりづらいのだがね。

 

ダウンロードが終わると、自動的にインストール準備が始まった。
なお、これはWindows10 64bit Homeなので、Updateについては制御できないと思う。

image

 

放置して作業していると、ばーん、とダイアログが出てきた。

image

覚悟は・・・できている・・・。


30分くらい放置していると、いつの間にかアップデートが終わっていた。

 

違いはよくわからんが、アクティブ時間が18時間まで設定できるようになった。

image

 

フォントが、また細いのに戻されたから、元に戻したり。
Defenderを使っているのだが、サンプルの送信を無効にしておくと警告マークが出てくるので気持ち悪い。。ここは我慢だ。

メニューに「更新プログラムとプライバシーの設定」というのが追加されているのだけど、選択してもブラウザが開いてページに飛ぶだけだった。

 

あとは、Bash on Ubuntu on Windowsのアップデートくらいか。
valgrindやgolangがちゃんと動くようになっているとよいのだが。

Bash on Ubuntu on Windowsの、Creators Updateでの強化点&新機能【Insiders Preview版】 - Build Insider
BoWの再インストールがいるらしいが、ホームディレクトリにあるデータも消えるとは。。。
ESP8266のRTOSビルド環境や、RaspberryPiのkernelビルド環境を作っていたのだが、もう一度構築し治した方がよいだろうな。

uninstallコマンドを打つと、消えるけどよい?と確認してくれるのは親切だ。
アンインストールは、案外早く終わる。

インストールも同じようなものかと思ったが、ダウンロード後にプロンプトが出てきた。

image

えーっと、これで"y"入力するとja-JPに変更されるのか?
それとも続行して、ja-JPに変更するか聞かれるのだろうか。
あるいは、ja-JPに変更しつつ続行か。。。
じゃあ、"n"にしたらどうなるのか。。。

最初からやり直せばいいや、と"n"にすると、アカウント作成に進んだ。
アカウント作成すると、終わりだ。
Bash on Windowsのプロンプトを起動して、確認。

$ echo $LANG
en_US.UTF-8

lsすると、Esp8266などのフォルダはそのまま残っていた。
.viminfoは残っているので、最初からあったと思われる.bashrcが消えただけか。

valgrindをインストールしようとしたが怒られるので、apt update/upgradeしておく。
makeもgccもg++もないので、あれこれインストール。。。
いつも何も考えずに足りないものをインストールしているけど、build-essentialだけやっておけばよいのかも。

googletestのビルドに失敗するので、libgtest-devとgoogle-mockもinstall。
・・・だめだ。
c++11 - Converting std::__cxx11::string to std::string - Stack Overflow
ああ、gccのバージョンが変わったということか?
Makefileに-D_GLIBCXX_USE_CXX11_ABI=0を追加して、ビルドできた。

valgrindは、動いているような気がする。
これは様子見だ。
そういえば、以前はvalgrindも自分で何とかしないと行けなかったような気がするが、apt installしたもので動きそうな気配だ。


2017/04/19

前回は、_GLIBCXX_USE_CXX11_ABI=0を追加してビルドできたのだが、今日はダメだ。。。
Ubuntu16.04でもダメだった。
=1にするとビルドできたので、make cleanが中途半端な状態になっていたのかもしれない。

 

valgrindは動いているようなのだけど、私が使っているライブラリではcalloc()を内部で使っているらしく、calloc()があるとvalgrindが誤検知するというか、解放タイミングが違うために解放漏れとして検知してしまうようなのだ。

-fsanitize=leakでやるのがいいんじゃないの?というStackoverflowがあったので試したのだが、BoWではビルドできるものの実行すると固まってしまった(valgrindは使ってない)。
Ctrl+Cでもタスクマネージャーでもすぐには効いてくれず、かなり時間がかかってから停止した。
むう。。。

組み込み環境だとメモリリークのチェックは大変だから、できるだけこういう環境でチェックしておきたいのだがなあ。

プロトコル実装するライブラリを探したが、用途に合うものが無かった

2点間で通信しようとすると、まず通信仕様を決めなくてはならない。
プロトコルというやつだ。

物理的な通信仕様が決まったら、次は論理的な通信仕様を決めて、どこかの段階でデータの仕様も決めることになるだろう。
あるいは、データ仕様はRFCだったり既存の機種だったりで決められているものかもしれない。

 

さあ、ではこれを実装しよう、となったとき、内部で持っているデータ構造をプロトコルに合わせなくてはならない。
これが面倒で、比較的機械的な作業なのだけど、やらないといかん。

ただ、そういうものであれば、誰かユーティリティを作っていないだろうか?


まず思いついたのは、protobufだ。
名前はあちこちで見かけるので、使えそうな気がする。
しかしWikipediaを見ると「XMLとの比較で~」などと書かれているので、protobufフォーマットのプロトコルで通信したり、ファイルに保存したりするのであればよさそうだけど、決められたデータ形式に合わせた入出力にする、というものではないのだと思う。
Protocol Buffers - Wikipedia

 

他にもシリアライザーという種類のライブラリはあったのだけど、やはり独自フォーマットになるようだ。
まあ、よく考えれば、「プロトコル」と一言で書いても、テキストやバイナリがあるし、バイナリだってType-Length-Valueもあれば、Length-Type-Valueもあるし、データに構造が載っておらず順番だけで決めてしまうものもあろう。

そういうものに対応したライブラリを作ろうとしたら、作りが複雑になって、使うのも複雑になって、結局誰にも使われない、ということになってしまいそうだ。
だから、そういうライブラリはないんじゃなかろうか、という結論に至った。


では、部品レベルでもよいから作っておきたい場合、どういうものがよいだろうか。

私の場合、だいたいバイナリで通信するから、まずはバイナリが前提となる。
TLVなり、LTVなりが固定されている方がありがたい。ソースファイルだけ取り替えれば構造が変わるのがよいだろう。

あとは、エンディアンとアラインメントか。
私が使う環境はリトルエンディアンが多いのだが、プロトコルはビッグエンディアンだったり、ものによってはビッグとリトルが入り交じっていることもある。
そして、プロトコルの方は無駄がないようにデータを詰めるけど、プログラム上ではメモリ境界に沿わないと使えない。

アラインメントは、gccだと#pragma packで詰めたりもするのだけど、いつも罪悪感というか、そういうものを感じてしまう。。。
気にせずアクセスできるCPUならよいけど、そうじゃなかったら裏でコードを書いて対応していたと思うので、全体的にサイズが大きくなってしまうこともありそうだ。

 

そんなことを考えていくと・・・部品化せずに全部実装することになるんじゃないのか?
プロトコルの内容によって、機械的に解釈する方が効率的だったり、個別に解釈する方が効率的だったりするのを考慮してしまうと、部品化できなくなってしまうのだ。

そうではなくて、メンテナンス性の良さとか、今後の使い回しとか、そういうのも含めて考えないと。。。
とは思うのだが、また今回も個別に実装するような気がしている。

2017/04/15

[c#]フォルダ選択ダイアログを、普通のファイル選択ダイアログ風にしたい

久々にC#だ。

Windows10を使っているのだが、フォルダ選択ダイアログとしてToolboxに入っているFolderBrowserDialogを使ったのだが、初期フォルダをツリーの下の方にあるようなフォルダにしておくと、表示させたときにそこまでスクロールしてくれないことがわかった。

何か設定すればよいのかと思ったが、そうではなくて、このしくみ自体が.NETの部品じゃなくていじるのが面倒な様子がStackoverflowに書かれていた。
うん、そこまでしてやりたくはない。

 

そういえば、私が使っているEmEditorというテキストエディタでは、フォルダ選択が普通のファイル選択風になっているのを思い出した。
それなら、スクロールなど考慮せずに済むはずだ。


ようやく出てきたのが、こちら。

ファイルは選ぶ事あるけど、フォルダを選ぶことは少ない。 | C#等と戯れる日々

NuGetでWindows7APICodePack-Shellというものをインストールし、Microsoft.WindowsAPICodePack.Dialogs.CommonOpenFileDialogをnewして、IsFolderPickerをtrueにすることで、期待するダイアログが表示できた。

image

ボタンが「フォルダーの選択」になっていて、ファイルが表示されないようになっていた。

 

ただ、初期フォルダを設定しなかった場合、どこが開かれるのかがよくわからん。
なんとなく、前回最後に開いたフォルダのような感じはする。
System.Windows.FormsのInitialDirectoryがそうだから、同じような動作になるのかな?
このCode PackでもInitialDirectoryプロパティは使えるようになっていたから、指定した方が無難かもしれん。

2017/04/13

[bc]アドレスを作るまでに得られた結果の使い方

前回、秘密鍵、公開鍵、公開鍵ハッシュ、Bitcoinアドレス(P2PKH)の求め方を説明した。
今回は、それぞれの使いどころを説明しよう。

 

まず覚えておいてほしいのは、こういう前提だ。

  • 公開鍵ハッシュからBitcoinアドレスを求めることができる
  • Bitcoinアドレスから公開鍵ハッシュを求めることができる
  • 公開鍵から公開鍵ハッシュを求めることができる
  • 公開鍵ハッシュから公開鍵を求めるのはほぼ不可能
  • 秘密鍵から公開鍵を求めることができる
  • 公開鍵から秘密鍵を求めるのはほぼ不可能

秘密鍵→公開鍵→公開鍵ハッシュ、の部分は一方向ハッシュという計算を使っている。
A→Bは計算できるし、毎回同じ計算結果が得られるが、B→Aは計算できない、というやつだ。

「ほぼ不可能」としたのは、力任せに一方向ハッシュの計算をし続ければ、いつかは期待する値を見つけることができるからだ。
たとえば秘密鍵は32byte=256bitなので、2256回試せば、そのどこかで出てくるはずだ。

image

1秒間に1億回計算できたら、何秒かかるだろうか?

image

うーん、生きてる間には無理そうだ。。。
まあ、0から計算を始める必要もないと思うが、割に合う作業ではないように思う。
ノイマン型のコンピュータだときついが、並列世界を作り出して正しい答を持つ世界だけを選択できるようなことができれば。。。


こういう難しい話は賢い人やずる賢い人が考えてくれていると思うので、今回は単純に「逆方向の計算はできない」ということにしておく。

 

まず、Bitcoinアドレス。
これは人間が見るためのものだ。
Bitcoinのブロックチェーンとしては使っていない。

 

次は公開鍵ハッシュ。
これは、「このアドレスに送金します」という出力で使われる。

image

左が送金元、右が送金先だ。
青い文字がBitcoinアドレスだが、右側の「scriptPubKey」のところに、OP_DUP、OP_HASH160に続いて16進数がずらずら並んでいるのが見えると思う。
これが、公開鍵ハッシュだ。

試しに「mwtvLXha2y5wiMt3XGFGx7EpTNG9pMdQLw」をBase58デコーダで戻してみよう。

image

「なってないやん!」と思うかもしれないが、落ち着いておくれ。
Bitcoinアドレスに変換する際、公開鍵ハッシュにプレフィクスとサフィックス(CRC)をつけているのだ。
頭1byteとお尻4byteを切り取って、

6FB3A987A2561CFFDFCFB0FE90AFD309576D7F88295FBF2A80

一致したでしょう?

 

秘密鍵はデジタル署名をするために、公開鍵はデジタル署名したのが誰かを示すために使われる。
Bitcoinの支払いは送金元と送金先を示すので、送金元の人が許可していないと送金できないようにしたい。
だから「私が送金を許可しました」という意味で、送金の記録(トランザクション)に送金元の人がデジタル署名を行うのだ。

デジタル署名の計算は、秘密鍵を使う。
秘密鍵を持つ人じゃないとBitcoinの支払いを行うことができないことになる。
ただ「これは私の秘密鍵で計算したデジタル署名ですよ~」と宣言しても信用できないので、チェックする方法が必要になる。
そのチェックに秘密鍵が必要になってしまうと意味が無い(秘密鍵を持っている人しか署名できないというルールが崩れる)。
そこで公開鍵があれば、トランザクションとデジタル署名のセットが正しいかどうかのチェックができるという計算式がある。

 

なので、秘密鍵だけは絶対にバラしてはいけないのだ。
そのBitcoinアドレスに入っているお金は、秘密鍵を知っている人なら誰でも送金できるようになるからだ。
カードの暗証番号みたいなものだと思えば良いか。

もう1つバラしてはいかんのが、ウォレットアプリのバックアップ。
これは秘密鍵よりもまずい。
Bitcoinアドレスの秘密鍵だけなら、そのアドレスに入っているお金だけが対象なのだが、ウォレットアプリのバックアップが漏れてしまうとウォレットに入っているすべてが対象になってしまうのだ。。。

だから、こういうのはクラウドに置いたりせず、できればPC内にも置かず、ネットや人目から切り離されたところに置いておきたいところ。
私は実験用にしかBitcoinを持っていないのであきらめられるくらいの額なのだけど、心配ならハードウェアウォレットを検討すべきだろう。

2017/04/11

[c/c++]gccではglobalでstructのinitializerにconst intは代入できない

タイトルを見てもなんだかわからないと思うので、ソースを載せる。

#include <stdio.h>

static const int A = 1;
static const char B[] = "abc";

static const struct {
    int a;
    const char *b;
} VAL[] = {
    { A, B }
};

int main(int argc, char *argv[])
{
    printf("a=%d, b=%s\n", VAL[0].a, VAL[0].b);

    return 0;
}

これをgccでコンパイルすると、エラーになる。

$ gcc -Wall -o tst test.c
test.c:10:7: error: initializer element is not constant
     { A, B }
       ^
test.c:10:7: note: (near initialization for 'VAL[0].a')

 

確かC++だと、const値は定数扱いだったような気がするので、g++にしてみる。

$ g++ -Wall -o tst test.c
$

うん、OKだ。

 

ただ、gccでもこれはOKだ。

#include <stdio.h>

static const int A = 1;
static const char B[] = "abc";

int main(int argc, char *argv[])
{
    const struct {
        int a;
        const char *b;
    } VAL[] = {
        { A, B }
    };

    printf("a=%d, b=%s\n", VAL[0].a, VAL[0].b);

    return 0;
}

staticを外して、関数の中に入れただけだ。
もしstaticを外さなかったら、やはりエラーになる。

やっぱりCだと、constはダメなのか。

 

これは、通るのだ。

#include <stdio.h>

//static const int A = 1;
#define A (1)
static const char B[] = "abc";

static const struct {
    int a;
    const char *b;
} VAL[] = {
    { A, B }
};

int main(int argc, char *argv[])
{
    printf("a=%d, b=%s\n", VAL[0].a, VAL[0].b);

    return 0;
}

整数の方だけをマクロにしたのだ。
なぜポインタの方はエラーにならないのだろうか?

 

#include <stdio.h>

//static const int A = 1;
#define A (1)
static const char B[] = "abc";
static const char *C = B;

static const struct {
    int a;
    const char *b;
} VAL[] = {
    { A, C }
};

int main(int argc, char *argv[])
{
    printf("a=%d, b=%s\n", VAL[0].a, VAL[0].b);

    return 0;
}

Bは、ポインタと言うよりは、そのアドレスからデータが始まっているからよいのか?
だったら、intだって似たようなものだと思うのだ。

納得がいく理由が導き出せないが、g++だと通るところからすると、値を解決するタイミングが違うとか、そういうことだろうか。。。

[mqtt]v3.1とv3.1.1

ESP8266でMQTTを動かすため、他のMQTT clientを動かしてwiresharkログを取っていたのだが、CONNECTのプロトコルが最初違っていた。
設定が「v3.1.1準拠」になっていたので、それをやめると期待する値になった。

 

私が期待していたのは、v3.1で見ていた値だ。
http://public.dhe.ibm.com/software/dw/webservices/ws-mqtt/mqtt-v3r1.html#connect

Protocol Nameが"MQIsdp"で、Protocol Version Numberが3だ。

 

しかし、v3.1.1準拠だと、こうだ。
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718030

Protocol Nameは"MQTT"で、Protocol Version Numberは"Protocol Level"という名称になり、4となっている。

 

そういえば、Ubuntu14で動かしたとき、v3.1設定にしないと動かなかったのだが、CONNECTが違っていたのか。
理由が分かってすっきりした。

しかし、v3.1の"MQIsdp"はどういう意味だったのだろうね?
sdpはService Discovery Protocolのような気がするが、MQIはわからん。

http://mqtt.org/faq
違った。
"MQ Integrator SCADA Device Protocol"の略だと。
知ったふりをしなくて良かった。。。

2017/04/09

[esp8266][rtos]MQTT publisher

MQTT v3.1の仕様を眺めたり、他のMQTT clientを動かしてwiresharkでログを取ったりしながら、ESP8266 RTOSでMQTT publishだけするアプリを作った。

https://github.com/hirokuma/Esp8266SimpleMqtt

 

仕様は、この辺を読んでいる。
https://www.ibm.com/developerworks/jp/websphere/library/wmq/mqtt31_spec/

ドキュメントとしては、あんまりわかりやすくないと思う。。。
が、日本語で書いてあるので、助かる。

 

これはプロトコルバージョン3なのだけど、wiresharkで見ていたクライアントは4のようで、校正が違っていた。
まあ、気にすまい。

2017/04/07

[bc][slack]botを作ってみる

朝起きると、hiro99maは一匹の巨大な毒虫に・・・なってはいなかったが、なぜかslackのbotを作ってみたくなっていた。

仕事の連絡手段としてslackを使っているのだが、左上に「Apps」という項目があることに気付いた。
どうやら、プラグインのようなものと連携して、挙動を追加できるらしい。

ほほう!

そういえば、botというやつで何かできた記憶がある、と思い出し「slack bot」で検索しようとしたら、候補に「python」が出てきた。
pythonなら多少は使えるので、せっかくだから何か作ってみよう。

何がよいか・・・。
ああ、最近、仕事に関係しないbitcoinネタを書いているので、それにしてみよう。


PythonでSlackbotを作る(1) – ビットログ

一番上に出てきたので、これを参照した。
さすが一番上だけあって、読んでできた。

第1回で、botを使えるようにするまでできた。
API Tokenの取得などだ。
なお、私はpython2を使った。
素直に書いてあるbotの実装も試しておこう。

第2回を読めば、だいたいやりたいことがわかる。
私の場合は、こちらからBitcoinのTXIDを伝えて、blockexplorer.com(リンク先はtestnet用)みたいなサイトから情報を取ってきて、テキストで吐き出そうと思ったので、このくらいでよいのだ。


作ったのは、こちら。
https://github.com/hirokuma/slackbot_bitcoin_txid

API Tokenは自分で埋めておくれ。
あと、testnet用にしているので、必要に応じて修正しよう。
難しいことはやってないので、pythonがわかる人なら変更もすぐできるんじゃなかろうか。

 

困ったのは、むしろtestnetの挙動だった。
なんか、ちょうど作っている最中、攻撃が行われていたようなのだ。
やーねー、もう。

2017/04/06

[bc]アドレスを作るまでの計算

前回は、Bitcoinのアドレス、と一言にいってもいろいろ種類がありますよ、ということを書いた。
そして、先頭の文字を見ると、だいたいどういう種類かや、お金に関わる方のBitcoinブロックチェーン(mainnet)なのか、お金が関わらない方のBitcoinブロックチェーン(testnet)なのかわかる、というところまで説明した。

 

わざわざ「Bitcoinのブロックチェーン」と書いているように、ブロックチェーンにもいろいろ種類がある。
というよりも、それぞれ別のブロックチェーンのネットワークを作っている。
例えば、mainnetとtestnetは、ブロックチェーンの構造としては同じだが、TCP/IPのポート番号が異なる。
Ethereumという、こちらも有名なブロックチェーンを使った仮想通貨があるが、これはこれで別のブロックチェーンだ。

「ブロックチェーン」という1つのものをみんなが使っているわけではなく、めいめいが自分が好きなようにブロックチェーンを作っているのである。


では、話を戻そう。

Bitcoinアドレスは、似たような文字列でできているように見えるが、そもそもどうやってアドレスを作っているのか、という話をしたい。

http://chimera.labs.oreilly.com/books/1234000001802/ch04.html
ここに全部書いてあるので、読むとわかる。

・・・ではあんまりなので、大雑把に説明しよう。
なお、私はtestnetでしかやってないので、説明もtestnetだ。

 

Pythonでの実装例がExample4-4に載っているので、それを見ていこう。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#_implementing_keys_and_addresses_in_python

まず、32byteの乱数を用意する。
16進数32個分だ。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#ec_math
Example4-6の、

byte_array = os.urandom(32)

がそれにあたる。
この値を「秘密鍵(private key)」と呼ぶ。

 

秘密鍵は単なる大きい値というだけで、この次に楕円曲線暗号というものが出てくる。
楕円、ではなく、楕円曲線、だ。
金魚鉢のような、オバQのO次郎を横向きにしたような、そんな形だ(Figure 4-2)。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#pubkey

楕円曲線にもいろいろ種類があるのだが、とにかくBitcoinで使用する楕円曲線上の点Gに、楕円曲線座標系での乗算を行うことで「公開鍵(public key)」が求められる(Figure 4-4)。
もちろん、点Gに掛けるのは秘密鍵だ。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#ecc_illustrated
この図では、G→-2G→+2G→-4G→+4G→-8G→+8G、という演算が行われている。
もし秘密鍵が「8」だったら、この8Gが公開鍵の座標になる。
なんで接線方向に移動したりX軸に直角に移動したりするの?と問われても、私にはわからん。。。

公開鍵は座標なので、(x, y)の形式になる。
ノーマル形式の公開鍵は、このxとyを連結した値になる。
秘密鍵が32byteだからか、xも32byte、yも32byteにするようで、連結すると64byteになる。
それだけだとなんだかわからないので、「0x04」を頭につけて「ノーマル形式の公開鍵」という表現の仕方をすることになっている。
だから、65byteだ。

ただ、楕円曲線を見るとわかるように、X軸に対して線対称だ。
では、X座標とそれに対応するY座標の正負情報だけで公開鍵を表して短くしよう、という説明がFigure 4-7だ。
http://chimera.labs.oreilly.com/books/1234000001802/ch04.html#pubkey_compression
x座標からy座標を求める演算はy2 mod p = (x3 + 7) mod pになるため、y2を解くと±の結果になるから、どっちなのよ、ということを示すために、ノーマル形式の「0x04」に対して「0x02」 or 「0x03」という値を頭につけて、33byte形式にしたのが「圧縮された公開鍵」と呼ばれるようになっている。
今では、「0x04」の公開鍵はデータが大きくなるのでほぼ使われていないと思う。

 

公開鍵に、SHA256というハッシュ計算をすると、32byteになる。
それにRIPEMD160というハッシュ計算をすると、20byteになる。
理由は知らんが、Bitcoinではハッシュ計算を2回連続して行うことが多い。
ともかく、公開鍵をSHA256→RIPEMD160、という計算で出てきた20byteの値を公開鍵ハッシュ(Public Key Hash)と呼ぶ。
通称、PubKeyHash。
略称、PKH。

 

PKHに、前回出てきたmainnet/testnetのプレフィクスをつけ、CRCをサフィックスにつけ、それをBase58Checkというエンコード方式で演算すると、Bitcoinアドレスが出てくる。
Base64という、メール添付するときのエンコード形式から、目で見て見分けにくい文字を減らして58文字にしたのがBase58らしい。
Base58はハッシュではなくエンコード/デコードなので、今回で言えばBitcoinアドレスから公開鍵ハッシュまで戻すことはできる。
http://lenschulwitz.com/base58

 

公開鍵を公開鍵ハッシュにした値からアドレスを求めるので、このアドレス方式はPublic to Public Key Hash→P2PKHと呼ばれる(のだったと思う)。

このようにして、秘密鍵、公開鍵、公開鍵ハッシュ、Bitcoinアドレス(P2PKH)が得られる。
お疲れ様でした。

[c/c++][make]dependの解決

以前、こんな記事を書いた。

hiro99ma blog: [c/c++]Makefileのdependは名前一致なのか

ソースファイルの依存関係をMakefileに反映させるためにgcc -MMを使ったが、./のように関連とディレクトリを含むような書き方にするとダメだった、という話だ。

 

そして、同じ問題にまた遭遇してしまったのだが、対処するのにかなり時間がかかってしまった。
悔しいので、それっぽいものをgithubに上げることにする。

https://github.com/hirokuma/makefile_hello

 

 

しかし、dependだけではなく、makefileは書くのが難しいな。
今回だって、難しいことがしたかったわけではなく、ディレクトリをsrc, include, objectsに分けただけだったのだ。
Eclipseでプロジェクトを作るとうまいことやってくれるが、あれは偉大なのだな。
まあ、あれはあれで、うまくいかなかったら解決に時間がかかるのだが。。。

2017/04/05

RFC 6979を使った結果がライブラリによって違った→私の間違いだった

2017/04/05更新:mbedTLSに問題がなかったので更新

突然のRFCだ。
ESP8266のこともやりたいのだけど、仕事の調査もあるのでね。。。
せっかくなので、書いても問題なさそうなところは使おう。


RFC 6979という、楕円曲線を使った署名についてのRFCがある。

RFC 6979 - Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)

私の把握では、

  • 楕円曲線暗号の署名の乱数って、面倒よね
  • そもそも、乱数が乱数かどうかなんてあやしいし
  • 別の署名で同じ乱数が使われたりすると、目も当てられないわ
  • じゃあ、いっそのこと、データによって乱数の値が変わるような計算式を作ってしまわない?
  • さんせいさんせい!!

というところだ。
RFC 6979に基づいた署名計算を行うと、乱数要素がなくなるので、毎回同じ署名結果が得られる。


それはよいのだが、この決定性署名(Deterministic Signature)を持つ暗号化ライブラリを使ったのだが、結果は乱数を使っていないので同じ結果になるものの、ライブラリによって得られる署名が異なることがあった。

やむなくRFC 6979を見てみたが、うん、全然わからん。。。
ただ、3.2章が「Generation of k」で、3.3章が「Alternate Description of the Generation of k」となっている。

Alternate Description ?
別の説明、ってなんだ?
3.2章で使った用語とは別の言葉(X9.62の用語か)で説明しているだけだとは思う。

たぶん、kは、ここの手順3の整数kだと思う。
「セキュリティ」のところにもそう書かれていた。
https://ja.wikipedia.org/wiki/%E6%A5%95%E5%86%86%E6%9B%B2%E7%B7%9ADSA#.E7.BD.B2.E5.90.8D.E7.94.9F.E6.88.90

 

一致しているライブラリは、先にnonceを求めてから署名を行っている。
nonceは、たぶんkのことだろう。乱数っぽいし。
困ったことに、一致していないライブラリは違う計算方法で、直接比較ができない。

mbedTLSなのだが、うーん、どうしたものか。。。
https://github.com/ARMmbed/mbedtls/blob/development/library/ecdsa.c#L72
nonceを作らず、f_rngでうまいことやるようなのだが、乱数っぽい値はtに入るようだし、kはkeypairとかから設定されているし、なんだかよくわからんのだ。


2017/04/05

この問題はけっこう大きいので、引き続き調査を行う。
まあ、違う実装を使えばよいと言えばよいのだけど、それでは負けた気がしてしまう。。。
mbedTLSは負けないのだ!

間違われないように書いておくが、署名が間違っているわけではないのだ。
verifyは成功する。
単に、署名が一致しないだけなのだが、それがあり得るのかどうかだけが気になっているのだ。

 

mbedTLSの実装でDeterministicっぽいことをしているのはここだと思う。
https://github.com/ARMmbed/mbedtls/blob/development/library/ecdsa.c#L178-L182

よくわかってないが、HMAC_DRBGという言葉が出てくるので、RFC6979の3.3章のような実装なのだろうか。
この辺で設定したrng_ctxを使ってECDSAの署名に使う乱数を作っているのだろうと思う。
呼び出すのは、mbedtls_hmac_drbg_random()
これを使っているのが、L97のgen_keyapir()と、L121のfill_random()
RFCと実装が一致しているのかを確認するのは、私にはちょっと難しい。。

でも、mbedTLSもちゃんとtestsuitesでRFC 6979に載っているデータのパターンはOKなのだよ。。。
だから、間違えているとは考えにくい。
例えば、RFCのA.2.3は、この辺がテストデータになっている。

 

全部正しいのに結果が違うということがあり得るとしたら、エンディアンじゃなかろうか?
RFC 6979にはbig-endianと書かれているけど、与えているハッシュ値がlittle-endianになっているからとか。
しかし、いろいろひっくり返したものの、署名は一致しなかった。

なんでだ??
そんなことあり得るのか???

 

わからなくなって、変更したところを元に戻し、自分のmbedTLSを使った処理を見直してみた。
あれ・・・署名計算だけしか見てなかったから気付かなかったけど、そもそもの署名計算に与えている値を間違えている・・・?
pythonで作ったのと同じパラメータになるように修正して・・・

あーーー、一致したーーーー
疑ってごめん、mbedTLS。
やっぱり私が間違っていたよ。。。

2017/04/04

[esp8266][rtos]ほどよいMQTT client

せっかくESP8266でSmartConfigすれば外部からWiFi APの設定ができることが分かったので、なにか動くアプリを作りたい。
ただ、今はセンサも何もつないでいないので、定期的にどこかに送信する、程度のことができれば良い。

であれば、MQTT brokerに向かってpublishするだけ、というのが簡単そうな気がする。
ほどよいMQTT client APIがなにかあるだろう。


Pythonではpahoを使っていたが、そのC版をESP8266のRTOS版に移植したものがあった。
baoshi/ESP-RTOS-Paho: Port of Eclipse Paho C client on ESP8266

よさそうなのだけど、ちょっと大きいなぁ。
メモリに制限があるから大きなpublishをすることもないし、QoSも0しか使わないだろうから(publishにQoSあったっけ?)、v3.1くらいの内容であれば自分で実装してもよいかもしれない。

でも、既にできているプロジェクトを取り込むのも勉強になるし。
うーーーーむ。。。

 

そうか、両方やればいいんだ。
自分で作ると柔軟性も拡張性もないがサイズが小さなライブラリができるだろうから、それはそれで使い道があるかもしれない。
その後でPahoを移植したライブラリを組み込めば、あれこれできるようになるので、それもよいことだ。

むかし仕事で作った実装を見るのはさすがに反則だから、ちまちまやっていこう。

2017/04/03

[bc]segwitのこと

Bitcoinで、segwitというのがある。
segwitは"Segregated Witness"の略なのだが、まあ語源はどうでもよい。
Bitcoinがハードフォークするとかしないとか話が出ているが、そういうのもどうでもよい。
私はsegwitの話をしたいだけだ。


取引の内容を表す「トランザクション」は単なるバイナリデータなのだが、いくつかの部分に分かれている。
部分の正式名称は、こんな感じだったと思う。

  • version
  • [marker]
  • [flag]
  • txin
  • txout
  • [witness]
  • locktime

カギ括弧を付けているものが、segwitで追加された部分だ。

 

そして、話が面倒なことに、作り方によってトランザクションに入れ込むデータが変わってくる。
ここではscriptPubKeyと書いたが、これはたぶんP2PKH向けの名前で、locking scriptという呼び方の方が正しいかも。
txout(txは"transaction"の略で、inが入力、outが出力)に書くスクリプトの部分だ。

  • segwitではないscriptPubKey
  • segwitで、データがちょっと長めのscriptPubKey
  • segwitで、データがちょっと短めのscriptPubKey

「ちょっと長め」ってなんだよ、となるが、これはsegwit対応していないウォレットアプリからでも送金先として指定できるタイプである。
見た目はP2SHなのだけど、中身はsegwit向けというやつだ。
通常がP2PKHとしたら、そのちょっと長めバージョンはP2WPKH nested in BIP16と呼ばれる。
データだけじゃなくて、名前も長い。。。

 

「ちょっと短め」ってなんだよ、ともなるが、これはsegwitに対応したウォレットじゃないと送金先に指定できない。
こっちは単にP2WPKHと呼ばれている。
nested inしている方のscriptPubKey(0xA914{20-byte-script-hash}87=23byte)に比べると、1byte小さい(0x0014{20-byte-key-hash}=22byte)ことがわかる。

これだけだと大差ないのだが、このトランザクションをInputとするトランザクションを作ると差が出やすい。
witnessに「<signature> <pubkey>」を置くのはどちらも同じなのだが、nested inの方はscriptSigに23byteのデータを置くことになっている。

 

ただ、ふつうのP2PKHと比べると、ちょっと短めの方でsegwitのトランザクションを作ったとしても、そっちの方がわずかにサイズが大きい。
nested inになれば、なおさらだ。
大ざっぱにsegwitのP2WPKHトランザクションを作ろうとすると、

  • ふつうのP2PKHみたいな構造を作る
  • [marker]と[flag]を追加する(+2byte)
  • scriptSigに置いていた<signature>と<pubkey>をsegwitに移動
  • nested in BIP16なら、scriptSigに代わりのデータを置く(+23byte ?)

というところか。
lengthの付け方がどうだったか忘れたので、1,2byteくらいは違うかも。
あと、署名の計算方法も変わるのだけど、サイズはほぼ同じだからいいや(サイズの範囲は非segwitと同じ)。

 

じゃあsegwitの何がうれしいかというと、トランザクション展性を抜きにすれば、ブロックに入れるときのデータ量が減らせる、ということだろう。
witnessの部分、P2WPKHなら<signature>と<pubkey>を取り外すらしい。<marker>と<flag>もかな?
これだけで110byteくらいあるから、トランザクションは大きくなるけどブロックに入れるサイズはだいたい小さくなる。
MultiSigみたいに署名が複数あると、効果が大きい。

 

ただ、segwitのトランザクションを作るには、INPUTのところがsegwitになってないとダメだ。
だからP2PKHアドレスの場合は、一度P2WPKHのアドレスを作ってそこに送金し、その次からがsegwitのトランザクションを作ることになる。

nested inだとscriptSigもブロックに入れないといけないので、もったいない。
そうなると、ウォレットアプリも対応しないとなぁ、となってくる。
署名の計算も、前のトランザクションを一部使うことになり、その検証も同じようなことになるので、P2PKHなどよりも面倒だ。


今回書いた内容も、BIPを見れば分かる範囲なのだが、私がsegwitのことを調べ始めたときは、

  • 署名を分離してcoinbaseに置く
  • サイズが小さくなる

くらいで、技術的なところは結局BIPを読むしかなかった。
そしてBIPがわかりづらいのよね。。。英語だし。。。

 

今ではsegwitに対応したBitcoinライブラリもあると思うので、これから始める人はそれを読んでいった方がよいのかも。

2017/04/02

[esp8266]ESP-TOUCHのしくみ (3)

"android udp tethering"などのキーワードで検索すると、port forwardingのことがよく出てきた。
adb forwardコマンドでできると書いてあるので、何も考えずにやってみたが、やはりダメ。

 

android - UDP packets between WiFi-tethered device and WiFi tether provider? - Stack Overflow
単にばらまきたいだけだったのだが、そういえば作りとしては"234.xx.xx.xx"に送信しようとしていた。。。
Androidが取得しているIPアドレスは、"10.xx.xx.xx"みたいな番号なので、マスクで止められたのだろうか?
いや、それだったら、うまくいっているときは"192.168.xx.xx"みたいな番号だから、違うといえば違う。

 

えーっと、IPアドレスのクラスCは、192.0.0.X~223.255.255.Xまでらしい(入社時に購入した古い本より)。
じゃあ、234.xx.xx.xxはクラスCじゃないやん。
その次のクラスDは、224.0.0.0~239.255.255.255とのこと。
この中には入っている。
そして、クラスDはIPマルチキャスト用らしい。

 

5. IPマルチキャスト | TECHSCORE(テックスコア)
MulticastSocketというクラスがあるそうだ。
MulticastSocket | Android Developers
sending and receiving、と書いてあるけど、SmartConfigアプリには使われていないのだよなぁ。
とりあえず置き換えてみよう。
ちっ、DatagramSocketはSocketExceptionなのに、MulticastSocketはIOExceptionなのか。
そして、変更したが動かない。。。

 

http://stackoverflow.com/questions/6550618/multicast-support-on-android-in-hotspot-tethering-mode
setNetworkInterface()で送信対象のインターフェースを指定せよ、という回答が出てきた。
はいはい、やればいいんでしょう、やれば。。。

あ、送信された!

 

じゃあ、あとはBSSIDを取得するだけか。
http://stackoverflow.com/questions/33159224/getting-mac-address-in-android-6-0
うーん、取得はできたが、設定画面に表示されているWiFi MACアドレスと違う。。。
が、動かすと、ESP8266と通信できて、Nexus5のIPアドレス取得はできていないが、自分のIPアドレスはとれているから、うまくいったんじゃなかろうか。

 

使う人はいないと思うが、githubに上げておこう。
AndroidManifestなんかは、ほぼimportしたままになっているので、うまいことやっておくれ。
https://github.com/hirokuma/Esp8266SmartConfigTether

[esp8266]ESP-TOUCHのしくみ (2)

AndroidをテザリングさせてSmartConfigするとうまくいかない件。
ESP8266をSniffer modeにしようかと思ったが、たぶんAndroidからパケットが出てないか、変なパケットが出ているのだろうから、そっちを見ることにした。

困ったときのWiresharkなのだが、Windowsではいろいろ制約があってやりづらい。
VirtualBoxで動かしているLinuxで動かそうと思ったが、NATだと結局Windowsを経由するだろうから、USBドングルのWiFiモジュールを使うことにした。

 

が、ここで問題が。。。
Ubuntuのあるところから、rt8192cuのドライバは修正版を使わないとLinux自体死んでしまうようになっているのだ。
https://github.com/pvaret/rtl8192cu-fixes
別のPC(Native Linux)ではこの手順通りにやればうまくいったのだが、VirtualBoxでやっているためかうまくいかない。。。
dkms installのところで「/usr/src/8192cu/1.10がない」と怒られるのだ。
実際に、ない。
いろいろ試したが、普通にmake & sudo make installし、depmod -aして、blacklistファイルをコピーすればよかった。
困らせやがって。

 

動かしてみると、WiFiのAPに接続しているときはパケットが飛んでいるが、テザリングの時は出ていなかった。
出ていない画像は載せられないので、出ていたときの画像だけ載せよう。

image

AndroidのテザリングとUDPについて調べるべきなのか。。。

[esp8266]ESP-TOUCHのしくみ (1)

ESP8266のESP-TOUCHというか、SmartConfigというか、その辺のしくみを見ていく。
参考にするドキュメントは、これだ。

http://espressif.com/sites/default/files/documentation/30b-esp-touch_user_guide_en_v1.1_20160412_0.pdf

実は、以前も調べたことがあるのだが、深くは追っていなかったのだ。
hiro99ma blog: [esp8266]SmartConfig == ESP-TOUCH


まず、ESP-TOUCHとSmartConfigの関係だが、

  • Espressif's ESP-TOUCH protocol
  • Smart Config technology

ということで、Smart Configというのが方式の名前で、そこで使っているプロトコルがESP-TOUCHということらしい。
Espressif's、とあるので、ESP-TOUCHはEspressif独自だと思って良いだろう。
AirKissというプロトコルも使えるので、Smart ConfigではESP-TOUCHかAirKissが使える、ということになるのか。

今回はESP-TOUCHのみ見ていく。

 

APIは開始と中断、あとはタイムアウト時間設定とバージョン取得くらいか。
プロトコルでどれを使うのかを設定するAPIもあり、開始前に呼んでおくとのこと。
サンプルは設定していないので、デフォルトはおそらくSC_TYPE_ESPTOUCH_AIRKISSだ。

smartconfig_start()すると、あとはコールバックで進んでいく。

image

ESP8266のアプリとしては、SC_STATUS_LINKでwifi_station_set_config()するくらいしかやることがない。
起動してWiFi APと接続できなかったらSmartConfigモードになる、とか、ボタン押したらSmartConfigモードになる、というのが望ましいか。

 

さて、start()すると、ステータスはFIND_CHANNELまでは進むのだが、Nexus5をテザリングさせたままやると、次に進めなかった。
通信できなかったからだとは思うのだが、そもそもどうやってAndroidアプリと通信しているのだろうか?

ドキュメントでは、UDPを使っていると書かれている。
説明図は、こうなっていた。

image

このパケットは、本で調べるとIEEE802.3フレーム形状というもののようだ。
UDPかどうかは"DATA"の部分に載ると思うので、ESP-TOUCHとしてはEthernetパケットに載せているのだろうか?
あるいは、UDPのデータとしてこれが入っているのだろうか。
IEEE802.11標準だとアドレスが4つくらい入っているようだから、データ部に載せる・・・?

いや、Interface誌2012/11月号を読むと、送信側はアドレスとして「自分・AP・相手」を必要とするが、APはそれを受け取って流すときは「自分・相手」だけにしてしまうようだ。
ということは、SmartConfigアプリが自分をAPとして送信する?

そもそも、何も設定していない状態でどうやって希望する無線を見つけ出すのだろうか。
WPSで設定できるのだから、何か手段はあるはずだ。
ただ、なんとなくだが、Androidアプリからそんな深いパケットは制御できないような気がするのだ。
うーーーん。。。。


動かしながらやった方が早そうだ。

おそらく、AndroidアプリのConfirmボタンを押して送信開始するのは、ここだ。
違ってたら、済まん。

https://github.com/EspressifApp/EsptouchForAndroid/blob/master/src/com/espressif/iot/esptouch/udp/UDPSocketClient.java#L97

データを見てみると、0x31をひたすら送っている。
プリアンブルか?
ログでは"send gc code"となっている。ソースのコメントは"send guide code"となっていた。

https://github.com/EspressifApp/EsptouchForAndroid/blob/master/src/com/espressif/iot/esptouch/protocol/EsptouchGenerator.java#L30
gcがguide code、dcはdata codeを指しているようだ。

guide codeを流し続けて、相手が応答したらdata codeを流すのかと思ったが、どうもguide codeとdata codeを交互に流しているようだ。

  • WiFi AP接続中で偽パスワードだと、UDP受信しない
  • WiFi AP接続中で空パスワードだと、UDP受信しない
  • WiFi AP接続中で正しいパスワードだと、UDP受信する

という動きをしたので、ESP8266が応答したらデータを投げるのではなく、とにかくデータを投げ続けて、ESP8266が設定できたら何か送信するので応答できる、という作りのようだ。

 

ということは、テザリングしているときは相手が受け取れていないか、自分がうまく送信できていないかのどちらかだろう。
ドキュメントを読むと、ESP8266はSniffer modeを使っているらしい。
Sniffer modeは使ったこと無いのだけど、無線が出ていたら読み取ってくれるようになってるのではなかろうか。

UDPの送信先は、IPアドレスが"234.xx.xx.xx"(xxはカウント値で毎回変わる)、ポート番号は7001になっている。
これが出ていないのか、受け取れていないのか。
そもそも、テザリングで作ったアクセスポイントをWiFiのアクセスポイントと一緒にして良いものなのか。。。

 

うーん、Sniffer_DEMOを動かしてみた方が良いのか。
長くなってきたので、今回はここで打ち切ろう。

2017/04/01

[android]WiFiテザリング中だったらSSIDを知りたい

ESP8266のSmartConfigを使えるようになっておきたい。
Androidの設定アプリから、今つないでいるWiFiのAPを登録することはできた。
WiFiがない場所でも、Nexus5のテザリングで使えるようにしたいのだが、動かすと<unknown ssid>になり、アプリが死んでしまった。

面倒だが、対応できるのかどうか調べてみよう。


http://tools.oesf.biz/android-6.0.0_r1.0/xref/frameworks/base/wifi/java/android/net/wifi/WifiManager.java#1541

WifiManager#getWifiApState()なり、isWifiApEnabled()なりを使えば、テザリング中かどうかを知ることはできるらしい。
@hideなので今後はわからんが、Android 7.1.1まではありそうだ。
あ、Android7では@SystemApiとかいう修飾が付いてるから、制限されるのかも。
持ってないので知らん(Java reflection is impossible、と書いているから、できんのかも)。

名前からすると、getWifiApConfiguration()で情報がとって来れそうだが、SmartConfigアプリと違ってWifiConfigurationを返す。
まあ、SSIDだけわかればよいから、問題なかろう。

幸い、reflectionしたサンプルがstackoverflowにあったので、使わせてもらう。
http://stackoverflow.com/questions/10850936/android-tether-get-current-ssid


テザリングしていたら、という条件を入れようかと思ったが、今のところ「<unknown ssid>」という文字列になっているから、その場合だけWifiApから取ってくることにした。

 

Javaが、ハードTABでインデントしているので、置換。
これでたぶんできたんだと思う。自信はないが。。。

$ find ./ -name "*.java" -exec sh -c 'expand -t 4 {} > $$$ ; mv $$$ {}' \;

 

よし、と実行すると、SSIDはテザリングの設定画面で入力していたものが表示された。
よしよし、と進めると・・・やはり死んでしまった。
どうやら、BSSIDがnullだったためのようだ。
無線LAN - BSSIDとESSID
通常は、BSSIDはMACアドレスと同じ、ということだったので、Nexus5の端末情報からWiFi MACアドレスを見て、まずはコード埋め込みにして動作確認することにした。

うん、BSSIDを入れておくと、死ぬことはなくなった。
が、ESP8266がNexus5を見つけられないのか、コンソールには何も出ない。

 

なんとなくだが、SmartConfigはWiFiクライアント同士が通信するようなものになってるのではないだろうか?
だからAPになったNexus5からはうまくいかない、と。

面倒だが、SmartConfigがどういうしくみなのかを調べる段階に来てしまったようだ。

2017/03/31

[esp8266]Non-OS版もgithubに?

RTOS版の環境ができたので、ほかにESP8266のgithubに何か更新されたものがないか見ていたら、Non-OS版が2時間前にアップされていた。

espressif/ESP8266_NONOS_SDK: ESP8266 nonOS SDK

ESP8266を数ヶ月ぶりに見たその日に更新されるなんて、これはNon-OSに戻って来いという暗示だろうか?
でも、ソケットとか使うとスレッドがほしいのよねぇ。

 

私が探していたのは、ESP-TouchのAndroidソースだったのだが、それはここになかった。
が、EspressifAppという別のgithubアカウントにあるようだ。
https://github.com/EspressifApp

本物かなぁ。

[esp8266][rtos]RTOS環境のビルド

Bash on Ubuntu on Windowsの動きがあやしかったので、Xubuntu 16.04にESP8266のRTOS環境を作り直した。
以前も同じ作業をしたのだが、別VMになったから、復習も含めて書いておこう。
まあ、Arduino版を使っている人の方が多い気はするんだけどね。。。


今回は、$HOMEの直下にEsp8266というディレクトリを作り、そこで作業した。
ここを読んで、apt installが必要なものは済ませてある。
https://github.com/pfalcon/esp-open-sdk

$ mkdir Esp8266
$ cd Esp8266
$ git clone --recursive https://github.com/pfalcon/esp-open-sdk.git
$ cd esp-open-sdk
$ time make STANDALONE=n

VMをHDD上に作っているし、あまりリソースを割り当てていないせいもあるが、40分くらいかかった。

$ cd ..
$ git clone https://github.com/espressif/ESP8266_RTOS_SDK.git

こちらはcloneするだけだ。

 

次は、環境変数などの設定。
.bashrcなどに置くか、使いたいときだけ設定するのかは個人の自由だ。
私は、使いたいときだけ設定するようにした。

$ mkdir rom

romディレクトリは、ビルド後にESP8266へ焼く物が置かれる場所だ。
SDK環境だとbinという名前なのだけど、binだと「ここに実行ファイルおいたっけ?」といつも思ってしまうので、名前を変えただけだ。

 

そして、HOME/Esp8266の直下にこういうスクリプトファイルを置いた。
私は「compile.sh」という名前にしたが、別にどうでもよい。
コンパイルできる環境変数を設定するためのスクリプトだから、名前は今ひとつだったか。。。

#!/bin/sh
export SDK_PATH=`pwd`/ESP8266_RTOS_SDK
export BIN_PATH=`pwd`/rom
export ESP8266_PATH=`pwd`/esp-open-sdk
export PATH=$ESP8266_PATH/xtensa-lx106-elf/bin:$PATH
export ESP8266_INCLUDE_PATH=$ESP8266_PATH/sdk/include
export ESP8266_LIB_PATH=$ESP8266_PATH/sdk/lib

これは、HOME/Esp8266ディレクトリで使うように`pwd`を使っている。

 

設定はこのくらいだ。
おまけで、こういうスクリプトファイルを作って、オリジナルのgen_misc.shと置き換えている。

ESP8266 RTOSビルド用gen_misc.sh

いつもgen_misc.shするたびにコンソールで答えていくのが面倒なので、自分がよく使う設定を書いただけだ。
うちはWROOM-02なので、各自好きに変更するのもよし、使わないのもよし、だ。


試しにビルドしておこう。

$ source compile.sh
$ cd ESP8266_RTOS_SDK/examples/wps_demo
$ (gen_misc.shを置き換えた)
$ ./gen_misc.sh

うまくいくと、rom/upgrade/user1.4096.new.6.binができているので、それをESP8266へ焼けばよかろう。

ただ、ESP8266のWPSはAPによってうまくいかないものがあったので、正しく動くかどうかは保証できん。
それに、デフォルトだとうちのUSBシリアル変換ではアクセスできないbpsでログが出てくるので、うまくいったかどうかわからん。
試す場合は、その辺に気をつけるのがよかろう。