Générateur de mots de passe XKCD

34

introduction

Apparemment, cette question a été posée ici et elle a malheureusement été fermée. Je pensais que c'était une bonne idée d'essayer à nouveau, mais j'ai bien fait.

XKCD examine la manière dont nous sommes formés pour utiliser des mots de passe difficiles à retenir. Il pense que c'est sécurisé, mais prendrait 3 jours pour craquer un ordinateur. D'un autre côté, se souvenir de 4 ou 5 mots apporte l'intropie du mot de passe de Kuan et est facile à retenir. C'est fou comment ça marche, hein?

Défi

Le travail actuel consiste à créer 5 mots de passe en utilisant des mots. 4 mots par mot de passe et un minimum de 4 lettres par mot, mais pas de maximum. L'intropie du mot de passe de Kuan devra être calculée pour chaque mot de passe, mais aucun minimum forcé ne sera défini.

Qu'est-ce que l'intropie du mot de passe de Kuan?

L'intropie de mots de passe de Kuan est une mesure de l'imprévisibilité d'un mot de passe, selon Kuan. Il y a un calcul simple: E = log 2 (R) * L . E étant l'intropie du mot de passe de Kuan, R étant la plage de caractères disponibles et L la longueur du mot de passe.

La gamme de caractères disponibles est explicite. C'est la gamme de caractères qu'un mot de passe peut avoir, en l'occurrence les majuscules et les minuscules. Comme il y a 26 caractères dans l'alphabet, 26 x 2 = 52 caractères dans toute la plage du mot de passe.

La longueur du mot de passe est également explicite. C'est la longueur totale du mot de passe après la création.

Contraintes

  • Pas d'entrée.
  • Un mot ne peut pas réapparaître dans le même mot de passe.
  • Aucun symbole ou nombre autorisé dans un mot de passe.
  • 4 mots par mot de passe, mais un minimum forcé de 4 lettres par mot.
  • Pas d'espaces entre les mots.
  • Vous ne pouvez pas générer le même mot de passe encore et encore.
  • Chaque mot doit être mis en majuscule dans un mot de passe.
  • La sortie doit être lisible par l'homme et doit être espacée. Doit également inclure l'intropie du mot de passe de Kuan du mot de passe en utilisant l'équation de l'intropie du mot de passe de Kuan ci-dessus.
  • Dictionnaire . Vous devez l’utiliser, le télécharger en tant que fichier texte et l’intégrer en conséquence. Ce sera la liste à partir de laquelle vous récupérerez des mots. Votre code devrait supposer qu'il est disponible.
  • C'est le , la plus courte victoire d'octets.

Sortie

