Hochwertiger, einfacher Generator für zufällige Passwörter

73

Ich bin daran interessiert, einen sehr einfachen Zufallskennwortgenerator mit hoher (kryptografischer) Qualität zu erstellen. Gibt es einen besseren Weg, dies zu tun?

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))
Mike R.
quelle
4
Sind diese Passwörter für Menschen oder Maschinen?
Wange
21
@JarrodRoberson Die Aussage, dass „Zufälligkeit! = Kryptographie“ an und für sich nur ungeheuerlich ist, da die moderne Kryptographie auf Zufälligkeit beruht. Nicht alle Zufälligkeiten sind gleich (z. B. ein zufällig aus "Passwort" und "Passwörtern" ausgewähltes Passwort ist offensichtlich nicht sicher), aber im Kern ist Kryptographie == Zufälligkeit.
NullUserException
4
Ist random.seedeine Methode nicht, random.seed = 'random_string'zerstört sie also im Grunde genommen diese Methode und macht nichts? Meinst du random.seed('random_string')?
Nick T
1
os.urandom(1024)ruft 1024 Bytes ab. Es scheint mir ein bisschen übertrieben. Vielleicht wäre das Seeding mit 16 oder 32 Bytes besser geeignet.
JWW
1
@nealmcb, wenn Sie es nützlich finden - mein Ziel war, wie in der Frage angegeben, ein "Zufallspasswortgenerator". In meinem Fall wird es für die Verschlüsselung von Token (JWT) von Flask für den Web-API-Zugriff verwendet, und daher ist meine einzige Sorge, dass es zufällig ist. Und in vordefinierter Länge. Daher suchte ich nur nach einer technischen Lösung, nicht nach einer Diskussion darüber, was ein gutes Passwort / eine gute Phrase ist. Ja, ich verwende genau für diesen Zweck KeePass-ähnliche Lösungen. Diese Dinge sind aus meiner Sicht Schlüssel und nicht auswendig zu lernen. Manchmal ist es sicherer, kein Passwort zu kennen.
Alen Siljak

Antworten:

48

Das Schwierige bei Passwörtern ist, sie stark genug zu machen und sich trotzdem an sie erinnern zu können. Wenn das Passwort nicht dazu gedacht ist, dass sich ein Mensch daran erinnert, ist es nicht wirklich ein Passwort.

Sie verwenden Pythons os.urandom(): das ist gut. Für jeden praktischen Zweck (sogar Kryptographie) ist die Ausgabe von os.urandom()nicht von wahrem Alea zu unterscheiden. Dann verwenden Sie es als Startwert random, was weniger gut ist: Es handelt sich um ein nicht kryptografisches PRNG, und seine Ausgabe weist möglicherweise eine Struktur auf, die sich nicht in einem statistischen Messwerkzeug registriert, sondern von einem intelligenten Angreifer ausgenutzt wird. Sie sollten die os.urandom()ganze Zeit mit arbeiten. Um die Sache zu vereinfachen: Wählen Sie ein Alphabet mit der Länge 64, z. B. Buchstaben (Groß- und Kleinbuchstaben), Ziffern und zwei zusätzliche Satzzeichen (z. B. '+' und '/'). Holen Sie sich dann für jedes Kennwort ein Byte ab os.urandom(), reduzieren Sie den Wert modulo 64 (dies ist unverzerrt, da 64 256 teilt) und verwenden Sie das Ergebnis als Index in Ihrem charsArray.

Mit einem Alphabet der Länge 64 erhalten Sie 6 Entropiebits pro Zeichen (weil 2 6 = 64). Mit 13 Zeichen erhalten Sie also 78 Entropiebits. Dies ist letztendlich nicht in allen Fällen stark, aber bereits sehr stark (es könnte mit einem Budget besiegt werden, das in Monaten und Milliarden von Dollar gezählt wird, nicht nur in Millionen).

