Skip to main content
added 707 characters in body
Source Link
Michal Charemza
  • 26.6k
  • 14
  • 106
  • 176

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 specWinZip'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

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',),
    ),
)

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.

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

Source Link
Michal Charemza
  • 26.6k
  • 14
  • 106
  • 176

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',),
    ),
)

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.