TriedScarProgressPopulation 153.9
TryingPastOnesPutting 119.7
YearnGasesDeerGiven 108.3
DoubtFeetSomebodyCreature 142.5
LiquidSureDreamCatch 114.0
KuanHulio
la source
16
Pour les cas de test, pourquoi l' entropie du mot de passe varie-t-elle? Tous les mots de passe de 4 mots générés à partir du même dictionnaire doivent avoir la même entropie.
NonlinearFruit
20
L'entropie du mot de passe dépend du jeu de symboles. Si votre mot de passe est constitué des Nsymboles de l'ensemble S, l'entropie du mot de passe est log2(|S|)*N. Ici, la taille du jeu de symboles est la taille du dictionnaire ( |S|=4284) et le nombre de symboles est le nombre de mots ( N=4), donc l'entropie de chaque mot de passe est 48.3.
NonlinearFruit
48
Cette définition de l'entropie est dangereusement fausse! Si chaque caractère est choisi uniformément au hasard dans un ensemble de taille R, alors un mot de passe de longueur L a R ^ L de possibilités, de sorte que l'entropie est le log de celui-ci: log₂ (R ^ L) = log₂ (R) * L quelle est ta formule Cependant, si les mots de passe sont choisis au hasard dans un jeu différent (par exemple, vous ne disposerez jamais d'un mot de passe similaire 3t1ta#asd), l'entropie correspondra au logarithme du nombre de mots de passe possibles. Si vous choisissez toujours 4 mots de manière uniforme et aléatoire dans un dictionnaire de 4284 mots, il existe 4284 ^ 4 mots de passe, chacun avec une entropie log₂ (4284) * 4 ≈ 48.26.
ShreevatsaR
5
Pour mémoire, ce type de mots de passe est antérieur à la bande dessinée XKCD. On les appelle des mots de passe "diceware".
user2428118
5
Outre la question des mots ayant moins d'entropie que de caractères aléatoires, votre question demande que les mots soient en majuscule, ce qui signifie que la casse est fixe et ne peut pas être comptée pour l'entropie.
Niet the Dark Absol

Réponses:

13

Python 2, 102 101 97 91 octets

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

Suppose que le dictionnaire est une liste nommée f.

Peut être testé en enregistrant le fichier sous dict.txtet en appelant

f = open('dict.txt').readlines()
Martistes
la source
Les listes Python n’ont pas de méthode shuffle et vous pouvez enregistrer deux octets dans Python 2 en supprimant les parenthèses autour exec( execc’est un mot clé dans Python 2).
Konrad Borowski
@xfix Ouais, ça devrait l'être shuffle(f);.
Jonathan Allan
Oups, réparer ça dès que possible
Martmists
4
Vous pouvez utiliser mon astuce pour noter que l’arrondi à 5.7 convient très bien à une décimale, tant que les erreurs en virgule flottante ne sont pas introduites et que vous enregistrez cinq octets 57*len(x)/10.. Enregistrez un autre octet en supprimant les parenthèses pour que l’impression prenne un tuple. Voici une version réduite: TIO
Jonathan Allan
Utilisez sample(f,4)au lieu de shuffle. Aussi fpeut-être open('dict.txt').read().split('\n'), open('dict.txt').readlines()ou tout simplement open('dict.txt')(je sais que ce n'est pas encore , mais golfed).
Alex Hall
10

PowerShell (3.0+), 77 octets

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

Essayez-le en ligne!

En utilisant le truc de Jonathan Allan57*len/10 .

$dcontient le dictionnaire sous forme de tableau de mots. Si vous jouez à la maison et que vous voulez combler $d:

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

Utiliser une version golfée de (Get-Culture).TextInfo.ToTitleCase()pour capitaliser la première lettre; Je ne pense pas qu'il y ait un moyen plus court de faire cela dans PowerShell.

Le reste est assez simple, je pense.

Le lien TIO contient l’ensemble du dictionnaire; désactivez le cache et allez fou!

briantiste
la source
Quelqu'un peut-il m'indiquer une référence pour "Le tour de 57 * len / 10 de Jonathan Allan"?
James Curran
@JamesCurran Voir la répartition de sa réponse ici , ainsi que son commentaire sur cette réponse .
Briantist
Cela ne fonctionnera pas en 2.0 correctement. Cela devrait être noté dans le titre. Je pense aussi que vous devez interpréter $dcomme supposé supposer qu’il est présent dans l’environnement. (gc d)| random..où le dictionnaire est un fichier appelé d dans le même répertoire.
Matt
1
@ Matt sur SO, je ferais peut-être un travail de réponse avec v2 (ou 2 versions), mais c'est du code golf man! Le plus mystérieux le mieux ;-p
briantist
1
J'essaye juste de sauver des octets dans mes titres de réponse.
Matt
7

Gelée , 22 octets

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

Un lien monadique prenant une liste de caractères, le dictionnaire analysé (comme autorisé dans le chat ).

Essayez-le en ligne! (Cliquez sur "Arguments" pour masquer le dictionnaire et réduire le besoin de défilement.)

Comment?

Comme le dictionnaire ne contient que des mots valides ( 4caractères ou plus, uniquement [a-z]), il n’est pas nécessaire de vérifier cette condition.

Étant donné que tous les mots du dictionnaire ont une longueur, [4-8]les longueurs de mot de passe possibles sont [16,32]comprises et les entropies possibles ne seront jamais arrondies différemment à une décimale supérieure à celle du remplacement log(52,2)par 5.7. Le seul problème est que l' utilisation d' une valeur en virgule flottante 5.7donnera des erreurs d' arrondi en virgule flottante pour les longueurs 18, 26et 31. Cependant, multiplier par 57, puis diviser par 10utiliser ×57÷⁵permet d'éviter ce problème (tout en restant un octet plus court que l'impression de la valeur de précision de virgule flottante complète ×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)
Jonathan Allan
la source
5

Ruby, 89 83 octets

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

Suppose que les mots de passe sont stockés dans la variable d. Vous pouvez ajouter cette ligne avant le code:

d=$<.map(&:chomp)

et appelez le script par exemple comme ceci:

$ ruby generate_passwords.rb < dictionary_file.txt

Exemple de sortie:

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

KitchenMiseryLurkJoints ... wow.


-6 octets de Ajedi32

Daniero
la source
1
Peut-être en mesure de sauvegarder quelques octets en supprimant shuffle!et en remplaçant poppar sample.
Ajedi32
@ Ajedi32 Oh, tu as raison! J'y ai bien réfléchi, mais j'avais mal interprété cette règle A word cannot reappear in the same password, pensant que cela signifiait ne pas réutiliser les mots avec tous les mots de passe. Merci :)
daniero
4

Mathematica, 178 octets

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

Essayez-le en ligne

copier et coller en utilisant ctrl-v et appuyer sur Maj + Entrée pour exécuter


Mathematica, 136 octets

en supposant que m est le dictionnaire, le code est

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++]
J42161217
la source
"Le travail actuel consiste à créer 5 mots de passe en utilisant des mots." Besoin de 5 au lieu d'un.
KuanHulio
ok ... 5 mots de passe .. corrigé ..
J42161217
Pourquoi n'avez-vous pas mis le dictionnaire à disposition en local pour raccourcir le code en évitant le lien hypertexte?
sergiol
pour pouvoir le tester facilement ...
J42161217
Il est préférable de fournir un code d’aide simple et non golfé pour faciliter les tests, mais aussi moins pour la soumission de votre soumission afin qu’elle soit autonome. En outre, le dictionnaire est supposé être variable sans détourner le serveur DNS local (ni modifier le hostsfichier).
wizzwizz4
4

Bash ,66 65 octets

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

Essayez-le en ligne!

Le dictionnaire est recived par STDIN. Mélange tous les mots du dictionnaire et affiche les premiers 4.

Pour chaque mot, additionne sa longueur dans la variable et rappelle le mot en majuscule. En fin de compte, appelle BC pour faire le calcul.

Solution Awk, 112 octets, quatre mots de passe:

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}'
marcosme
la source
3