Thomas Pornin
quelle
Warte eine Minute ... Das klingt vielleicht nach einer dummen Frage, gibt aber den os.urandom()Typ zurück bytes. Wie kann ich diesen Mod 64 reduzieren?
Sean Bone
2
Fragen Sie nach einem Byte und erhalten Sie den Bytewert, der eine Ganzzahl im Bereich von 0 bis 255 ist.
Thomas Pornin
1
Aber es ist ziemlich schwer, sich an 13 zufällige Zeichen zu erinnern. Das ist eigentlich Randalls Argument im berühmten XKCD-Comic. Ich würde vorschlagen, dass github.com/redacted/XKCD-password-generator die Option --acrostic verwendet, um ein Muster zu erhalten, an das Sie sich noch leichter erinnern können.
Nealmcb
2
Für alle anderen, die noch verwirrt sind, wäre @ ThomasPornins Lösung zBchars[ord(os.urandom(1)) % len(chars)]
Christian Benke
3
@ChristianBenke: Beachten Sie, dass dies unvoreingenommen ist, da das chars[]Array, über das wir sprechen, die Länge 64 hat und 256 (die Anzahl der möglichen Werte für ein Byte) ein Vielfaches von 64 ist. Wenn Sie eine Array-Länge verwenden, die kein exakter Teiler von ist 256 dann wird die Auswahl verzerrt (einige der Zeichen sind wahrscheinlicher als andere).
Thomas Pornin
45

XKCD hat eine großartige Erklärung dafür, warum das, was Sie für sichere Passwörter halten, nicht der Fall ist .

http://xkcd.com/936/

Ich entschuldige mich aufrichtig bei allen, die Informationstheorie und Sicherheit verstehen und sich in einem wütenden Streit mit jemandem befinden, der dies nicht tut (möglicherweise in gemischten Fällen). - Randall Munroe

Und wenn Sie die Mathematik hinter dem, was diese Abbildung erklärt , nicht verstehen , versuchen Sie nicht, etwas zu schreiben, das kryptografisch sicher sein sollte, da dies nicht der Fall ist. Legen Sie einfach die Maus hin und treten Sie von der Tastatur weg.

Gemeinschaft
quelle
4
Für das, was es wert ist, gibt es auf IT Security SE einen Beitrag über diesen Comic, den Jeff kürzlich als Beispiel für eine großartige Frage verwendet hat.
Pops
14
Lassen Sie uns die Kommentare bitte konstruktiv halten.
Tim Post
8
Der erste Satz ist falsch: Zufälligkeit macht "kryptografisch starke" Passwörter, und der Comic kontrastiert gezielt ein nicht zufälliges, schwieriges Passwort mit einer zufälligen, einfachen Passphrase. Die Entropie englischer Wörter ist eine Funktion der Wörterbuchgröße, nicht der Wortlänge. Anstelle von 4,7 Bit pro Buchstabe entspricht dies eher 17 Bit pro Wort. Es ist für mich einfacher, eine Mnemonik für eine Folge von Wurzelwörtern mittlerer Länge zu erstellen. Nehmen wir also an, ich erstelle ein Wörterbuch mit 2048 solchen Wörtern. Selbst wenn ein Angreifer meine Liste stiehlt, fügt jedes zufällig ausgewählte Wort der Passphrase mindestens 11 Entropiebits hinzu.
Erickson
2
@jww 17 Bit basieren auf einer zufälligen Auswahl aus einem Wörterbuch mit 130.000 Wörtern (ungefähr die Anzahl der Turnier-zulässigen Scrabble-Wörter zwischen 5 und 11 Buchstaben in der OWL2-Liste). Dies ist nur die Entropie eines 130k-seitigen Würfels und kann genau berechnet werden. Eine Schätzung von 1,2 Bit pro Wort basiert auf der Fähigkeit, das nächste Wort in echtem englischen Text vorherzusagen. Dies ist nur eine Schätzung und hängt vom jeweiligen Text ab. Mein Kommentar versuchte, den Unterschied zwischen den beiden Fällen herauszustellen; Ein verstümmelter "Troubadour" ist nicht zufällig. Das Zeichnen von Wörtern aus einem gemischten Wörterbuch ist.
Erickson
4
@jww Betrachten Sie als Beispiel "Ich ____ Sie ____ viel!" Wenn Sie einen großen Korpus englischen Textes überblicken, werden Sie feststellen, dass Sie mit hoher Wahrscheinlichkeit vorhersagen können, was in den Lücken steht. Die Leerzeichen verlieren nicht viele Informationen. oder mit anderen Worten, die Entropie dieser fehlenden Wörter ist sehr gering. Wie hoch ist die Wahrscheinlichkeit, dass Sie die Lücken in "aspergilli ____ graveness ____ doable" korrekt ausfüllen können? (In diesem Fall handelt es sich um "Chawbacons" und "Monogamisten".) Da die fehlenden Symbole zufällig aus einer großen Menge ausgewählt wurden, ist ihre Entropie hoch.
Erickson
13

