Generador de contraseñas XKCD


34

Introducción

Aparentemente, esta pregunta se hizo aquí y desafortunadamente se cerró. Pensé que era una buena idea intentarlo de nuevo, pero lo hice bien.

XKCD analiza la forma en que estamos capacitados para usar "contraseñas difíciles de recordar", pensando que es seguro, pero en cambio, le tomaría a una computadora 3 días para descifrarla. Por otro lado, recordar 4-5 palabras hace surgir la Intropía de contraseña de Kuan, y es fácil de recordar. Loco como funciona eso, ¿eh?

Reto

El trabajo de hoy es crear 5 contraseñas con palabras. 4 palabras por contraseña y un mínimo de 4 letras por palabra, pero no un máximo. La Intropía de contraseña de Kuan deberá calcularse para cada contraseña, pero no se establecerá un mínimo forzado.

¿Qué es la Intropía de contraseñas de Kuan?

La contraseña de Kuan Intropy es una medida de lo impredecible que es una contraseña, según Kuan. No es un simple cálculo: E = log 2 (R) * L . E es la Intropía de contraseña de Kuan, R es el rango de caracteres disponibles y L para la longitud de la contraseña.

El rango de caracteres disponibles se explica por sí mismo. Es el rango de caracteres que puede tener una contraseña, en este caso, mayúsculas y minúsculas. Como hay 26 caracteres en el alfabeto, 26 x 2 = 52 caracteres en todo el rango de la contraseña.

La longitud de la contraseña también se explica por sí misma. Es la longitud total de la contraseña después de la creación.

Restricciones

  • Sin entrada.
  • Una palabra no puede reaparecer en la misma contraseña.
  • No se permiten símbolos o números en una contraseña.
  • 4 palabras por contraseña, pero un mínimo forzado de 4 letras por palabra.
  • No hay espacios entre palabras.
  • No puede generar la misma contraseña una y otra vez.
  • Cada palabra debe estar en mayúscula en una contraseña.
  • La salida tiene que ser legible por humanos, debe estar espaciada. También debe incluir la Intropía de contraseña de Kuan de la contraseña con la ecuación de Intropía de contraseña de Kuan anterior.
  • Diccionario . Debe usar esto, descargarlo como un archivo de texto e integrarlo en consecuencia. Esta será la lista de la que tomarás palabras. Su código debe asumir que está disponible.
  • Este es el , gana el byte más corto.

Salida

TriedScarProgressPopulation 153.9
TryingPastOnesPutting 119.7
YearnGasesDeerGiven 108.3
DoubtFeetSomebodyCreature 142.5
LiquidSureDreamCatch 114.0

16
Para los casos de prueba, ¿por qué varía la entropía de la contraseña ? Las contraseñas de 4 palabras que se generan a partir del mismo diccionario deben tener la misma entropía.
NonlinearFruit

20
La entropía de la contraseña depende del conjunto de símbolos. Si su contraseña son Nsímbolos del conjunto S, la entropía de la contraseña es log2(|S|)*N. Aquí el tamaño del conjunto de símbolos es el tamaño del diccionario ( |S|=4284) y el número de símbolos es el número de palabras ( N=4), por lo que la entropía para cada contraseña es 48.3.
NonlinearFruit