(Ceci est une adaptation de la réponse des martistes, mais je n'ai pas le représentant à commenter)

Python, 88 86 octets

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

En exploitant le caractère setnon déterministe, vous évitez d'importer des bibliothèques aléatoires.

dain
la source
Cela produit systématiquement le même résultat pour moi. Si cela fonctionne avec certaines implémentations, vous pouvez économiser quelques octets en faisant set(f).pop().
Jonathan Allan
1
Je ne pense pas que ce soit vraiment valable. Ce n'est pas déterministe, il n'est donc pas garanti de produire le même mot de passe, mais dans la pratique, cela donnera rarement des résultats différents.
DJMcMayhem
Je soupçonnais que cela pouvait dépendre de la mise en œuvre. Je l'ai fait sur une version Windows récemment installée d'Anaconda Python 3, et cela a fonctionné. Cependant, set(f).pop()cela ne fonctionne pas, je l'ai essayé. Cela donne le même résultat à chaque fois.
Dain
"Dans la pratique, il sera rarement possible d'obtenir des résultats différents" - il me semble en voici un exemple: pastebin.com/raw/ZHiHgzxV
dain
@dain je suis curieux. Veuillez fournir des informations sur votre version de Python.
wizzwizz4
3

Japt , 30 octets

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

Essayez-le en ligne!

Luke
la source
Agréable! Mais malheureusement, il crée le même mot de passe 5 fois, et il devrait être différent à chaque fois.
Iain Ward
Cela peut être 30 caractères, mais au moins en UTF-8, mon système le calcule à 35 octets.
un CVn
1
@ MichaelKjörling Japt utilise ISO 8859-1, pas UTF-8.
Dennis
@ Dennis Intéressant. Merci.
un CVn
3

JavaScript (ES6), 164 octets

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

Suppose que le dictionnaire est passé à la fonction en tant que tableau.

Test Snippet

Justin Mariner
la source
2

Mathematica, 71 octets

En supposant que le dictionnaire est déjà chargé dans un tableau appelé d.

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

Explication:

                                        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.
Ian Miller
la source
Qu'en est-il du nombre d'entropie?!
Jonathan Allan
Oups a manqué ce bit. Mis à jour.
Ian Miller
2

ColdFusion 216 octets

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

Cela fonctionne dans ColdFusion 11+ et Lucee 4.5+

Pour l'exécuter: https://trycf.com/gist/ff14e2b27d66f28ff69ab90365361b12/acf11?theme=monokai

Le lien TryCF a moins de golf, mais le même code.

Je ne m'attendais pas vraiment à avoir une réponse compétitive au golf; Je voulais juste voir ce qu'il faudrait faire pour relever ce défi dans ColdFusion. Surtout qu'il n'y a pas beaucoup de FC dans ces réponses. :-) Après l'installation, c'était étonnamment plus court que prévu.

