it-swarm.com.de

Hochwertiger, einfacher Zufallsgenerator

Ich bin daran interessiert, einen sehr einfachen, qualitativ hochwertigen (kryptografischen) Zufallskennwortgenerator zu erstellen. Gibt es einen besseren Weg, dies zu tun?

import os, random, string

length = 13
chars = string.ascii_letters + string.digits + '[email protected]#$%^&*()'
random.seed = (os.urandom(1024))

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

Die Schwierigkeit bei Passwörtern besteht darin, sie stark genug zu machen und sich trotzdem daran erinnern zu können. Wenn sich das Passwort nicht an einen Menschen erinnern soll, handelt es sich nicht wirklich um ein Passwort.

Sie verwenden Pythons os.urandom(): das ist gut. Für jeden praktischen Zweck (auch für die Kryptographie) ist die Ausgabe von os.urandom() nicht von True Alea zu unterscheiden. Dann verwenden Sie es als Ausgangswert in random, was weniger gut ist: Es handelt sich um einen nicht-kryptographischen PRNG, dessen Ausgabe möglicherweise eine Struktur aufweist, die sich nicht in einem statistischen Messwerkzeug registriert, aber von einem intelligenten Angreifer ausgenutzt wird. Sie sollten die ganze Zeit mit os.urandom() arbeiten. Zur Vereinfachung: Wählen Sie ein Alphabet der Länge 64, z. Buchstaben (Groß- und Kleinbuchstaben), Ziffern und zwei zusätzliche Interpunktionszeichen (wie '+' und '/'). Rufen Sie dann für jedes Kennwortzeichen ein Byte von os.urandom() ab, reduzieren Sie den Wert modulo 64 (dies ist unparteiisch, da 64 256 teilt) und verwenden Sie das Ergebnis als Index in Ihrem chars-Array.

Mit einem Alphabet der Länge 64 erhalten Sie 6 Zeichen Entropie pro Zeichen (weil 26 = 64). So erhalten Sie mit 13 Zeichen 78 Bit Entropie. Dies ist letztlich nicht in allen Fällen stark, aber bereits sehr stark (es könnte mit einem Budget geschlagen werden, das in Monaten und Milliarden von Dollar und nicht in Millionenhöhe gezählt wird).

45
Thomas Pornin

XKCD hat eine großartige Erklärung dafür, warum was Ihrer Meinung nach starke Kennwörter sind keine sind.

http://xkcd.com/936/

Für alle, die Informationstheorie und -sicherheit verstehen und in einer ärgerliche Auseinandersetzung mit jemandem, der nicht (möglicherweise mit einem gemischten Fall) befasst ist, entschuldige ich mich aufrichtig. - Randall Munroe

Und wenn Sie die Mathe hinter dem, was diese Abbildung erklärt nicht verstehen, schreiben Sie nichts, was kryptographisch sicher sein sollte, da dies nicht der Fall ist. Legen Sie einfach die Maus ab und treten Sie von der Tastatur weg.

38
user177800

Vor nur zwei Tagen hat Kragen Javier Sitaker ein Programm veröffentlicht, um dies zu tun unter http://lists.canonical.org/pipermail/kragen-hacks/2011-September/000527.html (gegangen jetzt - versuchen Sie https : //github.com/jesterpm/bin/blob/master/mkpasswd )

Generieren Sie ein zufälliges, einprägsames Passwort: http://xkcd.com/936/

Beispiellauf:

kragen bei unaufhaltsam: ~/devel/unaufhaltsam-misc $ ./mkpass.py 5 12 Ihr Passwort lautet "erlernter Schaden gesparter Wohnsitz". Das entspricht einem 60-Bit-Schlüssel.

Dieses Passwort würde bei meinem preiswerten Celeron E1200 aus dem Jahr 2008 2,5e + 03 CPU-Jahre beanspruchen, vorausgesetzt, es handelt sich um einen Offline-Angriff auf einen MS-Cache-Hash, den übelsten Passwort-Hashing-Algorithmus, der etwas schlimmer ist als der einfache MD5.

Der häufigste Passwort-Hashing-Algorithmus dieser Tage ist FreeBSDs wiederholter MD5. ein solcher Hash zu knacken würde 5.2e + 06 CPU-Jahre dauern.

Eine moderne GPU kann jedoch 250 Mal so schnell knacken, dass dasselbe iterierte MD5 in 2e + 04 GPU-Jahren abnehmen würde.

Diese GPU kostet im Jahr 2011 etwa 1,45 US-Dollar pro Tag, sodass das Knacken des Passworts etwa 3 Euro + 09 US-Dollar kosten würde.

