You can now use https://github.com/uktrade/stream-zip (full disclosure: made/maintained mostly by me) to make AES-256 encrypted ZIP files that adhere to WinZip's AE-2 spec.
A small bit of specific documentation is at https://stream-zip.docs.trade.gov.uk/advanced-usage/#password-protection-%2F-encryption, but to make a fully working example:
import secrets
from datetime import datetime
from stat import S_IFREG
from stream_zip import ZIP_32, stream_zip
member_files = (
(
'my-file-1.txt', # File name
datetime.now(), # Modification time
S_IFREG | 0o600, # Mode - regular file that owner can read and write
ZIP_32, # ZIP_32 has good support but limited to 4GiB
(b'Some bytes 1',), # Iterable of chunks of contents
),
(
'my-file-2.txt',
datetime.now(),
S_IFREG | 0o600,
ZIP_32,
(b'Some bytes 2',),
),
)
# Should use a long and random password
password = secrets.token_urlsafe(32)
encrypted_zipped_chunks = stream_zip(member_files, password=password)
with open('password-protected-zip', 'wb') as f:
for encrypted_zipped_chunk in encrypted_zipped_chunks:
f.write(encrypted_zipped_chunk)
This example the source data is hard coded in memory, and then saves the ZIP disk, but this isn't required by stream-zip. The source data has to be an iterable of bytes
, and then can be sent do any code that accepts an iterable of bytes
instances.
Warning AE-2 is better than ZipCryto, but it has flaws and so isn't suitable for all cases. Very briefly:
- Metadata (like file names) are not encrypted
- If someone can intercept the ZIP and replace parts of it, this can go undetected and can itself lead to information leakage
- The more files there are in the ZIP, then there is a higher risk of information leakage. But for AES-256 like in stream-zip, the risk is probably low enough to be acceptable for most use cases.
See “Attacking and Repairing the WinZip Encryption Scheme” by Tadayoshi Kohno for more details