XKCD Şifre Üretici


34

Giriş

Görünüşe göre, bu soru burada soruldu ve ne yazık ki kapandı. Tekrar denemenin iyi bir fikir olduğunu düşündüm, ama doğru yaptım.

XKCD , "şifreleri hatırlaması zor" u kullanmak için nasıl eğitildiğimize bakar, güvenli olduğunu düşünür , ancak bunun yerine, bir bilgisayarın kırılması 3 gün sürer. Kapak tarafında, 4-5 kelimeyi hatırlamak, Kuan'ın Şifre Girişimini getiriyor ve hatırlaması kolaydır. Çılgınca bu nasıl çalışıyor?

Meydan okuma

Bugün iş, kelimeleri kullanarak 5 şifre oluşturmaktır. Her şifre için 4 kelime ve kelime başına en az 4 harf olmakla birlikte en fazla sayı yapılmamalıdır. Kuan'ın Şifre Girişimi her şifre için hesaplanacak, ancak zorunlu bir minimum ayarlanmadı.

Kuan'ın Şifresi Girişimi nedir?

Kuan'ın Şifresi İfadesi, Kuan'a göre bir şifrenin ne kadar tahmin edilemez olduğunun bir ölçümüdür. Bir hesaplama vardır: E = log 2 * l (R) . E, Kuan'ın Şifre Girişimi, R, kullanılabilir karakterlerin aralığı ve şifre uzunluğu için L'dir.

Kullanılabilir karakter aralığı kendi kendini açıklayıcı niteliktedir. Bu, bir şifrenin sahip olabileceği karakter aralığıdır, bu durumda Üst ve küçük harflerdir. Alfabede 26 karakter olduğundan, parolanın tamamında 26 x 2 = 52 karakter.

Parola uzunluğu da kendi kendini açıklayıcıdır. Oluşturulduktan sonra parolanın toplam uzunluğu.

Kısıtlamalar

  • Giriş yok.
  • Bir kelime aynı şifrede tekrar görünemez .
  • Parolada sembol veya numaralara izin verilmez.
  • Şifre başına 4 kelime, ancak kelime başına en az 4 harf zorunlu.
  • Kelimeler arasında boşluk yok.
  • Aynı şifreyi tekrar tekrar oluşturamazsınız.
  • Her kelimenin bir parola ile büyük harfle yazılması gerekir.
  • Çıktı insan tarafından okunabilir olmalı, aralıklı olmalıdır. Ayrıca yukarıdaki Kuan'ın Password Intropy denklemini kullanarak, Kuan's Password Intropy'yi de içermelidir.
  • Sözlük . Bunu kullanmanız, bir metin dosyası olarak indirmeniz ve buna göre bütünleştirmeniz gerekir. Bu, kelimelerden aldığınız liste olacaktır. Kodunuz uygun olduğunu varsaymalıdır.
  • Bu , en kısa bayt kazanır.

Çıktı

TriedScarProgressPopulation 153.9
TryingPastOnesPutting 119.7
YearnGasesDeerGiven 108.3
DoubtFeetSomebodyCreature 142.5
LiquidSureDreamCatch 114.0

16
Test durumlarında, şifre entropisi neden değişiyor? Aynı sözlükten oluşturulan 4 kelime şifresinin tamamı aynı entropiye sahip olmalıdır.
NonlinearFruit

20
Şifre entropisi, sembol setine bağlıdır. Eğer şifreniz Nsetteki semboller ise S, şifre entropisi log2(|S|)*N. Burada sembol kümesinin boyutu ( |S|=4284) sözlüğünün boyutu ve sembollerin sayısı kelime sayısıdır ( N=4), yani her bir parola için entropi 48.3.
NonlinearFruit