Ich habe angefangen, ein auf diese Weise generiertes Passwort anstelle eines aus 9 druckbaren ASCII-Zeichen bestehenden, zufälligen Passworts zu verwenden, das ebenso stark ist. Munroes Behauptung, diese Passwörter seien viel einfacher zu merken, ist richtig. Es gibt jedoch immer noch ein Problem: Da es viel weniger Entropiebits pro Zeichen gibt (ungefähr 1,7 anstelle von 6,6), ist das Passwort sehr redundant, und Angriffe wie der ssh-Timing-Channel-Angriff (der Song Wagner und Tian Herbivore Attack (was ich vor ein paar Jahren von Bram Cohen im Bagdad Café in den frühen Morgenstunden erfahren habe) und Tastatur-Audioaufnahmeangriffe haben eine viel bessere Chance, genügend Informationen zu erfassen, um das Passwort angreifbar zu machen.

Meine Gegenmaßnahme zum Herbivore-Angriff, der gut mit dem 9-stelligen Passwort funktioniert, aber mit meinem neuen Passwort äußerst ärgerlich ist, besteht darin, das Passwort mit einer halben Sekunde Verzögerung zwischen den Zeichen einzugeben, so dass der Timing-Kanal nicht viel Informationen über das Kennwort enthält tatsächliche Zeichen verwendet. Darüber hinaus ist die Herbivore-Methode aufgrund der geringeren Länge des 9-stelligen Passworts inhärent weniger Informationen, über die man kauen kann.

Andere mögliche Gegenmaßnahmen umfassen die Verwendung des Emacs Shell-Modus, der Sie lokal zur Eingabe des Kennworts auffordert, wenn es eine Kennwortabfrage erkennt, das gesamte Kennwort auf einmal sendet und das Kennwort an anderer Stelle kopiert und eingefügt wird.

Wie zu erwarten, dauert die Eingabe dieses Kennworts auch etwas länger: etwa 6 Sekunden statt etwa 3 Sekunden.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import random, itertools, os, sys

def main(argv):
    try:
        nwords = int(argv[1])
    except IndexError:
        return usage(argv[0])

    try:
        nbits = int(argv[2])
    except IndexError:
        nbits = 11

    filename = os.path.join(os.environ['HOME'], 'devel', 'wordlist')
    wordlist = read_file(filename, nbits)
    if len(wordlist) != 2**nbits:
        sys.stderr.write("%r contains only %d words, not %d.\n" %
                         (filename, len(wordlist), 2**nbits))
        return 2

    display_password(generate_password(nwords, wordlist), nwords, nbits)
    return 0

def usage(argv0):
    p = sys.stderr.write
    p("Usage: %s nwords [nbits]\n" % argv0)
    p("Generates a password of nwords words, each with nbits bits\n")
    p("of entropy, choosing words from the first entries in\n")
    p("$HOME/devel/wordlist, which should be in the same format as\n")
    p("<http://canonical.org/~kragen/sw/wordlist>, which is a text file\n")
    p("with one Word per line, preceded by its frequency, most frequent\n")
    p("words first.\n")
    p("\nRecommended:\n")
    p("    %s 5 12\n" % argv0)
    p("    %s 6\n" % argv0)
    return 1

def read_file(filename, nbits):
    return [line.split()[1] for line in
            itertools.islice(open(filename), 2**nbits)]

def generate_password(nwords, wordlist):
    choice = random.SystemRandom().choice
    return ' '.join(choice(wordlist) for ii in range(nwords))

def display_password(password, nwords, nbits):
    print 'Your password is "%s".' % password
    entropy = nwords * nbits
    print "That's equivalent to a %d-bit key." % entropy
    print

    # My Celeron E1200
    # (<http://ark.intel.com/products/34440/Intel-Celeron-Processor-E1200-(512K-Cache-1_60-GHz-800-MHz-FSB)>)
    # was released on January 20, 2008.  Running it in 32-bit mode,
    # john --test (<http://www.openwall.com/john/>) reports that it
    # can do 7303000 MD5 operations per second, but I’m pretty sure
    # that’s a single-core number (I don’t think John is
    # multithreaded) on a dual-core processor.
    t = years(entropy, 7303000 * 2)
    print "That password would take %.2g CPU-years to crack" % t
    print "on my inexpensive Celeron E1200 from 2008,"
    print "assuming an offline attack on a MS-Cache hash,"
    print "which is the worst password hashing algorithm in common use,"
    print "slightly worse than even simple MD5."
    print

    t = years(entropy, 3539 * 2)
    print "The most common password-hashing algorithm these days is FreeBSD’s"
    print "iterated MD5; cracking such a hash would take %.2g CPU-years." % t
    print

    # (As it happens, my own machines use Drepper’s SHA-2-based
    # hashing algorithm that was developed to replace the one
    # mentioned above; I am assuming that it’s at least as slow as the
    # MD5-crypt.)

    # <https://en.bitcoin.it/wiki/Mining_hardware_comparison> says a
    # Core 2 Duo U7600 can do 1.1 Mhash/s (of Bitcoin) at a 1.2GHz
    # clock with one thread.  The Celeron in my machine that I
    # benchmarked is basically a Core 2 Duo with a smaller cache, so
    # I’m going to assume that it could probably do about 1.5Mhash/s.
    # All common password-hashing algorithms (the ones mentioned
    # above, the others implemented in John, and bcrypt, but not
    # scrypt) use very little memory and, I believe, should scale on
    # GPUs comparably to the SHA-256 used in Bitcoin.

    # The same mining-hardware comparison says a Radeon 5870 card can
    # do 393.46 Mhash/s for US$350.

    print "But a modern GPU can crack about 250 times as fast,"
    print "so that same iterated MD5 would fall in %.1g GPU-years." % (t / 250)
    print

    # Suppose we depreciate the video card by Moore’s law,
    # i.e. halving in value every 18 months.  That's a loss of about
    # 0.13% in value every day; at US$350, that’s about 44¢ per day,
    # or US$160 per GPU-year.  If someone wanted your password as
    # quickly as possible, they could distribute the cracking job
    # across a network of millions of these cards.  The cards
    # additionally use about 200 watts of power, which at 16¢/kWh
    # works out to 77¢ per day.  If we assume an additional 20%
    # overhead, that’s US$1.45/day or US$529/GPU-year.
    cost_per_day = 1.45
    cost_per_crack = cost_per_day * 365 * t
    print "That GPU costs about US$%.2f per day to run in 2011," % cost_per_day
    print "so cracking the password would cost about US$%.1g." % cost_per_crack

def years(entropy, crypts_per_second):
    return float(2**entropy) / crypts_per_second / 86400 / 365.2422

if __== '__main__':
    sys.exit(main(sys.argv))
13
Roshan Mathews

implementierung der @Thomas Pornin-Lösung

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
10
yossi

Eine weitere Implementierung der XKCD-Methode:

#!/usr/bin/env python
import random
import re

# apt-get install wbritish
def randomWords(num, dictionary="/usr/share/dict/british-english"):
  r = random.SystemRandom() # i.e. preferably not pseudo-random
  f = open(dictionary, "r")
  count = 0
  chosen = []
  for i in range(num):
    chosen.append("")
  prog = re.compile("^[a-z]{5,9}$") # reasonable length, no proper nouns
  if(f):
    for Word in f:
      if(prog.match(Word)):
        for i in range(num): # generate all words in one pass thru file
          if(r.randint(0,count) == 0): 
            chosen[i] = Word.strip()
        count += 1
  return(chosen)

def genPassword(num=4):
  return(" ".join(randomWords(num)))

if(__== "__main__"):
  print genPassword()

Beispielausgabe:

$ ./randompassword.py
affluent afford scarlets twines
$ ./randompassword.py
speedboat ellipse further staffer
7
OJW

Ich weiß, dass diese Frage bereits 2011 veröffentlicht wurde, aber für alle, die 2014 und später dazu kommen, habe ich eines zu sagen: WIDERST DEN REICH, UM DAS RAD ZU ERNEUERN.

In diesen Situationen suchen Sie am besten nach Open-Source-Software, z. B. beschränken Sie Ihre Suche auf Github-Ergebnisse. Bei weitem das Beste, was ich gefunden habe:

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

7
rsaw

Sie können dem Python-Pseudo-Zufallszahlengenerator beim Erstellen eines Kennworts nicht vertrauen. Es ist nicht unbedingt kryptographisch zufällig. Sie säen den Pseudo-Zufallszahlengenerator aus os.urandom, der ein guter Anfang ist. Aber danach sind Sie auf Pythons Generator angewiesen.

Eine bessere Wahl wäre die Klasse random.SystemRandom() , die Zufallszahlen aus derselben Quelle wie urandom entnimmt. Laut der Python-Dokumentation sollte dies für kryptografische Zwecke ausreichend sein. Die SystemRandom-Klasse bietet Ihnen alles, was die zufällige Hauptklasse tut.

Beispielcode mit random.SystemRandom (für Python 2.6):

import random, string
length = 13
chars = string.ascii_letters + string.digits + '[email protected]#$%^&*()'

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

Hinweis: Ihre Laufleistung kann variieren. Die Python-Dokumentation besagt, dass die Verfügbarkeit von random.SystemRandom je nach Betriebssystem variiert.

4
Winston Ewert

In Anbetracht Ihres Kommentars

Ich muss nur in der Lage sein, Passwörter zu generieren, die sicherer sind als die, die ich in meinem Kopf finden würde.

anscheinend möchten Sie Ihr Programm verwenden, um Passwörter zu generieren, anstatt es lediglich als Übung zu schreiben. Die Verwendung einer vorhandenen Implementierung ist zu bevorzugen, da bei einem Fehler die Ausgabe möglicherweise beeinträchtigt wird. Lesen Sie über Zufallszahlengenerator-Angriffe ; Insbesondere ein bekannter RNG-Fehler in Debian enthüllte die privaten SSL-Schlüssel von Personen.

Erwägen Sie stattdessen die Verwendung von pwgen . Es bietet mehrere Optionen, die Sie je nach Verwendungszweck der Kennwörter auswählen sollten.

3

Implementierung von @Thomas Pornin-Lösung: (@Yossi kann keine genaue Antwort kommentieren)

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))
2
foudfou
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 __== '__main__':
    with open('./google-10000-english-usa.txt') as f:
        words = [w.strip() for w in f]
    print(generate_password(words, numbers='0123456789', characters='[email protected]#$%'))
  • Erzeugt Kennwörter, die Sie sich merken können
  • Verwendet os.urandom()
  • Behandelt reale Regeln wie das Hinzufügen von Zahlen, Großbuchstaben und Zeichen.

