XKCD 비밀번호 생성기


34

소개

분명히이 질문은 여기 에서 요청되었으며 불행히도 닫힙니다. 나는 그것을 다시 시도하는 것이 좋은 생각이라고 생각했지만 올바르게했습니다.

XKCD 는 "암호를 기억하기 어렵다"를 사용하도록 훈련 된 방법을 살펴보고, 보안이 안전하다고 생각하지만 컴퓨터를 해독하는 데 3 일이 소요됩니다. 반대로 4-5 단어를 기억하면 Kuan의 암호 ​​인트로 피가 나타나고 기억하기 쉽습니다. 어떻게 작동하는지 미쳤습니까?

도전

오늘해야 할 일은 단어를 사용하여 5 개의 암호를 만드는 것입니다. 암호 당 4 단어, 단어 당 최소 4 글자이지만 최대 값은 없습니다. Kuan의 비밀번호 인트로 피는 모든 비밀번호에 대해 계산해야하지만 강제 최소값은 설정되지 않습니다.

Kuan의 비밀번호 인트로 피란 무엇입니까?

Kuan의 비밀번호 인트로 피는 비밀번호가 얼마나 예측할 수 없는지 측정 한 결과입니다. 간단한 계산이있다 : E는 로그 = 2 * L (R)를 . E는 Kuan 's Password Intropy이며 R은 사용 가능한 문자 범위이며 L은 암호 길이입니다.

사용 가능한 문자 범위는 자명합니다. 암호가 가질 수있는 문자 범위이며,이 경우 대문자와 소문자입니다. 알파벳에는 26자가 있으므로 암호의 전체 범위에 26 x 2 = 52자가 있습니다.

암호 길이도 설명이 필요합니다. 생성 후 비밀번호의 총 길이입니다.

제약

  • 입력이 없습니다.
  • 같은 비밀번호로 단어 를 다시 표시 할 수 없습니다 .
  • 비밀번호에는 기호 나 숫자를 사용할 수 없습니다.
  • 암호 당 4 단어이지만 단어 당 4 자 이상이어야합니다.
  • 단어 사이에 공백이 없습니다.
  • 동일한 비밀번호를 반복해서 생성 할 수 없습니다.
  • 각 단어는 비밀번호로 대문자로 입력해야합니다.
  • 출력은 사람이 읽을 수 있어야하며 간격을 두어야합니다. 또한 위의 Kuan의 비밀번호 인트로 피 방정식을 사용하여 비밀번호의 Kuan의 비밀번호 인트로 피를 비밀번호와 함께 포함해야합니다.
  • 사전 . 이 파일을 사용하고 텍스트 파일로 다운로드하여 적절히 통합해야합니다. 이것은 당신이 단어를 얻는 목록이 될 것입니다. 코드는 사용 가능한 것으로 가정해야합니다.
  • 이것은 이며 가장 짧은 바이트가 이깁니다.

산출

TriedScarProgressPopulation 153.9
TryingPastOnesPutting 119.7
YearnGasesDeerGiven 108.3
DoubtFeetSomebodyCreature 142.5
LiquidSureDreamCatch 114.0

16
테스트 사례에서 비밀번호 엔트로피 가 왜 다른가요? 동일한 사전에서 생성 된 4 개의 단어 비밀번호는 모두 동일한 엔트로피를 가져야합니다.
NonlinearFruit

20
비밀번호 엔트로피는 심볼 세트에 따라 다릅니다. 암호가 N세트의 기호 S인 경우 암호 엔트로피는 log2(|S|)*N입니다. 여기에서 기호 세트의 크기는 사전 크기 ( |S|=4284)이고 기호 수는 단어 수 ( N=4)이므로 각 암호의 엔트로피는 48.3입니다.
NonlinearFruit