Vor zwei Tagen hat Kragen Javier Sitaker ein Programm dazu unter http://lists.canonical.org/pipermail/kragen-hacks/2011-September/000527.html veröffentlicht (jetzt weg - versuchen Sie es mit 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 "Gelernte Schäden gerettet Wohnphasen". Das entspricht einem 60-Bit-Schlüssel.

Es würde 2,5e + 03 CPU-Jahre dauern, bis dieses Passwort auf meinem kostengünstigen Celeron E1200 aus dem Jahr 2008 geknackt ist, vorausgesetzt, es handelt sich um einen Offline-Angriff auf einen MS-Cache-Hash, der der schlechteste häufig verwendete Passwort-Hashing-Algorithmus ist, der etwas schlechter ist als selbst einfaches MD5.

Der heutzutage am häufigsten verwendete Passwort-Hashing-Algorithmus ist das iterierte MD5 von FreeBSD. Das Knacken eines solchen Hashs würde 5,2e + 06 CPU-Jahre dauern.

Aber eine moderne GPU kann ungefähr 250-mal so schnell knacken, so dass dieselbe iterierte MD5 in 2e + 04 GPU-Jahren fallen würde.

Die Ausführung dieser GPU im Jahr 2011 kostet ungefähr 1,45 US-Dollar pro Tag. Das Knacken des Passworts würde also ungefähr 3e + 09 US-Dollar kosten.

