Gerador de Senhas XKCD


34

Introdução

Aparentemente, esta pergunta foi feita aqui e, infelizmente, foi encerrada. Eu pensei que era uma boa idéia tentar novamente com ele, mas feito da maneira certa.

O XKCD analisa como somos treinados para usar senhas "difíceis de lembrar", pensando que é seguro, mas, em vez disso, levaria um computador três dias para ser descoberto. Por outro lado, lembrar de 4 a 5 palavras traz a Intranet da Senha do Kuan e é fácil de lembrar. Louco como isso funciona, hein?

Desafio

O trabalho hoje é criar 5 senhas usando palavras. 4 palavras por senha e no mínimo 4 letras por palavra, mas não máximo. A Intropy de senha de Kuan precisará ser calculada para cada senha, mas um mínimo forçado não será definido.

O que é a intropia de senha do Kuan?

A Intropy de senha da Kuan é uma medida de quão imprevisível é uma senha, de acordo com Kuan. Não é um cálculo simples: E = log 2 (R) * L . Sendo a Intropy da senha de Kuan, R sendo o intervalo de caracteres disponíveis e L para o comprimento da senha.

O intervalo de caracteres disponíveis é auto-explicativo. É o intervalo de caracteres que uma senha pode ter, nesse caso, maiúscula e minúscula. Como há 26 caracteres no alfabeto, 26 x 2 = 52 caracteres em todo o intervalo da senha.

O comprimento da senha também é auto-explicativo. É o tamanho total da senha após a criação.

Restrições

  • Sem entrada.
  • Uma palavra não pode reaparecer na mesma senha.
  • Não são permitidos símbolos ou números em uma senha.
  • 4 palavras por senha, mas um mínimo forçado de 4 letras por palavra.
  • Não há espaços entre as palavras.
  • Você não pode gerar a mesma senha repetidamente.
  • Cada palavra deve ser maiúscula em uma senha.
  • A saída deve ser legível por humanos, deve ser espaçada. Também deve incluir a senha Intropy da senha de Kuan usando-a usando a equação Password Intropy da senha de Kuan acima.
  • Dicionário . Você deve usar isso, fazer o download como um arquivo de texto e integrar de acordo. Esta será a lista da qual você extrai palavras. Seu código deve assumir que está disponível.
  • Isso é , os bytes mais curtos vencem.

Saída

TriedScarProgressPopulation 153.9
TryingPastOnesPutting 119.7
YearnGasesDeerGiven 108.3
DoubtFeetSomebodyCreature 142.5
LiquidSureDreamCatch 114.0

16
Para os casos de teste, por que a entropia da senha está variando? Todas as senhas de quatro palavras geradas no mesmo dicionário devem ter a mesma entropia.
NonlinearFruit

20
A entropia da senha depende do conjunto de símbolos. Se sua senha for um Nsímbolo do conjunto S, a entropia da senha é log2(|S|)*N. Aqui, o tamanho do conjunto de símbolos é o tamanho do dicionário ( |S|=4284) e o número de símbolos é o número de palavras ( N=4), portanto, a entropia para cada senha é 48.3.
NonlinearFruit

