[ AES 暗号化 ZIP 書庫 (AES Encryption) ]
対応ソフトの例
WinZip 11 (WinZip 社)
SecureZIP Version 11.10.0022 (PKWARE 社)
Explzh v.5.24
7-Zip 4.57
7-ZIP32.DLL Version 4.57.00.01
仕様:公開、暗号化処理部分は互換性のあるソースコードが公開されてます。
標準的な ZIP 書庫の圧縮データ部分だけを暗号化したものです。暗号アルゴリズムは Rijndael (ブロック・サイズ 128bit、鍵サイズ 128 / 192 / 256bit) で、CTRモードが使われています。Gladman 博士が WinZip 方式でファイルを暗号化する例のソースコードを公開してます。パスワードから暗号鍵を生成する際や完全性チェックには HMAC-SHA-1 が使われています。
評価、鍵強度:128~160bit程度、実装上の安全性:○、処理速度:△ (無圧縮なら◎)
標準的な ZIP 書庫のフォーマットに従いつつ一部の拡張領域だけを変更してるので、従来の ZIP 圧縮・解凍アプリケーションが WinZip 9 形式に対応するのは簡単です。その割に、対応してるアプリケーションが少ないのは、暗号化の実装が中途半端なせいかもしれません。PKWARE 社の新しい暗号化方式の仕様が非公開だった為、WinZip 社が互換性のあるものを作れなくて、独自に ZIP 書庫のフォーマットを拡張して AES 暗号化を実装しました。フォーマットの変更点は最小限に抑えられていて、未対応のソフトでも圧縮形式を認識できないだけで書庫として操作することはできます。WinZip 形式の AES 暗号化 ZIP 書庫 (AE-1 / AE-2) は、教科書的な実装例をそのまま使うので暗号化処理自体にはあまり問題はありませんが、ZIP 書庫の基本的なフォーマットを維持してるので、ファイル名や CRC といったヘッダー部分が暗号化されません。そのため中途半端というか、PKWARE 社の暗号化方式に比べると安全性ではどうしても劣ってしまいます。仕様が公開されていて実装も容易であるにもかかわらず、ほとんど普及してないのは仕方ないのかもしれません。
WinZip 形式の AES 暗号化 ZIP 書庫の暗号化方式は AE-1 と AE-2 の二種類があります。違いは CRC を記録するかしないかという点だけです。AE-2 方式では完全性チェックには HMAC-SHA1 だけを使い、AE-1 方式では従来の CRC も併用します。WinZip 9/10 では安全性を重視して AE-2 が使われていて、AE-1 はオプションでした。そのため、一般に WinZip 9 互換の AES 暗号化 ZIP 書庫というと AE-2 形式であるようです。しかし、WinZip 11 ではユーザーの利便性を考えたのか、サイズの小さくないファイルに対してはAE-1 方式を使うように変更されています。CRC を記録することで正しく復号解凍できたかを二重にチェックできますが、暗号化されていてもファイルが同じかどうかを識別することができるようにもなります。ここらへんがまた WinZip 方式の中途半端さの象徴というかなんというか、どうも完全な秘匿性よりも使い勝手を重視する傾向があるように感じます。オリジナルの暗号化 ZIP 書庫の暗号化がしょぼいのは明白なのですが、それに対して暗号化アルゴリズムを AES に変えれば解決するのか?、というと抜本的な修正無しには解決できなかったということです。まあ、WinZip が ZIP フォーマットの本家でない以上、大幅な修正ができなかったのは仕方ないことで、サードパーティー企業の悲哀を感じさせてくれます。
暗号化方式の詳細は例示されてるソースコードを見ればわかりますが、とりあえず、簡単に解説しておきます。乱数を作るにあたっては SHA-1 を使った乱数生成器が使われます。乱数の初期値はアプリケーションに依存してますが、CPU クロックを取得するのが一般的みたいです。パスワードから暗号鍵や HMAC鍵を生成するには HMAC-SHA-1 を利用した鍵生成関数 (PBKDF2-HMAC-SHA1) が使われます。PBKDF2-HMAC-SHA1 では パスワードと Salt (毎回異なる乱数) からハッシュ関数を繰り返して毎回異なる暗号鍵を計算します。繰り返し回数は最低ラインの 1000回のようですが、これでも単純なハッシュ値を暗号鍵にする方式に比べれば、総当り攻撃に対しては 1000倍強固と言えます。PKZIP ストリーム暗号よりも SHA-1 の方が計算量が多いので一概には言えませんが、ZIP 書庫をパスワードで総当り攻撃する場合は AES 暗号化書庫なら同じパスワードに対しても 1000倍以上時間がかかるということです。繰り返し回数は総当り攻撃に対する強度と処理速度の兼ね合いですが、そもそも繰り返し回数の多さはパスワードに対する総当り攻撃を防ぐ役には立っても、暗号鍵自体を総当り攻撃されれば意味が無いです。ちなみに、PBKDF2 では HMAC-SHA-1 を使ってるので、64バイトより長いパスワードを使うと 20バイトに短縮されてしまい、パスワードは半角英数で 64文字 (日本語の 2バイト文字なら 32文字) までしか意味が無く、暗号鍵の強度も 160bit 程度に制限されます。
パスワードが同じでも実際に暗号化に使われる鍵は毎回異なるというのが特徴で、暗号鍵を総当り攻撃で突き止められても被害が他に及ぶことがありません。WinZip 方式で CTRモードの初期値が乱数ではなく全て 0 になってるのは、この暗号鍵が毎回異なるはずというのが前提条件になってます。CTRモードではブロック暗号をストリーム暗号と同じ使い勝手で使うことになり、カウンターで変化する値と暗号鍵から乱数ストリームが生成されて、それと平文が XOR されて暗号文になります。したがって、初期値と暗号鍵が同じだと、解読される危険があります。Gladman 博士のソースコードを見ると「乱数性を持たせたいならここで乱数をセットしなさい」と注釈があるのですが、WinZip 方式では暗号鍵の乱数性に頼ることにしたのかもしれません。CTRモードのカウンターは 8バイト (64bit) なので、2 の 64乗ブロックまで乱数の再利用は無く、ファイルの暗号化には充分です。完全性チェックのために、暗号化した後のデータの HMAC-SHA-1 が計算されていて、その結果の先頭 10バイトがファイルに書き込まれます。毎回異なる鍵を使った HMAC 値なので、この値からオリジナル・ファイルの内容を推測するのは困難です。PBKDF2 の出力は鍵サイズ(AES-128 なら 16バイト、AES-256 なら 32バイト) によって変わり、「鍵サイズ * 2 + 2 」になります。これが順に、暗号鍵と HMAC鍵、パスワード・チェック用の値になります。実際に WinZip が Gladman 博士のコードを使ってるかはわかりませんが、Gladman 博士のコードを使えば互換性のあるものは容易に作れるそうです。
実際にファイルを 256bit の AES 暗号化してデータの処理を追ってみました。
パスワードを「abc」にしたので、このバイナリ値は 16進数表記で「616263」です。
Salt は乱数で作られてファイルに書き込まれるので、それを探してみると
「8D7D0494 BA870411 974670B5 8ECD7062」でした。
これらのパスワードと Salt から PBKDF2-HMAC-SHA-1 関数を使って得た 32 * 2 + 2 = 66バイトの出力が
「A8EE7098 8735FEC3 669E78F1 EBDEB087 A700A2C7 79995AF3 1F7412F1 1E77DAF8」
「8FE5D8BE 40A3CB10 77108A0D 844EA0D3 F0FE9330 26343E83 A67D3241 0776BA82」
「CDE5」となりました。
最初の 32バイトが暗号化の鍵、次の 32バイトが HMAC鍵、最後の 2バイトがパスワード検証用の値になります。
実際にファイルに記録されてるパスワード検証用の値も
「CDE5」でした。
ファイルに記録されてる乱数ストリームを暗号鍵で復号すると、CTRモードのカウンターが
「01000000 00000000 00000000 00000000」
「02000000 00000000 00000000 00000000」
「03000000 00000000 00000000 00000000」
と順に一ずつ増えてることも確認できました。
完全性チェック用の署名は暗号文の HMAC の先頭 10バイトで、これも別に計算した通りの値が記録されてました。まあ、ソースコードが公開されてるので処理がその通りなのは当然ですが、WinZip 9 の暗号化処理の流れは確認できました。
WinZip 方式の問題点については英語の論文「 Analysis of the WinZip encryption method (Tadayoshi Kohno) 」に詳しく書いてあります。この Tadayoshi Kohno (漢字不明) という暗号学者は日本風の名前ですが、日本人ではなく日系アメリカ人だそうです。学者というと、雲の上で庶民と関係の無いことばかり研究してる大学教授やら、利益になることしか研究できない企業の御用学者を思い浮かべる所ですが、意外に普通のアプリケーションの研究もされてるのかと感心しました。日本では暗号研究は企業の製品開発のために行うのが普通みたいで、こういう利益にならない研究はなかなかしてくれないのが残念です。まあ、逆に言うとアメリカでいかに ZIP 書庫が普及していて WinZip の影響が大きいかということです。指摘されてる WinZip 方式 (AE-2) の問題点をいくつか解説しておきます。
・暗号化されたファイルからの情報漏洩
オリジナル・ファイルのファイル名や日付、平文や暗号文のサイズ、CRC などは暗号化されません。これらはファイルの内容を推測する手がかりになります。
・圧縮と暗号化の間の相互関係
圧縮と暗号化が完全に独立していて、正しく復号できたかは確認できますが、正しく解凍できたかは確認できません。暗号化されたファイルのヘッダーを改竄することで、パスワードが正しくて正常に復号できたように見えても正しく解凍できないようにできます。
・ファイル名と関連付け
ファイル名は暗号化されませんが、それだけではなくファイル名が改竄されていないかを確認することもできません。正しいパスワードで正常に解凍できたとしても、ファイル名が改竄されていて関連付けでうまく開けなくなる可能性があります。
・AE-1 と選択プロトコル攻撃の相互関係
AE-2 方式では CRC を記録しませんが、WinZip では AE-1 方式も使えます。AE-2 方式で暗号化されたファイルに推測した CRC 値を追加して、あえて AE-1 方式で復号させるように仕向けることで、その CRC 値が正しいかを確かめることができます。
・暗号化されたファイルとされてないファイルを含む書庫
ZIP 書庫はファイル単位で暗号化するので、解凍時にパスワードを必要として正しく復号できたからといって、全てのファイルが暗号化されていて改竄されてないとは限りません。第三者が暗号化された書庫の中に悪意のあるファイルを紛れ込ませることは可能です。
・鍵の衝突と鍵ストリームの再利用
パスワードが同じでも異なる暗号鍵が生成されるように設計されてますが、その際の Salt のサイズがあまり大きくありません。128bit 鍵を使う場合の Salt は 8バイト (64bit) なので、同じパスワードでだいたい 2 の 32乗個のファイルを暗号化すれば確率的には同じ鍵が生成される計算になります。CTRモードの初期値が固定されてる為、同じ鍵からは同じ鍵ストリームが作られてしまい、解読される危険性があります。( WinZip の仕様書には、同じパスワードで何百万個ものファイルを暗号化するなら、192bit や 256bit の鍵を使うようにと書いてあります。)
実際に使う上で問題になるかもしれないのは、ファイル名が暗号化されないということでしょうか。他のファイル圧縮暗号化ソフトではファイル名まで暗号化するのが長所になってるので、一概に脆弱性とは言えませんがマイナス・ポイントになります。フリーのファイル暗号化ソフトで完全性チェックをきちんとやってるものはほとんど無いので、ファイル名の改竄検知機能まで必要かどうかはわかりません。しかしまあ、一般ユーザーにとってはパスワードで暗号化してあったファイルが、エラー無しに正しく復号できたら、そのファイルは暗号化する前の状態に戻ってると思い込むのは普通です。ファイルの圧縮・解凍では正しく解凍できたかソフトの方で自動的に確認するのは当然ですし。暗号化したファイルを改竄されたせいで元通りに復号できなかったのなら、正しく復号できなかったとユーザーに通知するのが筋でしょう。まあ、学者だけに細かい点まで指摘していて、暗号関連の製品を設計する際の参考になることは確かです。
結論として、WinZip 互換の AES 暗号化 ZIP 書庫は、従来の暗号化 ZIP 書庫よりはずっと安全ですが、完全に情報を秘匿できるわけではありません。ファイルの内容さえ秘密にできればいいという用途には便利そうですが、対応してるZIP 圧縮・解凍アプリケーションが少ないのが一番の問題です。
対応ソフトの例
WinZip 11 (WinZip 社)
SecureZIP Version 11.10.0022 (PKWARE 社)
Explzh v.5.24
7-Zip 4.57
7-ZIP32.DLL Version 4.57.00.01
仕様:公開、暗号化処理部分は互換性のあるソースコードが公開されてます。
標準的な ZIP 書庫の圧縮データ部分だけを暗号化したものです。暗号アルゴリズムは Rijndael (ブロック・サイズ 128bit、鍵サイズ 128 / 192 / 256bit) で、CTRモードが使われています。Gladman 博士が WinZip 方式でファイルを暗号化する例のソースコードを公開してます。パスワードから暗号鍵を生成する際や完全性チェックには HMAC-SHA-1 が使われています。
評価、鍵強度:128~160bit程度、実装上の安全性:○、処理速度:△ (無圧縮なら◎)
標準的な ZIP 書庫のフォーマットに従いつつ一部の拡張領域だけを変更してるので、従来の ZIP 圧縮・解凍アプリケーションが WinZip 9 形式に対応するのは簡単です。その割に、対応してるアプリケーションが少ないのは、暗号化の実装が中途半端なせいかもしれません。PKWARE 社の新しい暗号化方式の仕様が非公開だった為、WinZip 社が互換性のあるものを作れなくて、独自に ZIP 書庫のフォーマットを拡張して AES 暗号化を実装しました。フォーマットの変更点は最小限に抑えられていて、未対応のソフトでも圧縮形式を認識できないだけで書庫として操作することはできます。WinZip 形式の AES 暗号化 ZIP 書庫 (AE-1 / AE-2) は、教科書的な実装例をそのまま使うので暗号化処理自体にはあまり問題はありませんが、ZIP 書庫の基本的なフォーマットを維持してるので、ファイル名や CRC といったヘッダー部分が暗号化されません。そのため中途半端というか、PKWARE 社の暗号化方式に比べると安全性ではどうしても劣ってしまいます。仕様が公開されていて実装も容易であるにもかかわらず、ほとんど普及してないのは仕方ないのかもしれません。
WinZip 形式の AES 暗号化 ZIP 書庫の暗号化方式は AE-1 と AE-2 の二種類があります。違いは CRC を記録するかしないかという点だけです。AE-2 方式では完全性チェックには HMAC-SHA1 だけを使い、AE-1 方式では従来の CRC も併用します。WinZip 9/10 では安全性を重視して AE-2 が使われていて、AE-1 はオプションでした。そのため、一般に WinZip 9 互換の AES 暗号化 ZIP 書庫というと AE-2 形式であるようです。しかし、WinZip 11 ではユーザーの利便性を考えたのか、サイズの小さくないファイルに対してはAE-1 方式を使うように変更されています。CRC を記録することで正しく復号解凍できたかを二重にチェックできますが、暗号化されていてもファイルが同じかどうかを識別することができるようにもなります。ここらへんがまた WinZip 方式の中途半端さの象徴というかなんというか、どうも完全な秘匿性よりも使い勝手を重視する傾向があるように感じます。オリジナルの暗号化 ZIP 書庫の暗号化がしょぼいのは明白なのですが、それに対して暗号化アルゴリズムを AES に変えれば解決するのか?、というと抜本的な修正無しには解決できなかったということです。まあ、WinZip が ZIP フォーマットの本家でない以上、大幅な修正ができなかったのは仕方ないことで、サードパーティー企業の悲哀を感じさせてくれます。
暗号化方式の詳細は例示されてるソースコードを見ればわかりますが、とりあえず、簡単に解説しておきます。乱数を作るにあたっては SHA-1 を使った乱数生成器が使われます。乱数の初期値はアプリケーションに依存してますが、CPU クロックを取得するのが一般的みたいです。パスワードから暗号鍵や HMAC鍵を生成するには HMAC-SHA-1 を利用した鍵生成関数 (PBKDF2-HMAC-SHA1) が使われます。PBKDF2-HMAC-SHA1 では パスワードと Salt (毎回異なる乱数) からハッシュ関数を繰り返して毎回異なる暗号鍵を計算します。繰り返し回数は最低ラインの 1000回のようですが、これでも単純なハッシュ値を暗号鍵にする方式に比べれば、総当り攻撃に対しては 1000倍強固と言えます。PKZIP ストリーム暗号よりも SHA-1 の方が計算量が多いので一概には言えませんが、ZIP 書庫をパスワードで総当り攻撃する場合は AES 暗号化書庫なら同じパスワードに対しても 1000倍以上時間がかかるということです。繰り返し回数は総当り攻撃に対する強度と処理速度の兼ね合いですが、そもそも繰り返し回数の多さはパスワードに対する総当り攻撃を防ぐ役には立っても、暗号鍵自体を総当り攻撃されれば意味が無いです。ちなみに、PBKDF2 では HMAC-SHA-1 を使ってるので、64バイトより長いパスワードを使うと 20バイトに短縮されてしまい、パスワードは半角英数で 64文字 (日本語の 2バイト文字なら 32文字) までしか意味が無く、暗号鍵の強度も 160bit 程度に制限されます。
パスワードが同じでも実際に暗号化に使われる鍵は毎回異なるというのが特徴で、暗号鍵を総当り攻撃で突き止められても被害が他に及ぶことがありません。WinZip 方式で CTRモードの初期値が乱数ではなく全て 0 になってるのは、この暗号鍵が毎回異なるはずというのが前提条件になってます。CTRモードではブロック暗号をストリーム暗号と同じ使い勝手で使うことになり、カウンターで変化する値と暗号鍵から乱数ストリームが生成されて、それと平文が XOR されて暗号文になります。したがって、初期値と暗号鍵が同じだと、解読される危険があります。Gladman 博士のソースコードを見ると「乱数性を持たせたいならここで乱数をセットしなさい」と注釈があるのですが、WinZip 方式では暗号鍵の乱数性に頼ることにしたのかもしれません。CTRモードのカウンターは 8バイト (64bit) なので、2 の 64乗ブロックまで乱数の再利用は無く、ファイルの暗号化には充分です。完全性チェックのために、暗号化した後のデータの HMAC-SHA-1 が計算されていて、その結果の先頭 10バイトがファイルに書き込まれます。毎回異なる鍵を使った HMAC 値なので、この値からオリジナル・ファイルの内容を推測するのは困難です。PBKDF2 の出力は鍵サイズ(AES-128 なら 16バイト、AES-256 なら 32バイト) によって変わり、「鍵サイズ * 2 + 2 」になります。これが順に、暗号鍵と HMAC鍵、パスワード・チェック用の値になります。実際に WinZip が Gladman 博士のコードを使ってるかはわかりませんが、Gladman 博士のコードを使えば互換性のあるものは容易に作れるそうです。
実際にファイルを 256bit の AES 暗号化してデータの処理を追ってみました。
パスワードを「abc」にしたので、このバイナリ値は 16進数表記で「616263」です。
Salt は乱数で作られてファイルに書き込まれるので、それを探してみると
「8D7D0494 BA870411 974670B5 8ECD7062」でした。
これらのパスワードと Salt から PBKDF2-HMAC-SHA-1 関数を使って得た 32 * 2 + 2 = 66バイトの出力が
「A8EE7098 8735FEC3 669E78F1 EBDEB087 A700A2C7 79995AF3 1F7412F1 1E77DAF8」
「8FE5D8BE 40A3CB10 77108A0D 844EA0D3 F0FE9330 26343E83 A67D3241 0776BA82」
「CDE5」となりました。
最初の 32バイトが暗号化の鍵、次の 32バイトが HMAC鍵、最後の 2バイトがパスワード検証用の値になります。
実際にファイルに記録されてるパスワード検証用の値も
「CDE5」でした。
ファイルに記録されてる乱数ストリームを暗号鍵で復号すると、CTRモードのカウンターが
「01000000 00000000 00000000 00000000」
「02000000 00000000 00000000 00000000」
「03000000 00000000 00000000 00000000」
と順に一ずつ増えてることも確認できました。
完全性チェック用の署名は暗号文の HMAC の先頭 10バイトで、これも別に計算した通りの値が記録されてました。まあ、ソースコードが公開されてるので処理がその通りなのは当然ですが、WinZip 9 の暗号化処理の流れは確認できました。
WinZip 方式の問題点については英語の論文「 Analysis of the WinZip encryption method (Tadayoshi Kohno) 」に詳しく書いてあります。この Tadayoshi Kohno (漢字不明) という暗号学者は日本風の名前ですが、日本人ではなく日系アメリカ人だそうです。学者というと、雲の上で庶民と関係の無いことばかり研究してる大学教授やら、利益になることしか研究できない企業の御用学者を思い浮かべる所ですが、意外に普通のアプリケーションの研究もされてるのかと感心しました。日本では暗号研究は企業の製品開発のために行うのが普通みたいで、こういう利益にならない研究はなかなかしてくれないのが残念です。まあ、逆に言うとアメリカでいかに ZIP 書庫が普及していて WinZip の影響が大きいかということです。指摘されてる WinZip 方式 (AE-2) の問題点をいくつか解説しておきます。
・暗号化されたファイルからの情報漏洩
オリジナル・ファイルのファイル名や日付、平文や暗号文のサイズ、CRC などは暗号化されません。これらはファイルの内容を推測する手がかりになります。
・圧縮と暗号化の間の相互関係
圧縮と暗号化が完全に独立していて、正しく復号できたかは確認できますが、正しく解凍できたかは確認できません。暗号化されたファイルのヘッダーを改竄することで、パスワードが正しくて正常に復号できたように見えても正しく解凍できないようにできます。
・ファイル名と関連付け
ファイル名は暗号化されませんが、それだけではなくファイル名が改竄されていないかを確認することもできません。正しいパスワードで正常に解凍できたとしても、ファイル名が改竄されていて関連付けでうまく開けなくなる可能性があります。
・AE-1 と選択プロトコル攻撃の相互関係
AE-2 方式では CRC を記録しませんが、WinZip では AE-1 方式も使えます。AE-2 方式で暗号化されたファイルに推測した CRC 値を追加して、あえて AE-1 方式で復号させるように仕向けることで、その CRC 値が正しいかを確かめることができます。
・暗号化されたファイルとされてないファイルを含む書庫
ZIP 書庫はファイル単位で暗号化するので、解凍時にパスワードを必要として正しく復号できたからといって、全てのファイルが暗号化されていて改竄されてないとは限りません。第三者が暗号化された書庫の中に悪意のあるファイルを紛れ込ませることは可能です。
・鍵の衝突と鍵ストリームの再利用
パスワードが同じでも異なる暗号鍵が生成されるように設計されてますが、その際の Salt のサイズがあまり大きくありません。128bit 鍵を使う場合の Salt は 8バイト (64bit) なので、同じパスワードでだいたい 2 の 32乗個のファイルを暗号化すれば確率的には同じ鍵が生成される計算になります。CTRモードの初期値が固定されてる為、同じ鍵からは同じ鍵ストリームが作られてしまい、解読される危険性があります。( WinZip の仕様書には、同じパスワードで何百万個ものファイルを暗号化するなら、192bit や 256bit の鍵を使うようにと書いてあります。)
実際に使う上で問題になるかもしれないのは、ファイル名が暗号化されないということでしょうか。他のファイル圧縮暗号化ソフトではファイル名まで暗号化するのが長所になってるので、一概に脆弱性とは言えませんがマイナス・ポイントになります。フリーのファイル暗号化ソフトで完全性チェックをきちんとやってるものはほとんど無いので、ファイル名の改竄検知機能まで必要かどうかはわかりません。しかしまあ、一般ユーザーにとってはパスワードで暗号化してあったファイルが、エラー無しに正しく復号できたら、そのファイルは暗号化する前の状態に戻ってると思い込むのは普通です。ファイルの圧縮・解凍では正しく解凍できたかソフトの方で自動的に確認するのは当然ですし。暗号化したファイルを改竄されたせいで元通りに復号できなかったのなら、正しく復号できなかったとユーザーに通知するのが筋でしょう。まあ、学者だけに細かい点まで指摘していて、暗号関連の製品を設計する際の参考になることは確かです。
結論として、WinZip 互換の AES 暗号化 ZIP 書庫は、従来の暗号化 ZIP 書庫よりはずっと安全ですが、完全に情報を秘匿できるわけではありません。ファイルの内容さえ秘密にできればいいという用途には便利そうですが、対応してるZIP 圧縮・解凍アプリケーションが少ないのが一番の問題です。