あるCTFでこれを使った問題が出ていたので勉強のために.
zlibで圧縮したものを暗号化する場合, 平文と暗号文の長さが同じになるアルゴリズムを使うのは危ないよという話. 例えばAES-CTRとかRC4とか.
16bytes等のパディングをした方が良さそう.
基本的な内容は以下のサイトに書いてある.
要するに,
data = zlib.compress(SECRET + your_input)
dataがわかるとき, 同じ文字列が複数回含まれるデータをzlib圧縮すると圧縮後のデータ数が小さくなるのを利用してSECRETが何かを推測することができる.
例えば
SECRET が "koresuki" であるとして
c1 = "koresuki" + "a" * 20
c2 = "koresuki" + "b" * 20
...
"koresuki" + [a-z]を20回繰り返した文字列 を c1, c2, ...
それぞれ圧縮して長さを見てみると
"koresuki" + "i" * 20
のときだけ小さくなる.
最後の文字が "i" であることがわかったので, 次は
"koresuk" + "[a-z] + i" * 20
を試すと "ki" が得られる.
これを繰り返していくと SECRET を得ることができる.
以上を踏まえて検証してみた.
それぞれの文字を与えたときの圧縮後のデータ長を確認して最も小さいものを候補としている.
このコードだとSECRETに連続して同じ文字が使われている場合に対応できないので注意.
実行結果は
[('a', 26), ('b', 26), ('c', 26), ('d', 26), ('e', 26)]
augimugi_suko
1文字目が復元できていないが, SECRET = "secret_mugimugi_suko" となっていればちゃんと
[('m', 31), ('a', 32), ('b', 32), ('c', 32), ('d', 32)]
mugimugi_suko
:ok_hand:
むぎむぎすこだぞ