不是来自已知的摘要,而是来自已知的状态。您可以使用纯 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 对象。