diff -r 63b45c959a2a Lib/zipfile.py --- a/Lib/zipfile.py Sun Nov 04 07:00:04 2012 +0200 +++ b/Lib/zipfile.py Sun Nov 04 17:43:04 2012 +0200 @@ -430,63 +430,59 @@ extra = extra[ln+4:] -class _ZipDecrypter: - """Class to handle decryption of files stored within a ZIP archive. +# ZIP encryption uses the CRC32 one-byte primitive for scrambling some +# internal keys. We noticed that a direct implementation is faster than +# relying on binascii.crc32(). - ZIP supports a password-based form of encryption. Even though known - plaintext attacks have been found against it, it is still useful - to be able to get data out of such a file. +def _gen_crc(crc): + for j in range(8): + if crc & 1: + crc = (crc >> 1) ^ 0xEDB88320 + else: + crc >>= 1 + return crc +_crctable = list(map(_gen_crc, range(256))) - Usage: - zd = _ZipDecrypter(mypwd) - plain_char = zd(cypher_char) - plain_text = map(zd, cypher_text) - """ +def _crc32(ch, crc, crctable=_crctable): + """Compute the CRC32 primitive on one byte.""" + return (crc >> 8) ^ crctable[(crc ^ ch) & 0xFF] - def _GenerateCRCTable(): - """Generate a CRC-32 table. +# ZIP supports a password-based form of encryption. Even though known +# plaintext attacks have been found against it, it is still useful +# to be able to get data out of such a file. +# +# Usage: +# zd = _ZipDecrypter(mypwd) +# plain_bytes = zd(cypher_bytes) - ZIP encryption uses the CRC32 one-byte primitive for scrambling some - internal keys. We noticed that a direct implementation is faster than - relying on binascii.crc32(). - """ - poly = 0xedb88320 - table = [0] * 256 - for i in range(256): - crc = i - for j in range(8): - if crc & 1: - crc = ((crc >> 1) & 0x7FFFFFFF) ^ poly - else: - crc = ((crc >> 1) & 0x7FFFFFFF) - table[i] = crc - return table - crctable = _GenerateCRCTable() +def _ZipDecrypter(pwd): + key0 = 305419896 + key1 = 591751049 + key2 = 878082192 - def _crc32(self, ch, crc): - """Compute the CRC32 primitive on one byte.""" - return ((crc >> 8) & 0xffffff) ^ self.crctable[(crc ^ ch) & 0xff] + def update_keys(c, _crc32=_crc32): + nonlocal key0, key1, key2 + key0 = _crc32(c, key0) + key1 = (key1 + (key0 & 0xFF)) & 0xFFFFFFFF + key1 = (key1 * 134775813 + 1) & 0xFFFFFFFF + key2 = _crc32(key1 >> 24, key2) - def __init__(self, pwd): - self.key0 = 305419896 - self.key1 = 591751049 - self.key2 = 878082192 - for p in pwd: - self._UpdateKeys(p) + for p in pwd: + update_keys(p) - def _UpdateKeys(self, c): - self.key0 = self._crc32(c, self.key0) - self.key1 = (self.key1 + (self.key0 & 255)) & 4294967295 - self.key1 = (self.key1 * 134775813 + 1) & 4294967295 - self.key2 = self._crc32((self.key1 >> 24) & 255, self.key2) + def decrypter(data, update_keys=update_keys, bytes=bytes): + """Decrypt a bytes object.""" + nonlocal key2 + result = [] + append = result.append + for c in data: + k = key2 | 2 + c ^= ((k * (k^1)) >> 8) & 0xFF + update_keys(c) + append(c) + return bytes(result) - def __call__(self, c): - """Decrypt a single character.""" - assert isinstance(c, int) - k = self.key2 | 2 - c = c ^ (((k * (k^1)) >> 8) & 255) - self._UpdateKeys(c) - return c + return decrypter class LZMACompressor: @@ -841,7 +837,7 @@ self._compress_left -= len(data) if self._decrypter is not None: - data = bytes(map(self._decrypter, data)) + data = self._decrypter(data) return data def close(self): @@ -1177,7 +1173,7 @@ # or the MSB of the file time depending on the header type # and is used to check the correctness of the password. header = zef_file.read(12) - h = list(map(zd, header[0:12])) + h = zd(header[0:12]) if zinfo.flag_bits & 0x8: # compare against the file type from extended local headers check_byte = (zinfo._raw_time >> 8) & 0xff