48
엔트로피의 이러한 정의는 위험합니다! 각 문자가 일련의 크기 R에서 무작위로 균일하게 선택되면 실제로 길이 L 암호는 R ^ L 가능성을 가지므로 엔트로피는 그 로그입니다. log₂ (R ^ L) = log₂ (R) * L 이것이 당신의 공식입니다. 그러나 비밀번호를 다른 세트에서 임의로 선택하면 (예 :와 같은 비밀번호를 사용하지 않음 3t1ta#asd) 엔트로피는 가능한 비밀번호 수의 로그입니다. 4284 단어 사전에서 항상 4 개의 단어를 무작위로 균일하게 선택하면 각각 엔트로피 로그 ₂ (4284) * 4 ≈ 48.26 인 4284 ^ 4 개의 비밀번호가 있습니다.
ShreevatsaR

5
기록을 위해, 이런 종류의 암호는 XKCD 만화 이전의 것입니다. 이것을 "다이스웨어"암호라고합니다.
user2428118

5
임의의 문자보다 엔트로피가 적은 단어 문제 외에도 질문에 대문자를 사용해야하므로 대소 문자가 고정되어 엔트로피로 계산할 수 없습니다.
어둠의 절대자 니트

답변:


13

파이썬 2 102 101 97 91 바이트

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

사전을이라는 목록으로 가정합니다 f.

파일을 다른 이름으로 저장 dict.txt하고 호출 하여 테스트 가능

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

파이썬 목록에는 셔플 방법이 없으며 괄호를 제거하여 파이썬 2에서 2 바이트를 절약 할 수 있습니다 exec( exec파이썬 2의 키워드입니다).
Konrad Borowski

@xfix 그래 그래야한다 shuffle(f);.
Jonathan Allan

으악, 최대한 빨리 해결
Martmists

4
부동 소수점 오류가 발생하지 않고 5.7에서 반올림이 소수점 이하 1 자리까지 올랐다는 것을 지적하는 내 트릭을 사용할 수 있습니다 57*len(x)/10.. 괄호를 제거하여 튜플을 인쇄하여 다른 바이트를 저장하십시오. 컷 다운 버전은 다음과 같습니다. TIO
Jonathan Allan

sample(f,4)대신에 사용하십시오 shuffle. 또한 f단지 일 수있다 open('dict.txt').read().split('\n'), open('dict.txt').readlines()또는 단지 open('dict.txt')(나는 아직도 golfed 아니에요 알고 있지만).
Alex Hall

10

PowerShell (3.0+), 77 바이트

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

온라인으로 사용해보십시오!

사용 조나단 앨런57*len/10트릭을.

$d사전을 단어의 배열로 포함합니다. 집에서 놀고 있고 채우고 싶다면 $d:

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

의 골프 버전을 사용 (Get-Culture).TextInfo.ToTitleCase()하여 첫 글자를 대문자로; PowerShell에서 더 짧은 방법이 있다고 생각하지 않습니다.

나머지는 매우 간단하다고 생각합니다.

TIO 링크에는 전체 사전이 있습니다. 캐시를 비활성화하고 문제를 해결하십시오!


누군가 "Jonathan Allan 's 57 * len / 10 trick"에 대한 참조를 알려줄 수 있습니까?
James Curran

@JamesCurran 여기에 대한 답변의 분석 과이 답변 에 대한 의견을 참조 하십시오 .
briantist

2.0에서는 제대로 작동하지 않습니다. 제목에 언급해야합니다. 또한 $d환경에 있다고 가정하고 읽어야한다고 생각 합니다. (gc d)| random..여기서 사전은 동일한 디렉토리에있는 d라는 파일입니다.
Matt

1
@Matt on 그래서 나는 v2 (또는 2 가지 버전)로 답변을하기 위해 나아갈 수 있지만 이것은 코드 골프 맨입니다! 더 비전이 좋을수록
;-p

1
답변 제목에 바이트를 저장하려고합니다.
Matt

7

젤리 , 22 바이트

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

문자 목록, 구문 분석 된 사전 ( chat에서 허용됨)을 가져 오는 모나드 링크 .

온라인으로 사용해보십시오! 사전을 숨기고 스크롤 필요성을 줄이려면 "인수"를 클릭하십시오.

어떻게?

사전에는 유효한 단어 ( 4문자 이상) 만 포함되므로이 [a-z]조건을 확인할 필요가 없습니다.

사전의 모든 단어 [4-8]는 가능한 암호 길이의 길이를 [16,32]가지므로 가능한 엔트로피는로 대체 log(52,2)하는 것보다 소수점 이하 한 자리로 반올림되지 않습니다 5.7. 유일한 문제는의 부동 소수점 값을 사용하는 것입니다 5.7길이에 대한 반올림 오류 부동 소수점을 줄 것이다 18, 26하고 31. 그러나 곱한 57하고 다음 에 의해 나누어 10사용 ×57÷⁵을 피를이 (여전히 사용 전체 정밀도 부동 소수점 값을 인쇄 바이트보다 짧게하면서 ×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

루비, 89 83 바이트

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

암호가 변수에 저장되어 있다고 가정합니다 d. 코드 앞에 다음 줄을 추가 할 수 있습니다.

d=$<.map(&:chomp)

예를 들어 다음과 같이 스크립트를 호출하십시오.

$ ruby generate_passwords.rb < dictionary_file.txt

샘플 출력 :

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

KitchenMiseryLurkJoints ... 와우.


Ajedi32에서 -6 바이트


1
제거하여 몇 바이트를 저장할 수 있습니다 shuffle!및 교체 pop와 함께 sample.
Ajedi32

@ Ajedi32 아, 맞아! 나는 실제로 그것에 대해 생각했지만이 규칙을 잘못 읽었으며 모든 암호 A word cannot reappear in the same password에서 단어를 재사용하지 않는다고 생각했습니다 . 감사합니다 :)
daniero

4

Mathematica, 178 바이트

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

온라인으로 사용해보십시오

ctrl-v를 사용하여 복사하여 붙여 넣고 Shift + Enter를 눌러 실행하십시오.


수학, 136 바이트

m이 코드 사전 인 것으로 가정

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

"오늘의 일은 단어를 사용하여 5 개의 암호를 만드는 것입니다."대신 5가 필요합니다.
KuanHulio 17 년

ok ... 5 개의 비밀번호 .. 고정 ..
J42161217

하이퍼 링크 텍스트를 피하여 코드를 줄이기 위해 사전을 로컬로 사용할 수없는 이유는 무엇입니까?
sergiol

당신이 그것을 쉽게 테스트하기 위해 ...
J42161217

자체 포함되도록 제출물을 덜 골프화하는 것보다 테스트를 쉽게 할 수 있도록 단순하고 골치 아픈 도우미 코드를 제공하는 것이 가장 좋습니다. 또한 사전은 로컬 DNS 서버를 하이재킹하거나 hosts파일을 수정하지 않고 가변적이어야합니다 .
wizzwizz4

4

배쉬 ,66 65 바이트

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

온라인으로 사용해보십시오!

STDIN이 사전을받습니다. 사전의 모든 단어를 섞고 먼저 4를 출력합니다.

각 단어에 대해 길이를 var l로 더하고 대문자로 된 단어를 에코합니다. 결국 bc를 호출하여 수학을 수행합니다.

Awk 솔루션, 112 바이트, 4 개의 비밀번호 :

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

(이것은 Martmists의 답변에 대한 적응이지만 의견을 말할 담당자는 없습니다.)

파이썬, 88 86 바이트

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

set비 결정적 방법을 활용 하면 임의성 라이브러리를 가져 오지 않아도됩니다.


이것은 지속적으로 나에게 동일한 출력을 생성합니다. 일부 구현에서 작동하면을 수행하여 몇 바이트를 절약 할 수 set(f).pop()있습니다.
Jonathan Allan

1
나는 이것이 실제로 유효하다고 생각하지 않습니다. 결정적이지 않으므로 동일한 암호를 생성한다고 보장되지는 않지만 실제로는 다른 결과를 생성하지 않습니다.
DJMcMayhem

구현에 따라 다를 것으로 의심됩니다. Anaconda Python 3의 새로 설치된 Windows 릴리스 에서이 작업을 수행했습니다. 그러나 set(f).pop()작동하지 않아 시도했습니다. 매번 동일한 결과를 제공합니다.
다인

"실제로 다른 결과를 생성하는 경우는 거의 없습니다."– 다음은 샘플입니다. pastebin.com/raw/ZHiHgzxV
dain

@dain 궁금합니다. Python 빌드에 대한 정보를 제공하십시오.
wizzwizz4

3

Japt , 30 바이트

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

온라인으로 사용해보십시오!


좋은! 그러나 불행히도 동일한 비밀번호를 5 번 작성하며 매번 달라야합니다.
Iain Ward

이것은 30 자일 수 있지만 적어도 UTF-8에서는 시스템이 35 바이트로 클럭합니다.
CVn

1
@ MichaelKjörling Japt는 UTF-8이 아닌 ISO 8859-1을 사용합니다.
Dennis

@Dennis 재미있는. 고맙습니다.
CVn

3

자바 스크립트 (ES6), 164 바이트

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

사전이 배열로 함수에 전달되었다고 가정합니다.

테스트 스 니펫


2

매스 매 티카, 71 바이트

사전이 이미라는 배열에로드되었다고 가정합니다 d.

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

설명 :

                                        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.

엔트로피 숫자는 어떻습니까?!
Jonathan Allan

죄송합니다. 업데이트되었습니다.
Ian Miller

2

ColdFusion 216 바이트

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

ColdFusion 11 이상 및 Lucee 4.5 이상에서 작동

이를 실행하려면 다음을 수행하십시오. https://trycf.com/gist/ff14e2b27d66f28ff69ab90365361b12/acf11?theme=monokai

TryCF 링크는 덜 골프지만 코드는 동일합니다.

나는 경쟁적인 골프 답변을 기대하지 않았다. ColdFusion에서이 과제를 완료하는 데 무엇이 필요한지 확인하고 싶었습니다. 특히이 답변에 CF가 많지 않기 때문에. :-) 설정 후 예상보다 짧았습니다.

