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


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))



import random


r = random.SystemRandom()


def generate_password(words, top=2000, k=4, numbers=None, characters=None,
                      first_upper=True):
    """Return a random password based on a sorted word list."""
    elements = r.sample(words[:top], k)

    if numbers:
        elements.insert(r.randint(1, len(elements)), r.choice(numbers))
    if characters:
        elements.insert(r.randint(1, len(elements)), r.choice(characters))
    if first_upper:
        elements[0] = elements[0].title()

    return ''.join(elements)


if __name__ == '__main__':
    with open('./google-10000-english-usa.txt') as f:
        words = [w.strip() for w in f]
    print(generate_password(words, numbers='0123456789', characters='!@#$%'))
  • あなたが思い出すことのできるパスワードを生成する
  • os.urandom()使用しos.urandom()
  • 数字、大文字、文字の追加などの現実のルールを処理します。

確かにそれは改善することができますが、これは私が使用するものです。




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

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

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つは、アプリケーションのユーザーまたはフォーカスグループとチューンに支配的な言語の母音と子音を使用する必要があります



少しトピックオフビット、私はまた、Tkinterのを使用して、これを作りました。それが役立ちますことを願って:

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()



@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



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

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

https://github.com/redacted/XKCD-password-generator




あなたの実装にいくつかの問題があります。

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

これは、乱数ジェネレータをシードしません。それは置き換えseedバイト文字列で関数を。あなたはコールする必要がありseed、同様、random.seed(…)

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

PythonのデフォルトPRNGは、暗号強いPRNGないメルセンヌツイスター、であるので、私は、暗号化の目的のためにそれを使用しての警戒です。randomモジュールは、random.SystemRandom少なくともほとんどの* nixシステム上で、CSPRNGを使用すべき、。しかし

random.choice(chars)

...として実装されています...

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

...でのPython 2。残念ながら、self.randomここではCの関数であるので、これは見にくくなります。ここでのコードのにおいが、このコードはほぼ確実に一様に選択していないということです。コードは、完全にはPython 3に変更し、均一性を確保するより良い仕事をしています。用のPython 3のドキュメントrandrangeノート、

バージョン3.2で変更:randrange()均等に分散値を生成についてより洗練されています。以前は、それは次のようなスタイルで使用int(random()*n)わずかな凹凸分布を作り出すことができたし。

randrangeそしてchoice両方とも同じ方法(呼び出し_randbelowボンネットの下に)。

Pythonの3では、choice結構です。Pythonの2で、それだけで来る近い均一に分布するが、それを保証するものではありません。これは暗号化されますので、私はフェンスの「何のチャンスを取らない」側に傾くと、その保証を持っていると思います。




ここでは、このトピックを研究した後に、私のランダムなパスワードジェネレータは、次のとおりです。

`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)`

必要に応じてこれを調整することができる - これは、1つのランダム大文字、3つのランダム小文字、3桁のランダムな数字、および1つのランダムな特殊文字を持つランダムなパスワードを生成します。そして、それは、それぞれランダムな文字を組み合わせて、ランダムな順序を作成します。これは、「高品質」とみなされるかどうかは知りませんが、それは仕事を取得します。




@Thomas PorninソリューションをImplenting:(@Yossi不正確な答えをコメントすることはできません)

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))



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




これが何よりも楽しみのために多くのです。スコア好意passwordmeter.comでなく、覚えてすることは不可能。

#!/usr/bin/ruby

puts (33..126).map{|x| ('a'..'z').include?(x.chr.downcase) ?
                       (0..9).to_a.shuffle[0].to_s + x.chr :
                       x.chr}.uniq.shuffle[0..41].join[0..41]