Генератор паролів XKCD


34

Вступ

Мабуть, це питання було задано тут, і воно, на жаль, закрилося. Я подумав, що було б гарною ідеєю спробувати ще раз, але все зроблено правильно.

XKCD розглядає, як ми навчені користуватися "важко запам’ятовуваними паролями", думаючи, що це безпечно, але натомість для роботи комп'ютера знадобиться 3 дні. З іншого боку, запам'ятовування 4-5 слів викликає введення пароля Куана, і легко запам'ятовується. Божевільно, як це працює, так?

Виклик

Завдання сьогодні - створити 5 паролів за допомогою слів. 4 слова на пароль і мінімум 4 букви на слово, але не максимум. Інтропія пароля Куана потрібно буде розраховувати для кожного пароля, але примусовий мінімум не встановлюватиметься.

Що таке Інтропія пароля Куана?

Kuan's Password Intropy - це показник того, наскільки непередбачуваний пароль, згідно Куану. Існує простий розрахунок: Е = увійти 2 (R) * L . E - це введення пароля Куана, R - діапазон доступних символів і L - довжина пароля.

Діапазон доступних символів сам по собі пояснює. Це діапазон символів, який може мати пароль, у цьому випадку це верхній і нижній регістр. Оскільки в алфавіті є 26 символів, 26 x 2 = 52 символи у всьому діапазоні пароля.

Довжина пароля також пояснюється сама собою. Це загальна довжина пароля після створення.

Обмеження

  • Немає даних.
  • Слово не може знову з’явитися в одному паролі.
  • У паролі не допускаються символи чи цифри.
  • 4 слова на пароль, але примусовий мінімум 4 літери на слово.
  • Немає пробілів між словами.
  • Не можна генерувати один і той же пароль знову і знову.
  • Кожне слово має бути використано з великої літери у паролі.
  • Вихід повинен бути зрозумілим для людини і повинен бути розташований між собою. Необхідно також включити введення Куана в паролі з використанням пароля, використовуючи вищевказане рівняння введення Куана.
  • Словник . Ви повинні використовувати це, завантажити його як текстовий файл та інтегрувати відповідно. Це буде список, з якого ви захоплюєте слова. Ваш код повинен вважати його доступним.
  • Це , найкоротший виграш байтів.

Вихідні дані

TriedScarProgressPopulation 153.9
TryingPastOnesPutting 119.7
YearnGasesDeerGiven 108.3
DoubtFeetSomebodyCreature 142.5
LiquidSureDreamCatch 114.0

16
Чому для тестових випадків змінюється ентропія пароля ? Усі 4 слова паролів, що генеруються з одного словника, повинні мати однакову ентропію.
нелінійний

20
Ентропія пароля залежить від набору символів. Якщо ваш пароль - це Nсимволи з набору S, це ентропія пароля log2(|S|)*N. Тут розмір набору символів - це розмір словника ( |S|=4284), а кількість символів - кількість слів ( N=4), тому ентропія для кожного пароля є 48.3.
Нелінійний