Ich habe angefangen, ein auf diese Weise generiertes Passwort anstelle eines 9-druckbaren ASCII-Zeichen-Zufallspassworts zu verwenden, das ebenso stark ist. Munroes Behauptung, dass diese Passwörter viel einfacher zu merken sind, ist richtig. Es gibt jedoch immer noch ein Problem: Da pro Zeichen viel weniger Entropiebits vorhanden sind (etwa 1,7 statt 6,6), ist das Kennwort sehr redundant, sodass Angriffe wie der ssh-Timing-Channel-Angriff (der Song, Angriffe von Wagner und Tian Herbivore, von denen ich vor Jahren in den frühen Morgenstunden von Bram Cohen im Bagdad Café erfahren habe, und Angriffe auf Audio-Tastaturaufzeichnungen haben eine viel bessere Chance, genügend Informationen zu erfassen, um das Passwort angreifbar zu machen.

Meine Gegenmaßnahme gegen den Herbivore-Angriff, der mit einem 9-stelligen Passwort gut funktioniert, aber mit meinem neuen Passwort äußerst ärgerlich ist, besteht darin, das Passwort mit einer Verzögerung von einer halben Sekunde zwischen den Zeichen einzugeben, damit der Timing-Kanal nicht viele Informationen über das enthält tatsächlich verwendete Zeichen. Darüber hinaus bietet die geringere Länge des 9-stelligen Passworts dem Herbivore-Ansatz von Natur aus viel weniger Informationen zum Kauen.

Andere mögliche Gegenmaßnahmen sind die Verwendung des Emacs-Shell-Modus, bei dem Sie lokal zur Eingabe des Kennworts aufgefordert werden, wenn eine Kennwortabfrage erkannt wird, das gesamte Kennwort auf einmal gesendet wird und das Kennwort von einer anderen Stelle kopiert und eingefügt wird.

Wie zu erwarten, dauert die Eingabe dieses Kennworts auch etwas länger: ca. 6 Sekunden statt ca. 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 __name__ == '__main__':
    sys.exit(main(sys.argv))
Roshan Mathews
quelle
1
Könntest du sagen generate_password() (mit random.SystemRandom()) ganz oben auf Ihre Antwort setzen? Es könnte Leuten
jfs
11

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
Yossi
quelle
4
Sie könnten einfach os.urandom (1) (kryptografisch stark) verwenden und die Abhängigkeit von M2Crypto
Riccardo Galli
2
Die Verwendung % len(chars)dieser Methode hat eine leichte Tendenz zu den ersten 8 Zeichen in chars. Jeder dieser Buchstaben erscheint in 1,95% der Fälle, verglichen mit 1,56% bei den anderen Zeichen.
Nick Frost
7

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(__name__ == "__main__"):
  print genPassword()

Beispielausgabe:

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

Ich weiß, dass diese Frage bereits im Jahr 2011 gestellt wurde, aber für diejenigen, die jetzt im Jahr 2014 und darüber hinaus dazu kommen, muss ich eines sagen: Widerstehen Sie dem Drang, das Rad neu zu erfinden.

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

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

rsaw
quelle
Einverstanden. In der Github-Version gibt es einige nette Optionen, z. B. um auszudrucken, wie viel Entropie Ihr Passwort hat, und um Ihnen die Möglichkeit zu geben, einen "Akrostichon" anzugeben, damit das erste Zeichen jedes Wortes mit einem Wort Ihrer Wahl übereinstimmt.
Nealmcb
5

Sie können dem Pseudozufallszahlengenerator von Python beim Generieren eines Passworts nicht vertrauen. Es ist nicht unbedingt kryptografisch zufällig. Sie setzen den Pseudozufallszahlengenerator ein, von os.urandomdem aus ein guter Anfang ist. Aber danach sind Sie auf Pythons Generator angewiesen.

Eine bessere Wahl wäre die random.SystemRandom()Klasse, die Zufallszahlen aus derselben Quelle wie verwendet urandom. Laut der Python-Dokumentation sollte dies für die kryptografische Verwendung ausreichend sein. DasSystemRandom Klasse bietet Ihnen alles, was die Haupt-Zufallsklasse tut, aber Sie müssen sich keine Sorgen um die Pseudozufälligkeit machen.

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

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

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

Hinweis: Ihr Kilometerstand kann variieren. In der Python-Dokumentation heißt es, dass die Verfügbarkeit von random.SystemRandom je nach Betriebssystem unterschiedlich ist.

Winston Ewert
quelle
1
Das Linux PRNG ( /dev/urandom) gilt als kryptografisch sicher. Siehe security.stackexchange.com/questions/3936/… .
Mechanische Schnecke
5
Ich denke, Sie bringen Ihre Konzepte hier durcheinander. In einem deterministischen Computer gibt es keine echte Zufälligkeit; Alles (einschließlich /dev/urandom) ist pseudozufällig, es sei denn, Sie haben spezielle Hardware.
NullUserException
@NullUserException ఠ_ఠ +1 Ein Verbraucher kann dies mit einer Webcam oder CCD in einer pechschwarzen Umgebung tun (siehe LavaRnd).
@NullUserException ఠ_ఠ, Es gibt einige Zufallsquellen, die Ihr Computer sammelt. Ich habe mich jedoch geirrt, urandom mischt das mit einem Pseudozufallszahlengenerator. Trotzdem ist die Verwendung von SystemRandom eine gute Idee, da Sie sicher sein können, dass es kryptografisch zufällig ist, während dies für den Python-Zufallszahlengenerator nicht unbedingt der Fall ist.
Winston Ewert
3

In Anbetracht Ihres Kommentars,

Ich muss nur in der Lage sein, Passwörter zu generieren, die sicherer sind als die, die ich mir in meinem Kopf ausgedacht hätte.

Anscheinend möchten Sie Ihr Programm zum Generieren von Passwörtern verwenden, anstatt es nur als Übung zu schreiben. Es ist vorzuziehen, eine vorhandene Implementierung zu verwenden, da die Ausgabe möglicherweise beeinträchtigt wird, wenn Sie einen Fehler machen. Lesen Sie mehr ü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 pwgen. Es bietet verschiedene Optionen, die Sie auswählen sollten, je nachdem, wofür Sie die Kennwörter verwenden möchten.

Mechanische Schnecke
quelle
1
Die Debian-Sicherheitsanfälligkeit war ein Implementierungsfehler. Im Allgemeinen sind /dev/urando& /dev/randomnicht von echten Zufällen zu unterscheiden (mit Ausnahme der ersten 10 Minuten oder so nach dem Systemstart)
Jacco
3

Zu Ihrer Information für alle, die im Jahr 2020+ auf diese Frage stoßen. Python 3.6+ verfügt über ein secretsModul speziell für diesen Zweck:

import secrets

password_length = 13
print(secrets.token_urlsafe(password_length))
Reich
quelle
2

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 das tun:

print codegenerator()

Vielen Dank http://xkcd.com/936/

Tarek Kalaji
quelle
2
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='!@#$%'))
  • Generiert Passwörter, an die Sie sich erinnern 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 ist was ich benutze.