Sicher kann es verbessert werden, aber das verwende ich.

2
MikeRand

Meine eigene CLI-Antwort zu dem vorliegenden Thema erstellt (vollständiger Quellcode unter der folgenden URL):

http://0netenv.blogspot.com/2016/08/password-generator-with-argparse.html

Schrieb einen Passwortgenerator mit argparse . Hoffe, das hilft jemandem (entweder einen Passwortgenerator erstellen oder argparse verwenden)!

So oder so hat es Spaß gemacht zu bauen! 

$ ./pwgen.py -h
usage: pwgen.py [-h] [-c COUNT] [-a] [-l] [-n] [-s] [-u] [-p]

 Create a random password
 Special characters, numbers, UPPERCASE -"Oscar",
 and lowercase -"lima" to avoid confusion.
 Default options (no arguments): -c 16 -a
                Enjoy! [email protected]

optional arguments:
  -h, --help            show this help message and exit
  -c COUNT, --count COUNT
                        password length
  -a, --all             same as -l -n -s -u
  -l, --lower           include lowercase characters
  -n, --number          include 0-9
  -s, --special         include special characters
  -u, --upper           include uppercase characters
  -p, --license         print license and exit

Hier ist der Code:

#!/usr/bin/env python2
# -*- coding: utf-8 -*-