48
Esta definição de entropia está perigosamente errada! Se cada caractere é escolhido uniformemente aleatoriamente a partir de um conjunto de tamanho R, então uma senha de tamanho L tem possibilidades de R ^ L, de modo que a entropia é o log disso: log₂ (R ^ L) = log₂ (R) * L qual é a sua fórmula No entanto, se as senhas forem escolhidas aleatoriamente em um conjunto diferente (por exemplo, você nunca terá uma senha parecida 3t1ta#asd), a entropia será o logaritmo do número de senhas possíveis. Se você sempre escolher 4 palavras uniformemente aleatoriamente em um dicionário de 4284 palavras, haverá 4284 ^ 4 senhas, cada uma com log de entropia₂ (4284) * 4 × 48.26.
ShreevatsaR

5
Para constar, esse tipo de senha é anterior à história em quadrinhos do XKCD. Eles são chamados de senhas "diceware".
User2428118

5
Além da questão de palavras com menos entropia do que caracteres aleatórios, sua pergunta exige que as palavras sejam maiúsculas, o que significa que o caso está resolvido e não pode ser contado para entropia.
Niet the Dark Absol

Respostas:


13

Python 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

Assume o dicionário como uma lista chamada f.

Pode ser testado salvando o arquivo como dict.txte chamando

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

As listas Python não têm o método shuffle, e você pode salvar dois bytes no Python 2 removendo parênteses exec( execé uma palavra-chave no Python 2).
Konrad Borowski 25/05

@xfix Sim, deveria ser shuffle(f);.
Jonathan Allan

Whoops, fixando que o mais cedo possível
Martmists

4
Você pode usar o meu truque para observar que o arredondamento em 5,7 é bom para 1 casa decimal, desde que não sejam introduzidos erros de ponto flutuante e salve cinco bytes com 57*len(x)/10.. Salve outro byte removendo os parênteses, fazendo a impressão ter uma tupla. Aqui está uma versão resumida: TIO
Jonathan Allan

Use em sample(f,4)vez de shuffle. Também fpode ser apenas open('dict.txt').read().split('\n'), open('dict.txt').readlines()ou apenas open('dict.txt')(eu sei que não é golfed, mas ainda).
Alex Hall

10

PowerShell (3.0 ou superior), 77 bytes

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

Experimente online!

Usando Jonathan Allan s'57*len/10 truque de .

$dcontém o dicionário como uma matriz de palavras. Se você estiver jogando em casa e quiser preencher $d:

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

Usando uma versão em golfe de (Get-Culture).TextInfo.ToTitleCase()para colocar em maiúscula a primeira letra; Não acho que exista uma maneira mais curta de fazer isso no PowerShell.

O resto é bem direto, eu acho.

O link TIO possui o dicionário inteiro; desativar o cache e enlouquecer!


Alguém pode me indicar uma referência para o "truque de 57 * len / 10 de Jonathan Allan"?
James Curran

@JamesCurran Veja a descrição de sua resposta aqui e também seu comentário sobre esta resposta .
Briantist 26/05

Isso não funcionará no 2.0 correto. Isso deve ser observado no título. Também acho que você precisa ler $dcomo deveria assumir que está presente no ambiente. (gc d)| random..onde o dicionário é um arquivo chamado d no mesmo diretório.
26517 Matt

1
@ Matt no SO, eu poderia sair do meu caminho para fazer uma resposta funcionar com a v2 (ou fazer 2 versões), mas este é o código golf man! Quanto mais misterioso, melhor
;-p

1
Estou apenas tentando salvar bytes nos meus títulos de resposta.
26517 Matt

7

Gelatina , 22 bytes

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

Um link monádico que lista uma lista de caracteres, o dicionário analisado (conforme permitido no bate-papo ).

Experimente online! (Clique em "Argumentos" para ocultar o dicionário e reduzir a necessidade de rolar.)

Quão?

Como o dicionário contém apenas palavras válidas ( 4caracteres ou mais, apenas[a-z] ), não é necessário verificar esta condição.

Como todas as palavras do dicionário têm comprimentos nos [4-8]possíveis comprimentos de senha [16,32], as possíveis entropias nunca serão arredondadas de maneira diferente para uma casa decimal do que substituindo log(52,2)por 5.7. O único problema é que a utilização de um valor de ponto flutuante de 5.7vai dar ponto flutuante erros de arredondamento para comprimentos 18, 26e 31. No entanto multiplicando por 57e , em seguida, dividindo por 10usando ×57÷⁵evita este (enquanto ainda está sendo um byte menor do que a impressão do valor integral de ponto flutuante de precisão 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}

Assume que as senhas são armazenadas na variável d. Você pode adicionar esta linha antes do código:

d=$<.map(&:chomp)

e chame o script, por exemplo:

$ ruby generate_passwords.rb < dictionary_file.txt

Saída de amostra:

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

KitchenMiseryLurkJuntas ... uau.


-6 bytes de Ajedi32


1
Pode salvar alguns bytes removendo shuffle!e substituindo poppor sample.
Ajedi32

@ Ajedi32 Oh, você está certo! Na verdade, pensei sobre isso, mas havia interpretado mal essa regra A word cannot reappear in the same password, pensando que não significava reutilização de palavras em todas as senhas. Obrigado :)
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++]

Experimente online

copie e cole usando ctrl-ve pressione Shift + Enter para executar


Mathematica, 136 bytes

assumindo que m é o dicionário, o código é

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

"O trabalho hoje é criar 5 senhas usando palavras." Precisa de 5 em vez de uma.
KuanHulio

ok ... 5 senhas .. fixo ..
J42161217

Por que você não disponibilizou o dicionário local para encurtar o código, evitando o texto do hiperlink?
Sergiol # 25/17

a fim de ser fácil para você para testá-lo ...
J42161217

É melhor fornecer um código auxiliar simples e simples para facilitar o teste, do que reduzir menos a submissão para que ela seja independente. Além disso, o dicionário deve ser variável sem seqüestrar o servidor DNS local (ou modificar o hostsarquivo).
Wizzwizz4 25/05

4

Bater ,66. 65 bytes

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

Experimente online!

O dicionário é recebido pelo STDIN. Mistura todas as palavras no dicionário e emite primeiro 4.

Para cada palavra, soma seu comprimento em var l e ecoa a palavra em maiúscula. No final, chama bc para fazer as contas.