MikeRand
quelle
2

Implenting @Thomas Pornin Lösung (kann @Yossi ungenaue Antwort nicht kommentieren):

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

AKTUALISIERT für Python3 dank Stephan Lukits

Foudfou
quelle
In Python 3.8 muss 'string.ascii_letters' verwendet werden, und das Iterieren über Bytes ergibt bereits Ganzzahlen, sodass 'orc (c)' fehlschlägt und stattdessen 'c' funktioniert.
Stephan Lukits
1

So funktioniert es. Es ist vollkommen in Ordnung. Wenn Sie zusätzliche Regeln hatten, z. B. das Ausschließen von Wörterbuchwörtern, möchten Sie möglicherweise auch diese Filter einschließen, aber die Wahrscheinlichkeit, mit diesem Setup zufällig ein Wörterbuchwort zu generieren, ist äußerst gering.

mvrak
quelle
1

Es gibt einige Probleme mit Ihrer Implementierung:

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

Dadurch wird der Zufallszahlengenerator nicht gesetzt. Es ersetzt die seedFunktion durch einen Bytestring. Sie müssen anrufen seed, wie , random.seed(…).

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

Pythons Standard-PRNG ist ein Mersenne Twister, bei dem es sich nicht um ein kryptografisch starkes PRNG handelt. Daher bin ich vorsichtig, es für kryptografische Zwecke zu verwenden. Das randomModul enthält random.SystemRandom, die auf mindestens den meisten * nix-Systemen ein CSPRNG verwenden sollten. Allerdings ist

random.choice(chars)

… Wird 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 gibt es self.randomhier eine C-Funktion, so dass dies schwer zu erkennen ist. Der Code-Geruch hier ist, dass dieser Code mit ziemlicher Sicherheit nicht einheitlich wählt. Der Code hat sich in Python 3 vollständig geändert und sorgt viel besser für Einheitlichkeit. Die Python 3-Dokumente zur randrangeNotiz,

In Version 3.2 geändert: Es randrange()ist anspruchsvoller, gleichmäßig verteilte Werte zu erzeugen. Früher wurde ein Stil int(random()*n)verwendet, der zu leicht ungleichmäßigen Verteilungen führen konnte.

randrangeund choicebeide rufen dieselbe Methode ( _randbelow) unter der Haube auf.

In Python 3 choiceist in Ordnung; in Python 2, kommt es nur nahe zu einer gleichmäßigen Verteilung, sie aber nicht garantieren. Da es sich um Krypto handelt, lehne ich mich an die Seite des Zauns, auf der ich kein Risiko eingehen möchte, und möchte diese Garantie haben.

Thanatos
quelle
1

Ich habe meine eigene CLI-Antwort auf das jeweilige 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 beim Erstellen eines Passwortgenerators oder beim Verwenden von Argparse)!

Auf jeden Fall 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! --0[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 = '!@#$%^&*?<>'

    # 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
0NetEnv
quelle
1

Mit Base64 können wir Binärdaten in einem vom Menschen lesbaren / beschreibbaren Modus ohne Datenverlust codieren.

import os
random_bytes=os.urandom(12)
secret=random_bytes.encode("base64")
Daniel Bañobre Dopico
quelle
5
Ermutigen Sie immer ein wenig Text in den Antworten, um Code-Schnipsel einzuführen.
Demongolem
1

Ich liebe Linguistik. In meinem Ansatz erschaffe ich unvergessliche Pseudowörter mit einem hohen Grad an Entropie, indem ich Konsonanten und Vokale abwechsle.

  • Nicht anfällig für Wörterbuchangriffe
  • Aussprechbar und daher gute Chance, unvergesslich 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 Kennwortsicherheitsgedanken erstellt wurden, z. B. das Erfordernis einer Ziffer).

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 lateinisch- und germanischsprachige und mit Englisch vertraute Personen
  • Man sollte Vokale und Konsonanten der Sprache verwenden, die bei den Anwendungsbenutzern oder der Fokusgruppe vorherrschen, und abstimmen
