# 15.1. `hashlib` — 安全散列和消息摘要

源代码： Lib/hashlib.py

该模块实现了许多不同 Secure Hash 和 message digest 算法的通用接口。包括FIPS安全散列算法SHA1，SHA224，SHA256，SHA384和SHA512（在FIPS 180-2中定义）以及RSA的MD5算法（在因特网 RFC 1321 术语“安全散列”和“消息摘要”是可互换的。较旧的算法被称为消息摘要。现代术语是安全哈希。

注

如果你想要adler32或crc32哈希函数，它们在`zlib`模块中可用。

警告

一些算法具有已知的哈希冲突弱点，请参阅末尾的"另请参见"一节。

## 15.1.1.Hash 算法

对于每种类型的hash，都有一个构造函数方法 . 它们都返回一个具有相同的简单接口的哈希对象。例如：使用`sha1()`创建SHA1哈希对象。现在，你可以使用`update()`方法以类字节对象填充这个对象（通常为`字节`）。在连接数据的任何时候，你都可以使用`digest()`或`hexdigest()`方法来向它请求摘要。

注

为了更好的多线程性能，在对象创建或更新时，针对大于2047字节的数据发布Python GIL。

注

不支持将字符串对象添加到`update()`中，因为哈希在字节上工作，而不是字符。

此模块中始终存在的散列算法的构造函数为`md5()`，`sha1()`，`sha224()`，`sha256()`，`sha384()`和`sha512()`。可能还有其它算法，这取决于在你的平台上Python 使用的 OpenSSL 库。

例如，获取字节字符串`b'Nobody inspects the spammish repetition'`的摘要：

    >>> import hashlib
    >>> m = hashlib.md5()
    >>> m.update(b"Nobody inspects")
    >>> m.update(b" the spammish repetition")
    >>> m.digest()
    b'\xbbd\x9c\x83\xdd\x1e\xa5\xc9\xd9\xde\xc9\xa1\x8d\xf0\xff\xe9'
    >>> m.digest_size
    16
    >>> m.block_size
    64

更精炼的版本：

    >>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest()
    'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2'

`hashlib.``new`(name[, data])

  是一个通用构造函数，它接受所需算法的字符串名称作为其第一个参数。它也存在允许访问上面列出的哈希以及您的OpenSSL库可能提供的任何其他算法。命名的构造函数比`new()`快得多，应该是首选。

使用OpenSSL提供的算法使用`new()`：

    >>> h = hashlib.new('ripemd160')
    >>> h.update(b"Nobody inspects the spammish repetition")
    >>> h.hexdigest()
    'cc4a5ce1b3df48aec5d22d1f16b894a0b894eccc'

Hashlib提供以下常量属性：

`hashlib.``algorithms_guaranteed`

  包含保证在所有平台上此模块支持的哈希算法的名称的集合。

  版本3.2中的新功能。

`hashlib.``algorithms_available`

  一组包含在运行的Python解释器中可用的哈希算法的名称。当传递到`new()`时，这些名称将被识别。`algorithms_guaranteed`将始终是子集。相同的算法可能出现多次在此集中不同的名称（感谢OpenSSL）。

  版本3.2中的新功能。

构造函数返回的哈希对象提供以下值作为常量属性：

`hash.``digest_size`

  以字节为单位的哈希结果的大小。

`hash.``block_size`

  以字节为单位的哈希算法的内部块的大小。

哈希对象具有以下属性：

`hash.``name`

  此哈希的规范名称，始终小写，始终适合作为`new()`的参数，以创建此类型的另一个哈希。

  在版本3.4中更改： CPython自启动以来就存在name属性，但直到Python 3.4未正式指定，因此在某些平台上可能不存在。

哈希对象都具有以下方法：

`hash.``update`(arg)

  使用对象arg更新哈希对象，该对象必须可解释为字节缓冲区。重复调用等效于具有所有参数串联的单个调用：`m.update(a); m.update(b)`相当于`m.update(ab)`。

  在版本3.1中已更改：发布Python GIL以允许其他线程在使用OpenSSL提供的哈希算法时对大于2047字节的数据进行哈希更新时运行。

`hash.``digest`()

  返回传递给`update()`方法的数据的摘要。它是一个大小为`digest_size`的字节对象，包含的字节可以在0到255整个范围。

`hash.``hexdigest`()

  类似`digest()`，但是摘要以2倍长度的字符串对象返回，只包含十六进制数字。这可用于在电子邮件或其它非二进制环境中安全交换数据。

`hash.``copy`()

  返回哈希对象的一个副本（"克隆"）。这可以用于有效地计算共享公共初始子串的数据的摘要。

## 15.1.2.密钥导出

密钥派生和密钥stretching 设计用于安全的密码哈希。诸如`sha1(password)`的朴素算法不能抵抗暴力攻击。一个好的密码哈希函数必须是可调谐、 速度慢，并且包括一个salt。

`hashlib.``pbkdf2_hmac`(hash_name, password, salt, iterations, dklen=None)

  该函数提供 PKCS #5 基于密码的密钥派生函数 2。它使用 HMAC 作为伪随机函数。

  字符串hash_name是HMAC的所需的哈希摘要算法的名称，例如。'sha1'或'sha256'。password和salt被解释为缓冲区的字节数。应用程式和程式库应将密码限制为明智的长度（例如 1024）。salt应该是来自适当源的大约16个或更多个字节，例如 `os.urandom()`。

  迭代次数应基于散列算法和计算能力来选择。截至2013年，建议至少100,000次迭代的SHA-256。

  dklen是派生密钥的长度。如果dklen是`None`，则使用散列算法的摘要大小hash_name 64用于SHA-512。

      >>> import hashlib, binascii
      >>> dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 100000)
      >>> binascii.hexlify(dk)
      b'0394a2ede332c9a13eb82e9b24631604c31df978b4e2f0fbd2c549944f9d79a5'

  新版本3.4。

  注

  OpenSSL 中实现的pbkdf2_hmac 更加快速。Python实现使用`hmac`的内联版本。它慢了约三倍且不释放 GIL。

请参见

模块`hmac`
  使用哈希生成消息认证码的一个模块
模块`base64`
  用于非二进制环境的编码二进制哈希的另外一种方式
http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf T0>
  关于安全哈希算法的 FIPS 180-2 的公开发行
https://en.wikipedia.org/wiki/Cryptographic_hash_function#Cryptographic_hash_algorithms T0>
  维基百科的文章，关于哪些算法有已知问题和使用中的含义
https://www.ietf.org/rfc/rfc2898.txt T0>
  PKCS＃5：基于密码的加密规范2.0版