Install pyzipper via pip
masterInstall the pyzipper package using pip to enable AES encrypted zip file support in Python.
pip install pyzipperrepository·master·Indexed 40 days ago
https://github.com/danifus/pyzipperA replacement for Python's built-in zipfile module that adds support for reading and writing AES encrypted ZIP files while maintaining compatibility with the Python 3.7 zipfile API. It provides the AESZipFile class for WinZip AES encryption, supporting strengths of 128, 192, or 256 bits and WinZip AES versions V1 and V2.
Install the pyzipper package using pip to enable AES encrypted zip file support in Python.
pip install pyzipperThe library supports two versions of the WinZip AES specification, primarily differing in how they handle CRC (Cyclic Redundancy Check) values:
ZIP_BZIP2 because BZIP2 has its own integrity checks.You can force a version using force_wz_aes_version in the encryption configuration, or use conditionally_include_crc to switch between them based on file size.
Use pyzipper.AESZipFile as a drop-in replacement for Python's zipfile.ZipFile. To create an encrypted archive, specify encryption=pyzipper.WZ_AES in the constructor or use setencryption(), and provide a password via setpassword(). To read an encrypted archive, open it with AESZipFile and call setpassword() before attempting to read contents.
import pyzipper
secret_password = b'lost art of keeping a secret'
# Writing an encrypted file
with pyzipper.AESZipFile('new_test.zip',
'w',
compression=pyzipper.ZIP_LZMA,
encryption=pyzipper.WZ_AES) as zf:
zf.setpassword(secret_password)
zf.writestr('test.txt', "What ever you do, don't tell anyone!")
# Reading an encrypted file
with pyzipper.AESZipFile('new_test.zip') as zf:
zf.setpassword(secret_password)
my_secrets = zf.read('test.txt')From pyzipper v0.4.0 onwards, CRC32 values are not included in file headers by default to prevent information leakage about small files. You can conditionally enable CRC32 inclusion for files that meet a minimum uncompressed size threshold using setencryption() with the conditionally_include_crc and min_bytes_to_include_crc parameters. The recommended minimum for min_bytes_to_include_crc is 20.
with pyzipper.AESZipFile(
'new_test.zip',
'w',
compression=pyzipper.ZIP_LZMA,
) as zf:
zf.setencryption(
pyzipper.WZ_AES,
conditionally_include_crc=True,
min_bytes_to_include_crc=20, # Replace with your desired threshold
)
...You can specify the AES encryption strength (bit length) using the setencryption() method. Supported values for nbits are 128, 192, or 256. The default strength is 256 bits.
import pyzipper
secret_password = b'lost art of keeping a secret'
with pyzipper.AESZipFile('new_test.zip',
'w',
compression=pyzipper.ZIP_LZMA) as zf:
zf.setpassword(secret_password)
zf.setencryption(pyzipper.WZ_AES, nbits=256)
zf.writestr('test.txt', "What ever you do, don't tell anyone!")When creating an encrypted ZIP file using AESZipFile(..., encryption=WZ_AES), you can pass additional configuration via encryption_kwargs. These arguments are passed directly to the AESZipEncrypter constructor.
Available options for AESZipEncrypter:
nbits: The AES strength. Must be one of 128, 192, or 256. (Default is 256).force_wz_aes_version: Forces a specific WinZip AES version. Can be 1 (WZ_AES_V1) or 2 (WZ_AES_V2).conditionally_include_crc: If True, the CRC is included in the header only if the file size meets the min_bytes_to_include_crc threshold. This helps prevent leaking content info for small files.min_bytes_to_include_crc: The minimum file size (in bytes) required to include the CRC when conditionally_include_crc is True. Must be 20 or greater.from pyzipper import AESZipFile, WZ_AES
encryption_options = {
'nbits': 128,
'conditionally_include_crc': True,
'min_bytes_to_include_crc': 32
}
with AESZipFile('secure.zip', 'w',
encryption=WZ_AES,
pwd=b'password',
encryption_kwargs=encryption_options) as zf:
zf.write('data.txt')For ZIP archives using PKWARE password-based encryption, use the CRCZipDecrypter.
Usage Pattern:
ZipInfo object, the password, and the encryption header..decrypt(cypher_bytes) to get the plaintext bytes.Note: The first 12 bytes of the cypher stream is an encryption header used to strengthen the algorithm.
from pyzipper import CRCZipDecrypter
# zd = CRCZipDecrypter(zinfo, mypwd, encryption_header)
# plain_bytes = zd.decrypt(cypher_bytes)Use these methods to explore the contents of a ZipFile:
namelist(): Returns a list of file names in the archive.infolist(): Returns a list of ZipInfo instances for all files in the archive.getinfo(name): Returns the ZipInfo instance for a specific file name. Raises KeyError if not found.printdir(): Prints a formatted table of contents to stdout.with pyzipper.ZipFile('example.zip', mode='r') as zf:
# Get names
print(zf.namelist())
# Get detailed info
for info in zf.infolist():
print(f"{info.filename}: {info.file_size} bytes")
# Get specific info
info = zf.getinfo('data.txt')
print(info.compress_type)Use the ZipFile class to manage ZIP archives. You can open an existing archive or create a new one by specifying a mode.
Modes:
'r': Read an existing archive.'w': Create a new archive (exclusive create).'x': Exclusive create (fails if file exists).'a': Append to an existing archive.Parameters:
file: A path to the file or a file-like object.mode: The access mode (see above).compression: The compression method (e.g., ZIP_STORED, ZIP_DEFLATED, ZIP_BZIP2, ZIP_LZMA).allowZip64: If True, enables ZIP64 extensions for large files.compresslevel: An integer specifying the compression level (e.g., 0-9 for ZIP_DEFLATED).strict_timestamps: Boolean to control timestamp handling.from pyzipper import ZipFile, ZIP_DEFLATED
# Create a new zip file with DEFLATED compression
with ZipFile('example.zip', mode='w', compression=ZIP_DEFLATED) as zf:
pass
# Open an existing zip file for reading
with ZipFile('example.zip', mode='r') as zf:
passWrite data directly into the archive without using a file on disk. The data can be a str (which will be encoded as UTF-8) or bytes.
zinfo_or_arcname can be a ZipInfo instance or a string representing the filename in the archive.
# Write a string directly
zf.writestr('hello.txt', 'This is some text content')
# Write bytes directly
zf.writestr('data.bin', b'\x00\x01\x02\x03')
# Write using a ZipInfo object for fine-grained control
import time
from pyzipper import ZipInfo
zinfo = ZipInfo('custom.txt')
zinfo.date_time = time.localtime().tm_year, time.localtime().tm_mon, time.localtime().tm_mday, 0, 0, 0
zf.writestr(zinfo, 'Custom metadata content')The ZipInfo class contains attributes describing each file within a ZIP archive.
Key attributes include:
filename: The normalized name of the file in the archive.date_time: A tuple representing the timestamp (year, month, day, hour, min, sec).compress_type: The compression method used (e.g., ZIP_STORED, ZIP_DEFLATED).CRC: The CRC-32 checksum of the uncompressed file.file_size: The size of the uncompressed file.compress_size: The size of the compressed file.is_dir(): A method to check if the member is a directory.is_encrypted: A property indicating if the file is encrypted.is_utf_filename: A property indicating if the filename is encoded in UTF-8.You can create a ZipInfo object for an existing filesystem file using ZipInfo.from_file(filename).
from pyzipper import ZipInfo
# Create ZipInfo from a file on disk
zinfo = ZipInfo.from_file('path/to/my_file.txt')
print(f"Filename: {zinfo.filename}")
print(f"Is directory: {zinfo.is_dir()}")
print(f"Compressed size: {zinfo.compress_size}")You can associate a comment with the entire ZIP archive using the comment property. The comment must be provided as bytes.
Note: If the comment exceeds ZIP_MAX_COMMENT, it will be truncated with a warning.
with pyzipper.ZipFile('example.zip', mode='a') as zf:
zf.comment = b'This is an archive comment'