2018年7月28日

[c/c++][mbedtls]ChaCha20-Poly1305サポートとIETF variant (3)

第3弾まで書く気はなかったのだが、ネタは思いついたときに残しておかねば。



libsodiumからMbedTLSに全部置き換えたいと思っている。
別にlibsodiumに不満があるわけではないのだが、使っている理由がChaCha20とPoly1305だけなので、MbedTLSが対応したなら統一したいのである。


ChaCha20-Poly1305については、IETF variantのAPIを使っていたため、MbedTLSと置き換えできた。
しかし、見逃していたのだが、別の箇所でChaCha20を使っていることに気付いた。
こっちは純粋にChaCha20単体で使っていたのだが、nonceが8byteになっているからオリジナルのChaCha20っぽい。


さて、困った。
MbedTLSはChaCha20単体もIETF variantっぽい(nonceが12byteになっていたから)。

もしかしたら同じ結果になるかもしれない、と思ってやってみると、あら不思議、同じになるではないか。
しかし、条件があるに違いない。


libsodiumのChaCha20処理は、このあたりにある。
https://github.com/jedisct1/libsodium/tree/0468e778d229054a966d0fdc629ec8b677bc37c6/src/libsodium/crypto_stream/chacha20


呼ばれているのは、これのようだ。
_ietfが付いているかどうか。
https://github.com/jedisct1/libsodium/blob/bac61ebf506c1b32185a3f3cc6a582445d55bc75/src/libsodium/crypto_stream/chacha20/ref/chacha20_ref.c#L226-L262

この2つの違いはchacha_ivsetup()かchacha_ietf_ivsetup()かだけみたいだ。


IV設定は、ここ。
https://github.com/jedisct1/libsodium/blob/bac61ebf506c1b32185a3f3cc6a582445d55bc75/src/libsodium/crypto_stream/chacha20/ref/chacha20_ref.c#L62-L78

counterのバイト数と、ivのバイト数が違うだけのように見える。


RFC-7539の7ページ目に図が載っている。
https://tools.ietf.org/html/rfc7539#page-7

image

IETF variantは、bが1つ、nが3つになっている。
ということは、オリジナル版は、bが2つ、nが2つということだろう。
それなら、IV設定の関数と整合がとれる。


ということは、これを利用して、MbedTLSでもcounterとnonceの配分をうまくやればいけるのだろう。
stream()ではcounterがNULLになっているから、0扱い。
nonceは8byteだから、何も考えずに置き換えて使えるんじゃなかろうか。
エンディアンがちょっとわからんのだが、必要があれば4バイトシフトさせればいいだけだ。


私が置き換えたかったのはcrypto_stream_chacha20()だったので、前回と同じようにソースを書いてみた。

https://gist.github.com/hirokuma/f9ee0da7bd428458662473964b57fa6c

nonceの前方に4byteの0を入れると同等になるみたいね。

[c/c++][mbedtls]ChaCha20-Poly1305サポートとIETF variant (2)

前回の続きだが、あまり大したことは書けない。

  • MbedTLSにChaCha20-Poly1305がサポートされたけどIETF variantなのか?
  • ソースファイルからするとIETF variantっぽいし、libsodiumのIETF variant APIで同じ結果になった
  • じゃあ、なんで私がやったAPI置き換え版は結果が同じにならないの??


はい、なんとなく予想できたかと思うが「置き換えに失敗していたから」でした・・・。



これだけだとあんまりなので、どう間違えたのか書いておこう。

libsodiumは、エンコードしたデータ+MACをまとまったデータとして扱っていたのだ。
しかし、MbedTLSでは別々に扱っている。
だから置き換える際に、MACのアドレスも指定するし、データ長もMACを外したサイズにせねばならなかったのだ。

そこら辺を間違えていたのですな。
まあ、ありがちといえばありがちだが。

[c/c++][mbedtls]ChaCha20-Poly1305サポートとIETF variant (1)

Mbed TLS 2.12.0, 2.7.5 and 2.1.14 released


