Omn*_*ous 3 python security cryptography
天真的尝试失败了:
import hashlib
class fred(hashlib.sha256):
pass
-> TypeError: Error when calling the metaclass bases
cannot create 'builtin_function_or_method' instances
Run Code Online (Sandbox Code Playgroud)
好吧,事实证明hashlib.sha256是一个可调用的,而不是一个类.尝试更有创意的东西也不起作用:
import hashlib
class fred(type(hashlib.sha256())):
pass
f = fred
-> TypeError: cannot create 'fred' instances
Run Code Online (Sandbox Code Playgroud)
嗯...
那么,我该怎么做?
这是我想要实际实现的目标:
class shad_256(sha256):
"""Double SHA - sha256(sha256(data).digest())
Less susceptible to length extension attacks than sha256 alone."""
def digest(self):
return sha256(sha256.digest(self)).digest()
def hexdigest(self):
return sha256(sha256.digest(self)).hexdigest()
Run Code Online (Sandbox Code Playgroud)
基本上我希望一切都能通过,除非有人要求结果我想插入我自己的额外步骤.是否有一种聪明的方法可以通过__new__某种类型的元类魔法来实现这一目标?
我有一个解决方案,我很满意我发布的答案,但我真的很想知道是否有人能想到更好的东西.可读性要低得多,或者更快(特别是在调用时update),同时仍然具有一定的可读性.
更新:我运行了一些测试:
# test_sha._timehash takes three parameters, the hash object generator to use,
# the number of updates and the size of the updates.
# Built in hashlib.sha256
$ python2.7 -m timeit -n 100 -s 'import test_sha, hashlib' 'test_sha._timehash(hashlib.sha256, 20000, 512)'
100 loops, best of 3: 104 msec per loop
# My wrapper based approach (see my answer)
$ python2.7 -m timeit -n 100 -s 'import test_sha, hashlib' 'test_sha._timehash(test_sha.wrapper_shad_256, 20000, 512)'
100 loops, best of 3: 108 msec per loop
# Glen Maynard's getattr based approach
$ python2.7 -m timeit -n 100 -s 'import test_sha, hashlib' 'test_sha._timehash(test_sha.getattr_shad_256, 20000, 512)'
100 loops, best of 3: 103 msec per loop
Run Code Online (Sandbox Code Playgroud)
创建一个新类,派生自object,在init中创建hashlib.sha256成员var ,然后定义哈希类所需的方法,并代理成员变量的相同方法.
就像是:
import hashlib
class MyThing(object):
def __init__(self):
self._hasher = hashlib.sha256()
def digest(self):
return self._hasher.digest()
Run Code Online (Sandbox Code Playgroud)
等等其他方法.
只是__getattr__用来导致你没有自己定义的所有属性回退到底层对象:
import hashlib
class shad_256(object):
"""
Double SHA - sha256(sha256(data).digest())
Less susceptible to length extension attacks than sha256 alone.
>>> s = shad_256('hello world')
>>> s.digest_size
32
>>> s.block_size
64
>>> s.sha256.hexdigest()
'b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9'
>>> s.hexdigest()
'bc62d4b80d9e36da29c16c5d4d9f11731f36052c72401a76c23c0fb5a9b74423'
>>> s.nonexistant()
Traceback (most recent call last):
...
AttributeError: '_hashlib.HASH' object has no attribute 'nonexistant'
>>> s2 = s.copy()
>>> s2.digest() == s.digest()
True
>>> s2.update("text")
>>> s2.digest() == s.digest()
False
"""
def __init__(self, data=None):
self.sha256 = hashlib.sha256()
if data is not None:
self.update(data)
def __getattr__(self, key):
return getattr(self.sha256, key)
def _get_final_sha256(self):
return hashlib.sha256(self.sha256.digest())
def digest(self):
return self._get_final_sha256().digest()
def hexdigest(self):
return self._get_final_sha256().hexdigest()
def copy(self):
result = shad_256()
result.sha256 = self.sha256.copy()
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
Run Code Online (Sandbox Code Playgroud)
这主要消除了update呼叫的开销,但并非完全消除.如果要完全消除它,请将其添加到__init__(并相应地copy):
self.update = self.sha256.update
Run Code Online (Sandbox Code Playgroud)
这将__getattr__在查找时消除额外的呼叫update.
这一切都利用了Python成员函数中一个更有用且经常被忽略的属性:函数绑定.回想一下,你可以这样做:
a = "hello"
b = a.upper
b()
Run Code Online (Sandbox Code Playgroud)
因为对成员函数的引用不会返回原始函数,而是返回该函数与其对象的绑定.这就是为什么,当__getattr__上面的返回时self.sha256.update,返回的函数正确地操作self.sha256,而不是self.