7

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

几年前我在 comp.lang.python 发现了一个基于 md5的很酷的黑魔法 hack ,但它用于orctypes的特定版本,因此对于不同的 python 解释器版本或其他编程语言来说,它不是完全可移植的代码。此外,该模块自 2.5 起在 python 标准库中已弃用,因此我需要找到更通用的解决方案。md5.so_md5.dllmd5

更重要的是,散列的状态可以存储在十六进制摘要本身中吗?(所以我可以继续使用现有的哈希摘要对数据流进行哈希处理,而不是肮脏的内部破解。)

4

3 回答 3

2

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

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 实现不适合这种黑客攻击,因为 OpenSSL EVP API 不提供任何调用/方法来可靠地序列化 EVP_MD_CTX 对象。

于 2011-05-03T07:14:32.233 回答
2

这在理论上是可能的(到目前为止的 md5应该包含您需要继续的所有状态)但看起来普通的 API 不能提供您需要的东西。如果您可以使用 CRC 代替,这可能会容易得多,因为这些更常用于您需要的“流”案例。看这里:

binascii.crc32(数据[, crc])

crc32()接受一个可选crc输入,它是要继续的校验和。

希望有帮助。

于 2011-05-03T06:43:00.240 回答
1

我也遇到了这个问题,没有找到现有的解决方案,所以我写了一个库,它使用 ctypes 来解构持有哈希状态的 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()
于 2017-07-12T18:37:14.017 回答