48
¡Esta definición de entropía es peligrosamente incorrecta! Si cada carácter se elige de manera uniforme al azar de un conjunto de tamaño R, entonces una contraseña de longitud L tiene posibilidades R ^ L, por lo que la entropía es el registro de eso: log₂ (R ^ L) = log₂ (R) * L cual es tu formula Sin embargo, si las contraseñas se eligen al azar de un conjunto diferente (por ejemplo, nunca tendrá una contraseña como 3t1ta#asd), entonces la entropía será el logaritmo del número de contraseñas posibles. Si siempre elige 4 palabras uniformemente al azar de un diccionario de 4284 palabras, entonces hay 4284 ^ 4 contraseñas, cada una con entropía log₂ (4284) * 4 ≈ 48.26.
ShreevatsaR

55
Para el registro, este tipo de contraseñas es anterior al cómic XKCD. Se llaman contraseñas "diceware".
user2428118

55
Además del tema de las palabras que tienen menos entropía que los caracteres aleatorios, su pregunta requiere que las palabras estén en mayúscula, lo que significa que el caso es fijo y no se puede contar para la entropía.
Niet the Dark Absol

Respuestas:


13

Pitón 2, 102 101 97 91 bytes

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

Asume el diccionario como una lista llamada f.

Se puede probar guardando el archivo como dict.txty llamando

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

Las listas de Python no tienen un método aleatorio, y puede guardar dos bytes en Python 2 eliminando el paréntesis exec( execes una palabra clave en Python 2).
Konrad Borowski

@xfix Sí, debería ser shuffle(f);.
Jonathan Allan

Whoops, arreglando eso lo antes posible
Martmists

44
Podría usar mi truco para señalar que el redondeo en 5.7 está bien a 1 decimal, siempre que no se introduzcan errores de coma flotante y ahorre cinco bytes con 57*len(x)/10.. Guarde otro byte quitando los paréntesis haciendo que la impresión tome una tupla. Aquí hay una versión reducida: TIO
Jonathan Allan

Usar en sample(f,4)lugar de shuffle. También fpuede ser open('dict.txt').read().split('\n'), open('dict.txt').readlines()o simplemente open('dict.txt')(sé que no es golf pero aún así).
Alex Hall

10

PowerShell (3.0+), 77 bytes

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

Pruébalo en línea!

El uso de Jonathan Allan 's57*len/10 truco de .

$dcontiene el diccionario como un conjunto de palabras. Si estás jugando en casa y quieres llenar $d:

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

Usando una versión de golf (Get-Culture).TextInfo.ToTitleCase()para poner en mayúscula la primera letra; No creo que haya una forma más corta de hacerlo en PowerShell.

El resto es bastante sencillo, creo.

El enlace TIO tiene todo el diccionario; desactivar el caché y volverse loco!


¿Alguien puede señalarme una referencia para el "truco de 57 * len / 10 de Jonathan Allan"?
James Curran

@JamesCurran Vea el desglose de su respuesta aquí , y también su comentario sobre esta respuesta .
briantist

Esto no funcionará en 2.0 correcto. Eso debe notarse en el título. También creo que debes leer $dcomo se supone, suponiendo que esté presente en el entorno. (gc d)| random..donde el diccionario es un archivo llamado d en el mismo directorio.
Matt

1
@Matt en SO, podría hacer todo lo posible para que una respuesta funcione con v2 (o hacer 2 versiones), pero este es el código golf man! Cuanto más arcano, mejor ;-p
briantist

1
Solo estoy tratando de guardar bytes en mis títulos de respuesta.
Matt

7

Jalea , 22 bytes

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

Un enlace monádico que toma una lista de la lista de caracteres, el diccionario analizado (como se permite en el chat ).

Pruébalo en línea! (Haga clic en "Argumentos" para ocultar el diccionario y reducir la necesidad de desplazarse).

¿Cómo?

Como el diccionario solo contiene palabras válidas ( 4caracteres o más, solo[a-z] ), no es necesario verificar esta condición.

Dado que todas las palabras en el diccionario tienen longitudes en [4-8]la contraseña, las longitudes posibles están en [16,32], y las posibles entropías nunca se redondearán de manera diferente a un decimal si se reemplaza log(52,2)con 5.7. El único problema es que el uso de un valor de punto flotante 5.7dará punto flotante errores de redondeo para las longitudes 18, 26y 31. Sin embargo, multiplicar por 57y luego dividir mediante el 10uso ×57÷⁵evita esto (mientras sigue siendo un byte más corto que imprimir el valor de precisión de punto flotante completo usando ×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

Ruby, 89 83 bytes

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

Asume que las contraseñas se almacenan en la variable d. Puede agregar esta línea antes del código:

d=$<.map(&:chomp)

y llame al script por ejemplo así:

$ ruby generate_passwords.rb < dictionary_file.txt

Salida de muestra:

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

KitchenMiseryLurkJoints ... wow.


-6 bytes de Ajedi32


1
Es posible que pueda guardar algunos bytes al eliminar shuffle!y reemplazar popcon sample.
Ajedi32

@ Ajedi32 ¡Oh, tienes razón! Realmente lo pensé, pero había leído mal esta regla A word cannot reappear in the same password, pensando que no significaba la reutilización de palabras en todas las contraseñas. Gracias :)
daniero

4

Mathematica, 178 bytes

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++]

Pruébalo en línea

copia y pega usando ctrl-v y presiona shift + enter para ejecutar


Mathematica, 136 bytes

suponiendo que m es el diccionario, el código es

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++]

"El trabajo de hoy es crear 5 contraseñas con palabras". Se necesitan 5 en lugar de una.
KuanHulio

ok ... 5 contraseñas ... arreglado ..
J42161217

¿Por qué no hizo que el diccionario estuviera disponible localmente para acortar el código evitando el texto del hipervínculo?
sergiol

para que sea fácil para usted probarlo ...
J42161217

Lo mejor es proporcionar un código de ayuda simple y no oculto para facilitar las pruebas, en lugar de jugar menos en su envío para que sea autónomo. Además, se supone que el diccionario es variable sin secuestrar el servidor DNS local (o modificar el hostsarchivo).
wizzwizz4

4

Bash ,66 65 bytes

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

Pruébalo en línea!

El diccionario es recibido por STDIN. Baraja todas las palabras en el diccionario y genera las primeras 4.

Para cada palabra, suma su longitud en var l, y hace eco de la palabra en mayúscula. Al final llama a bc para hacer los cálculos.

Solución Awk, 112 bytes, cuatro contraseñas:

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

