diff --git a/docs/get-started.md b/docs/get-started.md index 4cf7468..d0c80e3 100644 --- a/docs/get-started.md +++ b/docs/get-started.md @@ -147,21 +147,24 @@ The `stat.S_IFDIR` on the file is technically optional, but is probably good pra It is not required to have a directory member file in order to have files in that directory. So this pattern is most useful to have empty directories in the ZIP. -## Password +## Password protection / encryption -The data of ZIP files can be password protected by passing a password as the `password` parameter to `stream_zip` +The data of ZIP files can be password protected / encrypted by passing a password as the `password` parameter to `stream_zip`. ```python -password_protected_zipped_chunks = stream_zip(member_files(), password='my-password'): +import secrets + +password = secrets.token_urlsafe(32) +encrypted_zipped_chunks = stream_zip(member_files(), password=password) ``` -Note: +Notes: 1. This encrypts the data with AES-256, adhering to the [WinZip AE-2 specification](https://www.winzip.com/en/support/aes-encryption/). 2. This is seen as more secure than ZipCrypto, the original mechanism of password protecting ZIP files, but fewer clients can open such ZIP files. -3. While a step forward from ZipCrypto, it has flaws that you should be aware of before using it. See ["Attacking and Repairing the WinZip Encryption Scheme" by Tadayoshi Kohno](https://homes.cs.washington.edu/~yoshi/papers/WinZip/winzip.pdf). +3. While a step forward from ZipCrypto, it has flaws that you should be aware of before using it. See ["Attacking and Repairing the WinZip Encryption Scheme" by Tadayoshi Kohno](https://homes.cs.washington.edu/~yoshi/papers/WinZip/winzip.pdf) and [fgrieu's answer to a question about WinZip's AE-1 and AE-2 on Crytography Stack Exchange](https://crypto.stackexchange.com/a/109269/113464). ## Methods diff --git a/test_stream_zip.py b/test_stream_zip.py index 17dafbb..3997b92 100644 --- a/test_stream_zip.py +++ b/test_stream_zip.py @@ -2,6 +2,7 @@ from io import BytesIO import contextlib import os +import secrets import stat import subprocess import zlib @@ -1100,7 +1101,7 @@ def test_unzip_modification_time_extended_timestamps_disabled(method, timezone, def test_password_unzips_with_stream_unzip(method): now = datetime.strptime('2021-01-01 21:01:12', '%Y-%m-%d %H:%M:%S') mode = stat.S_IFREG | 0o600 - password = 'my-pass' + password = secrets.token_urlsafe(32) files = ( ('file-1', now, mode, method, (b'a' * 9, b'b' * 9)), @@ -1127,7 +1128,7 @@ def test_password_unzips_with_stream_unzip(method): def test_bad_password_not_unzips_with_stream_unzip(method): now = datetime.strptime('2021-01-01 21:01:12', '%Y-%m-%d %H:%M:%S') mode = stat.S_IFREG | 0o600 - password = 'my-pass' + password = secrets.token_urlsafe(32) files = ( ('file-1', now, mode, method, (b'a' * 9, b'b' * 9)), @@ -1151,7 +1152,7 @@ def test_bad_password_not_unzips_with_stream_unzip(method): def test_password_unzips_with_7z(method): now = datetime.strptime('2021-01-01 21:01:12', '%Y-%m-%d %H:%M:%S') mode = stat.S_IFREG | 0o600 - password = 'my-pass' + password = secrets.token_urlsafe(32) files = ( ('file-1', now, mode, method, (b'a' * 9, b'b' * 9)), @@ -1187,7 +1188,7 @@ def test_password_unzips_with_7z(method): def test_password_unzips_with_pyzipper(method): now = datetime.strptime('2021-01-01 21:01:12', '%Y-%m-%d %H:%M:%S') mode = stat.S_IFREG | 0o600 - password = 'my-pass' + password = secrets.token_urlsafe(32) files = ( ('file-1', now, mode, method, (b'a' * 9, b'b' * 9)), @@ -1221,7 +1222,7 @@ def test_password_unzips_with_pyzipper(method): def test_password_bytes_not_deterministic(method): now = datetime.strptime('2021-01-01 21:01:12', '%Y-%m-%d %H:%M:%S') mode = stat.S_IFREG | 0o600 - password = 'my-pass' + password = secrets.token_urlsafe(32) files = ( ('file-1', now, mode, method, (b'a' * 9, b'b' * 9)), @@ -1251,7 +1252,7 @@ def test_crc_32_not_in_file(method): now = datetime.strptime('2021-01-01 21:01:12', '%Y-%m-%d %H:%M:%S') mode = stat.S_IFREG | 0o600 - password = 'my-pass' + password = secrets.token_urlsafe(32) files = ( ('file-1', now, mode, method, (b'a' * 9, b'b' * 9)),