ZIP 用于加密的 CRC-32 不完全是 zlib 的 crc32...为什么?
ZIP's CRC-32 for encryption isn't quite zlib's crc32... why?
我正在编写自己的解压缩代码,并且(通过反复试验,没有理解)它看起来像解密所需的一个字节的 CRC-32 算法与 zlib 的不完全匹配。要从一个转换为另一个:
def crc32(ch, crc):
crc = zlib.crc32(bytes([~ch & 0xFF]), crc)
return (~crc & 0xFF000000) + (crc & 0x00FFFFFF)
这是为什么? (/我错了吗?)
编辑:之所以我认为至少有可能我是对的,在https://github.com/uktrade/stream-unzip/blob/d23400028abbe3b0d7e1951cb562cd0541bfc960/stream_unzip.py#L89我成功地使用上面的方法解密了加密的 ZIP 文件
def decrypt(chunks):
key_0 = 305419896
key_1 = 591751049
key_2 = 878082192
def crc32(ch, crc):
crc = zlib.crc32(bytes([~ch & 0xFF]), crc)
return (~crc & 0xFF000000) + (crc & 0x00FFFFFF)
def update_keys(byte):
nonlocal key_0, key_1, key_2
key_0 = crc32(byte, key_0)
key_1 = (key_1 + (key_0 & 0xFF)) & 0xFFFFFFFF
key_1 = ((key_1 * 134775813) + 1) & 0xFFFFFFFF
key_2 = crc32(key_1 >> 24, key_2)
def decrypt(chunk):
chunk = bytearray(chunk)
for i, byte in enumerate(chunk):
temp = key_2 | 2
byte ^= ((temp * (temp ^ 1)) >> 8) & 0xFF
update_keys(byte)
chunk[i] = byte
return chunk
yield_all, _, get_num, _ = get_byte_readers(chunks)
for byte in password:
update_keys(byte)
if decrypt(get_num(12))[11] != mod_time >> 8:
raise ValueError('Incorrect password')
for chunk in yield_all():
yield decrypt(chunk)
但是,如果我用调用 zlib 的函数替换上面的 crc32
函数,它不会(例如,它会抱怨密码不正确)
好的,你没有完全错。它确实是相同的 CRC-32 算法,但没有预处理和 post 处理(反转 CRC 的输入和输出)。试图用 zlib.crc32
函数复制它的代码确实很奇怪。你只需要这个:
def crc32(ch, crc):
return ~zlib.crc32(bytes([ch]), ~crc) & 0xffffffff
我正在编写自己的解压缩代码,并且(通过反复试验,没有理解)它看起来像解密所需的一个字节的 CRC-32 算法与 zlib 的不完全匹配。要从一个转换为另一个:
def crc32(ch, crc):
crc = zlib.crc32(bytes([~ch & 0xFF]), crc)
return (~crc & 0xFF000000) + (crc & 0x00FFFFFF)
这是为什么? (/我错了吗?)
编辑:之所以我认为至少有可能我是对的,在https://github.com/uktrade/stream-unzip/blob/d23400028abbe3b0d7e1951cb562cd0541bfc960/stream_unzip.py#L89我成功地使用上面的方法解密了加密的 ZIP 文件
def decrypt(chunks):
key_0 = 305419896
key_1 = 591751049
key_2 = 878082192
def crc32(ch, crc):
crc = zlib.crc32(bytes([~ch & 0xFF]), crc)
return (~crc & 0xFF000000) + (crc & 0x00FFFFFF)
def update_keys(byte):
nonlocal key_0, key_1, key_2
key_0 = crc32(byte, key_0)
key_1 = (key_1 + (key_0 & 0xFF)) & 0xFFFFFFFF
key_1 = ((key_1 * 134775813) + 1) & 0xFFFFFFFF
key_2 = crc32(key_1 >> 24, key_2)
def decrypt(chunk):
chunk = bytearray(chunk)
for i, byte in enumerate(chunk):
temp = key_2 | 2
byte ^= ((temp * (temp ^ 1)) >> 8) & 0xFF
update_keys(byte)
chunk[i] = byte
return chunk
yield_all, _, get_num, _ = get_byte_readers(chunks)
for byte in password:
update_keys(byte)
if decrypt(get_num(12))[11] != mod_time >> 8:
raise ValueError('Incorrect password')
for chunk in yield_all():
yield decrypt(chunk)
但是,如果我用调用 zlib 的函数替换上面的 crc32
函数,它不会(例如,它会抱怨密码不正确)
好的,你没有完全错。它确实是相同的 CRC-32 算法,但没有预处理和 post 处理(反转 CRC 的输入和输出)。试图用 zlib.crc32
函数复制它的代码确实很奇怪。你只需要这个:
def crc32(ch, crc):
return ~zlib.crc32(bytes([ch]), ~crc) & 0xffffffff