いやあ、とうとうリリースされました。

私にとって大きいのは、ChaCha20-Poly1305サポート。
だいたいの部分はMbedTLSで実装していたのだが、ChaCha20-Poly1305だけはlibsodiumを使っていたのだ。
libsodiumを別の環境でビルドするのは難しそうだったのだけど、MbedTLSなら何とかできる気がする!



で、APIを置き換えてみたものの・・・結果が違う。
全部じゃなくて、MACのチェックで失敗するものがあるのだ。


何も考えずに置き換えていたのだが、libsodiumは3種類APIがあるのだ。

Authenticated Encryption with Additional Data using ChaCha20-Poly1305

  • The original construction can safely encrypt up to 2^64 messages with the same key (even more with most protocols), without any practical limit to the size of a message (up to 2^64 bytes for a 128-bit tag).
  • The IETF variant. It can safely encrypt a pratically unlimited number of messages, but individual messages cannot exceed 64*(2^32)-64 bytes (approximatively 256 GB).
  • The XChaCha20 variant, introduced in libsodium 1.0.12. It can safely encrypt a practically unlimited number of messages of any sizes, and random nonces are safe to use.

私が使っていたのは、この真ん中のIETF variantというAPI。
ソースファイルを見比べたのだが、originalのものに似ているが、追加されているような感じがする。

MbedTLSでも同じことができるものかは別として、IETF variantが何なのかを調べておこう。


"variant"は「変形」とか「変種」というような意味。
だから、originalに対してIETFなりの変更を加えたバージョンということだろう。

libsodiumのIETF variant APIページの一番下にリンクがあった。

ChaCha20 and Poly1305 for IETF protocols

IETF variantの仕様らしい。
リンク先は、RFC-7539。

あれー、と思うだろう。
だって、MbedTLSのソースファイルにもRFC-7539と書いてあるのだから。。。



むう、もしかして、APIが違うんじゃなくて、置き換え損なっているのだろうか?
APIが同じ種類かどうかは、テストデータを動かして確認するしかあるまい。



https://gist.github.com/hirokuma/e8d3e68300810d284b7d65df5473fe22

データをMbedTLSのtestから持ってきて、APIはlibsodium 1.0.16で実装。
困ったことに、"ok"が出力されてしまった。


なんで困ったかというと、encryptのテストしかないからだ。
失敗していたのはMACのチェックなので、どちらかといえばdecryptの方なのだ。

これは、もっとちゃんと調べろ、ということなんだろう。

2018年7月21日

[git失敗]最新のpushから1つresetして編集

gitで起こしてしまった、現在進行形のお話。


別の場所で作業するので、一旦pushした。
かなり適当な内容なので、pushよりはファイルごとコピーしておきたいくらいだったのだが、面倒になったのでpushした。


で、今見直したところ、あまりにもいい加減な変更だったので、前のcommitは止めようと思った。
が、そのままではダメだけど、書き換えれば使い物にならないわけでもなさそうだったので、差分を見ながら書き換えようとした。
私はvscodeを使っているのだが、差分が見やすいので助かるのだ。


そして、何も考えずにこうやった。

$ git pull
$ git reset --soft HEAD^

そうすると、ソースファイルはpushしたものが残っているが、差分としてはまだ反映されていないような形になるので、最後に変更した箇所が見える。


無事に変更を終え、push。

$ git push

error: failed to push some refs to 'git@github.com:xxxx.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

エラーらしい。
resetしたからだろう。

$ git pull

CONFLICT (content): Merge conflict in xxxxxxx
Automatic merge failed; fix conflicts and then commit the result.

コンフリクトした。

そして困ったことに、オートマージされたので、前回削除したり追加したりしてコンフリクトしなかったところが反映されてしまったのだ。

「gitでやったらいかんこと(その1)」というところか。。。



gitだけで解決できそうだけど、調べるのが面倒だったので、手動で対応させることにした。