48
Entropinin bu tanımı tehlikeli bir şekilde yanlış! Her karakter rastgele R boyutu kümesinden eşit olarak seçilirse, aslında L uzunluk şifresi R ^ L olanaklarına sahiptir, bu nedenle entropi bunun günlüğüdür: log₂ (R ^ L) = log₂ (R) * L bu senin formülün. Bununla birlikte, eğer şifreler farklı bir setten rastgele seçilirse (örneğin, asla böyle bir şifreniz olmaz 3t1ta#asd), entropi olası şifrelerdeki sayının logaritması olacaktır. Her zaman 4284 kelimelik bir sözlükten rastgele aynı anda 4 kelime seçerseniz, her biri entropi log₂ (4284) * 4 ≈ 48.26 olan 4284 ^ 4 şifre vardır.
ShreevatsaR

5
Kayıt için, bu tür şifreler XKCD çizgi romanından önce gelir. Bunlara "diceware" şifreleri denir.
user2428118

5
Rastgele karakterlerden daha az entropiye sahip sözcüklerin yanı sıra, sorunuz, kelimelerin büyük harflerle yazılmasını gerektirir; yani durum sabitlenir ve entropi için sayılmaz.
Karanlık Mutlak Niet

Yanıtlar:


13

Python 2, 102 101 97 91 bayt

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

Sözlüğü adlandırılmış bir liste olarak kabul eder f.

Dosyayı kaydederek dict.txtve arayarak test edilebilir

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

Python listelerinde shuffle yöntemi yoktur ve etrafındaki parantezi kaldırarak Python 2'de iki bayt kaydedebilirsiniz exec( execPython 2'de bir anahtar kelimedir).
Konrad Borowski

@ xfix Evet öyle olmalı shuffle(f);.
Jonathan Allan


4
5.7'deki yuvarlamanın, kayan nokta hataları ortaya çıkmadığı ve beş bayttan tasarruf edildiği sürece 1 ondalık basamağa kadar iyi olduğunu belirtme numaramı kullanabilirsiniz 57*len(x)/10.. Baskının bir parça almasını sağlayan parantezleri kaldırarak başka bir bayttan tasarruf edin. İşte kesilmiş bir versiyonu: TIO
Jonathan Allan

Yerine sample(f,4)kullanın shuffle. Ayrıca fsadece olabilir open('dict.txt').read().split('\n'), open('dict.txt').readlines()ya da sadece open('dict.txt')(biliyorum ki golf oynamak değil ama yine de).
Alex Hall

10

PowerShell (3.0+), 77 bayt

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

Çevrimiçi deneyin!

Jonathan Allan 'ın 57*len/10numarasını kullanarak .

$dSözlüğü bir sözcük dizisi olarak içerir. Evde oynuyorsanız ve doldurmak istiyorsanız $d:

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

(Get-Culture).TextInfo.ToTitleCase()İlk harfi büyük harf yapmak için golf versiyonunu kullanmak ; PowerShell'de bunu yapmanın daha kısa bir yolu olduğunu sanmıyorum.

Gerisi oldukça basit sanırım.

TIO bağlantısı tüm sözlüğe sahip; önbelleği devre dışı bırak ve fındık git!


Biri beni "Jonathan Allan'ın 57 * len / 10 numarası" referansına yönlendirebilir mi?
James Curran

@JamesCurran Burada cevabının dökümünü ve bu cevaba yaptığı yorumunu da gör .
briantist

Bu 2.0 doğru çalışmayacak. Bu başlıkta belirtilmelidir. Ayrıca $d, ortamda bulunduğunu varsaymak için gereken şekilde okumalısınız . (gc d)| random..Sözlüğü, aynı dizinde d adlı bir dosyadır.
Matt

1
SO @Matt Bir cevap v2 ile çalışmak için yolumdan gidebilirim (veya 2 sürüm yapmak), ama bu kod golf adam! Ne kadar
eğlenici olursa

1
Ben sadece cevap başlıklarıma bayt kaydetmeye çalışıyorum.
Matt

7

Jöle , 22 bayt

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

Karakterlerin bir listesini içeren monadik bir bağlantı, ayrıştırılmış sözlük ( sohbette izin verildiği şekilde ).

Çevrimiçi deneyin! (Sözlüğü gizlemek ve kaydırma gereksinimini azaltmak için "Bağımsız Değişkenler" i tıklayın.)

Nasıl?

Sözlük sadece geçerli kelimeler içerdiğinden ( 4sadece veya daha fazla karakter [a-z]), bu durumu kontrol etmeye gerek yoktur.

