Generatore di password XKCD


34

introduzione

Apparentemente, questa domanda è stata posta qui e purtroppo è stata chiusa. Ho pensato che fosse una buona idea riprovarci, ma fatto bene.

XKCD esamina il modo in cui siamo addestrati a utilizzare password difficili da ricordare, pensando che sia sicuro, ma invece impiegherebbe un computer a 3 giorni per decifrare. Il rovescio della medaglia, ricordare 4-5 parole fa apparire la password Intropy di Kuan ed è facile da ricordare. Pazzo come funziona, eh?

Sfida

Oggi il lavoro è creare 5 password usando le parole. 4 parole per password e un minimo di 4 lettere per parola, ma non un massimo. La password Intropy di Kuan dovrà essere calcolata per ogni password, ma non verrà impostato un minimo forzato.

Qual è l'intropia della password di Kuan?

Kuan's Password Intropy è una misura di quanto sia imprevedibile una password, secondo Kuan. V'è un semplice calcolo: E = log 2 (R) * L . E essendo Intropia password di Kuan, R essendo intervallo di caratteri disponibili e L per lunghezza password.

La gamma di caratteri disponibili si spiega da sé. È la gamma di caratteri che può avere una password, in questo caso è maiuscola e minuscola. Poiché l'alfabeto contiene 26 caratteri, 26 x 2 = 52 caratteri nell'intero intervallo della password.

Anche la lunghezza della password è autoesplicativa. È la lunghezza totale della password dopo la creazione.

vincoli

  • Nessun input
  • Una parola non può riapparire nella stessa password.
  • Nessun simbolo o numero consentito in una password.
  • 4 parole per password, ma un minimo forzato di 4 lettere per parola.
  • Nessuno spazio tra le parole.
  • Non è possibile generare più volte la stessa password.
  • Ogni parola deve essere in maiuscolo in una password.
  • L'output deve essere leggibile dall'uomo, deve essere distanziato. Deve includere anche la password di Kuan Intropy della password con essa usando l'equazione di Kuan's Password Intropy sopra.
  • Dizionario . È necessario utilizzarlo, scaricarlo come file di testo e integrarlo di conseguenza. Questa sarà la lista da cui prendi le parole. Il tuo codice dovrebbe supporre che sia disponibile.
  • Questo è , vincono i byte più brevi.

Produzione

TriedScarProgressPopulation 153.9
TryingPastOnesPutting 119.7
YearnGasesDeerGiven 108.3
DoubtFeetSomebodyCreature 142.5
LiquidSureDreamCatch 114.0

16
Per i casi di test, perché l' entropia della password varia? Tutte le password di 4 parole generate dallo stesso dizionario devono avere la stessa entropia.
NonlinearFruit

20
L'entropia della password dipende dal set di simboli. Se la password è un Nsimbolo dell'insieme S, l'entropia della password è log2(|S|)*N. Qui la dimensione del set di simboli è la dimensione del dizionario ( |S|=4284) e il numero di simboli è il numero di parole ( N=4), quindi l'entropia per ogni password è 48.3.
NonlinearFruit

48
Questa definizione di entropia è pericolosamente sbagliata! Se ogni carattere viene scelto in modo uniforme a caso da un set di dimensioni R, allora in effetti una password di lunghezza L ha possibilità R ^ L, quindi l'entropia è il registro di ciò: log₂ (R ^ L) = log₂ (R) * L qual è la tua formula Tuttavia, se le password vengono scelte a caso da un set diverso (ad es. Non avrai mai una password simile 3t1ta#asd), l'entropia sarà il logaritmo del numero di possibili password. Se scegli sempre 4 parole in modo uniforme in modo casuale da un dizionario di 4284 parole, allora ci sono 4284 ^ 4 password, ognuna con registro entropiay (4284) * 4 ≈ 48.26.
ShreevatsaR,

5
Per la cronaca, questo tipo di password precede il fumetto XKCD. Si chiamano password "diceware".
user2428118,

5
A parte la questione delle parole che hanno meno entropia dei caratteri casuali, la tua domanda richiede che le parole siano maiuscole, il che significa che il caso è fisso e non può essere conteggiato per l'entropia.
Niet the Dark Absol,

Risposte:


13

Python 2, 102 101 97 91 byte

from random import*
exec"x=''.join(x.title()for x in sample(f,4));print(x,57*len(x)/10);"*5

Presume il dizionario come un elenco denominato f.

Può essere testato salvando il file come dict.txte chiamando

