首页 文章

用于动态增长/流数据的哈希算法?

提问于
浏览
7

是否有任何算法可以从已知的哈希摘要中进行哈希处理?例如,客户端将一大块文件上传到ServerA,我可以获得上传内容的总和,然后客户端将剩余的文件块上传到ServerB,我可以将 md5 内部的状态转移到ServerB并完成哈希?

有一个cool black magic hack基于我多年前在comp.lang.python上发现的md5,但是它使用 ctypes 用于特定版本的 md5.so_md5.dll ,所以它不是用于不同python解释器版本或其他编程语言的可移植代码,除了 md5 自2.5以来,模块在python标准库中已弃用,因此我需要找到更通用的解决方案 .

更重要的是,散列的状态是否可以存储在十六进制摘要本身中? (因此,我可以继续使用现有的哈希摘要散列数据流,而不是内部黑客攻击 .

任何想法都表示赞赏 . 提前致谢 :)

3 回答

  • 1

    不是来自已知的摘要,而是来自已知的状态 . 您可以使用纯python MD5实现并保存其状态 . 以下是使用_md5.py from from PyPy的示例:

    import _md5
    
    def md5_getstate(md):
        return (md.A, md.B, md.C, md.D, md.count + [], md.input + [], md.length)
    
    def md5_continue(state):
        md = _md5.new()
        (md.A, md.B, md.C, md.D, md.count, md.input, md.length) = state
        return md
    
    m1 = _md5.new()
    m1.update("hello, ")
    state = md5_getstate(m1)
    m2 = md5_continue(state)
    m2.update("world!")
    print m2.hexdigest()
    
    m = _md5.new()
    m.update("hello, world!")
    print m.hexdigest()
    

    正如e.dan所指出的,你也可以使用几乎任何一种校验算法(CRC,Adler,Fletcher),但它们并不能保护你免受故意的数据修改,只能保护你的随机错误 .

    编辑:当然,您也可以使用您以更便携方式引用的线程中的ctypes重新实现序列化方法(没有魔术常量) . 我相信这应该是版本/体系结构独立的(在python 2.4-2.7上测试,i386和x86_64):

    # based on idea from http://groups.google.com/group/comp.lang.python/msg/b1c5bb87a3ff5e34
    
    try:
        import _md5 as md5
    except ImportError:
        # python 2.4
        import md5
    import ctypes
    
    def md5_getstate(md):
        if type(md) is not md5.MD5Type:
            raise TypeError, 'not an MD5Type instance'
        return ctypes.string_at(id(md) + object.__basicsize__,
                                md5.MD5Type.__basicsize__ - object.__basicsize__)
    
    def md5_continue(state):
        md = md5.new()
        assert len(state) == md5.MD5Type.__basicsize__ - object.__basicsize__, \
               'invalid state'    
        ctypes.memmove(id(md) + object.__basicsize__,
                       ctypes.c_char_p(state),
                       len(state))
        return md
    
    m1 = md5.new()
    m1.update("hello, ")
    state = md5_getstate(m1)
    m2 = md5_continue(state)
    m2.update("world!")
    print m2.hexdigest()
    
    m = md5.new()
    m.update("hello, world!")
    print m.hexdigest()
    

    它不兼容Python 3,因为它没有_md5 / md5模块 .

    不幸的是,hashlib的openssl_md5实现不适用于此类hacks,因为OpenSSL EVP API不提供任何调用/方法来可靠地序列化EVP_MD_CTX对象 .

  • 2

    这在理论上是可行的(到目前为止md5应该包含你需要继续的所有状态),但看起来普通的API并不能提供你需要的东西 . 如果你可以用CRC代替,那么这可能会容易得多,因为那些更常用于你需要的"streaming"情况 . 看这里:

    binascii.crc32(data[, crc])

    crc32() 接受可选的 crc 输入,这是要继续的校验和 .

    希望有所帮助 .

  • 2

    我也遇到了这个问题,并且没有找到现有的解决方案,所以我写了一个库,它使用ctypes来解构保持hasher状态的OpenSSL数据结构:https://github.com/kislyuk/rehash . 例:

    import pickle, rehash
    hasher = rehash.sha256(b"foo")
    state = pickle.dumps(hasher)
    
    hasher2 = pickle.loads(state)
    hasher2.update(b"bar")
    
    assert hasher2.hexdigest() == rehash.sha256(b"foobar").hexdigest()
    

相关问题