XKCD Password Generator

34

pengantar

Rupanya, pertanyaan ini telah ditanyakan di sini dan sayangnya ditutup. Saya pikir itu ide yang bagus untuk mencoba lagi dengannya, tetapi dilakukan dengan benar.

XKCD melihat bagaimana kita dilatih untuk menggunakan "kata sandi yang sulit untuk diingat", berpikir itu aman, tetapi sebaliknya, akan membutuhkan komputer 3 hari untuk retak. Di sisi lain, mengingat 4-5 kata-kata akan meningkatkan Kata Sandi Kuan, dan mudah diingat. Gila cara kerjanya, ya?

Tantangan

Pekerjaan hari ini adalah membuat 5 kata sandi menggunakan kata-kata. 4 kata per kata sandi dan minimal 4 huruf per kata, tetapi tidak maksimal. Kata sandi Kuan akan perlu dihitung untuk setiap kata sandi, tetapi minimum yang dipaksakan tidak akan ditetapkan.

Apakah Intropi Kata Sandi Kuan?

Kuan's Password Intropy adalah ukuran seberapa tidak terduga suatu kata sandi, menurut Kuan. Ada perhitungan sederhana: E = log 2 (R) * L . E menjadi Kuan's Password Intropy, R menjadi rentang karakter yang tersedia dan L untuk panjang kata sandi.

Rentang karakter yang tersedia cukup jelas. Rentang karakter yang dapat dimiliki kata sandi, dalam hal ini huruf besar dan kecil. Karena ada 26 karakter dalam alfabet, 26 x 2 = 52 karakter di seluruh rentang kata sandi.

Panjang kata sandi juga cukup jelas. Panjang total kata sandi setelah pembuatan.

Kendala

  • Tidak ada input
  • Sebuah kata tidak dapat muncul kembali dengan kata sandi yang sama.
  • Tidak ada simbol atau angka yang diizinkan dalam kata sandi.
  • 4 kata per kata sandi, tetapi dipaksa minimal 4 huruf per kata.
  • Tidak ada spasi di antara kata-kata.
  • Anda tidak dapat membuat kata sandi yang sama berulang kali.
  • Setiap kata harus dikapitalisasi dengan kata sandi.
  • Keluaran harus dapat dibaca oleh manusia, harus diberi spasi. Harus juga menyertakan Kata Sandi Intropi kata sandi Kuan dengan menggunakan persamaan Intropi Kata Kuan di atas.
  • Kamus . Anda harus menggunakan ini, mengunduhnya sebagai file teks dan mengintegrasikannya. Ini akan menjadi daftar dari mana Anda mengambil kata-kata. Kode Anda harus mengasumsikan tersedia.
  • Ini adalah , byte terpendek menang.

Keluaran