f = open('dict.txt').readlines()

Gli elenchi di Python non hanno il metodo shuffle e puoi salvare due byte in Python 2 rimuovendo la parentesi exec( execè una parola chiave in Python 2).
Konrad Borowski

@xfix Sì, dovrebbe essere shuffle(f);.
Jonathan Allan,

Whoops, che
risolve

4
Potresti usare il mio trucco per notare che l'arrotondamento a 5,7 va bene con 1 decimale purché non vengano introdotti errori in virgola mobile e si salvi cinque byte 57*len(x)/10.. Salvare un altro byte rimuovendo le parentesi facendo in modo che la stampa diventi una tupla. Ecco una versione ridotta: TIO
Jonathan Allan,

Usa sample(f,4)invece di shuffle. Inoltre fpuò essere open('dict.txt').read().split('\n'), open('dict.txt').readlines()o solo open('dict.txt')(so che non è golf ma ancora).
Alex Hall,

10

PowerShell (3.0+), 77 byte

1..5|%{($p=-join($d|random -c 4|%{culture|% te*|% tot* $_}));57*$p.Length/10}

Provalo online!

Usando il trucco di Jonathan Allan57*len/10 .

$dcontiene il dizionario come una matrice di parole. Se stai giocando a casa e vuoi riempire $d:

$d=-split(irm pastebin.com/raw/eMRSQ4u2)

Utilizzando una versione golfizzata (Get-Culture).TextInfo.ToTitleCase()per capitalizzare la prima lettera; Non penso che ci sia un modo più breve per farlo in PowerShell.

Il resto è piuttosto semplice, credo.

Il collegamento TIO ha l'intero dizionario; disabilita la cache e impazzisci!


Qualcuno può indicarmi un riferimento per "Il trucco 57 * len / 10 di Jonathan Allan"?
James Curran,

@JamesCurran Vedi la ripartizione della sua risposta qui , e anche il suo commento su questa risposta .
Briantist,

Questo non funzionerà nella versione 2.0 corretta. Questo dovrebbe essere notato nel titolo. Penso anche che devi leggere $dcome si suppone che sia presente nell'ambiente. (gc d)| random..dove il dizionario è un file chiamato d nella stessa directory.
Matt,

1
@Matt su SO Potrei fare di tutto per far funzionare una risposta con v2 (o fare 2 versioni), ma questo è il codice golf man! Più arcani sono, meglio è ;-p
briantista,

1
Sto solo cercando di salvare byte nei titoli delle mie risposte.
Matt,

7

Gelatina , 22 byte

Ẋḣ4ŒtFµL×57÷⁵⁸,K
çЀ5Y

Un collegamento monadico che prende un elenco di un elenco di caratteri, il dizionario analizzato (come consentito nella chat ).

Provalo online! (Fai clic su "Argomenti" per nascondere il dizionario e ridurre la necessità di scorrere.)

Come?

Poiché il dizionario contiene solo parole valide (solo 4caratteri o più [a-z]), non è necessario controllare questa condizione.

Dal momento che tutte le parole nel dizionario hanno lunghezze nelle [4-8]possibili lunghezze della password [16,32], e le possibili entropie non si arrotondano mai diversamente a una cifra decimale rispetto alla sostituzione log(52,2)con 5.7. L'unico problema è che utilizzando un valore di virgola mobile 5.7darà virgola mobile errori di arrotondamento per lunghezze 18, 26e 31. Tuttavia, la moltiplicazione per 57e poi la divisione 10utilizzando ×57÷⁵evita questo (pur essendo un byte più breve rispetto alla stampa del valore di precisione in virgola mobile utilizzando ×52l2¤).

çЀ5Y - Main link: list of list of characters (the parsed dictionary)
   5  - literal 5
 Ѐ   - map across the implicit range [1,2,3,4,5]:
ç     -   last link (1) as a dyad
    Y - join with newlines
      - implicit print

Ẋḣ4ŒtFµL×57÷⁵⁸,K - Link 1, get password and entropy: list of lists of characters, number
Ẋ                - shuffle the list of lists (shuffle all the words)
 ḣ4              - head to 4 (the first four words)
   Œt            - title case (make the first letter of each uppercase)
     F           - flatten into one list of characters
      µ          - monadic chain separation, call that p
       L         - length of p
         57      - 57
        ×        - multiply
            ⁵    - 10
           ÷     - divide -> entropy to 1 decimal place
             ⁸   - link's left argument, p
              ,  - pair -> [p, entropy]
               K - join with (a) space(s)