Fmalina
quelle
0

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 das Wörterbuch für jedes Wort zu durchlaufen scheint, trotz des gegenteiligen Kommentars / der gegenteiligen Implikation. Timing des OJW-Skripts auf meinem Computer 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.

Dies generiert auch 10 Passphrasensätze, ermöglicht das Übergeben von Befehlszeilenparametern zum Anpassen der Anzahl von Wörtern und fügt das Auffüllen von Zahlen und Symbolen hinzu (ebenfalls 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 auf einen Onlinedienst gestoßen bin, der die Verwendung dieser Leerzeichen zulässt, sodass ich sie einfach ignorieren würde. Dies könnte definitiv mit argparse oder getopt bereinigt werden und Schalter zum Einschließen von Leerzeichen oder nicht, einschließlich / ohne Symbole, Großbuchstaben usw., sowie einige zusätzliche Umgestaltungen zulassen, 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 = '0123456789!@#$%^&*()'
    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(__name__ == "__main__"):
    for i in range (1,11):
       print "item "+str(i)+"\n"+genPassword(getargs()[0], getargs()[1])

Beispielausgabe:

[✗]─[user@machine]─[~/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-Heftklammer" (CHBS), keine Polsterung:

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

Laut https://www.grc.com/haystack.htm würde es für alle praktischen Zwecke unter der Annahme von 100 Billionen Vermutungen pro Sekunde (dh 100 TH / s) etwa 50-60 Millionen Jahrhunderte dauern, bis die Crack-Version geknackt ist. das volle CHBS = 1,24 hundert Billionen Billionen Jahrhunderte; Hinzu kommen 15,51 Billionen Billionen Billionen Jahrhunderte.

Selbst wenn das gesamte Bitcoin-Mining-Netzwerk (~ 2500 TH / s zum Zeitpunkt dieses Schreibens) in Anspruch genommen wird, würde es wahrscheinlich noch 250 bis 300 Millionen Jahre dauern, bis die Kurzversion funktioniert, was für die meisten Zwecke wahrscheinlich sicher genug ist.

Rechtsanwalt OnLinux
quelle
Ihre Schätzung von "50-60 Millionen Jahrhunderten, um die Passphrase" Graves Riese & 118 "(anscheinend) zu knacken, ist ein großer Fehler. Sie müssen (wie Randall) davon ausgehen, dass der Angreifer auf die gleiche Weise wie Sie Vermutungen generiert - indem Sie zufällige Wörter aus dem Wörterbuch auswählen. Randall berechnet sogar für 4 Wörter 44 Entropiebits. Außerdem spielt es kaum eine Rolle, zusätzliche 3 Sekunden zu benötigen, um ein solches Programm auszuführen.
Nealmcb
Und Ihre Pads sind schwer zu merken, aber leicht zu knacken, da es nur 20 Möglichkeiten für jedes Zeichen gibt (weniger als ein Kleinbuchstabe des Alphabets!), Also jeweils nur etwa 4 Entropiebits. In Anbetracht Ihrer Annahme, dass die Geschwindigkeit des Knackens schnell ist, würde das Knacken eines 4-Wort-Passworts wie Randalls mit 44 Entropiebits weniger als eine Sekunde dauern, und das Knacken eines Passworts wie Ihres 2-Wort-Beispiels plus 4 zufälliger Pads wäre weitaus einfacher (nur etwa 22 + 4 *) 4 = 38 Bit Entropie).
Nealmcb
0
import uuid
print('Your new password is: {0}').format(uuid.uuid4())
Alex
quelle
1
Ich bin nicht sicher, ob uuid einen Zufallsgenerator verwendet, der kryptografisch sicher ist. Eine Referenz wäre ein Muss.
ThorSummoner
Die Implementierung von uuid4 ist betriebssystemabhängig. github.com/python/cpython/blob/master/Lib/uuid.py#L463
Alex
0

Ein bisschen abseits des Themas, aber ich habe das gemacht, auch mit TKinter. 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 + '!@#$%^&*()?\/'
    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()
Dekadenz
quelle
0

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

Führen Sie das Programm einfach auf einer Befehlskonsole aus und geben Sie eine Reihe von Buchstaben ein, die Ihnen bekannt vorkommen. Auf der Grundlage Ihrer Eingabe wird eine Folge von Symbolen generiert.

Natürlich unterstützt das Programm die Generierung mehrerer Sequenzen nicht.

Sie können den Code von meinem Github Pull herunterladen: 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 __name__ == '__main__':
    x = user_input()
    print(generator(x, positions_to_change(x)))
A. Ihya
quelle
0

Hier ist mein Zufallspasswortgenerator, nachdem ich dieses Thema untersucht 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('!@#$%^&*()')
   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 1 zufälligen Großbuchstaben, 3 zufälligen Kleinbuchstaben, 3 zufälligen Ziffern und 1 zufälligen Sonderzeichen generiert - dies kann nach Bedarf angepasst werden. Dann kombiniert es jedes zufällige Zeichen und erstellt eine zufällige Reihenfolge. Ich weiß nicht, ob dies als "hohe Qualität" angesehen wird, aber es erledigt die Arbeit.

d84_n1nj4
quelle
0

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 gibt ein zufälliges Passwort zurück (ohne eine Zahl oder ein Symbol am Anfang des Passworts).

Avikd
quelle
Dieser Code ist zutiefst fehlerhaft und leidet unter dem gleichen Verzerrungsproblem, von dem Pornin spricht, da die charsListenlänge 69 Zeichen und nicht 64 beträgt. Die Zeichen vor 'A' werden nur etwa 75% so oft angezeigt wie die anderen. Siehe stattdessen die Antwort von @foudfou. Außerdem funktioniert es überhaupt nicht ganz: Die letzte Zeile sollte seinprint(get_pass())
nealmcb
0

Ich habe erst kürzlich angefangen, Python zu lernen, und das habe ich heute geschrieben. Hoffe das hilft.

import random

characters = 'abcdefghijklmnopqrstuvwxyz1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^()}{/<>'
print('Password Length: ')
passwordLength = int(input())
password = ''

for i in range(passwordLength):
    password += random.choice(characters)
print(password)
Prashant Gonga
quelle
0
"""
This code below in any shape or form is owned by A.S Gallery 

This code is the asnwer for Password Generator quiz - CodeHs 
This code works 100%
Have fun exploring !!!

"""

# Imports 
import random
import time
print "Hi !!!"
password_output = "this is your new password : "
ask_name = input("Enter your Name : ")
greetings_name = "Hi "+ str(ask_name) + "!!! "
print greetings_name
print "Now we will make your new password using the ULTIMATE password generator !!!"
time.sleep(8)
print "Our password generator will give you multiple choices, you can choose any password generator you want !!! "
time.sleep(8)
print "You can choose if you want a strong password or a weak password !! (strong recommended) "
time.sleep(8)
print "You can also make your own password, to make your own password type own !!! "
time.sleep(8)
print "If you want to choose strong type strong, if weak then type weak !!! "
time.sleep(8)




# Example:
# Returns random number within and including 0 and 10.
def strong_password():
    user_input = int(input("Enter a number : "))
    print type(user_input)
    time.sleep(3)
    # calculate_input = user_input * user_input
    calculate_types = input("Do you want to add, multiply or mod the numbers : ")
    time.sleep(3)
    if calculate_types == "add":
        calculate_input = user_input + user_input
    elif calculate_types == "multiply" :
        calculate_input = user_input * user_input
    elif calculate_types == "mod":
        calculate_input = user_input & user_input 
    else:
        print "Check your spelling and try again :( "

    # Random element in a string
    time.sleep(4)
    want_symbols = input("Do you want symbols ?(Y/N) : ")
    time.sleep(4)
    random_element = random.choice('abcdefg345')
    if want_symbols == "Y":
        random_element2 = random.choice('@#()@*($*(@)(*^()*()(#$)*@#)*((@*()@*#)(*)@*($*(%#*)#(*@@_!_()(')
    elif want_symbols == "N":
        random_element2 = random.choice('29371294203712492703740182903820498201381204AKSJFKSHEHJKFJAODL')
    random_element3 = random.choice('abcdefghiiasudasdjsiasdhwudagsjdgaskdjsafgjasj')
    random_element4 = random.choice('abcdefghijsdhjaskdhkasjdhakdjhaskdasjdhakjsd')
    random_element5 = random.choice('abcdefghijsdhsakjdhsajdldasjdasdjasldas')
    random_elements6 = random.choice('129389230928308290382109830293943827492347')
    random_elements7 = random.choice('2473285473q9mdnuwyr8KSDJKDSJKL932uc3487389473289479h3289wjdi94802w')
    random_elements8 = random.choice('AKDJKAJDKJIKJDUIFHSJHUFRUDIJFDKLDJKDJLJFKLJKLDJLDJKLDJLDJLSKJDKLJDLJDKSLJD')


    time.sleep(8)

    print str(ask_name) + " " + str(password_output) + str(calculate_input) + str(random_element) + str(random_element2) + str(random_element3) + str(random_element4) + str(random_element5) + str(random_elements6) + str(random_elements7) + str(random_elements8)

def weak_password():
    user_input = int(input("Enter a number : "))
    print type(user_input)
    time.sleep(3)
    # calculate_input = user_input * user_input
    calculate_types = input("Do you want to add, multiply or mod the numbers : ")
    time.sleep(3)
    if calculate_types == "add":
        calculate_input = user_input + user_input
    elif calculate_types == "multiply" :
        calculate_input = user_input * user_input
    elif calculate_types == "mod":
        calculate_input = user_input & user_input 
    else:
        time.sleep(3)
        print "Check your spelling and try again :( "

    # Random element in a string


    random_ness = random.choice("ABCDEFGHI*(#*#$()#*$)(E)(UWIJEDSH(*#U$()UDSLKH)UW*)$(*&#*(YE(*DY#*YUHSLDF:LKDDSDK")
    my_tuple = (calculate_input, random_ness, user_input, ask_name)
    new_tuple = my_tuple[1] 
    new_tuple1 = my_tuple[2]
    new_tuple2 = my_tuple[3]
    time.sleep(7)
    print str(ask_name) + str(password_output) + str(new_tuple) + str(new_tuple1) + str(new_tuple2) 

def own_password():
    my_list = []
    ask_times = int(input("How many characters do you want ? (between 1 - 8) : "))
    time.sleep(10)
    if ask_times > 8:
        print "Invalid Request"
    elif ask_times < 1:
        print "Invalid Request"
    else:
        time.sleep(2)
        print "You CANNOT include symbols or numbers in this option !!! "
        for i in range(ask_times):
            user_ask = input("Enter the character: ")
            time.sleep(0.6)
            my_list.append(user_ask)
        own_password =  "".join(map(str,my_list))
        time.sleep(4)
        print "Your own password is : " + own_password




strong_pass = input("Do you want a strong password or a weak one or make your own password !! ? : ")
if strong_pass == "strong":
    strong_password()
elif strong_pass == "weak":
    weak_password()
elif strong_pass == "own":
    own_password()
else :
    print "Invalid Request"

time.sleep(3)
print "Congrats, on creating your best password !!! I belived you used strong password generator because its the BEST !!"
time.sleep(7)
print "If not, no problem just restart the program and type strong when prompted !!! "
time.sleep(6)
print "Have a nice day !"

Dieser Code ist auch die Antwort für das CodeHs-Quiz (falls vorhanden) !!!

AS Galerie
quelle
-1

Ja, kein Amateur-Hacker wird dieses Passwort knacken. Danach empfehle ich, mit Ihrem Projekt zur Generierung zufälliger Kennwörter fortzufahren und eine Benutzeroberfläche oder GUI-Schnittstelle entweder mit Tkinter oder Flask zu erstellen, damit andere sie verwenden können. Zum Beispiel fand ich dieses nette kleine Projekt nur durch die Suche nach 'Passwortgenerator Python UI'. https://passwordgenerator.pythonanywhere.com/

Vielleicht möchten Sie etwas Ähnliches wie oben machen? Es ist eine gute Fähigkeit zu wissen, wie man Python in die Webentwicklung implementiert.

Viel Glück.

Entspann dich

Paul McBurney
quelle
-3

Das ist mehr zum Spaß als alles andere. In passwordmeter.com positiv bewertet, aber nicht zu merken.

#!/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]
Mitja
quelle