暗号化Zipファイルは本当に危険なのか?

最近、PPAPとかZip暗号化とかが色々言われているので書きます。

**結論** `ZipCryptio`と呼ばれる標準の暗号化は**脆弱**です。7-zipで使える`wzAES`を使いましょう。ただしWindowsの標準機能では復号化できませんが。

# 暗号化Zipファイルの仕様について

[Zipファイルの仕様](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)によれば、Zipファイルは以下のような構造になっています。

```
[local file header 1]
[encryption header 1]
[file data 1]
[data descriptor 1]
. 
.
.
[local file header n]
[encryption header n]
[file data n]
[data descriptor n]
[archive decryption header] 
[archive extra data record] 
[central directory header 1]
.
.
.
[central directory header n]
[zip64 end of central directory record]
[zip64 end of central directory locator] 
[end of central directory record]
```

ここで関係するのは`[local file header]`及び`[encryption header]`、`[archive decryption header]`です。

## local file headerについて

`[local file header]`の定義は以下になります。

```
local file header signature     4 bytes  (0x04034b50)
version needed to extract       2 bytes
general purpose bit flag        2 bytes
compression method              2 bytes
last mod file time              2 bytes
last mod file date              2 bytes
crc-32                          4 bytes
compressed size                 4 bytes
uncompressed size               4 bytes
file name length                2 bytes
extra field length              2 bytes

file name (variable size)
extra field (variable size)
```

ここで関係するのが、`general purpose bit flag`及び`compression method`です。

### general purpose bit flagについて

関係ある部分のみ抜き出します。

```
        Bit 0: If set, indicates that the file is encrypted.
        Bit 6: Strong encryption.  If this bit is set, you MUST
               set the version needed to extract value to at least
               50 and you MUST also set bit 0.  If AES encryption
               is used, the version needed to extract value MUST 
               be at least 51. See the section describing the Strong
               Encryption Specification for details.  Refer to the 
               section in this document entitled "Incorporating PKWARE 
               Proprietary Technology into Your Product" for more 
               information.
```

ここで、`BIT 0`はすべての暗号化されたファイルで有効になっています。`BIT 0`が有効かつ`BIT 6`が有効な場合、`StrongCrypto`と呼ばれる暗号アルゴリズムが用いられれます。`BIT 6`が有効でない場合、後述するように`compression method`に暗号アルゴリズムが入っています。

### compression method

この辺りはzipファイルの処理系に大きく依存していますが、たとえば`7-zip`(`7z`や`p7zip`などとも呼ばれる)の場合、以下のドキュメントに記述されています

[7-Zip method IDs for 7z and xz archives](https://github.com/kornelski/7z/blob/cb75c2b5bf0d347114d59ff7ba9b51d435c01e40/DOC/Methods.txt#L83-95)

関係ある部分を抜き出します。

```
      00 - Copy (not used. Use {00} instead)
      01 - Shrink
      06 - Implode
      08 - Deflate
      09 - Deflate64
      0A - Imploding
      0C - BZip2 (not used. Use {040202} instead)
      0E - LZMA (LZMA-zip)
      5F - xz
      60 - Jpeg
      61 - WavPack
      62 - PPMd (PPMd-zip)
      63 - wzAES
```

この中で、暗号化に係るのは`0x63 - wzAES`です。すなわち、`local header`内の`compression method`が`0x63`の時は暗号アルゴリズムとしてwzAESが選択されます。それ以外の場合は`ZipCrypto`と呼ばれる古いアルゴリズムが用いられます。

## encryption header について

`ZipCrypto`が選択される場合、encryption headerが各ファイルのヘッダ(`[local file header]`)と`[file data]`の間に追加されます。これは128bitの乱数を暗号化したものとなっています。ユーザーが入力したキーは`encryption header`の暗号化に用いられ、データ自体の暗号化にはこの128bitの乱数が使われることになります。

```
    6.1.3 Each encrypted file has an extra 12 bytes stored at the start 
    of the data area defining the encryption header for that file.  The
    encryption header is originally set to random values, and then
    itself encrypted, using three, 32-bit keys.  The key values are
    initialized using the supplied encryption password.  After each byte
    is encrypted, the keys are then updated using pseudo-random number
    generation techniques in combination with the same CRC-32 algorithm
    used in PKZIP and described elsewhere in this document.

    6.1.4 The following are the basic steps required to decrypt a file:

    1) Initialize the three 32-bit keys with the password.
    2) Read and decrypt the 12-byte encryption header, further
       initializing the encryption keys.
    3) Read and decrypt the compressed data stream using the
       encryption keys.
```

## archive decryption headerについて

一方、`StrongCryptio`の場合は以下のヘッダがファイル末尾に追加されます。

```
        Value     Size     Description
        -----     ----     -----------
        0x0017    2 bytes  Tag for this "extra" block type
        TSize     2 bytes  Size of data that follows
        Format    2 bytes  Format definition for this record
        AlgID     2 bytes  Encryption algorithm identifier
        Bitlen    2 bytes  Bit length of encryption key
        Flags     2 bytes  Processing flags
        CertData  TSize-8  Certificate decryption extra field data
                           (refer to the explanation for CertData
                            in the section describing the 
                            Certificate Processing Method under 
                            the Strong Encryption Specification)
```

しかし、[ZIPのより強力な暗号はPKWARE社が特許を持っていて、エクスプローラーには復号処理が実装されていない。](https://qiita.com/kusano_k/items/f945b6a7fd150bae23b7)という事なので、Windows エクスプローラでも各種OSSでも`StrongCrypto`を復号化することはできないでしょう。

# まとめ

`ZipCrypto`は暗号キーが実質`128bit`しかないので危険。使うなら`wzAES`を使いましょう。
(`StrongCrypto`は多分使えないと思うので)

# 追記

`ZipCryptio`の場合、[キーの長さ以前に以下の致命的な脆弱性がある](https://twitter.com/_yyu_/status/1335496360620040195)ようです。

BIHAM, Eli; KOCHER, Paul C. A known plaintext attack on the PKZIP stream cipher. In: International Workshop on Fast Software Encryption. Springer, Berlin, Heidelberg, 1994. p. 144-153.

# 追記2 既存Zipファイルの暗号化アルゴリズムの確認方法

```bash
$ 7z l -slt file.zip
...snip...
Encrypted = +
...snip...
Method = ZipCrypto Deflate
```