goo blog サービス終了のお知らせ 

EverQuestできない日記

EverQuestの研究の一環として、活動記録から研究成果や攻略法、ネタばれ情報までいろいろ書いてました。

暗号化 7z 書庫 の評価

2008年02月13日 | 暗号
[ 暗号化 7z 書庫 (7-Zip) ]


対応ソフトの例
 7-Zip 4.57
 7-ZIP32.DLL Version 4.57.00.01


仕様:公開、ソース・コードが公開されてます。
 暗号アルゴリズムは Rijndael (ブロック・サイズ 128bit、鍵サイズ 256bit) です。利用モードは CBCモードです。バージョン 4.57 では IV の半分が乱数になってます。暗号鍵はパスワードとカウンターの繰り返しの SHA-256 ハッシュ値です。


評価、鍵強度:256bit、実装上の安全性:◎、処理速度:× (無圧縮なら◎)


 7-ZIP32.DLL でも基本仕様は本家 7-Zip と同じなので、書庫の仕様は本家 7-Zip のソースコードを参考にしてます。AES の実装ではブロック・サイズは 128bitですが、鍵サイズは 128, 192, 256bit の複数種類に対応できます。実際に 7z 書庫で使われるのは 256bit鍵だけですが、他の暗号化書庫にも対応するために複数使える設計になってるようです。SHA-256 の実装は Cryptopp のコードを利用しています。CRC の計算方法は ZIP などでも使われてる一般的な CRC32 と同じです。


 圧縮方法や圧縮率に関してはあまり気にしてないので、7z 書庫では処理速度が一番速いらしい「LZMA の最高速」を使って実験しました。それでも、ZIP 書庫や LHA 書庫に比べると 3倍近い差がある (当然 7-Zip の方が遅い) のが残念です。いかに圧縮率が良くてもアーカイバーとしていまいち普及してないのは、標準同士なら数倍も速度差があるせいではないかと思います。ファイルの暗号化だけが目的なら圧縮無しで暗号化することもでき、その場合の処理速度はかなり速いです。


 単純に圧縮や解凍をするだけなら、本家のコマンドライン版 (7z.exe) を使えば、簡単に 7-Zip を利用することができます。書庫の中身を確認したりするには GUI 版 (7zFM.exe) も便利です。他のソフトから 7-Zip と同等の機能を利用する為のライブラリー (7z.dll) も用意されてるのですが、インターフェースが標準的ではない COM だそうで、私には使い方が全然わかりませんでした。というか 7z.dll を使える人の方が少ないようで、日本の 7z 書庫対応ソフトでは 7-ZIP32.DLL を使ってることが多いです。7-ZIP32.DLL は統合アーカイバ仕様に基づいているので、LHA と同じようなコマンドにスイッチを書くだけで操作できます。UNLHA32.DLL を使ったことのある人なら LHA 用コードを流用できますし、他にも ZIP などの書庫を扱えたりとなかなか便利です。私が VB から動作実験する際にも 7-ZIP32.DLL を使ってます。




 ソース・コードと VB での動作実験を元に、7z 書庫の暗号化処理を調べてみました。パスワードから暗号鍵を生成する際には SHA-256 ハッシュ関数を使ってますが、単純にパスワードのハッシュ値をそのまま使ってるわけではありません。入力されたパスワードを何回も連続することで処理にかかる時間を増やして、総当り攻撃することができないようになってます。しかし、ソース・コードでは Salt を指定できるようになってるのに、なぜか実際には使ってなかったりして、今後のバージョン・アップで仕様が変わる可能性もあります。設定できるパスワードの長さに制限が無く、鍵生成の処理時間がパスワードの長さに正比例するので、CPU が非力なパソコンでは長いパスワードにしない方が身のためです。暗号鍵が 256bit (32バイト) なので、パスワードは半角英数で 32~40文字ぐらいが効果の上限でしょう。


 具体的にどうやってるのか説明しましょう。パスワードと 8バイトのカウンターを繰り返し 2の 18乗 (262144) 個並べて、そのハッシュ値を求めてます。繰り返しが 18bit 回なのにカウンターが 64bit 整数なのは、将来の拡張性を考えてるのかもしれません。とはいえ、この繰り返し回数は異常なほどの多さなので、これより更に増えることがあるかは疑問です。同じパスワードでも一ずつ増えるカウンターを挟んで何個も並べると、ハッシュ値を求める際の計算量が増えて鍵生成に時間がかかるので、パスワードを総当り攻撃しにくいです。


・入力したパスワードが1バイトの場合
(1 + 8) * 262144 = 2359296
約 2MB のハッシュ値を計算することになります。


・入力したパスワードが8バイトの場合
(8 + 8) * 262144 = 4194304
約 4MB のハッシュ値を計算することになります。


 短いパスワードでも文字数が 200~400万ぐらいに膨れ上がる訳で、これだけ長いと直接パスワードを総当り攻撃するより、32バイトのハッシュ値を攻撃した方が効率がよくなります。256bit のハッシュ値を総当り攻撃するのは現実的な時間では無理なので、Salt を使ってなくても、暗号化 7z の鍵生成方式はかなり安全性が高いです。