5

Rubino, 89 83 byte

d.select!{|w|w[3]}
5.times{p w=d.sample(4).map(&:capitalize)*'',5.700439718*w.size}

Presuppone che le password siano archiviate nella variabile d. Puoi aggiungere questa riga prima del codice:

d=$<.map(&:chomp)

e chiama lo script per esempio in questo modo:

$ ruby generate_passwords.rb < dictionary_file.txt

Uscita campione:

"MarginStarvedOnusInsulted"
142.51099295
"KitchenMiseryLurkJoints"
131.110113514
"InducesNotablePitfallsPrecede"
165.312751822
"FarmersAbortFutileWrapper"
142.51099295
"RoutesBishopGlowFaithful"
136.81055323200002

KitchenMiseryLurkJoints ... wow.


-6 byte da Ajedi32


1
Potrebbe essere in grado di salvare qualche byte rimuovendolo shuffle!e sostituendolo popcon sample.
Ajedi32,

@ Ajedi32 Oh, hai ragione! In realtà ci ho pensato, ma avevo letto male questa regola A word cannot reappear in the same password, pensando che non significasse il riutilizzo delle parole in tutte le password. Grazie :)
daniero,

4

Mathematica, 178 byte

t=1;l=Length;While[t<6,s=RandomChoice[Import["https://pastebin.com/raw/eMRSQ4u2"],4];c=Capitalize/@s;f=Flatten@Characters[c];Print[StringJoin[c]," ",Log[2,l@Union@f]*l@f//N];t++]

Provalo online

copia e incolla usando ctrl-v e premi Maiusc + Invio per eseguire


Mathematica, 136 byte

supponendo che m sia il dizionario del codice

m=ImportString[Import["C:\a.txt"]]

.

t=1;l=Length;While[t<6,s=RandomChoice[m,4];c=Capitalize/@s;f=Flatten@Characters[c];Print[StringJoin[c]," ",Log[2,l@Union@f]*l@f//N];t++]

"Il lavoro oggi è creare 5 password usando le parole." Ne servono 5 invece di una.
KuanHulio,

ok ... 5 password .. fisse ..
J42161217

Perché non hai reso il dizionario disponibile localmente per abbreviare il codice evitando il testo del collegamento ipertestuale?
sergiol

per essere facile per te testarlo ...
J42161217

È meglio fornire un codice helper semplice e non golfato per facilitare i test piuttosto che golfare la tua presentazione meno in modo che sia autonoma. Inoltre, il dizionario dovrebbe essere variabile senza dirottare il server DNS locale (o modificare il hostsfile).
wizzwizz4,

4

Bash ,66 65 byte

for w in `shuf -n4 -`;{((l+=${#w}));printf ${w^};};bc<<<$l*5.7004

Provalo online!

Il dizionario è ricevuto da STDIN. Mescola tutte le parole nel dizionario e produce prima 4.

Per ogni parola, somma la sua lunghezza in var 1 e fa eco alla parola in maiuscolo. Alla fine chiama bc per fare i conti.

Soluzione Awk, 112 byte, quattro password:

shuf -n16 -|xargs -n4|awk '{for(i=1;i<5;i++)printf toupper(substr($i,1,1))substr($i,2);print(length($0)-3)*5.7}'

3

(Questo è un adattamento della risposta dei martmisti, ma non ho il rappresentante per commentare)

Python, 88 86 byte

g={*f}
exec('x="".join(g.pop().title()for i in "a"*4);print(x,len(x)*5.700439718);'*5)

Sfruttando quanto setnon deterministico, puoi evitare di importare qualsiasi libreria di casualità.


Questo produce costantemente lo stesso risultato per me. Se funziona su alcune implementazioni, è possibile salvare alcuni byte facendo set(f).pop().
Jonathan Allan,

1
Non penso sia davvero valido. Non è deterministico, quindi non è garantito che produca la stessa password, ma in pratica raramente creerà risultati diversi.
DJMcMayhem

Sospettavo che potesse dipendere dall'implementazione. L'ho fatto su una versione Windows di Anaconda Python 3 appena installata e ha funzionato. Tuttavia set(f).pop()non funziona, l'ho provato. Dà lo stesso risultato ogni volta.
dain,

"In pratica raramente si ottengono risultati diversi" - sembra per me, ecco un esempio: pastebin.com/raw/ZHiHgzxV
dain

@dain sono curioso. Fornisci informazioni sulla tua build Python.
wizzwizz4,

3

Japt , 30 byte

5Ç[V=Uö4 ®g u +Zt1ìMm52 *Vl]¸

Provalo online!


Bello! Ma sfortunatamente crea la stessa password 5 volte e dovrebbe essere diversa ogni volta ..
Iain Ward,

Può trattarsi di 30 caratteri, ma almeno in UTF-8, il mio sistema lo cronometra a 35 byte.
un CVn

1
@ MichaelKjörling Japt utilizza ISO 8859-1, non UTF-8.
Dennis,

@Dennis Interessante. Grazie.
un CVn

3

JavaScript (ES6), 164 byte

d=>{for(i=5;i--;)console.log(p="....".replace(/./g,_=>(w=d.splice(Math.random()*d.length|0,1)[0])[0].toUpperCase()+w.slice(1)),(Math.log2(52)*p.length).toFixed(1))}

Presuppone che il dizionario sia passato alla funzione come un array.

Test dello snippet


2

Mathematica, 71 byte

Supponendo che il dizionario sia già caricato in un array chiamato d.

Table[{#,Log[2,52]StringLength[#]}&[""<>Capitalize@d~RandomSample~4],5]

spiegazione:

                                        Capitalize@d                    - Capitalize all the dictionary
                                                    ~RandomSample~4     - make an array with 4 values. By default values can not repeat.
                                    ""<>                                - Concatenate with empty string to turn array into single string.
      {#,Log[2,52]StringLength[#]}&[                               ]    - Put current string next to log(2,52) times length of current string
Table[                                                              ,5] - Repeat this 5 times.

E il numero di entropia ?!
Jonathan Allan,

Oops ha perso quel pezzo. Aggiornato.
Ian Miller,

2

ColdFusion 216 byte

p={};z=arrayLen(c);for(x=0;x<5;x++){pw="";r={};while(structCount(r)<4){n=RandRange(1,z);r.append({"#c[n]#":true});}for(w in structKeyList(r)){pw&=REReplace(w,"\b(\w)","\u\1","All");};p.append({"#pw#":57*len(pw)/10})}

Funziona con ColdFusion 11+ e Lucee 4.5+

Per eseguirlo: https://trycf.com/gist/ff14e2b27d66f28ff69ab90365361b12/acf11?theme=monokai

Il link TryCF ha meno golf-ish ma lo stesso codice.

Non mi aspettavo davvero di avere una risposta golfistica competitiva; Volevo solo vedere cosa ci sarebbe voluto per completare questa sfida in ColdFusion. Soprattutto perché non c'è molto CF in queste risposte. :-) Dopo l'installazione, è stato sorprendentemente più breve di quanto mi aspettassi.

Il mio primo tentativo fu un po 'più breve finché non mi ricordai che la stessa parola non poteva essere usata più di una volta. Anche se è altamente improbabile che il randomizzatore scelga lo stesso indice più di una volta, scarico gli indici nelle chiavi di una struttura, il che impedirà la duplicazione. Quindi uso quell'elenco di chiavi per creare la mia stringa di password finale. Ho anche usato il trucco matematico per trovare l'entropia.


2

PHP , 136 129 byte

-7 byte, grazie Jörg

for(shuffle($a);$i++<5;){for($s='',$c=0;$c<4;)strlen($w=$a[$k++])<4?:$s.=ucfirst($w).!++$c;echo$s.' '.log(52, 2)*strlen($s)."
";}

Provalo online!


@ JörgHülsermann Sembra funzionare, grazie.
ME,

2

Python 3, 252 byte

Questa è la mia prima sfida di golf in codice che abbia mai fatto! So che ci sono altre risposte Python qui (che probabilmente sono migliori delle mie) ma questo sembrava divertente, e quindi volevo provarlo comunque. Ecco la versione golfata:

import random, math
with open("d") as f: d=f.read()
l=d.split()
for a in range(5):
 u=[]
 p=""
 for b in range(4):
  w=random.choice([w for w in l if not w in u and len(w)>=4])
  u.append(w)
  w=w.title()
  p+=w
 print("%s %s"%(p,math.log2(52)*len(p)))

Vorrei pubblicare un Provalo online! link, ma questo non supporta più file. Quindi ecco un link repl.it: https://repl.it/InIl/0

Inoltre, ecco la versione non golfata:

import random
import math
with open("d") as f:
    dictionary = f.read() #this is the dictionary text file, simply saved as "d" as to use as few bytes as possible
words = dictionary.split() #here we turn that dictionary string into a list
for a in range(5): #here we iterate through 5 passwords
    used_words = []
    password = ""
    for b in range(4): #here we iterate through the 4 words in each password
        word = ""
        word = random.choice([word for word in words if not word in used_words and len(word) >= 4]) #Thanks to blackadder1337 from #python on freenode IRC for helping me with this.
        used_words.append(word)
        word = word.title()
        password = password + word
    print("%s %s"%(password, math.log2(52) * len(password)))

Come ho già detto, questa è la mia prima volta che gofling il codice, quindi sono sicuro che questo potrebbe essere migliorato molto.


Benvenuti in PPCG!
Taylor Scott,

2

tcl, 137

Non è certo un vincitore, ma penso che possa essere un po 'più golfato.

time {set p "";time {set p [string totitle [lindex $d [expr int(rand()*[llength $d])]]]$p} 4;puts $p\ [expr 5.7004*[string length $p]]} 5

demo - Lo scopo della riga 1 è solo quello di inserire il contenuto del dizionario nella variabiled


Probabilmente potresti giocare a golf poiché la password richiede 4 parole invece di 5.
KuanHulio,

E hai chiesto 5 password invece di 4. LOL! Ho sbagliato i numeri!
sergiol,

Hahaha! @sergiol
KuanHulio,

Fisso! @KuanHulio
sergiol

Va meglio. Bel lavoro.
KuanHulio,

0

Vim, 87 sequenze di tasti

qq:r!echo "$RANDOM"l<CR>D:w o|e w<CR>@"ev4bd:w|bp<CR>p0~wX~wX~wX~Y:.!wc -c<CR>A*5.7003<Esc>:.!bc<CR>PJq4@q

Presuppone che il dizionario si trovi in ​​un file denominato w. Userà sempre 4 parole consecutive

Spiegazione:

qq                       Start recording a macro named 'q'
:r!echo "$RANDOM"l<CR>   Append the result of the shell command `echo "$RANDOM"l`
D                        Delete what you just appended
:w o|                    Save the buffer to the file 'o' and ..
e w<CR>                  Open the file 'w'
@"                       Execute the text we deleted as a normal-mode command
                         This will move the cursor a random number of characters
                         to the right
e                        Go to the end of the next word
v4bd                     Delete 4 words backwards
:w|                      Save the file and ..
bp<CR>                   Open the last buffer (the 'o' file)
p                        Paste the 4 words we deleted
0                        Move the cursor to the beginning of the line
~wX~wX~wX~               Remove the spaces between the words and capitalize
Y                        Copy current line
:.!wc -c<CR>             Pipe the current line through 'wc -c'
A*5.7003<Esc>            Append "*5.7003" to the end of the line
:.!bc<CR>                Pipe the current line through 'bc'
P                        Paste the password above the current line
J                        Join with line bellow
q                        Stop recording the 'q' macro
4@q                      Run the 'q' macro 4 times

0

q / KDB +, 76 74 65 56 byte

Soluzione:

{(x;5.70044*(#)x)}(,/)@[;0;upper]each -4?" "vs(*)(0:)`:w

Esempio:

q){(x;5.70044*(#)x)}(,/)@[;0;upper]each -4?" "vs(*)(0:)`:w
"RulingOverheadSaddensPriest"
153.9119

Spiegazione:

Leggere nell'elenco delle parole, separare "", selezionare 4 parole casuali da questo elenco, lettere maiuscole prima di ogni parola, quindi unire. Inseriscilo in una funzione lambda che restituisce la password e l'entropia calcolata:

                                                     `:w / the wordlist is a file called 'w'
                                                 (0:)    / read in the file list (\n separated list)
                                              (*)        / take first (and only) item in the list
                                         " "vs           / split this on " "
                                      -4?                / take 4 random items from this list, neg means 'dont put back'
                      @[; ;     ]                        / apply a function to variable at indices (variable is implicit)
                           upper                         / uppercase (the function being applied)
                         0                               / index 0, the first character
                                 each                    / each of the 4 random items
                  (,/)                                   / 'raze' (flatten lists)
{                }                                       / anonymous lambda function
 (x;            )                                        / a 2-item list, x is first item
            (#)x                                         / count x, return the length of the list
    5.70044*                                             / multiply by 5.70044

Gli appunti:

Ho ceduto e usato 5.70044 invece di 2 xlog 52 xexp...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.