license = """
#  pwgen -- the pseudo-random password generator 
#
#  This software is distributed under the MIT license.
#    
#  The MIT License (MIT)
#
#  Copyright (c) 2016 0NetEnv [email protected]
#  Permission is hereby granted, free of charge, to any 
#  person obtaining a copy of this software and associated 
#  documentation files (the "Software"), to deal in the 
#  Software without restriction, including without 
#  limitation the rights to use, copy, modify, merge, 
#  publish, distribute, sublicense, and/or sell copies 
#  of the Software, and to permit persons to whom the 
#  Software is furnished to do so, subject to the following 
#  conditions:
#
#  The above copyright notice and this permission notice 
#  shall be included in all copies or substantial portions 
#  of the Software.
#
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 
#  ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 
#  TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
#  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 
#  SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 
#  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
#  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 
#  IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
#  DEALINGS IN THE SOFTWARE.
#  
#  NOTE:
#  This software was tested on Slackware 14.2, Raspbian, & 
#  Mac OS X 10.11
#
"""

import string
import random
import sys
# first time using argparse library
import argparse
# wanted to change the formatting of the help menu a little bit, so used RawTextHelpFormatter directly
from argparse import RawTextHelpFormatter

typo = ''
c = 16
counter = 0
line = '-' * 40

# CREATE FUNCTION for PWGEN
def pwgen(z, t):
    # EMPTY SET OF CHARACTERS
    charsset = ''
    # UPPERCASE -"O"
    U = 'ABCDEFGHIJKLMNPQRSTUVWXYZ'
    # lowercase -"l"
    L = 'abcdefghijkmnopqrstuvwxyz'
    N = '0123456789'
    S = '[email protected]#$%^&*?<>'

    # make sure we're using an integer, not a char/string
    z = int(z)
    for type in t:
        if 'u' in t:
            charsset = charsset + U
        if 'l' in t:
            charsset = charsset + L
        if 'n' in t:
            charsset = charsset + N
        if 's' in t:
            charsset = charsset + S
        if 'a' == t:
            charsset = charsset + U + L + N + S

    return ''.join(random.choice(charsset) for _ in range(0, int(z)))

