secrets【暗号論的擬似乱数】3.6

メモ  (  概要 パスワードジェネレータ クラス・関数  ) 

メモ

  • 概要
    • パスワード等の機密情報を扱う場合に利用
    • シミュレーション等の用途で設計された random【擬似乱数】は、 推測されやすいので不適切
    • 元々存在していた random.SystemRandom【システム提供乱数】があまり認知されていない為に、別途標準ライブラリとして定義
  • パスワードジェネレータ
    • 有効文字を含んだ文字列から choice【要素選択】で長さ分取得して結合
    • 必要であれば、各種文字グループの最低数をチェックする等の制限
  • クラス・関数
    クラス備考
    class secrets.SystemRandomシステム提供乱数 (内部使用)
    関数備考
    choice(sequence) 要素選択
    戻り値sequence内の1つ
    sequence空でないシーケンス
    compare_digest(a, b) 文字列比較 (処理時間から推測する タイミング攻撃 のリスク軽減)
    戻り値比較結果 (True:一致 / False:不一致)
    a (str)比較文字列A
    b (str)比較文字列B
    randbelow(n) ランダム整数生成 (上限指定)
    戻り値ランダム整数 (0 以上n未満)
    n上限値 (含まない)
    randbits(k) ランダム整数生成 (ビット指定)
    戻り値ランダム整数 (kビット)
    kビット数
    token_bytes( [nbytes=None] ) ランダムバイト文字列生成
    戻り値バイト文字列 (nbytesバイト分)
    nbytesバイト数 (省略:内部デフォルト値)
    token_hex( [nbytes=None] ) ランダム16進数文字列生成
    戻り値16進数文字列 (nbytesバイト分)
    nbytesバイト数 (省略:内部デフォルト値)
    token_urlsafe( [nbytes=None] ) ランダム URL 文字列生成
    戻り値URL 文字列 ( Base64 エンコードの為、nbytesバイト分より長い)
    nbytesバイト数 (省略:内部デフォルト値)

パスワードジェネレータ

# パスワードジェネレータ
# 各種文字グループの最低数あり
import string
import secrets

LENGTH_PASSWORD = 60
MIN_UPPERS = 10
MIN_LOWERS = 10
MIN_DIGITS = 10
MIN_OTHERS = 10
chars = string.ascii_letters + string.digits + '!#$%&@+-*/'
print(chars)
# 出力:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!#$%&@+-*/
while True:
    password = ''.join(secrets.choice(chars) for i in range(LENGTH_PASSWORD))
    sum_upper = sum(c.isupper() for c in password)
    sum_lower = sum(c.islower() for c in password)
    sum_digit = sum(c.isdigit() for c in password)
    sum_other = LENGTH_PASSWORD - sum_upper - sum_lower -sum_digit
    print(password, sum_upper, sum_lower, sum_digit, sum_other)
    if (MIN_UPPERS <= sum_upper
            and MIN_LOWERS <= sum_lower
            and MIN_DIGITS <= sum_digit
            and MIN_OTHERS <= sum_other
        ):
        break
# 出力例:
# $ZsJDpwlDetJIO#JkXKjW%HHoZUm#LoPPcpTwRw%ixdS*GXNeCf!X1r40N3r 27 22 4 7
# hIfaw*v@XfA*ayUgPCcxTFbL$n$xI/3!hEBUU/6z2VOyqR0gNlmiBVl4lTEg 22 25 5 8
# xp#UaPN/Dmb2*I5F8PPQP6*AKrl&wC*ljdxg/wpiL#/@U6P1A0zgDKJh@WH4 22 19 8 11
# 1bDWZ6gc-8&4h$R#%Yud*GQ-*4%6feNA$h27eh4bQS@@$s5mIMSG#2JDpy+Q 18 16 11 15

関数

import secrets

# choice(sequence)【要素選択】
nums = [3, 5, 7, 11, 13, 17, 19]
for i in range(5):
    num = secrets.choice(nums)
    print(num)
# 出力例:
# 7
# 5
# 11
# 3
# 17

# compare_digest(a, b)【文字列比較】
password = 'password_PASSWORD'
user_input_1 = 'password_PASSWORD'
user_input_2 = 'password__PASSWORD'
print(secrets.compare_digest(password, user_input_1))
# 出力:True
print(secrets.compare_digest(password, user_input_2))
# 出力:False

# randbelow(n)【ランダム整数生成 (上限指定)】
MAX_RANDOM = 100
for i in range(5):
    rnd = secrets.randbelow(MAX_RANDOM)
    print(rnd)
# 出力例:
# 9
# 83
# 43
# 66
# 49

# randbits(k)【ランダム整数生成 (ビット指定)】
for i in range(5):
    k = (i + 1) * 8
    rnd = secrets.randbits(k)
    print(f'({k}) {rnd:#012x}')
# 出力例:
# (8) 0x000000002d
# (16) 0x000000ad58
# (24) 0x00002a01bc
# (32) 0x00562b5834
# (40) 0x458e79fab1

# token_bytes([nbytes=None])【ランダムバイト文字列生成】
bytes = secrets.token_bytes()
print(bytes)
# 出力例:b'\xbe\xc6\xb5@\xec\xd7\xaa\x8b\xf0\xd0y~R\xd9C\xa2U\xf2+w\x1aa\xc5/\x0c\x1cK\x07\xbaM$\x18'
for i in range(1, 6):
    bytes = secrets.token_bytes(i)
    print(i, bytes)
# 出力例:
# 1 b'0'
# 2 b'\xb2\x89'
# 3 b'.s\x17'
# 4 b'\\\xd1\xc2\x18'
# 5 b'h\xdcO\x14~'

# token_hex([nbytes=None])【ランダム16進数文字列生成】
hex = secrets.token_hex()
print(hex)
# 出力例:95e4f60424f98e3c2293948e70dbf2ba86afbd469763e8e4a1098392804e80db
for i in range(1, 6):
    hex = secrets.token_hex(i)
    print(i, hex)
# 出力例:
# 1 c1
# 2 bcdc
# 3 512458
# 4 a406c692
# 5 bb1c68a467

# token_urlsafe([nbytes=None])【ランダム URL 文字列生成】
urlsafe = secrets.token_urlsafe()
print(urlsafe)
# 出力例:jEWbCz_4H5yTI73joaHH69vUMdt6G2WSHJprXhb_5Ls
for i in range(1, 6):
    urlsafe = secrets.token_urlsafe(i)
    print(i, urlsafe)
# 出力例:
# 1 NA
# 2 JX8
# 3 fMHx
# 4 P7lTxg
# 5 yNXFSZw