TriedScarProgressPopulation 153.9
TryingPastOnesPutting 119.7
YearnGasesDeerGiven 108.3
DoubtFeetSomebodyCreature 142.5
LiquidSureDreamCatch 114.0
KuanHulio
sumber
16
Untuk kasus uji, mengapa entropi kata sandi berbeda-beda? Semua kata sandi 4 kata yang dihasilkan dari kamus yang sama harus memiliki entropi yang sama.
NonlinearFruit
20
Entropi kata sandi tergantung pada set simbol. Jika kata sandi Anda adalah Nsimbol dari set S, kata sandi entropi adalah log2(|S|)*N. Di sini ukuran set simbol adalah ukuran kamus ( |S|=4284) dan jumlah simbol adalah jumlah kata ( N=4), sehingga entropi untuk setiap kata sandi adalah 48.3.
NonlinearFruit
48
Definisi entropi ini sangat salah! Jika setiap karakter dipilih secara seragam secara acak dari ukuran R, maka memang panjang-L kata sandi memiliki kemungkinan R ^ L, sehingga entropinya adalah log dari itu: log: (R ^ L) = log₂ (R) * L yang merupakan formula Anda. Namun, jika kata sandi dipilih secara acak dari perangkat yang berbeda (misalnya Anda tidak akan pernah memiliki kata sandi seperti 3t1ta#asd), maka entropi akan menjadi logaritma dari jumlah kata sandi yang mungkin. Jika Anda selalu memilih 4 kata secara acak dari kamus 4284 kata, maka ada 4284 ^ 4 kata sandi, masing-masing dengan log entropi (4284) * 4 ≈ 48,26.
ShreevatsaR
5
Sebagai catatan, kata sandi jenis ini ada sebelum komik XKCD. Mereka disebut kata sandi "diceware".
user2428118
5
Selain masalah kata-kata yang memiliki entropi lebih sedikit daripada karakter acak, pertanyaan Anda mengharuskan kata-kata ditulis dengan huruf kapital, artinya case sudah diperbaiki dan tidak dapat dihitung untuk entropi.
Niet the Dark Absol

Jawaban:

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

Menganggap kamus sebagai daftar bernama f.

Dapat diuji dengan menyimpan file sebagai dict.txtdan memanggil

f = open('dict.txt').readlines()
Martmists
sumber
Daftar Python tidak memiliki metode acak, dan Anda dapat menyimpan dua byte di Python 2 dengan menghapus tanda kurung exec( execadalah kata kunci dalam Python 2).
Konrad Borowski
@ Memperbaiki Ya seharusnya shuffle(f);.
Jonathan Allan
Ups, perbaiki itu secepatnya
Martmists
4
Anda dapat menggunakan trik saya untuk mencatat bahwa pembulatan di 5,7 baik-baik saja untuk 1 tempat desimal selama kesalahan floating point tidak diperkenalkan dan menghemat lima byte dengan 57*len(x)/10.. Simpan byte lain dengan menghapus tanda kurung membuat cetakan mengambil tuple. Berikut ini adalah versi cut-down: TIO
Jonathan Allan
Gunakan sample(f,4)sebagai ganti shuffle. Juga fbisa menjadi open('dict.txt').read().split('\n'), open('dict.txt').readlines(), atau hanya open('dict.txt')(saya tahu itu tidak golfed tapi masih).
Alex Hall
10

PowerShell (3.0+), 77 byte

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

Cobalah online!

Menggunakan Jonathan Allan 's 57*len/10trik.

$dberisi kamus sebagai susunan kata. Jika Anda bermain di rumah dan ingin mengisi $d:

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

Menggunakan versi golf (Get-Culture).TextInfo.ToTitleCase()untuk memanfaatkan huruf pertama; Saya tidak berpikir ada cara yang lebih singkat untuk melakukan itu di PowerShell.

Sisanya cukup mudah saya pikir.

TIO memiliki seluruh kamus; menonaktifkan cache dan menjadi gila!

briantis
sumber
Dapatkah seseorang mengarahkan saya ke referensi untuk "Trik 57 * len / 10 Jonathan Allan's"?
James Curran
@ Jamesames Lihat uraian jawabannya di sini , dan juga komentarnya atas jawaban ini .
briantist
Ini tidak akan berfungsi dalam 2.0 yang benar. Itu harus dicatat dalam judul. Saya juga berpikir Anda perlu membaca $dsebagaimana seharusnya dengan asumsi itu ada di lingkungan. (gc d)| random..di mana kamus adalah file yang disebut d dalam direktori yang sama.
Matt
1
@Mat pada SO Saya mungkin pergi keluar dari jalan saya untuk membuat jawaban bekerja dengan v2 (atau melakukan 2 versi), tetapi ini adalah kode golf man! Semakin misterius, semakin baik ;-p
briantis
1
Saya hanya mencoba menyimpan byte dalam judul jawaban saya.
Matt
7

Jelly , 22 byte

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

Tautan monadik yang mengambil daftar daftar karakter, kamus yang diuraikan (sebagaimana diizinkan dalam obrolan ).

Cobalah online! (Klik "Argumen" untuk menyembunyikan kamus dan mengurangi kebutuhan untuk menggulir.)

Bagaimana?

Karena kamus hanya berisi kata-kata yang valid ( 4karakter atau lebih, hanya [a-z]), tidak perlu memeriksa kondisi ini.

Karena semua kata-kata dalam kamus memiliki panjang di [4-8]mungkin panjang sandi berada di [16,32], dan mungkin entropi tidak akan pernah putaran berbeda ke satu tempat desimal dari dengan mengganti log(52,2)dengan 5.7. Satu-satunya masalah adalah bahwa menggunakan nilai floating point dari 5.7akan memberikan floating point kesalahan pembulatan untuk panjang 18, 26dan 31. Namun mengalikan dengan 57dan kemudian membaginya dengan 10menggunakan ×57÷⁵menghindari ini (sementara masih byte lebih pendek daripada mencetak nilai presisi menggunakan titik mengambang penuh ×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
sumber
5

Ruby, 89 83 byte

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

Diasumsikan bahwa kata sandi disimpan dalam variabel d. Anda dapat menambahkan baris ini sebelum kode:

d=$<.map(&:chomp)

dan panggil skrip misalnya seperti ini:

$ ruby generate_passwords.rb < dictionary_file.txt

Output sampel:

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

KitchenMiseryLurkJoints ... wow.


-6 byte dari Ajedi32

daniero
sumber
1
Mungkin dapat menyimpan beberapa byte dengan menghapus shuffle!dan mengganti popdengan sample.
Ajedi32
@ Ajedi32 Oh, kamu benar! Saya benar-benar memikirkannya, tetapi saya telah salah membaca aturan ini A word cannot reappear in the same password, berpikir itu berarti tidak ada penggunaan kembali kata-kata di semua kata sandi. Terima kasih :)
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++]