# GET ARGUMENTS using ARGPARSE
parser = argparse.ArgumentParser(description='\n Create a random password\n\
 Special characters, numbers, UPPERCASE -"Oscar",\n\
 and lowercase -"lima" to avoid confusion.\n\
 Default options (no arguments): -c 16 -a\n\
 \t\tEnjoy! [email protected]', formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("-c", "--count", dest="count", action="store", help="password length")
parser.add_argument("-a", "--all", help="same as -l -n -s -u", action="store_true")
parser.add_argument("-l", "--lower", help="include lowercase characters", action="store_true")
parser.add_argument("-n", "--number", help="include 0-9", action="store_true")
parser.add_argument("-s", "--special", help="include special characters", action="store_true")
parser.add_argument("-u", "--upper", help="include uppercase characters", action="store_true")
parser.add_argument("-p", "--license", help="print license and exit", action="store_true")

# COLLECT ARGPARSE RESULTS
results = args = parser.parse_args()

# CHECK RESULTS
# Check that a length was given.
# If not, gripe and exit.
if args.count == '0':
    print ("Input error:\nCannot create a zero length password.\nExiting")
    exit (0)
# check character results and add to counter if 
# selection is made.
if args.lower:
    typo = typo + 'l'
    counter = counter + 1
    #print "lower"
if args.number:
    typo = typo + 'n'
    counter = counter + 1
    #print "number"
if args.special:
    typo = typo + 's'
    counter = counter + 1
    #print "special"
if args.upper:
    typo = typo + 'u'
    counter = counter + 1
    #print "upper"
if args.all:
    typo = 'a'
    counter = counter + 1
    #print "all"
if args.license:
    print (license)
    exit (1)

# CHECK COUNTER
# Check our counter and see if we used any command line 
# options. We don't want to error out.
# try it gracefully. If no arguments are given, 
# use defaults and tell the user.
# args.count comes from argparse and by default requires
# an input to '-c'. We want to get around that for the 
# sake of convenience.
# Without further adieu, here's our if statement:
if args.count:
    if counter == 0:
        typo = 'a'
        print ("defaulting to '--all'")
    print (line)
    print (pwgen(results.count,typo))
else:
    if counter == 0:
        typo = 'a'
        print ("defaulting to '--count 16 --all'")
    print (line)
    print (pwgen(c,typo))
print (line)
#print typo
1
0NetEnv

Es ist leicht :)

def codegenerator():
    alphabet = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    pw_length = 8
    mypw = ""

    for i in range(pw_length):
        next_index = random.randrange(len(alphabet))
        mypw = mypw + alphabet[next_index]
    return mypw

und die do:

print codegenerator()

Danke http://xkcd.com/936/

1
Tarek Kalaji

Das funktioniert so. Es ist vollkommen in Ordnung. Wenn Sie zusätzliche Regeln hatten, z. B. den Ausschluss von Wörterbuchwörtern, möchten Sie möglicherweise auch diese Filter einschließen. Die Wahrscheinlichkeit, ein Wörterbuchwort mit diesem Setup zufällig zu generieren, ist jedoch äußerst gering.

1
mvrak

Ich liebe die Linguistik. In meiner Herangehensweise erstelle ich einprägsame Pseudowörter mit hohem Entropiegrad durch abwechselnde Konsonanten und Vokale.

  • Nicht anfällig für Wörterbuchangriffe
  • Aussprechbar und daher gute Chance, erinnerungswürdig zu sein
  • Kurze Passwörter mit anständiger Stärke
  • Optionaler Parameter zum Hinzufügen einer zufälligen Ziffer aus Kompatibilitätsgründen (weniger einprägsam, entspricht jedoch Apps, die mit dem alten Kennwortsicherheitsdenken erstellt wurden, z. B. eine Ziffer erfordern)

Python-Code:

import random
import string


