"crypt" —— 检查 Unix 口令的函数
*******************************

**源代码：** Lib/struct.py

======================================================================

本模块实现了连接 *crypt(3)* 的接口，是一个基于改进 DES 算法的单向散列
函数；更多细节请参阅 Unix man 手册。可能的用途包括保存经过哈希的口令，
这样就可以在不存储实际口令的情况下对其进行验证，或者尝试用字典来破解
Unix 口令。

请注意，本模块的执行取决于当前系统中 *crypt(3)* 的实际实现。 因此，当
前实现版本可用的扩展均可在本模块使用。

可用性: Unix。 在 VxWorks 上不可用。


哈希方法
========

3.3 新版功能.

"crypt" 模块定义了哈希方法的列表（不是所有的方法在所有平台上都可用）。

crypt.METHOD_SHA512

   基于 SHA-512 哈希函数的模块化加密格式方法，具备 16 个字符的 salt 和
   86个字符的哈希算法。这是最强的哈希算法。

crypt.METHOD_SHA256

   另一种基于 SHA-256 哈希函数的模块化加密格式方法，具备 16 个字符的
   salt 和 43 个字符的哈希算法。

crypt.METHOD_BLOWFISH

   另一种基于 Blowfish 的模块化加密格式方法，有 22 个字符的 salt 和 31
   个字符的哈希算法。

   3.7 新版功能.

crypt.METHOD_MD5

   另一种基于 MD5 哈希函数的模块化加密格式方法，具备 8 个字符的 salt
   和 22 个字符的哈希算法。

crypt.METHOD_CRYPT

   传统的方法，具备 2 个字符的 salt 和 13 个字符的哈希算法。这是最弱的
   方法。


模块属性
========

3.3 新版功能.

crypt.methods

   可用口令哈希算法的列表，形式为 "crypt.METHOD_*" 对象。该列表从最强
   到最弱进行排序。


模块函数
========

"crypt" 模块定义了以下函数：

crypt.crypt(word, salt=None)

   *word* 通常是用户在提示符或图形界面上输入的口令。可选参数 *salt* 要
   么是 "mksalt()" 返回的字符串，即 "crypt.METHOD_*" 之一（尽管不是所
   有平台都可用），要么就是一个完全加密的包含 salt 值的口令，正如本函
   数的返回值。如果未给出 *salt*，将使用最强的哈希方法（ "methods()"
   返回）。

   查验口令通常是传入纯文本密码 *word* ，和之前 "crypt()" 调用的结果进
   行比较，应该与本次调用的结果相同。

   *salt* (随机的 2 或 16 个字符的字符串，可能带有 "$digit{TX-PL-
   LABEL}#x60;" 前缀以提示相关方法) 将被用来扰乱加密算法。  *salt* 中
   的字符必须在 "[./a-zA-Z0-9]" 集合中，但 Modular Crypt Format 除外，
   它会带有 "$digit{TX-PL-LABEL}#x60;" 前缀。

   返回哈希后的口令字符串，将由 salt 所在字母表中的字符组成。

   由于有些 *crypt(3)* 扩展允许不同的值， *salt* 大小也可不同，建议在
   查验口令时采用完整的加密后口令作为 salt。

   在 3.3 版更改: 除了字符串之外， *salt* 还可接受 "crypt.METHOD_*" 值
   。

crypt.mksalt(method=None, *, rounds=None)

   返回用指定方法随机生成的 salt。如果没有给出 *method*，则使用
   "methods()" 返回的最强方法。

   返回一个字符串，可用作传入 "crypt()" 的 *salt* 参数。

   *rounds* 指定了 "METHOD_SHA256", "METHOD_SHA512" 和
   "METHOD_BLOWFISH" 的循环次数。 对于 "METHOD_SHA256" 和
   "METHOD_SHA512" 而言，必须为介于 "1000" 和 "999_999_999" 之间的整数
   ，默认值为 "5000"。 而对于 "METHOD_BLOWFISH"，则必须为 "16" (2^4)
   和 "2_147_483_648" (2^31) 之间的二的幂，默认值为 "4096" (2^12)。

   3.3 新版功能.

   在 3.7 版更改: 加入  *rounds* 参数。


示例
====

以下简单示例演示了典型用法（需要一个时间固定的比较操作来限制留给计时攻
击的暴露面。 "hmac.compare_digest()" 即很适用）：

   import pwd
   import crypt
   import getpass
   from hmac import compare_digest as compare_hash

   def login():
       username = input('Python login: ')
       cryptedpasswd = pwd.getpwnam(username)[1]
       if cryptedpasswd:
           if cryptedpasswd == 'x' or cryptedpasswd == '*':
               raise ValueError('no support for shadow passwords')
           cleartext = getpass.getpass()
           return compare_hash(crypt.crypt(cleartext, cryptedpasswd), cryptedpasswd)
       else:
           return True

采用当前强度最高的方法生成哈希值，并与原口令进行核对：

   import crypt
   from hmac import compare_digest as compare_hash

   hashed = crypt.crypt(plaintext)
   if not compare_hash(hashed, crypt.crypt(plaintext, hashed)):
       raise ValueError("hashed version doesn't validate against original")
