CRC32 和 zip文件的crc 字段

python中的计算

注意,python 的计算结果是有符号的,如果要转为unsigned 可以和0xffffffff与操作

>>> import zlib
>>> import binascii
s = b'hello,word!'
>>> zlib.crc32(s)
3035098857

>>> binascii.crc32(s)
3035098857

>>> zlib.crc32(b"hello") & 0xffffffff
907060870

0x04c11db7 和 0xedb88320

Python中用的是后面的
这两个数字其实是相互的二进制形式的反转,具体参考链接2
所以两个数字相对应的table 也是各自的反转(不只是table中每个位置对应的数字要反转,下标也要反转)
相应的两个table 的 实质的计算顺序分辨是,先高位,和先低位
比如要校验的串是\x01\x02

先高位,用0x04c11db7

第一步是把bit0 和初始串(0xffffffff)的高位抑或,也就是
1111 1111 1111 1111 1111 1111 1111 1111
然后因为第一位是1,补0后的后面的16位 和 0x04c11db7 抑或操作
按照上面的步骤16次预算的结果,相当于在0x04c11db7下 计算下面这个串的校验码
1110 1101 1111 1111 1111 1111 1111 1111 0000 0000
从左向右算,计算过程要左移

先低位,用0xedb88320

相当于用0xedb88320计算串
0000 0000 1111 1111 1111 1111 1111 1111 1101 1110
从右向左算,计算过程要右移

下面是生成crc table 和测试的代码:

from zlib import crc32

def mycrc(input):
    x=inverse32(0x04c11db7)
    init=0xffffffff
    t=init
    for i in input:
        t=t^ord(i)
        for j in range(8):
            mask=1
            if(mask&t!=0):
                t=(t>>1)^x
            else:
                t=(t>>1)
    return t^0xffffffff

def inverse8(x):
    y=0
    for i in range(8):
        y=(y<<1)|(x&1)
        x=x>>1
    return y

def inverse32(x):
    r=0x00000000
    for i in range(32):
        r=(r<<1)|(x&1)
        x=x>>1
    return r

def creat_table1():
    x=0x04c11db7
    init=0
    l=[0L]*256
    for i in range(256):
        t=init^(i<<24)
        for j in range(8):
            mask=1<<31
            if(mask&t!=0):
                t=(t<<1)^x
            else:
                t=(t<<1)
        l[i]=t
    return l

def creat_table3():#table1 inverse
    l1=creat_table1()
    l3=[0L]*256
    for i in range(256):
        j=inverse8(i)
        l3[j]=inverse32(l1[i])
    return l3

def creat_table2():
    x=inverse32(0x04c11db7)
    init=0
    l=[0]*256
    for i in range(256):
        t=init^i
        for j in range(8):
            mask=1
            if(mask&t!=0):
                t=(t>>1)^x
            else:
                t=(t>>1)
        l[i]=t
    return l

def test():
    assert (0==inverse8(0))
    assert (0x80==inverse8(1))
    assert (0x40==inverse8(2))
    assert (0xc0==inverse8(3))
    assert (0==inverse32(0))
    assert (0x80000000==inverse32(1))
    assert (0x40000000==inverse32(2))
    assert (0xc0000000==inverse32(3))
    l1=creat_table1()
    l2=creat_table2()
    l3=creat_table3()
    assert (l2==l3)
    for i in range(256):
        i=chr(i)
        assert (mycrc(i)&0xffffffff==crc32(i)&0xffffffff)
    # for i in range(256):
    #     print(bin(i),bin(inverse8(i)))
    # l=l2
    # for i in range(0,256,4):
    #     print(hex((l[i])&0xffffffff),hex((l[i+1])&0xffffffff),hex((l[i+2])&0xffffffff),hex((l[i+3])&0xffffffff))

if __name__=="__main__":
    test()

zip 文件中的校验字段

文件格式参考:
1.格式:https://en.wikipedia.org/wiki/Zip_(file_format)
2.格式文档:https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.2.0.txt
3.算法和文件格式的汇总:http://www.cnblogs.com/esingchan/p/3958962.html
首先zip中使用的crc32 和python 中的这中是相同的
文档中提到的magic number(0xdebb20e3 ) 应该并不是多项式的表示。
不过串”\x00\x00\x00\x00”crc32后取反刚好是这个数字

>>> hex(crc32("\x00\x00\x00\x00")^0xffffffff&0xffffffff)
'0xdebb20e3L'

可能因为英文水平差,看了好久也没有找到crc字段具体是如何计算的,到底是什么内容的crc32,然后把zip文件的头,整体,都crc了一下,结果还是对不上。。。(好像网络协议中的crc是有包含package头的,然后就被误导了)
卡了两天后发现,这个crc是压缩前文件的crc。。。如果只有一个文件,那么local header 和central header 中的crc 是一样的。
一个例子,
这个zip文件是test.txt的压缩,第二行末尾和第三行开始可以看出文件名。text.txt 的内容是

abcd

就是第三行文件名和central header标识中间的部分
蓝色分别是local header 和 central header的标识,红色是两个部分的crc
abcd 的CRC刚好就是红框中的数字,只不过差个大端小端,你懂的
CRC32 和 zip文件的crc 字段_第1张图片

>>> hex(crc32("abcd")&0xffffffff)
'0xed82cd11L'

参考
0.
http://www.cnblogs.com/darkpig/p/5676076.html
1.crc table
http://blog.csdn.net/joeblackzqq/article/details/37910839
2.详细计算
http://blog.csdn.net/sparkliang/article/details/5671510

你可能感兴趣的:(CRC32 和 zip文件的crc 字段)