まず、今のコンフリクトしたファイルを適当に修正して、別の場所にコピー。
そして、ローカルでやった修正をなかったことにするため、git reset --hard HEAD^。
pushした内容に戻すため、git pull。
そして、その修正はいらないので、git revert HEAD。

あとは、移動させたファイルとオリジナルのファイルをWinMergeで比較しながら手動マージ。
アナログじゃろう?


今回はコンパイルエラーが出たので気付いたが、もっとぼーっとしていたら、オートマージに気付かなかったかもしれない。


さて、今回調べたいのは、どうするのが楽だったのか、だ。
やりたかったのは「最新pushを1つ前に戻しつつ、最新pushのソースも見ながら編集したい」だ。


うん、そうだね。

$ git pull
$ 差分を見たいソースファイルをどこかにコピー
$ git revert HEAD^
$ 差分を見ながら編集

ファイルをどこかに置けばよかっただけか。


ただ、vscode+GitLensだと、履歴と比較する機能がありそうだ。
Working Treeとも比較ができるので、次回はそれを使おう。

image

2018年7月9日

[java]64bit値を扱うのにBigIntegerもある

Cからもらったunsignedな64bit値をビット演算するだけでよいかと思っていたら、数値としても扱う箇所があるのに気付いた。

うーん、uint64_tはプリミティブだから、Javaもlongで受け取って、中で数値に変換できないものか。。。


調べていると、BigIntegerというものがあった。
これを使って、引数はlongで受取り、中で16進数文字列に置き換え、それをBigIntegerにすればよさそうだ。

https://gist.github.com/hirokuma/f365c2a85dae3962ff3d5f19562b9029/a0e48bef4148691ce3fcc135c9911662ce21afc3

結果

long: -81985529216486896
long 2byte: -2
BigInteger: 18364758544493064720
BigInteger 2byte: 254

意味も無くビットシフトなんかさせてみたが、ちゃんと正の数として扱っている。

文字列は好きではないのだが、C側でやらなくてよいので、まあよかろう。

2018年7月7日

[java]uint64_t相当のデータをビット演算したい

JNIを使って、CとJavaをつなごうとしている。
C側でuint64_tを使っている箇所があるので、Javaで何とかしなくてはならん。


Javaのlongは64bitなのだが、Javaにはunsignedがないので、たぶん最上位ビットが立ってたら負の数と思うだろう。
byteもそうだったし。

確認しておくべし。


longだけではなく、BigDecimalも使ってみよう。

https://gist.github.com/hirokuma/c8a67b1db8e44ce45236942088d81865/1aaa1e1893b3f83f9d1d14d494b1d4902da454ee

同じようなことをさせたいが、BigDecimalにビットシフトがないので、割り算で代用。
処理が遅くなりそうだが、まあ動作確認だからな。

結果

big decimal 2byte: fe
long 2byte: fffffffffffffffe

やはり、そうなるのか。
BigDecimalは演算してるから2byte分きっちりになったが、longはビットシフトで符号が引きずられたんだ。


そういえば、Javaには「>>>」があったな。

https://gist.github.com/hirokuma/c8a67b1db8e44ce45236942088d81865/0161393d1d388b1ad97754dbc84d3efb2eff8370

結果

big decimal 2byte: fe
long 2byte: fe

おお!
なんか、うれしくなりますな。


これはHEXで出しているから、変数として正負どちらになっているかわからん。
数字で出力させて確認。

BigDecimal : 正
longで>>:負
longで>>>:正

まあ、予想通りか。
当然だが、これをbyte型にキャストして代入すると、どれも負の数になる。

2018年6月30日

[github]古いgistのURLを知りたい

ちょっとしたソースコードを載せるのに、githubのgistをしばしば使っている。
便利なのだが、編集すると、その前の内容を確認するのが難しい。
いや、差分はわかるのだけど、githubのcommit historyみたいに、その時の内容だけが見たいのだ。


どうやら、その時のハッシュが分かれば載せられるらしい。
例えば、これはzlibサンプルのrevision1のURLだ。

