Skip to main content

35.5. crypt —检查Unix密码的功能

源代码: Lib/crypt.py


该模块实现了 crypt(3) 例程的接口,该例程是基于修改的DES算法的单向散列函数;有关更多详细信息,请参阅Unix手册页。可能的用途包括存储散列密码,以便您可以在不存储实际密码的情况下检查密码,或尝试使用字典破解Unix密码。

请注意,此模块的行为取决于运行系统中 crypt(3) 例程的实际实现。因此,当前实现中可用的任何扩展也将在此模块上可用。

35.5.1. 散列方法

3.3 新版功能.

crypt 模块定义了哈希方法列表(并非所有平台上的所有方法都可用):

crypt.METHOD_SHA512

一个16字符盐和86字符哈希的模块化地址格式方法。这是最强的方法。

crypt.METHOD_SHA256

另一个模块化地址格式方法,具有16个字符的盐和43个字符的哈希。

crypt.METHOD_MD5

另一个模块化地址格式方法,具有8个字符的盐和22个字符的哈希。

crypt.METHOD_CRYPT

传统方法使用2个字符的盐和13个字符的哈希。这是最弱的方法。

35.5.2. 模块属性

3.3 新版功能.

crypt.methods

可用密码散列算法的列表,作为 crypt.METHOD_* 对象。此列表按从最强到最弱排序。

35.5.3. 模块功能

crypt 模块定义以下功能:

crypt.crypt(word, salt=None)

word 通常是在提示符或图形界面中键入的用户密码。可选的 salt 是从 mksalt() 返回的字符串,crypt.METHOD_* 值之一(尽管不是所有平台都可用),或者是由此函数返回的包含salt的完全加密密码。如果不提供 salt,将使用最强的方法(由 methods() 返回。

检查密码通常是通过传递明文密码作为 word 和以前的 crypt() 调用的完整结果,应该与此调用的结果相同。

salt (随机的2或16个字符的字符串,可能带有 $digit$ 的前缀以指示该方法),这将用于扰乱加密算法。 salt 中的字符必须在集合 [./a-zA-Z0-9] 中,除了前缀 $digit$ 的模块加密格式例外。

以字符串形式返回散列的密码,该字符串将由与盐相同的字母表中的字符组成。

由于少数 crypt(3) 扩展允许不同的值,在 salt 中具有不同的大小,因此建议在检查密码时使用完全加密的密码作为盐。

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

crypt.mksalt(method=None)

返回指定方法的随机生成的盐。如果没有给出 method,则使用由 methods() 返回的最强的方法。

返回值是 crypt.METHOD_CRYPT 的长度为2个字符,或者以 $digit$ 开头的19个字符和来自集合 [./a-zA-Z0-9] 的16个随机字符的字符串,适合作为 salt 参数传递给 crypt()

3.3 新版功能.

35.5.4. 例子

一个简单的例子说明典型的使用(需要恒定时间比较操作来限制暴露于定时攻击) 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")