"secrets" --- 機密を扱うために安全な乱数を生成する
**************************************************

Added in version 3.6.

**ソースコード:** Lib/secrets.py

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

"secrets" モジュールは、パスワード、アカウント認証、セキュリティトーク
ン、その他の機密情報の管理に適した、暗号学的に強い乱数を生成するために
使います。

特に、"random" モジュールのデフォルトの擬似乱数生成器よりも、"secrets"
を優先して使ってください。 その擬似乱数生成器は、セキュリティや暗号処
理ではなく、モデリングとシミュレーションのために設計されています。

参考: **PEP 506**


乱数
====

"secrets" モジュールは、オペレーティングシステムが提供する最も安全な乱
数源へのアクセスを提供します。

class secrets.SystemRandom

   OS が提供する最も高品質なソースを用いて乱数を生成するためのクラスで
   す。更に詳しいことについては "random.SystemRandom" を参照してくださ
   い。

secrets.choice(seq)

   空でないシーケンスから要素をランダムに選択して返します。

secrets.randbelow(exclusive_upper_bound)

   [0, *exclusive_upper_bound*) の範囲のランダムな整数を返します。

secrets.randbits(k)

   ランダムな *k* ビットの非負の整数を返します。


トークンの生成
==============

"secrets" モジュールは、パスワードのリセットや推測しにくい URL などの
用途に適した、安全なトークンを生成する関数を提供します。

secrets.token_bytes(nbytes=None)

   *nbytes* バイトのランダムなバイト文字列を返します。

   *nbytes* を指定しない場合や "None" の場合は、代わりに
   "DEFAULT_ENTROPY" を使います。

      >>> token_bytes(16)
      b'\xebr\x17D*t\xae\xd4\xe3S\xb6\xe2\xebP1\x8b'

secrets.token_hex(nbytes=None)

   16 進数で表したランダムな文字列を返します。 *nbytes* バイトのランダ
   ムなデータの各バイトを、16 進数の 2 桁に変換した文字列です。

   *nbytes* を指定しない場合や "None" の場合は、代わりに
   "DEFAULT_ENTROPY" を使います。

      >>> token_hex(16)
      'f9bf78b9a18ce6d46a0cd2b0b86df9da'

secrets.token_urlsafe(nbytes=None)

   *nbytes* バイトのランダムなデータを含む、URL に安全に使えるランダム
   な文字列を返します。 Base64 でエンコードするため、各バイトは平均し
   て約 1.3 文字になります。

   *nbytes* を指定しない場合や "None" の場合は、代わりに
   "DEFAULT_ENTROPY" を使います。

      >>> token_urlsafe(16)
      'Drmhze6EPcv0fN_81Bj-nA'


トークンは何バイト使うべきか？
------------------------------

総当たり攻撃 に対して安全であるには、トークンに十分なランダムさが必要
です。 残念ながら、コンピューターの性能が向上し、短時間でより多くの候
補を試せるようになるにつれて、十分とされるランダムさは増えていきます。
2015 年時点では、"secrets" モジュールに想定される典型的な用途には、32
バイト (256 ビット) のランダムさで十分と考えられています。

独自の長さのトークンを扱いたい場合、様々な "token_*" 関数に "int" 引数
で渡すことで、トークンに使用するランダムさを明示的に指定することができ
ます。引数はランダムさのバイト数として使用されます。

引数を指定しない場合や引数が "None" の場合、"token_*" 関数は代わりに
"DEFAULT_ENTROPY" を使います。

secrets.DEFAULT_ENTROPY

   "token_*" 関数が使う、ランダムなデータのデフォルトのバイト数。

   具体的な値は、メンテナンスリリースも含め、いつでも変更される可能性
   があります。


その他の関数
============

secrets.compare_digest(a, b)

   文字列または *bytes-like object* である *a* と *b* が等しければ
   "True"、それ以外は "False" を返します。 タイミング攻撃 のリスクを減
   らすため、「定数時間の比較」を使います。 詳しくは
   "hmac.compare_digest()" を参照してください。


レシピとベストプラクティス
==========================

この節では、"secrets" を使って基本的なセキュリティ水準を維持するための
レシピとベストプラクティスを示します。

8文字のアルファベットと数字を含むパスワードを生成するには:

   import string
   import secrets
   alphabet = string.ascii_letters + string.digits
   password = ''.join(secrets.choice(alphabet) for i in range(8))

注釈:

  アプリケーションは、平文であろうと暗号化されていようと、 **復元可能
  な形式でパスワードを保存** してはいけません。パスワードは暗号学的に
  強い一方向 (非可逆) ハッシュ関数を用いてソルトしハッシュしなければな
  りません。

小文字を少なくとも1つ、大文字を少なくとも1つ、数字を少なくとも3つ含む
、英数字10文字のパスワードを生成する例です。

   import string
   import secrets
   alphabet = string.ascii_letters + string.digits
   while True:
       password = ''.join(secrets.choice(alphabet) for i in range(10))
       if (any(c.islower() for c in password)
               and any(c.isupper() for c in password)
               and sum(c.isdigit() for c in password) >= 3):
           break

XKCD スタイルのパスフレーズ を生成するには:

   import secrets
   # 標準的な Linux システムでは、利用できる辞書ファイルを使う。
   # 他のプラットフォームでは、単語リストを自分で用意する必要がある場合がある。
   with open('/usr/share/dict/words') as f:
       words = [word.strip() for word in f]
       password = ' '.join(secrets.choice(words) for i in range(4))

パスワードの復元用途に適したセキュリティトークンを含む、推測しにくい一
時 URL を生成するには:

   import secrets
   url = 'https://example.com/reset=' + secrets.token_urlsafe()
