35.5. crypt
--- Unix パスワードをチェックするための関数¶
ソースコード: Lib/crypt.py
このモジュールは修正 DES アルゴリズムに基づいた一方向ハッシュ関数である crypt(3) ルーチンを実装しています。詳細については 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 will usually be a user's password as typed at a prompt or in a graphical interface. The optional salt is either a string as returned from
mksalt()
, one of thecrypt.METHOD_*
values (though not all may be available on all platforms), or a full encrypted password including salt, as returned by this function. If salt is not provided, the strongest method will be used (as returned bymethods()
).通常は、生の文字列のパスワードを word として渡し、前回の
crypt()
を呼び出した結果と今回の呼び出しの結果が同じになることで、パスワードの確認を行います。salt (2文字から16文字のランダムな文字列で、方式を示す
$digit$
が先頭に付いているかもしれません) は、暗号化アルゴリズムにぶれを生じさせるために使われます。 salt に含まれる文字は、モジュラー暗号形式の先頭にある$digit$
を除いて、集合[./a-zA-Z0-9]
に含まれていなければいけません。ハッシュ化されたパスワードを文字列として返します。それは salt と同じアルファベット文字から構成されます。
いくつかの拡張された crypt(3) は異なる値と salt の長さを許しているので、パスワードをチェックする際には crypt されたパスワード文字列全体を salt として渡すよう勧めます。
バージョン 3.3 で変更: 文字列に加え、 salt が
crypt.METHOD_*
値も受け取るようになりました。
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")