不是从已知的摘要中获取,而是从已知的状态中获取。你可以使用一个纯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)。
try:
import _md5 as md5
except ImportError:
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()
由于没有_md5/md5模块,它与Python 3不兼容。
不幸的是,hashlib的openssl_md5实现对于这种黑客攻击并不适用,因为OpenSSL EVP API没有提供任何调用/方法来可靠地序列化EVP_MD_CTX对象。
cyptes
直接调用libopenssl.so
并获取EVP_MD_CTX
呢? - est