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

源代码: Lib / crypt.py

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

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

35.5.1. Hashing Methods

版本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. Module Attributes

版本3.3中的新功能。

crypt.methods

可用密码散列算法的列表,如crypt.METHOD_*对象。该列表从最强到最弱排序,并且保证至少具有crypt.METHOD_CRYPT

35.5.3. Module Functions

crypt模块定义以下函数:

crypt.crypt(word, salt=None)

通常是在提示或图形界面中输入的用户密码。可选的salt是从mksalt()返回的字符串,crypt.METHOD_*值之一(虽然不是全部可用在所有平台上),或完整加密的密码,包括盐,由此函数返回。如果未提供salt,将使用最强的方法(由methods()返回)。

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

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

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

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

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

crypt.mksalt(method=None)

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

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

版本3.3中的新功能。

35.5.4. Examples

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