첫 번째 시도는 같은 단어를 두 번 이상 사용할 수 없다는 것을 기억할 때까지 조금 짧았습니다. randomizer가 동일한 인덱스를 두 번 이상 선택할 가능성은 거의 없지만 인덱스를 구조의 키에 덤프하여 중복을 방지합니다. 그런 다음 해당 키 목록을 사용하여 최종 비밀번호 문자열을 작성합니다. 또한 수학 트릭을 사용하여 엔트로피를 찾았습니다.



2

파이썬 3, 252 바이트

이것은 내가 한 최초의 코드 골프 도전입니다! 나는 여기에 다른 파이썬 답변이 있다는 것을 알고 있지만 (아마도 나보다 낫습니다) 재미있게 보였으므로 어쨌든 시도하고 싶었습니다. 골프 버전은 다음과 같습니다.

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

온라인으로 사용해보십시오! 링크하지만 여러 파일을 지원하지 않습니다. 다음은 repl.it 링크입니다 : https://repl.it/InIl/0

또한 다음은 ungolfed 버전입니다.

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

내가 말했듯이, 이것은 첫 번째 코드 고플 링이므로 이것이 많이 향상 될 것이라고 확신합니다.


PPCG에 오신 것을 환영합니다!
Taylor Scott

2

tcl, 137

확실히 승자는 아니지만, 조금 더 골프를 칠 수 있다고 생각합니다.

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 — 1 행은 사전 내용을 변수에 넣는 것입니다d


암호 대신 5 단어 대신 4 단어가 필요하기 때문에 골프를
밟을 수 있습니다

그리고 당신은 4 대신에 5 개의 암호를 요구했습니다. LOL! 숫자가 일치하지 않습니다!
sergiol

하하하! @sergiol
KuanHulio

결정된! @KuanHulio
sergiol

그게 낫다. 좋은 작업.
KuanHulio

0

Vim, 87 번의 키 스트로크

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

사전이라는 파일에 있다고 가정합니다 w. 항상 4 개의 연속 단어를 사용합니다

.

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 바이트

해결책:

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

예:

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

설명:

단어 목록을 읽고 ""를 분리 한 다음이 목록에서 임의의 단어 4 개를 선택하고 각 단어의 첫 글자를 대문자로 한 다음 함께 결합하십시오. 이것을 암호와 계산 된 '엔트로피'를 반환하는 람다 함수에 입력하십시오.

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

노트:

나는 대신에 5.70044를 사용하고 사용했습니다 2 xlog 52 xexp...

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.