Sözlükteki tüm kelimelerin uzunlukları [4-8]olası olduğundan, şifre uzunlukları içindedir [16,32]ve muhtemel entropiler, yerine koymak yerine tek bir ondalık basamağa asla farklı bir şekilde yuvarlanmaz . Tek sorun bir kayan nokta değeri kullanarak olmasıdır uzunlukları ilgili hataları yuvarlama kayan nokta verecektir , ve . Ancak bunu kullanarak çarpmak ve sonra bölmek bunu önler (yine de kullanarak tam kayan nokta hassasiyetinin değerini yazdırmaktan bir bayt daha kısa iken ).log(52,2)5.75.71826315710×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

Ruby, 89 83 bayt

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

Şifrelerin değişkende saklandığını varsayar d. Bu satırı koddan önce ekleyebilirsiniz:

d=$<.map(&:chomp)

ve betiği şöyle söyleyin:

$ ruby generate_passwords.rb < dictionary_file.txt

Örnek çıktı:

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

KitchenMiseryLurk Ortaklar ... vay.


Ajedi32'den -6 bayt


1
Kaldırarak birkaç byte kaydetmek mümkün olabilir shuffle!ve değiştirilmesi popile sample.
Ajedi32

@ Ajedi32 Oh, haklısın! Aslında bunu düşündüm, ama bu kuralı yanlış okudum A word cannot reappear in the same password, kelimelerin tüm şifreler arasında tekrar kullanılmayacağı anlamına geliyordu . Thanks :)
daniero

4

Mathematica, 178 bayt

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

Çevrimiçi deneyin

ctrl-v kullanarak kopyalayıp yapıştırın ve çalıştırmak için shift + enter tuşlarına basın


Mathematica, 136 bayt

m'nin, kodun sözlük olduğunu varsayarsak

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

“Bugün iş, sözcükleri kullanarak 5 parola oluşturmaktır.” Bir yerine 5'e ihtiyacınız var.
KuanHulio

Tamam ... 5 parola .. düzeltildi ..
J42161217

Köprü metninden kaçınarak sözlüğü neden kodu kısaltmak için yerel olarak kullanmadınız?
sergiol

test etmeni kolaylaştıracak şekilde ...
J42161217

Testinizi kolaylaştırmak için basit, ungolfed yardımcı kodunu sağlamak, gönderiminizi daha az golf oynamaktan, kendi kendine yetmesi için en iyisidir. Ayrıca, sözlüğün yerel DNS sunucusunu kaçırmadan (veya hostsdosyayı değiştirmeden ) değişken olması gerekiyordu .
wizzwizz4

4

Bash ,66 65 bayt

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

Çevrimiçi deneyin!

Sözlük STDIN tarafından recived. Sözlükteki tüm kelimeleri karıştırır ve ilk çıktılar 4.

Her bir kelime için, varil cinsinden uzunluğunu ekler ve büyük harfle yazılanları ekolar. Sonunda matematik yapmak için bc çağırır.

Awk çözümü, 112 bayt, dört şifre:

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

(Bu Martmistlerin cevabının bir uyarlamasıdır, fakat yorum yapacak cevabım yok)

Python, 88 86 bayt

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

setBelirsiz olanın ne olduğunu kullanarak , herhangi bir rastgelelik kütüphanesi almak zorunda kalmazsın.


Bu sürekli benim için aynı çıktıyı üretir. Bazı uygulamalar üzerinde çalışırsa, o zaman birkaç bayttan tasarruf edebilirsiniz set(f).pop().
Jonathan Allan

1
Bunun gerçekten geçerli olduğunu sanmıyorum. Belirleyici değildir, bu yüzden aynı şifreyi üretme garantisi yoktur, ancak pratikte nadiren farklı sonuçlar doğuracaktır.
DJMcMayhem

Uygulamaya bağlı olabileceğinden şüphelendim. Anaconda Python 3'ün yeni kurulmuş bir Windows sürümünde yaptım ve işe yaradı. Ancak set(f).pop()işe yaramıyor, denedim. Her seferinde aynı sonucu verir.
dain

"Uygulamada nadiren farklı sonuçlar üretecek" - benim için görünüyor, işte bir örnek: pastebin.com/raw/ZHiHgzxV
dain

@ dain merak ediyorum. Lütfen Python derlemeniz hakkında bilgi verin.
wizzwizz4

3

Japt , 30 bayt

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

Çevrimiçi deneyin!