Ma première tentative a été un peu plus courte jusqu'à ce que je me souvienne que le même mot ne peut pas être utilisé plus d'une fois. Même s'il est très improbable que le randomiseur sélectionne le même index plusieurs fois, je dépose les index dans les clés d'une structure, ce qui évite les doublons. Ensuite, j'utilise cette liste de clés pour construire ma chaîne de mot de passe finale. J'ai aussi utilisé le truc mathématique pour trouver l'entropie.

Shawn
la source
2

PHP , 136 129 octets

-7 octets, merci 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)."
";}

Essayez-le en ligne!

MOI
la source
@ JörgHülsermann Cela semble fonctionner, merci.
ME
2

Python 3, 252 octets

C’est mon tout premier défi de golf de code que j’ai fait! Je sais qu'il existe d'autres réponses Python ici (qui sont probablement meilleures que les miennes), mais cela avait l'air amusant, et je voulais donc l'essayer de toute façon. Voici la version golfée:

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

Je posterais un Essayez-le en ligne! lien, mais cela ne supporte pas plusieurs fichiers. Alors, voici un lien de repl.it: https://repl.it/InIl/0

En outre, voici la version sans 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)))

Comme je l’ai dit, c’est ma première fois dans le code gofling, alors je suis sûr que cela pourrait être beaucoup amélioré.

ATMunn
la source
Bienvenue chez PPCG!
Taylor Scott
2

tcl, 137

Pas un gagnant à coup sûr, mais je pense que ça peut être un peu plus joué au 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 - Le but de la ligne 1 est seulement de mettre le contenu du dictionnaire dans la variabled

sergiol
la source
Vous pourriez probablement
jouer au
Et vous avez demandé 5 mots de passe au lieu de 4. LOL! J'ai mal assorti les nombres!
sergiol
Hahaha! @sergiol
KuanHulio
Fixé! @KuanHulio
sergiol
C'est mieux. Bon travail.
KuanHulio
0

Vim, 87 frappes

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

Suppose que le dictionnaire est dans un fichier nommé w. Utilisera toujours 4 mots consécutifs

Explication:

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
BlackCap
la source
0

q / kdb +, 76 74 65 56 octets

Solution:

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

Exemple:

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

Explication:

Lire dans la liste de mots, se séparer de "", choisir 4 mots au hasard dans cette liste, mettre la première lettre en majuscule de chaque mot, puis se joindre. Introduisez ceci dans une fonction lambda qui renvoie le mot de passe et l’entropie calculée:

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

Remarques:

J'ai cédé et utilisé 5.70044 au lieu de 2 xlog 52 xexp...

streetster
la source