加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Python > 正文

我如何从Python中派生出hashlib.sha256?

发布时间:2020-12-20 12:37:26 所属栏目:Python 来源:网络整理
导读:天真的尝试失败了: import hashlibclass fred(hashlib.sha256): pass- TypeError: Error when calling the metaclass bases cannot create 'builtin_function_or_method' instances 好吧,事实证明hashlib.sha256是一个可调用的,而不是一个类.尝试更有创意的
天真的尝试失败了:

import hashlib

class fred(hashlib.sha256):
    pass

-> TypeError: Error when calling the metaclass bases
       cannot create 'builtin_function_or_method' instances

好吧,事实证明hashlib.sha256是一个可调用的,而不是一个类.尝试更有创意的东西也不起作用:

import hashlib

 class fred(type(hashlib.sha256())):
     pass

 f = fred

 -> TypeError: cannot create 'fred' instances

嗯…

那么,我该怎么做?

这是我想要实际实现的目标:

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()

基本上我希望一切都能通过,除非有人要求结果我想插入我自己的额外步骤.是否有一种聪明的方法可以用__new__或某种类型的元类魔法来实现这一目标?

我有一个解决方案,我很满意我发布的答案,但我真的很想知道是否有人能想到更好的东西.要么更简洁,可读性成本非常低,要么更快(特别是在调用更新时),同时仍具有一定的可读性.

更新:我运行了一些测试:

# 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,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,best of 3: 103 msec per loop

解决方法

只需使用__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()

这主要消除了更新调用的开销,但并非完全消除.如果要完全消除它,请将其添加到__init__(并相应地复制):

self.update = self.sha256.update

在查找更新时,这将消除额外的__getattr__调用.

这一切都利用了Python成员函数中一个更有用且经常被忽略的属性:函数绑定.回想一下,你可以这样做:

a = "hello"
b = a.upper
b()

因为对成员函数的引用不会返回原始函数,而是返回该函数与其对象的绑定.这就是为什么,当__getattr__返回self.sha256.update时,返回的函数正确地在self.sha256上运行,而不是self.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读