Güzel! Fakat ne yazık ki 5 kez aynı şifreyi oluşturuyor ve her seferinde farklı olmalı ..
Iain Ward

Bu 30 karakter olabilir, ancak en azından UTF-8’de sistemim onu ​​35 byte’da tutar.
Bir CVn

1
@ MichaelKjörling Japt UTF-8 yerine ISO 8859-1 kullanıyor.
Dennis

@Dennis İlginç. Teşekkür ederim.
Bir CVn

3

JavaScript (ES6), 164 bayt

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

Sözlüğün işleve bir dizi olarak iletildiğini varsayar.

Test Parçacığı


2

Mathematica, 71 Bayt

Sözlüğün zaten adlandırılmış bir diziye yüklendiğini varsayalım d.

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

Açıklama:

                                        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.

Entropi numarası ne olacak?
Jonathan Allan,

Oops bu kısmı kaçırdı. Güncellenmiş.
Ian Miller

2

ColdFusion 216 bayt

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

Bu ColdFusion 11+ ve Lucee 4.5+ sürümlerinde çalışır.

Çalıştırmak için: https://trycf.com/gist/ff14e2b27d66f28ff69ab90365361b12/acf11?theme=monokai

TryCF bağlantısı daha az golf-ish ama aynı kodda.

Rekabetçi bir golf cevabım olmasını beklemiyordum; Sadece ColdFusion'da bu mücadeleyi tamamlamanın ne olacağını görmek istedim. Özellikle bu cevaplarda çok fazla CF olmadığı için. :-) Kurulumdan sonra beklediğimden şaşırtıcı bir şekilde kısaydı.

İlk girişimim, aynı kelimenin bir defadan fazla kullanılamayacağını hatırlayana kadar biraz daha kısaydı. Randomizer'in aynı endeksi bir defadan fazla seçmesi pek mümkün olmasa da, indeksleri bir yapının anahtarlarına dökerek çoğaltmayı önleyeceğim. Sonra son şifre dizimi oluşturmak için bu anahtar listesini kullanıyorum. Entropi bulmak için matematik numaramı da kullandım.


2

PHP , 136 129 bayt

-7 bayt, teşekkürler 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)."
";}

Çevrimiçi deneyin!


@ JörgHülsermann İşe benziyor, teşekkürler.
ME,

2

Python 3, 252 bayt

Bu benim yaptığım ilk kod golf mücadelesi! Burada başka Python cevapları olduğunu biliyorum (bu muhtemelen benimkinden daha iyi) ama bu eğlenceli görünüyordu, ve yine de denemek istedim. İşte golf versiyonu:

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

Çevrimiçi Deneyin! bağlantı, ancak bu birden fazla dosyayı desteklemiyor. Yani burada bir repl.it link: https://repl.it/InIl/0

Ayrıca, işte ungolfed versiyonu:

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

Söylediğim gibi, bu benim ilk kez uygulanan gofling kodum, bu yüzden bunun daha da geliştirilebileceğinden eminim.


PPCG'ye Hoşgeldiniz!
Taylor Scott

2

tcl, 137

Kesinlikle bir kazanan değil, ama biraz daha golf oynayabileceğini düşünüyorum.

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 - Satır 1'in amacı sadece sözlük içeriklerini değişkene koymaktır.d


Parola 5 yerine 4 kelime gerektirdiğinden muhtemelen golf
oynayabilirsiniz

Ve 4 yerine 5 şifre istediniz. LOL! Rakamlarla uyuşmadım!
sergiol

Hahaha! @sergiol
KuanHulio

Sabit! @KuanHulio
sergiol

Bu daha iyi. İyi iş.
KuanHulio

0

Vim, 87 tuş vuruşlarını

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

Sözlüğün bir dosyada olduğunu varsayar w. Her zaman arka arkaya 4 kelime kullanacak mı

Açıklama:

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 bayt

Çözüm:

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

Örnek:

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

Açıklama:

Kelime listesini oku, "" ikiye ayır, bu listeden 4 rastgele kelime seç, her kelimenin ilk harfini büyük harfle topla ve birlikte katıl. Bunu parolayı ve hesaplanan 'entropi'yi döndüren bir lambda işlevine besleyin:

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

Notlar:

Ben çöktüğünde ve yerine 5.70044 kullanılan 2 xlog 52 xexp...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.