[python] 高品質、単純なランダムなパスワードジェネレータ



10 Answers

XKCDは、なぜ強力なパスワードではない と考えるのかについての大きな説明があります。

情報理論とセキュリティを理解していない人と激しい議論をしている人(おそらく大文字と小文字が混在している可能性がある人)にとって、私は心からお詫び申し上げます。 - ランダル・モンロー

そしてこのイラストレーションが説明していることの背後にある数学を理解していなければ、そうではないので、暗号的に安全なものを書こうとしないでください。 マウスを押し下げてキーボードから離すだけです。

Question

私は、非常にシンプルな、高(暗号)品質のランダムなパスワードジェネレータを作成することに興味があります。 これを行うより良い方法はありますか?

import os, random, string

length = 13
chars = string.ascii_letters + string.digits + '!@#$%^&*()'
random.seed = (os.urandom(1024))

print ''.join(random.choice(chars) for i in range(length))



Here is my random password generator after researching this topic:

`import os, random, string
   #Generate Random Password
   UPP = random.SystemRandom().choice(string.ascii_uppercase)
   LOW1 = random.SystemRandom().choice(string.ascii_lowercase)
   LOW2 = random.SystemRandom().choice(string.ascii_lowercase)
   LOW3 = random.SystemRandom().choice(string.ascii_lowercase)
   DIG1 = random.SystemRandom().choice(string.digits)
   DIG2 = random.SystemRandom().choice(string.digits)
   DIG3 = random.SystemRandom().choice(string.digits)
   SPEC = random.SystemRandom().choice('!@#$%^&*()')
   PWD = None
   PWD = UPP + LOW1 + LOW2 + LOW3 + DIG1 + DIG2 + DIG3 + SPEC
   PWD = ''.join(random.sample(PWD,len(PWD)))
   print(PWD)`

This will generate a random password with 1 random uppercase letter, 3 random lowercase letters, 3 random digits, and 1 random special character--this can be adjusted as needed. Then it combines each random character and creates a random order. I don't know if this is considered "high quality", but it gets the job done.




私はこの質問が2011年に返されたことを知っていますが、2014年以降に来る人には、私は言うべきことが1つあります。

このような状況では、オープンソースソフトウェアを検索することが最善の方法です。たとえば、検索結果をgithub結果に限定するなどです。 私が見つけた最高のもの:

github.com/redacted/XKCD-password-generator




There are some problems with your implementation:

random.seed = (os.urandom(1024))

This does not seed the random number generator; it replaces the seed function with a bytestring. You need to call seed , like, random.seed(…) .

print ''.join(random.choice(chars) for i in range(length))

Python's default PRNG is a Mersenne Twister, which is not a cryptographically strong PRNG, so I'm wary of using it for cryptographic purposes. The random module includes random.SystemRandom , which on at least most *nix systems, should use a CSPRNG. However ,

random.choice(chars)

…is implemented as…

def choice(self, seq):
    """Choose a random element from a non-empty sequence."""
    return seq[int(self.random() * len(seq))]  # raises IndexError if seq is empty

…in Python 2 . Unfortunately, self.random here is a C function, so this gets hard to see; the code smell here is that this code almost certainly doesn't choose uniformly. The code has completely changed in Python 3, and does a much better job of ensuring uniformity. The Python 3 docs for randrange note,

Changed in version 3.2: randrange() is more sophisticated about producing equally distributed values. Formerly it used a style like int(random()*n) which could produce slightly uneven distributions.

randrange and choice both call the same method ( _randbelow ) under the hood.

In Python 3, choice is fine; in Python 2, it only comes close to a uniform distribution, but does not guarantee it. Since this is crypto, I lean on the "take no chances" side of the fence, and would like to have that guarantee.




My solution based on @Thomas Pornin's answer

import os, string

def get_pass(password_len=12):
  new_password=None
  symbols='^&%$@#!'
  chars=string.ascii_lowercase+\
        string.ascii_uppercase+\
        string.digits+\
        symbols

  while new_password is None or \
        new_password[0] in string.digits or \
        new_password[0] in symbols:
     new_password=''.join([chars[ord(os.urandom(1)) % len(chars)] \
                             for i in range(password_len)])
  return new_password

print(get_pass)

この関数は、ランダムなパスワードを返します(パスワードの先頭に数字または記号はありません)。




そのように動作します。 それは完璧です。 辞書の単語を除外するなどの追加ルールがある場合は、これらのフィルタも含めることができますが、その設定で辞書単語をランダムに生成する可能性は非常に低くなります。




A little bit off topic, but I made this, using also TKinter. Hope it can helps:

import os, random, string
from tkinter import *