Cobalah online

salin dan tempel menggunakan ctrl-v dan tekan shift + enter untuk menjalankan


Mathematica, 136 byte

dengan asumsi bahwa m adalah kamus kodenya

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
sumber
"Pekerjaan hari ini adalah membuat 5 kata sandi menggunakan kata-kata." Perlu 5 bukannya satu.
KuanHulio
ok ... 5 kata sandi .. diperbaiki ..
J42161217
Mengapa Anda tidak membuat kamus tersedia secara lokal untuk mempersingkat kode dengan menghindari teks hyperlink?
sergiol
agar mudah bagi Anda untuk mengujinya ...
J42161217
Yang terbaik adalah memberikan kode pembantu yang sederhana dan tidak diseragamkan untuk memudahkan pengujian daripada mengurangi kiriman Anda sehingga kurang mandiri. Juga, kamus seharusnya menjadi variabel tanpa membajak server DNS lokal (atau memodifikasi hostsfile).
wizzwizz4
4

Bash ,66 65 byte

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

Cobalah online!

Kamus diterima oleh STDIN. Kocok semua kata dalam kamus dan hasilkan terlebih dahulu 4.

Untuk setiap kata, tambahkan panjangnya dalam var l, dan gema kata dengan huruf besar. Pada akhirnya panggilan bc untuk melakukan perhitungan.

Solusi awk, 112 byte, empat kata sandi:

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}'
marcosm
sumber
3

(Ini adalah adaptasi dari jawaban Martmists, tapi saya tidak punya perwakilan untuk berkomentar)

Python, 88 86 byte

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

Dengan mengeksploitasi bagaimana setnondeterministic, Anda dapat menghindari keharusan mengimpor pustaka acak.

lelah
sumber
Ini secara konsisten menghasilkan output yang sama untuk saya. Jika berhasil pada beberapa implementasi maka Anda bisa menghemat beberapa byte dengan melakukan set(f).pop().
Jonathan Allan
1
Saya rasa ini tidak benar. Ini tidak deterministik, jadi tidak dijamin untuk menghasilkan kata sandi yang sama, tetapi dalam praktiknya jarang menghasilkan hasil yang berbeda.
DJMcMayhem
Saya menduga itu mungkin tergantung pada implementasi. Saya melakukannya pada rilis Windows Anaconda Python 3 yang baru saja diinstal, dan itu berhasil. Namun set(f).pop()tidak berhasil, saya mencobanya. Ini memberikan hasil yang sama setiap kali.
dain
"Dalam praktiknya jarang akan menghasilkan hasil yang berbeda" - bagi saya, inilah contohnya: pastebin.com/raw/ZHiHgzxV
dain
@dain saya penasaran. Harap berikan informasi tentang pembuatan Python Anda.
wizzwizz4
3

Japt , 30 byte

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

Cobalah online!

