Генератор паролей XKCD

34

Введение

По-видимому, этот вопрос был задан здесь, и он, к сожалению, закрыт. Я подумал, что это хорошая идея, попробовать еще раз, но все сделано правильно.

XKCD смотрит на то, как нас обучают использовать «трудно запоминающиеся пароли», думая, что это безопасно, но вместо этого компьютеру потребуется 3 дня, чтобы взломать. С другой стороны, запоминание 4-5 слов приводит к появлению Kuan's Password Intropy, и его легко запомнить. Сумасшедший, как это работает, а?

Вызов

Работа сегодня состоит в том, чтобы создать 5 паролей, используя слова. 4 слова на пароль и минимум 4 буквы на слово, но не максимум. Интропия пароля Куана должна быть рассчитана для каждого пароля, но принудительный минимум не будет установлен.

Что такое парольная интропия Куана?

По словам Куана, интропия пароля Куана является мерой того, насколько непредсказуемым является пароль. Есть простой расчет: E = log 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
KuanHulio
источник
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), тогда энтропия будет логарифмом числа возможных паролей. Если вы всегда выбираете 4 слова случайным образом из словаря на 4284 слова, то есть 4284 ^ 4 паролей, каждый с энтропийным журналом₂ (4284) * 4 ≈ 48,26.
ShreevatsaR
5
Для справки, этот тип паролей предшествует комиксу XKCD. Они называются «двудомными» паролями.
user2428118
5
Помимо вопроса о словах, имеющих меньшую энтропию, чем случайные символы, ваш вопрос требует, чтобы слова были написаны заглавными буквами, то есть регистр фиксирован и не может быть засчитан для энтропии.
Niet the Dark Absol

Ответы:

13

Python 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()
Martmists
источник
Списки Python не имеют метода случайного выбора, и вы можете сохранить два байта в Python 2, удалив круглые скобки exec( execэто ключевое слово в Python 2).
Конрад Боровски
@xfix Да, так и должно быть shuffle(f);.
Джонатан Аллан
Упс, исправляя это как можно скорее
Martmists
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')(я знаю, что это не игра в гольф, но все же).
Алекс Холл
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 содержит весь словарь; отключить кеш и сходить с ума!

briantist
источник
Может ли кто-нибудь указать мне ссылку на «трюк Джонатана Аллана 57 * len / 10»?
Джеймс Керран
@JamesCurran Смотрите разбивку его ответа здесь , а также его комментарий к этому ответу .
бриантист
Это не будет работать в 2.0 правильно. Это следует отметить в названии. Я также думаю, что вам нужно читать, $dкак предполагается, если он присутствует в окружающей среде. (gc d)| random..где словарь представляет собой файл с именем d в том же каталоге.
Мэтт
1
@Matt на SO Я мог бы изо всех сил заставить ответ работать с v2 (или сделать 2 версии), но это - код гольфист! Чем более загадочно, тем лучше ;-p
briantist
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

daniero
источник
1
Может быть в состоянии сохранить несколько байтов, удалив shuffle!и заменив popна sample.
Ajedi32
@ Ajedi32 О, ты прав! Я действительно думал об этом, но я неправильно понял это правило A word cannot reappear in the same password, полагая, что оно не означает повторного использования слов во всех паролях. Спасибо :)
Даниеро
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, чтобы запустить


Mathematica, 136 байт

при условии, что м словарь код

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
источник
«Работа сегодня состоит в том, чтобы создать 5 паролей, используя слова.» Нужно 5 вместо одного.
KuanHulio
ок ... 5 паролей .. исправлено ..
J42161217
Почему вы не сделали словарь доступным локальным, чтобы сократить код, избегая текста гиперссылки?
Сергиол
чтобы вам было легко это проверить ...
J42161217
Лучше всего предоставить простой вспомогательный код для упрощения тестирования, а не меньше вносить изменения в свою работу, чтобы она была автономной. Кроме того, словарь должен быть переменным без перехвата локального DNS-сервера (или изменения hostsфайла).
wizzwizz4
4

удар ,66 65 байт

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

Попробуйте онлайн!

Словарь получен от STDIN. Перемешивает все слова в словаре и выводит первые 4.

Для каждого слова складывает его длину в var l и повторяет слово с заглавной буквы. В конце звонит БК, чтобы сделать математику.

Решение 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}'
marcosm
источник
3

(Это адаптация ответа Мартмистов, но у меня нет представителя, чтобы комментировать)

Python, 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 для Windows, и это сработало. Однако set(f).pop()не работает, я попробовал. Это дает один и тот же результат каждый раз.
Дейн
«На практике это редко приводит к разным результатам», - мне кажется, вот пример: pastebin.com/raw/ZHiHgzxV
Дейн
@ Дэйн, мне любопытно. Пожалуйста, предоставьте информацию о вашей сборке 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.
Деннис
@ Денис Интересно. Спасибо.
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

Mathematica, 71 байт

Предполагая, что словарь уже загружен в массив с именем d .

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

Explaination:

                                        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. Тем более, что в этих ответах не так много CF :-) После установки он оказался на удивление короче, чем я ожидал.

Моя первая попытка была немного короче, пока я не вспомнил, что одно и то же слово нельзя использовать более одного раза. Несмотря на то, что весьма маловероятно, что рандомизатор выберет один и тот же индекс более одного раза, я добавлю индексы в ключи структуры, что предотвратит дублирование. Затем я использую этот список ключей для построения моей последней строки пароля. Я также использовал математический трюк, чтобы найти энтропию.

Шон
источник
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)))

Как я уже сказал, это мой первый раз, когда я думаю о коде, поэтому я уверен, что это можно было бы значительно улучшить.

ATMunn
источник
Добро пожаловать в PPCG!
Тейлор Скотт
2

ткл, 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

sergiol
источник
Вы могли бы, вероятно,
KuanHulio
И вы попросили 5 паролей вместо 4. LOL! Я не соответствовал числам!
Сергиол
Хахаха! @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...

streetster
источник