https://gist.github.com/hirokuma/0f038adc04c1ec38ba6c01f8b2db4fb5/4b920d2c12d7893c23a93343cd74d116de731077

URLの最後がハッシュ値なのだが、どうやって取ってくれば良いのだろう?


・・・というのを、長々と調べていた。。。
いや、なに、"Revisions"というタブがあるのは知っていたよ。
そこで差分も出てきているのは知ってる。


ただ、そこに全Revisionの差分が出ているということにまでは気がつかなかったのだ。
下の方にスクロールさせると、過去の差分があるし、Viewボタンまで付いている。
Viewをクリックすれば、そのときのURLが出てくるのだな。


はは、ははは。
私は乾いた笑いを飲み込むしかなかった。

[c/c++]zlibを使ってみよう

zlibを使わなくてはならなくなった。
名前はよく聞く・・・。
リンクするときに「-lz」と短く済むので、印象に残っている。

よく使われているので、使い方も難しくは無いだろう。


WSLのUbuntu 16.04で試す。

sudo apt install zlib1g-dev


zlibのマニュアルは、こちら。

zlib 1.2.11 Manual https://zlib.net/manual.html


ただ・・・圧縮と解凍さえ分かればよいので、使い方だけ見ておこう。
やりたいのは、ファイルではなくRAMで持っているデータなので、そこは読み替えていく。

zlib Usage Example https://zlib.net/zlib_how.html

https://zlib.net/zpipe.c


まず、テストデータを作ろう。
xxdというコマンドを使うと、ファイルをC言語の配列形式にしてくれる。
便利だ・・・。

xxd -i hirokuma.png > hirokuma.h


Exampleでは、CHUNKサイズのバッファin[]とout[]を準備している。
def()が圧縮、inf()が展開。
どちらも、二重のdo-while()になっている。

まず、def()から。
外側のdo-while()は、ファイルをCHUNKずつ読み取るためのループ。
内側のdo-while()は、deflate()を実行して、avail_outが0になっている間はループする。
「keeps calling deflate() until it is done producing output」と書いてあるので、avail_outが0ということは処理が継続しているという意味なのだろう。

圧縮中、deflate()の引数はZ_NO_FLUSHで、最後だけZ_FINISHにする。
ストリーミングで圧縮するから、ある程度データが揃うまで吐き出さないのだろうね。

簡単なサンプルを作った。
圧縮のみで、圧縮しているデータは、うちのアイコン(PNG)だ。
PNG画像もzlibで圧縮されているようだが、気にするまい。

https://gist.github.com/hirokuma/0f038adc04c1ec38ba6c01f8b2db4fb5/4b920d2c12d7893c23a93343cd74d116de731077

image

まあ、データは何でもよいのだが、内側のdo-while()がどういう周り方をするのかが気になった。

$ gcc -o tst zlib_comp.c -lz
$ ./tst
p=0x6010a0
   avail_out=1022
p=0x6014a0
p=0x6014a0
   avail_out=1024
p=0x6018a0
p=0x6018a0
   avail_out=1024
p=0x601ca0
p=0x601ca0
   avail_out=1024
p=0x6020a0
p=0x6020a0
   avail_out=1024
p=0x6024a0
p=0x6024a0
   avail_out=1024
p=0x6028a0
p=0x6028a0
   avail_out=1024
p=0x602ca0
p=0x602ca0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=103
p=0x603030

next_inは自動的に進むようだから、全データがRAM上にあるなら、初期化だけしておけばよさそうだ。


内側のループが回ったのは、最後だけだ。
何かルールがあるのだろうか?
もし最後だけなら、通常は内側のdo-while無しでもよいのかもしれんが、これだけじゃわからんな。


というわけで、マニュアルを見てみよう。
けっこう、見づらい・・・。

https://zlib.net/manual.html#Basic

If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out).

In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return.

avail_outが0の場合は、flushオプションを同じ状態で呼び続けなくてはならん。
ということは、Z_FINISHの場合だけではないということか。