(Esta es una adaptación de la respuesta de Martmists, pero no tengo el representante para comentar)

Python, 88 86 bytes

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

Al explotar cómo setes no determinista, puede evitar tener que importar bibliotecas de aleatoriedad.


Esto produce constantemente la misma salida para mí. Si funciona en alguna implementación, puede guardar algunos bytes al hacerlo set(f).pop().
Jonathan Allan

1
No creo que esto sea realmente válido. No es determinista, por lo que no se garantiza que produzca la misma contraseña, pero en la práctica rara vez creará resultados diferentes.
DJMcMayhem

Sospeché que podría depender de la implementación. Lo hice en una versión de Windows recién instalada de Anaconda Python 3, y funcionó. Sin set(f).pop()embargo no funciona, lo probé. Da el mismo resultado cada vez.
desde

"En la práctica, raramente creará resultados diferentes", me parece a mí, aquí hay una muestra: pastebin.com/raw/ZHiHgzxV
fecha

@dain tengo curiosidad. Proporcione información sobre su compilación de Python.
wizzwizz4

3

Japt , 30 bytes

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

Pruébalo en línea!


¡Agradable! Pero desafortunadamente crea la misma contraseña 5 veces, y debería ser diferente cada vez ...
Iain Ward

Puede tener 30 caracteres, pero al menos en UTF-8, mi sistema lo registra a 35 bytes.
un CVn

1
@ MichaelKjörling Japt usa ISO 8859-1, no UTF-8.
Dennis

@Dennis Interesante. Gracias.
un CVn

3

JavaScript (ES6), 164 bytes

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

Asume que el diccionario se pasa a la función como una matriz.

Fragmento de prueba


2

Mathematica, 71 Bytes

Asumiendo que el diccionario ya está cargado en una matriz llamada d.

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

Explicación:

                                        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.

¿Qué pasa con el número de entropía?
Jonathan Allan

Oops se perdió ese bit. Actualizado.
Ian Miller

2

ColdFusion 216 bytes

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

Esto funciona en ColdFusion 11+ y Lucee 4.5+

Para ejecutarlo: https://trycf.com/gist/ff14e2b27d66f28ff69ab90365361b12/acf11?theme=monokai

El enlace TryCF tiene menos golf-ish pero el mismo código.

Realmente no esperaba tener una respuesta de golf competitiva; Solo quería ver qué se necesitaría para completar este desafío en ColdFusion. Especialmente porque no hay mucha FQ en estas respuestas. :-) Después de la configuración, fue sorprendentemente más corto de lo que esperaba.

Mi primer intento fue un poco más corto hasta que recordé que la misma palabra no se puede usar más de una vez. Aunque es muy poco probable que el aleatorizador elija el mismo índice más de una vez, vuelco los índices en las claves de una estructura, lo que evitará la duplicación. Luego uso esa lista de claves para construir mi cadena de contraseña final. También usé el truco matemático para encontrar la entropía.


2

PHP , 136 129 bytes

-7 bytes, gracias 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)."
";}

Pruébalo en línea!


@ JörgHülsermann Eso parece funcionar, gracias.
ME

2

Python 3, 252 bytes

¡Este es mi primer desafío de código de golf que he hecho! Sé que hay otras respuestas de Python aquí (que probablemente sean mejores que las mías), pero esto parecía divertido, por lo que quería probarlo de todos modos. Aquí está la versión de golf:

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

¡Publicaría una Prueba en línea! enlace, pero eso no admite múltiples archivos. Así que aquí hay un enlace repl.it: https://repl.it/InIl/0

Además, aquí está la versión sin golf:

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

Como dije, esta es la primera vez que hago gofling de código, así que estoy seguro de que esto podría mejorarse mucho.


Bienvenido a PPCG!
Taylor Scott

2

tcl, 137

No es un ganador seguro, pero creo que se puede jugar un poco más al golf.

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 - El propósito de la línea 1 es solo poner el contenido del diccionario en la variabled


Probablemente podría jugar golf ya que la contraseña requiere 4 palabras en lugar de 5.
KuanHulio

Y pediste 5 contraseñas en lugar de 4. LOL! ¡No combiné los números!
sergiol

¡Jajaja! @sergiol
KuanHulio

¡Fijo! @KuanHulio
sergiol

Eso es mejor. Buen trabajo.
KuanHulio

0

Vim, 87 pulsaciones de teclas

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

Asume que el diccionario está en un archivo llamado w. Siempre usará 4 palabras consecutivas

Explicación:

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 bytes

Solución:

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

Ejemplo:

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

Explicación:

Lea en la lista de palabras, separe en "", elija 4 palabras al azar de esta lista, la primera letra en mayúscula de cada palabra, luego únalas. Alimente esto en una función lambda que devuelve la contraseña y la 'entropía' calculada:

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

Notas:

Me derrumbé y usé 5.70044 en lugar de 2 xlog 52 xexp...

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.