def createPwd():
    try:
        length = int(e1.get())
    except ValueError:
        return
    chars = string.ascii_letters + string.digits + '!@#$%^&*()?\/'
    random.seed = (os.urandom(1024))
    e2.config(state=NORMAL)
    e2.delete(0,'end')
    e2.insert(0,''.join(random.choice(chars) for i in range(length)))
    e2.config(state="readonly")

mainWindow = Tk()
mainWindow.title('Password generator')

mainWindow.resizable(0,0)

f0 = Frame(mainWindow)

f0.pack(side=TOP,pady=5,padx=5,fill=X,expand=1)

Label(f0,text="Length: ",anchor=E).grid(row=0,column=0,sticky=E)

e1 = Entry(f0)
e1.insert(0,'12')
e1.grid(row=0,column=1)

btn = Button(f0,text="Generate")
btn['command'] = lambda: createPwd()
btn.grid(row=0,column=2,rowspan=1,padx=10,ipadx=10)

Label(f0,text="Generated password: ",anchor=E).grid(row=1,column=0,sticky=E)
e2 = Entry(f0)
e2.grid(row=1,column=1)

createPwd()

#starting main window
mainWindow.mainloop()



私は言語学を愛しています。私のアプローチでは、子音と母音を交互に入れて、高いレベルのエントロピーで思い出に残る疑似単語を作成します。

  • 辞書攻撃の影響を受けません
  • 発音可能なので、思い出に残るチャンス
  • まともな強さの短いパスワード
  • 互換性のためにランダムな桁を追加するためのオプションのパラメータ(記憶されにくいが、数字を必要とするような古いパスワードセキュリティ思考で構築されたアプリケーションに準拠)

Pythonコード:

import random, string

def make_pseudo_word(syllables=5, add_number=False):
    """Alternate random consonants & vowels creating decent memorable passwords
    """
    rnd = random.SystemRandom()
    s = string.ascii_lowercase
    vowels = 'aeiou'
    consonants = ''.join([x for x in s if x not in vowels])
    pwd = ''.join([rnd.choice(consonants)+rnd.choice(vowels)
               for x in 'x'*syllables]).title()
    if add_number:
        pwd += str(rnd.choice(range(10)))
    return pwd


>>> make_pseudo_word(syllables=5)
'Bidedatuci'
>>> make_pseudo_word(syllables=5)
'Fobumehura'
>>> make_pseudo_word(syllables=5)
'Seganiwasi'
>>> make_pseudo_word(syllables=4)
'Dokibiqa'
>>> make_pseudo_word(syllables=4)
'Lapoxuho'
>>> make_pseudo_word(syllables=4)
'Qodepira'
>>> make_pseudo_word(syllables=3)
'Minavo'
>>> make_pseudo_word(syllables=3)
'Fiqone'
>>> make_pseudo_word(syllables=3)
'Wiwohi'

短所:

  • ラテン語とゲルマン語の話者、英語に精通している方
  • 1つは、アプリケーションのユーザーまたはフォーカスグループとチューンに支配的な言語の母音と子音を使用する必要があります



@Thomas Porninソリューションの実装

import M2Crypto
import string

def random_password(length=10):
    chars = string.ascii_uppercase + string.digits + string.ascii_lowercase
    password = ''
    for i in range(length):
        password += chars[ord(M2Crypto.m2.rand_bytes(1)) % len(chars)]
    return password



Implenting @Thomas Pornin solution: (can't comment @Yossi inexact answer)

import string, os
chars = string.letters + string.digits + '+/'
assert 256 % len(chars) == 0  # non-biased later modulo
PWD_LEN = 16
print ''.join(chars[ord(c) % len(chars)] for c in os.urandom(PWD_LEN))



パスワードを生成するときには、Pythonの疑似乱数ジェネレータを信頼することはできません。 それは必ずしも暗号的にランダムではない。 あなたは良いスタートであるos.urandomから擬似乱数ジェネレータをos.urandomいます。 しかし、その後、Pythonのジェネレータに依存します。

より良い選択は、 random.SystemRandom()クラスで、乱数を同じソースからランダムに受け取ります。 暗号の使用に十分なはずのpythonのドキュメントによると。 SystemRandomクラスは、メインのランダムクラスが行うすべてを提供しますが、擬似ランダム性について心配する必要はありません。

random.SystemRandom(Python 2.6用)を使用したコード例:

import random, string
length = 13
chars = string.ascii_letters + string.digits + '!@#$%^&*()'

rnd = random.SystemRandom()
print ''.join(rnd.choice(chars) for i in range(length))

注:あなたの走行距離は多少異なる場合があります - Pythonのドキュメントによると、ランダムなシステムランダムの利用可能性はオペレーティングシステムによって異なります。




Related