"more output space (updated avail_out)"と書いてあるが、サンプルではavail_outを再設定しているだけで、out[]のサイズは同じだな。
そもそも、fwirte()するサイズは「CHUNK - strm.avail_out」だから、8KBくらいのデータでは外側のループで回っているときはout[]がほぼ出力されず、最後にZ_FINISHしたときに書き込まれていることになる。


flushオプションもいくつか種類があるようだが、圧縮したデータそのものがほしい場合はサンプル通りにやっておけばよいんじゃ無かろうかね。


展開する方も、同じようにやった。

https://gist.github.com/hirokuma/0f038adc04c1ec38ba6c01f8b2db4fb5/2ae53cdeb15bc6e79ed4c65474040a3327b5dbad

$ ./tst
exec: comp
retval=1
exec: decomp
retval=-5
retval=-5
retval=-5
retval=-5
retval=-5
retval=-5
retval=1

追加したのは、decomp()。
-5は、Z_BUF_ERROR。

サンプルではエラー処理していないし、最後に1(Z_STREAM_END)が出るところから見ると、普通なんだろう。

Z_BUF_ERROR if no progress was possible or if there was not enough room in the output buffer when Z_FINISH is used.

Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing.


APIに何があるのか読みづらかったので、こちらの解説記事の方がよさそう。
http://s-yata.jp/docs/zlib/

compress()なんてあったのか・・・。
https://zlib.net/manual.html#Utility

2018年6月24日

[excel]自由に線を引きたい

たまにはExcelのことを書こう。


私がExcelを使うのは、文字と画像をまぜこぜにして、なおかつ広いスペースが使えるからだ。
画像も、画像ファイルだけでなく、線画を描くこともできる。


よく使うのは、曲線コネクタだ。

image

直線だと他の図形とぶつかるけど、曲線だと迂回させることもできる。


できるのだが、あんまり自由度がないのが悩みどころだ。
黄色のマーカーを動かすと、少しは形が変わるのだが、そんなに大幅に変わらない。

image image


自分で使う図ならいいのだが、たまにはきれいな形で人に見せたいこともある。
ああ、大きく迂回させたい・・・。


どうしてもExcelを使って、迂回したような線を引きたい場合は、こういう技もある。

image


何のことはない、図形と直接コネクトさせるのではなく、別の図形にコネクトさせてしまうのだ。
ここでは、円にコネクトさせている。

image


円じゃなくて、四角形の方がうまくいくかも?
この辺は、倍率で見た目が変わったり、線の太さで影響がありそうなので、あれこれやってみるのがよかろう。

image

ただ、中継点のところが薄くなってしまうようだ。
image


曲線を使えば期待した線を描きやすいのだけど、あれは後から変更できないみたいだし。
うーむ。


他のお絵かきツールを探していると、draw.ioというものが紹介されていた。

https://www.draw.io/

image

ふむ、これは自由度が高い。
やはりExcelっぽくない絵にしたいときは、Excelじゃないツールを使うのがよいな。

2018年6月17日

[wireshark]npcapを使う

Windows版のWireSharkを久々に起動させ、最新版にした。
そのせいかどうかわからないが、起動しない。。。
プログレスバーの途中、pluginsがどうのこうのというところまで文字が出て、そこから進まない。

アンインストールしてやり直したり、ユーザデータを消したりしたが、関係なさそう。


https://osqa-ask.wireshark.org/questions/48178/wireshark-fails-to-start-on-windows-10

WinPcapだと動かない人もいるみたいだから、npcapにしてみるといいかもね、というところか。

WinPcapごとアンインストールし、npcapのWindowsインストーラを https://nmap.org/npcap/ から探して(今は0.99-r6が最新のようだ)、インストールしてPCを再起動。

そうすると、WireSharkが起動した。


うまくWinPcapでうまくいかないときにPC再起動はさせていないので、もしかしたら再起動だけで直ったかもしれない。
まあ、npcapだとWindowsでもlocalhostを見ることができるから、ちょうどよいだろう。