例えばパスワードを「abc」(Unicode では 610062006300) にすると、ハッシュ値を求める際のバイト配列の並びは
「610062006300 0000000000000000 610062006300 0100000000000000 610062006300 0200000000000000・・・」
という風に 262144 回も繰り返されます。(スペースはわかりやすいように付けただけです)
それの SHA-256 ハッシュ値が暗号鍵で、
「D44C2B6C 3F743D85 36F3ED2C C7AE6980 91EC03EF F0C3A652 E809299E DC09F684」
になります。
CBC モードの IV が全て 0 で固定されてる古いバージョンでは
「00000000 00000000 00000000 00000000, 00000000 00000000 00000000 00000000」
を暗号化すると
「BEB3170B 74331B9C CEB7474E 3668F999, 83F54E87 C905C4BE 46F317AB 0B8304B0」
になります。
新しいバージョンでは 8バイト分だけが乱数で記録されてるので、CBCモードの IVは
「080B6EE9 6913B85F 00000000 00000000」のように先頭 8バイトが変化します。
したがって、上記の例にある平文と同じ
「00000000 00000000 00000000 00000000, 00000000 00000000 00000000 00000000」
を同じパスワードで暗号化しても
「D2A7C13F 9BBD1B25 13EE9829 4C5CF6C3, D2A7C13F 9BBD1B25 13EE9829 4C5CF6C3」
と異なる暗号文になります。


 鍵生成では妙に凝ってるくせに、なぜか初期の 7z 書庫では IV が固定でしたが、最近のバージョン 4.57 では 8バイトだけ乱数になってます。古いバージョンでもファイルは圧縮されるし CBCモードなのでさほど問題になりませんが、無圧縮で暗号化だけする場合はファイルのどこまで同じかがばれます。新しいバージョンでは無圧縮で暗号化だけしても大丈夫です。ちなみに、古いバージョンでもヘッダーから IV を読み込むことには対応してるので、新しいバージョンで暗号化したファイルを古いバージョンで復号することもできます。ヘッダーに記録されてる IV のサイズは 8バイトなのに、AES のブロック・サイズは 16バイトなので、足りない 8バイト分は 0のままです。どうして、16バイト全てを乱数にして記録しないのかは謎ですが、できる限り書庫のサイズを小さくしたいということなのかもしれません。とりあえず、平文とパスワードが同じでも暗号文のパターンは 2の64乗個になるわけで、平文の内容がどこまで同じかばれる心配はほとんどありません。


 CBCモードの最終ブロックのパディングは単純に 0で埋めてます。これは、いちいちパディング・サイズを書き込まなくても、ヘッダーに書かれてるサイズを基にパディングを除去できるからです。無圧縮で暗号化だけした場合は、このパディングを基に末尾ブロックの既知平文攻撃ができるかもしれませんが、元のファイル・サイズに依存するので効果的かどうかはわかりません。下に書いてるようにヘッダーの暗号化もできるので、パディング部分はさほど気にすることはないでしょう。ちなみに、書庫への格納をファイルごとに独立して行う設定 (非ソリッド書庫) にすると、同じ書庫内の複数のファイルで別々に違うパスワードを付けたり、暗号化したりしてなかったりするファイルを混在させることも可能です。解凍時にパスワード入力を求められたからといって、その書庫の全てのファイルが暗号化されていたとは限りません。これは書庫の内容を一覧表示するアプリケーションで確認するしかありません。




 一般的なファイル暗号化ソフトとは異なり、パスワードに関する情報は一切記録されないので、復号する前にパスワードが合ってるかの検証はできません。しかし、解凍後に CRC チェックがあるので、パスワードが正しくなかったり、エラーや改竄によって暗号化された部分が 1バイトでも変化すると、「正しく復号できない」というようなエラーが発生します。なお、パスワードが異なるかが判定されるのは「ファイル全域を復号・解凍した後」になるので、CRC エラーを頼りに総当り攻撃するのは時間がかかって効率が悪いです。しかし、ただ単にパスワードを入力ミスしたぐらいで、解凍されるまで延々と待たされたあげく「パスワードが違うかもな~」とか言われることになって、精神衛生上よくないかもしれません。まあ、安全性を重視するなら時間がかかった方がいいのですが。


 7z 書庫の標準設定では「ヘッダーを暗号化しない」設定になってるので、ファイル名やサイズ、CRC がそのままファイルに書き込まれます。標準設定では複数ファイルなら自動的にヘッダーを圧縮するようになってるので、ぱっと見にはわかりにくいですが、ヘッダー部分を LZMA 解凍すれば内容はわかります。ファイルのサイズが非常に小さい時に、そのファイルの CRC が知られてしまうのは危険です。CRC からファイルの内容を逆算することができるからです。ただし、ファイル・サイズが大きくなると計算量が現実的でなくなるし、CRC が一致することが多いので、サイズが非常に小さい時だけの弱点です。この問題は「ヘッダーを暗号化する」設定にすれば解決します。ただし、ヘッダーの内容は書式が決まってるので、ヘッダーを暗号化すると既知平文攻撃される可能性があります。暗号化されたヘッダーを元に暗号鍵を総当り攻撃することはできますが、現実的な時間で 256bitの正しい暗号鍵を見つけれるかは疑問です。まあいずれ、暗号鍵の生成時に Salt が使われるようになれば、同じパスワードからでも異なる暗号鍵が生成されるようになって、暗号鍵の総当りは効果が激減するでしょう。




 結論として、暗号化 7z 書庫は圧縮速度こそ遅いですが、無圧縮で使えば非常に高速で暗号化できますし、ファイル名やチェックサムや更新日時などのヘッダー部分を暗号化することもでき、複数ファイルを一括して圧縮暗号化する目的には大変優れてます。これだけ優秀な書庫フォーマットであるにもかかわらず、ほとんど普及してないのは残念なことです。なお、ヘッダーも暗号化するように設定を変更することを忘れないようにしましょう。


最新の画像もっと見る