Solução Awk, 112 bytes, quatro senhas:

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 é uma adaptação da resposta dos marmistas, mas não tenho o 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)

Ao explorar como setnão é determinístico, você pode evitar a importação de qualquer biblioteca de aleatoriedade.


Isso sempre produz a mesma saída para mim. Se funcionar em alguma implementação, você poderá salvar alguns bytes fazendo isso set(f).pop().
Jonathan Allan

1
Eu não acho que isso seja realmente válido. Não é determinístico; portanto, não é garantido que você produza a mesma senha, mas, na prática, raramente criará resultados diferentes.
DJMcMayhem

Eu suspeitava que pudesse ser dependente da implementação. Fiz isso em uma versão do Windows recém-instalada do Anaconda Python 3 e funcionou. No entanto set(f).pop(), não funciona, eu tentei. Dá o mesmo resultado cada vez.
dain 25/05

"Na prática, raramente cria resultados diferentes" - parece-me, aqui está um exemplo: pastebin.com/raw/ZHiHgzxV
dain

@ Dain Estou curioso. Forneça informações sobre sua compilação Python.
Wizzwizz4 25/05

3

Japonês , 30 bytes

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

Experimente online!


Agradável! Mas, infelizmente, cria a mesma senha 5 vezes, e ele deve ser diferente a cada vez ..
Iain Ward

Pode ter 30 caracteres, mas pelo menos em UTF-8, meu sistema apresenta um clock de 35 bytes.
um CVn

1
@ MichaelKjörling Japt usa ISO 8859-1, não UTF-8.
Dennis

@Dennis Interessante. Obrigado.
um 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))}

Assume que o dicionário é passado para a função como uma matriz.

Snippet de teste


2

Mathematica, 71 bytes

Supondo que o dicionário já esteja carregado em uma matriz chamada d.

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

Explicação:

                                        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 o número da entropia ?!
Jonathan Allan

Opa perdeu essa parte. Atualizada.
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})}

Isso funciona no ColdFusion 11+ e no Lucee 4.5+

Para executá-lo: https://trycf.com/gist/ff14e2b27d66f28ff69ab90365361b12/acf11?theme=monokai

O link TryCF possui menos golf-ish, mas o mesmo código.

Eu realmente não esperava ter uma resposta competitiva no golfe; Eu só queria ver o que seria necessário para concluir esse desafio no ColdFusion. Especialmente porque não há muita CF nessas respostas. :-) Após a instalação, foi surpreendentemente mais curto do que eu esperava.

Minha primeira tentativa foi um pouco mais curta até lembrar que a mesma palavra não pode ser usada mais de uma vez. Embora seja altamente improvável que o randomizador escolha o mesmo índice mais de uma vez, despejo os índices nas chaves de uma estrutura, o que impedirá a duplicação. Então eu uso essa lista de chaves para criar minha string de senha final. Eu também usei o truque de matemática para encontrar entropia.


2

PHP , 136 129 bytes

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

Experimente online!


@ JörgHülsermann Isso parece funcionar, obrigado.
ME

2

Python 3, 252 bytes

Este é o meu primeiro desafio de golfe de código que eu já fiz! Eu sei que existem outras respostas em Python aqui (que provavelmente são melhores que as minhas), mas isso parecia divertido, e então eu queria tentar de qualquer maneira. Aqui está a versão do golfe:

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

Eu publicaria um Experimente Online! link, mas isso não suporta vários arquivos. Então, aqui está um link repl.it: https://repl.it/InIl/0

Além disso, aqui está a versão não destruída:

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 eu disse, esta é minha primeira vez em busca de códigos, então eu tenho certeza que isso poderia melhorar muito.


Bem-vindo ao PPCG!
Taylor Scott

2

tcl, 137

Não é um vencedor, com certeza, mas acho que pode ser um pouco mais golfe.

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 - O objetivo da linha 1 é apenas colocar o conteúdo do dicionário na variáveld


Provavelmente, você pode jogar com
calma

E você pediu 5 senhas em vez de 4. LOL! Eu não correspondi os números!
sergiol 25/05

Hahaha! @sergiol
KuanHulio

Fixo! @KuanHulio
sergiol

Isso é melhor. Bom trabalho.
KuanHulio

0

Vim, 87 pressionamentos 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

Supõe que o dicionário esteja em um arquivo chamado w. Sempre usará 4 palavras consecutivas

Explicação:

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

Solução:

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

Exemplo:

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

Explicação:

Leia na lista de palavras, separe "", escolha 4 palavras aleatórias nessa lista, maiúscula a primeira letra de cada palavra e junte-se. Alimente isso em uma função lambda que retorna a senha e a 'entropia' 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:

Eu cedi e usei 5.70044 em vez de 2 xlog 52 xexp...

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.