Luke
sumber
Bagus! Tapi sayangnya itu menciptakan kata sandi yang sama 5 kali, dan itu harus berbeda setiap saat ..
Iain Ward
Ini mungkin 30 karakter, tetapi setidaknya di UTF-8, sistem saya jam di 35 byte.
CVn
1
@ MichaelKjörling Japt menggunakan ISO 8859-1, bukan UTF-8.
Dennis
@Dennis Menarik. Terima kasih.
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))}

Menganggap kamus dilewatkan ke fungsi sebagai array.

Cuplikan Tes

Justin Mariner
sumber
2

Mathematica, 71 Bytes

Dengan asumsi kamus sudah dimuat ke dalam array yang disebut d.

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

Penjelasan:

                                        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
sumber
Bagaimana dengan nomor entropi ?!
Jonathan Allan
Ups melewatkan sedikit itu. Diperbarui.
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})}

Ini berfungsi di ColdFusion 11+ dan Lucee 4.5+

Untuk menjalankannya: https://trycf.com/gist/ff14e2b27d66f28ff69ab90365361b12/acf11?theme=monokai

Tautan TryCF memiliki lebih sedikit golf tetapi kode yang sama.

Saya tidak benar-benar berharap mendapat jawaban golf yang kompetitif; Saya hanya ingin melihat apa yang diperlukan untuk menyelesaikan tantangan ini di ColdFusion. Terutama karena tidak banyak CF dalam jawaban ini. :-) Setelah setup, ternyata lebih pendek dari yang saya duga.

Upaya pertama saya sedikit lebih pendek sampai saya ingat bahwa kata yang sama tidak dapat digunakan lebih dari sekali. Meskipun sangat tidak mungkin bahwa pengacak akan memilih indeks yang sama lebih dari sekali, saya membuang indeks ke dalam kunci struktur, yang akan mencegah duplikasi. Kemudian saya menggunakan daftar kunci untuk membangun string kata sandi terakhir saya. Saya juga menggunakan trik matematika untuk menemukan entropi.

Shawn
sumber
2

PHP , 136 129 byte

-7 byte, terima kasih 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)."
";}

Cobalah online!

SAYA
sumber
@ JörgHülsermann Tampaknya berhasil, terima kasih.
ME
2

Python 3, 252 byte

Ini adalah tantangan golf kode pertama yang pernah saya lakukan! Saya tahu ada jawaban Python lain di sini (yang mungkin lebih baik dari saya) tetapi ini tampak menyenangkan, jadi saya ingin mencobanya. Ini versi golfnya:

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

Saya akan memposting Coba Online! tautan, tetapi itu tidak mendukung banyak file. Jadi, inilah tautan repl.it: https://repl.it/InIl/0

Juga, inilah versi yang tidak disunat:

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

Seperti yang saya katakan, ini adalah kode waktu pertama saya gofling, jadi saya yakin ini bisa diperbaiki banyak.

ATMunn
sumber
Selamat datang di PPCG!
Taylor Scott
2

tcl, 137

Bukan seorang pemenang pasti, tapi saya pikir itu bisa menjadi golf sedikit lebih.

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 - Tujuan baris 1 hanya untuk memasukkan isi kamus ke dalam variabeld

sergiol
sumber
Anda mungkin dapat menurunkannya karena kata sandi membutuhkan 4 kata, bukan 5.
KuanHulio
Dan Anda meminta 5 kata sandi, bukan 4. LOL! Saya tidak cocok jumlahnya!
sergiol
Ha ha ha! @sergiol
KuanHulio
Tetap! @KuanHulio
sergiol
Itu lebih baik. Pekerjaan yang baik.
KuanHulio
0

Vim, 87 penekanan tombol

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

Mengasumsikan bahwa kamus ada dalam file bernama w. Akan selalu menggunakan 4 kata berurutan

Penjelasan:

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
sumber
0

q / kdb +, 76 74 65 56 byte

Larutan:

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

Contoh:

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

Penjelasan:

Baca di daftar kata, pisahkan pada "", pilih 4 kata acak dari daftar ini, huruf besar setiap kata, lalu gabung bersama. Masukkan ini ke dalam fungsi lambda yang mengembalikan kata sandi dan 'entropi' yang dihitung:

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

Catatan:

Saya menyerah dan menggunakan 5.70044 bukannya 2 xlog 52 xexp...

streetster
sumber