FUSEで遊んでいる最中に別件ではまる

fusepyにはloopbackファイルシステムのサンプルが付属している。
せっかくなので、これを使って何か面白いことができないかと考えてみた。
即座に思いつくのが圧縮ファイルシステム
書き込む前に圧縮して、読み出してから解いて戻すという手順を踏めば簡単にできるはず。
幸い、Pythonはzlibとかgzipとかのライブラリが標準で準備されているので、importして、
インスタンスを作って、楽勝、のはずが、そう簡単ではなかったようで。
正確には、圧縮/解凍することは、楽勝、だったのだけど、それをFUSEに喰わせるのがうまくない。


loopback.pyはosモジュールを介してシステムコールを呼んでいるっぽいのだけど、この前提は
書き込み、読み出しともにサイズが不変であることになっている(っぽい)
考えてみれば当たり前なんだけど、圧縮してるんだから、そういう原則は守れるわけもなく。

どうにかこうにかいじっては見るものの、どうも怪しい挙動しかしない。

cat /tmp/fuse
なんてやるとbad addressなどという見たことのないメッセージが出てくる。

これはユーザーランドで動いているからこれで済んでるんだろうけど、システムランドでこんなことやったら
カーネルパニックで一発でシステムが落ちることは火を見るよりも明らかだ。
FUSE万歳!

で、圧縮ファイルシステムをいったんあきらめて、暗号化ファイルシステムに切り替えることにした。
これならサイズが変わることもあるまい。

暗号といえば、やはりDESだよね。
ところが、pythonの標準ライブラリでは暗号系はサポートされていない。
opensslも単体ではDES/RC4/IDEA辺りをサポートするのだけど、そのラッパーであるpyopensslはなぜか、
この辺りのサポートはなし。
しょうがないので、pycryptoを使用してみる。
(M2Cryptも入れてみたけど、日本語のドキュメントが見当たらなかった)

で、だ。
DESで暗号化するとオリジナルファイルとサイズが合わない。

まぁ、考えてみればDESはブロック暗号なんだから、入力、出力ともに8byte(ブロック)の倍数である必要があるんだった。
今回、幸いにも?オリジナルファイル(のサイズ)が8Byteの倍数でなかったので気がついた。
危ない危ない。
でも、サイズが変わってしまうのではワークアラウンド?にはなりえない。

さて困った。と思うのはまだ早い。

ブロック暗号が駄目ならストリーム暗号があるさ。
そうとなれば、RC4だ。(他にもあるんだろうけど)

ところが、だ。
なぜか、サイズが変わる。

linux@KURO-BOX:~$ openssl enc -rc4 -k 'pass;pass' -in abcd1k.txt -out abcd1k.enc
linux@KURO-BOX:~$ ls -al abcd1k*

ただ、どこの資料を当たっても、RC4はストリーム暗号だから、入力と出力は同じだ、と書いている。
ここでは例示しないけど、他のファイルでいくつか試してみると、きっちり16Byte増えている。

で、駄目もとでダンプしてみた。

linux@KURO-BOX:~$ hexdump -C abcd1k.enc |head
00000000 53 61 6c 74 65 64 5f 5f b5 f7 f7 ef 69 10 c2 a7 |Salted__....i...|
00000010 3f ff 6d 2f e7 90 ff 0c d2 bb c2 3a 3a eb 8a 70 |?.m/.......::..p|
00000020 77 32 49 e9 32 8d 5f d3 11 0b 68 ad c7 e8 7b 39 |w2I.2._...h...{9|

先頭に、なにやら可読形式の?ヘッダっぽいのが見える。
複数のファイルのサンプルを見る限り、
Salted__
というのは不変っぽい。

で、よくよく調べてみたら、先頭16ByteはSalt(塩)が詰まっているとのこと。
冷静によくよく考えたらopensslのRC4は正確にはRC4-128なので、128bitの共通鍵が必要。
でも、与えているのは9byte=72bit(pass;pass)しかない。

1.足りない分はどうしてるんだ?
2.そもそも、asciiだけじゃ128bit空間使い切れないじゃないのか?
3.同じpassを使えば、同じ傾向の暗号文が出力されるんじゃ?
4.そのためのivだった気がするんだけど、指定不要?

とか思ったら、その辺りはうまく考えられていて、これらすべての解決策その他でSaltを使っているとのこと。
なので、これを外せば、サイズは一致する。
(当然だけど、これは激しく非推奨である旨、opensslのドキュメントに記載がある)

非推奨を承知で試してみる。

linux@KURO-BOX:~$ openssl enc -nosalt -rc4 -k 'pass;pass' -in abcd1k.txt -out abcd1k.enc
linux@KURO-BOX:~$ ls -al abcd1k*

確かにサイズは変わらない。

linux@KURO-BOX:~$ openssl enc -d -nosalt -rc4 -k 'pass;pass' -in abcd1k.enc -out abcd1k.de
c
linux@KURO-BOX:~$ ls -al abcd1k*

復号化しても同じサイズのまま

linux@KURO-BOX:~$ md5sum abcd1k*
69086d3a75d23ba5b2ce21f7c4c3055b abcd1k.dec
4b2eda49b0eb40ab4dad3a198599c5f1 abcd1k.enc
69086d3a75d23ba5b2ce21f7c4c3055b abcd1k.txt

暗号化したものは中身が違うけど、オリジナル(abcd1k.txt)と復号化したもの(abcd1k.dec)の中身が同じことを確認。

なんてやっていたら、日付が変わっていた。
日記を書きそこねたので、今頃書いている次第。

ふう、でも全然進んでないな。
しかも、pythonネタでもFUSEネタでもない。

今日は今日でloopback.pyをこねくり回していたのだけど、進展なし。
やれやれ。