secrets【暗号論的擬似乱数】3.6メモ ( 概要 パスワードジェネレータ 例 クラス・関数 例 ) 例 メモ概要 パスワード等の機密情報を扱う場合に利用 シミュレーション等の用途で設計された random【擬似乱数】は、 推測されやすいので不適切 元々存在していた random.SystemRandom【システム提供乱数】があまり認知されていない為に、別途標準ライブラリとして定義 パスワードジェネレータ〔 例 〕 有効文字を含んだ文字列から choice【要素選択】で長さ分取得して結合 必要であれば、各種文字グループの最低数をチェックする等の制限 クラス・関数〔 例 〕 クラス備考class secrets.SystemRandomシステム提供乱数 (内部使用)関数備考choice(sequence) 要素選択戻り値sequence内の1つsequence空でないシーケンスcompare_digest(a, b) 文字列比較 (処理時間から推測する タイミング攻撃 のリスク軽減)戻り値比較結果 (True:一致 / False:不一致)a (str)比較文字列Ab (str)比較文字列Brandbelow(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バイト数 (省略:内部デフォルト値) 外部リンクPython 標準ライブラリ secrets --- 機密を扱うために安全な乱数を生成する PEP 506 -- Adding A Secrets Module To The Standard Library (英語) random --- 擬似乱数を生成する 例パスワードジェネレータ # パスワードジェネレータ # 各種文字グループの最低数あり 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