def make_pseudo_Word(syllables=5, add_number=False):
    """Create decent memorable passwords.

    Alternate random consonants & vowels
    """
    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 range(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'

Nachteile:

  • für lateinische und germanische Sprecher sowie für diejenigen, die mit Englisch vertraut sind
  • man sollte Vokale und Konsonanten der Sprache verwenden, die bei den Anwendungsbenutzern oder der Fokusgruppe dominieren und abstimmen
1
F. Malina

Bei Ihrer Implementierung gibt es einige Probleme:

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

Der Zufallszahlengenerator wird dadurch nicht erzeugt. Er ersetzt die seed-Funktion durch einen Bytestring. Sie müssen seed aufrufen, z. B. random.seed(…).

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

Pythons Standardeinstellung PRNG ist ein Mersenne-Twister, der kein kryptographisch starkes PRNG ist. Ich bin daher vorsichtig, ihn für kryptographische Zwecke zu verwenden. Das random-Modul enthält random.SystemRandom, das auf mindestens den meisten * nix-Systemen einen CSPRNG verwenden soll. Jedoch,

random.choice(chars)

… Ist implementiert als…

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. Leider ist self.random hier eine C-Funktion, so dass dies schwer zu erkennen ist. Der Codegeruch hier ist, dass dieser Code fast sicher nicht einheitlich wählt. Der Code hat sich in Python 3 vollständig geändert und sorgt für eine wesentlich bessere Einheitlichkeit. Die Python 3-Dokumente für randrange beachten,

In Version 3.2 geändert: randrange() ist in Bezug auf die Erzeugung gleichverteilter Werte komplexer. Früher verwendete es einen Stil wie int(random()*n), der leicht ungleichmäßige Verteilungen erzeugen konnte.

randrange und choice rufen beide dieselbe Methode (_randbelow) unter der Haube auf.

In Python 3 ist choice in Ordnung; In Python 2 kommt es nur close zu einer gleichmäßigen Verteilung, garantiert dies jedoch nicht. Da dies Krypto ist, lehne ich mich auf die Seite "Keine Chance" des Zauns und möchte diese Garantie haben.

1
Thanatos

Ich habe gerade erst angefangen, python zu lernen, und das habe ich heute geschrieben. Hoffe das hilft.

import random

characters = '[email protected]#$%^()}{/<>'
print('Password Length: ')
passwordLength = int(input())
password = ''

for i in range(passwordLength):
    password += random.choice(characters)
print(password)
0
Prashant Gonga
import uuid
print('Your new password is: {0}').format(uuid.uuid4())
0
Alex

Ein bisschen abseits des Themas, aber ich habe dieses auch mit TKinter gemacht. Hoffe es kann helfen:

import os, random, string
from tkinter import *

def createPwd():
    try:
        length = int(e1.get())
    except ValueError:
        return
    chars = string.ascii_letters + string.digits + '[email protected]#$%^&*()?\/'
    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()
0
decadenza

Hier ist eine andere Implementierung (Python 2; würde einige kleinere Umschreibungen erfordern, damit es in 3 funktioniert), die viel schneller ist als die von OJW, die scheinbar das Wörterbuch für jedes Wort durchläuft, trotz der Kommentare/Implikationen im Gegenteil. Timing des OJW-Skripts auf meinem Rechner mit einer 80.000 IOP-SSD: 

real    0m3.264s
user    0m1.768s
sys     0m1.444s

Das folgende Skript lädt das gesamte Wörterbuch in eine Liste und wählt dann Wörter basierend auf einer zufälligen Auswahl des Indexwerts aus, wobei der reguläre Ausdruck von OJW zum Filtern verwendet wird. 

Dadurch werden auch 10 Passphrasen-Sets generiert, das Übergeben von Befehlszeilenparametern zum Anpassen der Anzahl von Wörtern sowie das Hinzufügen von Zahlen und Symbolen (auch einstellbare Länge). 

Beispielzeiten für dieses Skript:

real    0m0.289s
user    0m0.176s
sys     0m0.108s

Verwendung: xkcdpass-mod.py 2 4 (zum Beispiel; dies sind die Standardwerte). 

Es druckt Leerzeichen in der Ausgabe, um das Lesen zu erleichtern, obwohl ich fast nie einen Online-Dienst gefunden habe, der es erlaubt, sie zu verwenden. Ich würde sie einfach ignorieren. Dies könnte definitiv mit argparse oder getopt beseitigt werden, und Schalter, die Leerzeichen einschließen oder nicht, einschließlich Symbole, Großbuchstaben usw., sowie einige zusätzliche Refactoring-Optionen, aber ich bin noch nicht dazu gekommen. Also ohne weiteres: 

#!/usr/bin/env python
#Copyright AMH, 2013; dedicated to public domain.
import os, re, sys, random
from sys import argv

def getargs():
    if len(argv) == 3:
        numwords = argv[1]
        numpads = argv[2]
        return(numwords, numpads)
    Elif len(argv) == 2:
        numwords = argv[1]
        numpads = 4
        return (numwords, numpads)
    else:
        numwords = 2
        numpads = 4
        return (numwords, numpads)

def dicopen(dictionary="/usr/share/dict/american-english"):
    f = open(dictionary, "r")
    dic = f.readlines()
    return dic

def genPassword(numwords, numpads):
    r = random.SystemRandom()
    pads = '[email protected]#$%^&*()'
    padding = []
    words = dicopen()
    wordlist = []
    for i in range (0,int(numpads)):
        padding.append(pads[r.randint(0,len(pads)-1)])
    #initialize counter for only adding filtered words to passphrase
    j = 0
    while (j < int(numwords)):
        inclusion_criteria = re.compile('^[a-z]{5,10}$')
        #Select a random number, then pull the Word at that index value, rather than looping through the dictionary for each Word
        current_Word = words[r.randint(0,len(words)-1)].strip()
        #Only append matching words
        if inclusion_criteria.match(current_Word):
            wordlist.append(current_Word)
            j += 1
        else:
        #Ignore non-matching words
            pass
    return(" ".join(wordlist)+' '+''.join(padding))

if(__== "__main__"):
    for i in range (1,11):
       print "item "+str(i)+"\n"+genPassword(getargs()[0], getargs()[1])

Beispielausgabe:

[✗]─[[email protected]]─[~/bin]
└──╼ xkcdpass-mod.py
item 1
digress basketball )%^)
item 2
graves giant &118
item 3
impelled maniacs ^@%1