48
Це визначення ентропії небезпечно неправильне! Якщо кожен символ обраний навмання рівномірно з набору розміру R, тоді дійсно пароль L-довжини має можливості R ^ L, тому ентропія - це журнал цього: log₂ (R ^ L) = log₂ (R) * L яка ваша формула. Однак якщо паролі вибираються навмання з іншого набору (наприклад, у вас ніколи не буде подібного пароля 3t1ta#asd), то ентропія буде логарифмом кількості можливих паролів. Якщо у словнику 4284 слів завжди довільно вибирати 4 слова однорідно, то наявні 4284 ^ 4 паролі, кожен з логікою ентропії₂ (4284) * 4 ≈ 48,26.
ShreevatsaR

5
Для запису цей тип паролів передує коміксу XKCD. Їх називають паролями "програмного забезпечення".
користувач2428118

5
Окрім випуску слів, що мають меншу ентропію, ніж випадкові символи, ваше запитання вимагає, щоб слова були написані з великої літери, тобто випадок виправлений і не може бути зарахований до ентропії.
Niet the Dark Absol

Відповіді:


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

У списках Python немає методу перетасування, і ви можете зберегти два байти в Python 2, видаливши круглі дужки навколо exec( execце ключове слово в Python 2).
Конрад Боровський

@xfix Так має бути shuffle(f);.
Джонатан Аллан

Уопс, виправляючи це
якнайшвидше

4
Ви можете скористатися моїм трюком, зауваживши, що округлення в 5,7 є точним до 1 десяткового знака, доки помилки з плаваючою комою не будуть введені, і збережіть п'ять байтів 57*len(x)/10.. Збережіть ще один байт, видаливши круглі дужки, щоб змусити друк взяти кордон. Ось скорочена версія: TIO
Джонатан Аллан

Використовуйте sample(f,4)замість shuffle. Також fможе бути просто open('dict.txt').read().split('\n'), open('dict.txt').readlines()чи просто open('dict.txt')(я знаю , що це не golfed , але до сих пір).
Алекс Холл

10

PowerShell (3.0+), 77 байт

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

Спробуйте в Інтернеті!

Використання Jonathan Allan «s 57*len/10трюк.

$dмістить словник як масив слів. Якщо ви граєте вдома і хочете заповнити $d:

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

Використання гольф-версії (Get-Culture).TextInfo.ToTitleCase()великої літери; Я не думаю, що в PowerShell існує коротший спосіб зробити це.

Решта досить просто, я думаю.

Посилання TIO має весь словник; вимкніть кеш-пам'ять і перейдіть на гайки!


Чи може хтось вказати мені на посилання на "трюк Джонатана Аллана 57 * len / 10"?
Джеймс Курран


Це не буде працювати в 2.0 правильно. Це слід зазначити у назві. Я також думаю, що вам потрібно прочитати так, $dяк слід вважати, що він присутній у навколишньому середовищі. (gc d)| random..де словник - це файл, який називається d в одному каталозі.
Метт

1
@Matt on SO Я можу піти зі свого шляху, щоб зробити відповідь на роботу з v2 (або зробити 2 версії), але це код людини з гольфу! Чим більше таїнство, тим краще
;-p

1
Я просто намагаюся зберегти байти в заголовках відповідей.
Метт

7

Желе , 22 байти

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

Монадійне посилання зі списком списку символів, розібраним словником (як дозволено в чаті ).

Спробуйте в Інтернеті! (Клацніть "Аргументи", щоб приховати словник і зменшити необхідність прокрутки.)

Як?

Оскільки словник містить лише дійсні слова (лише 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 ... вау.


-6 байт від Ajedi32


1
Може бути в змозі зберегти кілька байт шляхом видалення shuffle!і заміни popз sample.
Ajedi32

@ Ajedi32 О, ти маєш рацію! Я насправді думав про це, але я неправильно прочитав це правило A word cannot reappear in the same password, думаючи, що це означає не повторне використання слів через усі паролі. Дякую :)
daniero

4

Математика, 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

ок ... 5 паролів .. виправлено ..
J42161217

Чому ви не зробили доступним словник для місцевого використання, щоб скоротити код, уникаючи тексту гіперпосилання?
сергіол

щоб вам було зручно перевірити його ...
J42161217

Найкраще надати простий невізовий кодекс помічника, щоб полегшити тестування, ніж це для того, щоб гольф подав менше, щоб він був самостійним. Крім того, словник повинен бути змінним, не викрадаючи локальний DNS-сервер (або змінюючи hostsфайл).
wizzwizz4

4

Bash ,66 65 байт

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

Спробуйте в Інтернеті!

Словник отримує STDIN. Переміщує всі слова у словнику та виводить перші 4.

Для кожного слова додається його довжина в var l і повторюється слово з великої літери. Врешті-решт закликає bc зробити математику.

Рішення Awk, 112 байт, чотири паролі:

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

(Це адаптація відповіді мармістів, але я не маю відповіді для коментаря)

Пітон, 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().
Джонатан Аллан

1
Я не думаю, що це дійсно справедливо. Це не детерміновано, тому не гарантується створення одного і того ж пароля, але на практиці він рідко створюватиме різні результати.
DJMcMayhem

Я підозрював, що це може залежати від реалізації. Я зробив це на щойно встановленому Windows-релізі Anaconda Python 3, і він спрацював. Однак set(f).pop()не виходить, я спробував це. Це дає кожен раз однаковий результат.
вдень

«На практиці це рідко створюють різні результати» , - це , здається, для мене, ось приклад: pastebin.com/raw/ZHiHgzxV
Дейн

@dain Мені цікаво. Будь ласка, надайте інформацію про вашу збірку Python.
wizzwizz4

3

Japt , 30 байт

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

Спробуйте в Інтернеті!


Приємно! Але, на жаль, він створює один і той же пароль 5 разів, і він повинен бути різним щоразу ..
Ієн Уорд,

Це може бути 30 символів, але принаймні в UTF-8 моя система працює на 35 байт.
CVn

1
@ MichaelKjörling Japt використовує ISO 8859-1, а не UTF-8.
Денніс

@Dennis Цікаво. Дякую.
CVn

3

JavaScript (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.

Що з номером ентропії ?!
Джонатан Аллан

Упс пропустив цей шматочок. Оновлено.
Ян Міллер

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. Тим більше, що в цих відповідях мало КФ. :-) Після налаштування це було напрочуд коротше, ніж я очікував.

Моя перша спроба була трохи коротшою, поки я не згадав, що те саме слово не можна вживати більше одного разу. Навіть незважаючи на те, що рандомізатор не один раз обирає той самий індекс, я скидаю індекси в ключі структури, що запобігає дублюванню. Тоді я використовую цей список ключів, щоб побудувати свій остаточний рядок пароля. Я також використав математичний трюк, щоб знайти ентропію.


2

PHP , 136 129 байт

-7 байт, дякую Йорге

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

Спробуйте в Інтернеті!


@ JörgHülsermann Це, здається, працює, дякую.
ME

2

Python 3, 252 байти

Це моя перша в історії коду проблема з гольфом, яку я зробив! Я знаю, що тут є інші відповіді Python (які, мабуть, краще, ніж у мене), але це виглядало весело, і тому я хотів спробувати це в будь-якому випадку. Ось версія для гольфу:

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

Крім того, ось версія, що не має волі:

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!
Тейлор Скотт

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

демонстрація - мета рядка 1 - лише ввести вміст словника до змінноїd


Ви, мабуть, могли
пограти в

І ви попросили 5 паролів замість 4. LOL! Я не відповідав цифрам!
сергіол

Ха-ха! @sergiol
KuanHulio

Виправлено! @KuanHulio
sergiol

Так краще. Хороша робота.
KuanHulio

0

Вім, 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...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.