Und für die volle "richtige Pferdebatterie" (CHBS), keine Polsterung:

┌─[[email protected]]─[~/bin]
└──╼ xkcdpass-mod.py 4 0
item 1
superseded warred nighthawk rotary 
item 2
idealize chirruping gabbing vegan 
item 3
wriggling contestant hiccoughs instanced 

Gemäß https://www.grc.com/haystack.htm würde aus praktischen Gründen bei Annahme von 100 Billionen Annahmen pro Sekunde (dh 100 TH/s) die kürzere Version etwa 50 bis 60 Millionen Jahrhunderte dauern zerbrechen; der volle CHBS = 1,24 Billionen Billionen Jahrhunderte; 15,51 Billionen Billionen Billionen Jahrhunderte. 

Selbst wenn das gesamte Bitcoin-Mining-Netzwerk (~ 2500 TH/s zum Zeitpunkt dieses Schreibens) in Anspruch genommen werden sollte, würde die kurze Version wahrscheinlich noch 250 bis 300 Millionen Jahre brauchen, um zu brechen, was wahrscheinlich für die meisten Zwecke sicher genug ist. 

0
LawyerOnLinux

Dies ist ein einfaches kleines Programm, das an Personen gerichtet ist, die keine sicheren Passwörter für ihre eigenen öffentlichen Konten ermitteln können.

Führen Sie einfach das Programm auf einer Befehlskonsole aus und übergeben Sie eine Reihe von Buchstaben, die Ihnen bekannt vorkommen, und es wird eine Folge von Symbolen generiert, die auf den von Ihnen eingefügten Elementen basiert.

natürlich unterstützt das Programm nicht die Erzeugung mehrerer Sequenzen.

Sie können den Code von meinem Github-Pull downloaden: https://github.com/abdechahidely/python_password_generator

from string import ascii_lowercase, ascii_uppercase, digits, punctuation
from random import randint, choice, shuffle
from math   import ceil
from re     import finditer

lower_cases  = ascii_lowercase
upper_cases  = ascii_uppercase
lower_upper  = dict(Zip(lower_cases, upper_cases))
upper_lower  = dict(Zip(upper_cases, lower_cases))
punctuations = '#$%&@!?.'
space        = ' '

class PunctOrDigit():

    def __init__(self, number_of_punctuations, number_of_digits):
        self.puncts = number_of_punctuations
        self.digits = number_of_digits
        self.dupl_puncts = self.puncts
        self.dupl_digits = self.digits

    def PorD(self):
        symbol_type = choice('pd')
        if symbol_type == 'p':
            if self.puncts == 0:
                return 'd'
            else:
                self.puncts -= 1
                return symbol_type
        if symbol_type == 'd':
            if self.digits == 0:
                return 'p'
            else:
                self.digits -= 1
                return symbol_type

    def reset(self):
        self.puncts = self.dupl_puncts
        self.digits = self.dupl_digits

def is_empty(text):
    for symbol in text:
        if symbol != space:
            return False
    return True

def contain_unauthorized_symbols(text):
    for symbol in text:
        if symbol in punctuation or symbol in digits:
            return True
    return False

def user_input():
    user_input = input('-- Sentence to transform: ')
    while is_empty(user_input) or len(user_input) < 8 or contain_unauthorized_symbols(user_input):
        user_input = input('-- Sentence to transform: ')
    return user_input

def number_of_punctuations(text):
    return ceil(len(text) / 2) - 3

def number_of_digits(text):
    return ceil(len(text) / 2) - 2

def total_symbols(text):
    return (number_of_digits(text) + number_of_punctuations(text), 
            number_of_punctuations(text),
            number_of_digits(text))

def positions_to_change(text):
    pos_objct = PunctOrDigit(number_of_punctuations(text), number_of_digits(text))
    positions = {}
    while len(positions) < total_symbols(text)[0]:
        i = randint(0,len(text)-1)
        while i in positions:
            i = randint(0,len(text)-1)
        positions[i] = pos_objct.PorD()
    pos_objct.reset()
    return positions

def random_switch(letter):
    if letter in lower_cases:
        switch_or_pass = choice('sp')
        if switch_or_pass == 's': return lower_upper[letter]
        else:                     return letter
    if letter in upper_cases:
        switch_or_pass = choice('sp')
        if switch_or_pass == 's': return upper_lower[letter]
        else:                     return letter

def repeated(text):
    reps = {}
    for letter in set(list(text)):
        indexs = [w.start() for w in finditer(letter, text)]
        if letter != ' ':
            if len(indexs) != 1:
                reps[letter] = indexs
    return reps

def not_repeated(text):
    reps = {}
    for letter in set(list(text)):
        indexs = [w.start() for w in finditer(letter, text)]
        if letter != ' ':
            if len(indexs) == 1:
                reps[letter] = indexs
    return reps

def generator(text, positions_to_change):
    rep     = repeated(text)
    not_rep = not_repeated(text)
    text    = list(text)

    for x in text:
        x_pos = text.index(x)
        if x not in positions_to_change:
            text[x_pos] = random_switch(x)

    for x in rep:
        for pos in rep[x]:
            if pos in positions_to_change:
                if positions_to_change[pos] == 'p':
                    shuffle(list(punctuations))
                    text[pos] = choice(punctuations)
                if positions_to_change[pos] == 'd':
                    shuffle(list(digits))
                    text[pos] = choice(digits)
    for x in not_rep:
        for pos in not_rep[x]:
            if pos in positions_to_change:
                if positions_to_change[pos] == 'p':
                    shuffle(list(punctuations))
                    text[pos] = choice(punctuations)
                if positions_to_change[pos] == 'd':
                    shuffle(list(digits))
                    text[pos] = choice(digits)

    text = ''.join(text)
    return text

if __== '__main__':
    x = user_input()
    print(generator(x, positions_to_change(x)))
0
A. Ihya

Base64 lässt uns binäre Daten in einem für Menschen lesbaren/schreibbaren Modus ohne Datenverlust kodieren.

import os
random_bytes=os.urandom(12)
secret=random_bytes.encode("base64")

Meine Lösung basiert auf der Antwort von @Thomas Pornin (Aktualisiert)

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

Diese Funktion liefert ein zufälliges Passwort (ohne Nummer oder Symbol am Anfang des Passworts).

0
Avikd

Hier ist mein Zufallsgenerator, nachdem ich mich mit diesem Thema befasst habe:

`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('[email protected]#$%^&*()')
   PWD = None
   PWD = UPP + LOW1 + LOW2 + LOW3 + Dig1 + Dig2 + Dig3 + SPEC
   PWD = ''.join(random.sample(PWD,len(PWD)))
   print(PWD)`

Dadurch wird ein zufälliges Passwort mit einem zufälligen Großbuchstaben, drei zufälligen Kleinbuchstaben, drei zufälligen Ziffern und einem zufälligen Sonderzeichen generiert. Dann kombiniert es jedes zufällige Zeichen und erstellt eine zufällige Reihenfolge. Ich weiß nicht, ob dies als "hohe Qualität" gilt, aber es erledigt die Arbeit. 

0
d84_n1nj4