Тема: AHK: Генератор паролей, ревизия кода.
Приветствую завсегдатаев Серого Форума! Ради освоения AHK, написал генератор паролей. В целом, он является дальнейшим развитием генератора из этой темы. Прошу, кому не трудно, провести ревизию кода. Для выявления явных или не очень ошибок.
; Версия Autohotkey : 1.1.22.03 Unicode 32bit
; Автор : Stremin
; Последняя модификация : 16 августа 2015
; Скрипт основан на : GenPass 0.01, forum.script-coding_com/viewtopic.php?id=7586
; : автор: Irbis
; Использованы ф-ии : PBKDF2, ahkscript_org/boards/viewtopic.php?t=3477
; : автор: Antonio Bueno
; : CreateDIB, ahkscript_org/boards/viewtopic.php?t=3203
; : автор: SKAN
; Описание :
; 1Pass4All – генератор и анализатор надёжности паролей.
; Генератор позволяет создавать сложные пароли, без необходимости запоминать их и хра-нить
; где-либо.
; Для анализа надёжности паролей, используется слегка изменённый алгоритм Джеффа Тоднема /
; Jeff Todnem, реализованный на сайте www.passwordmeter_com. Отличия заключаются в следующем
; (соответственно, для паролей содержащих перечисленные отличия, результат теста будет отличаться):
; - Обнаруживаются последовательности xyz / zyx.
; - Учитывается символ подчёркивания `_`.
;
; Пароль создаётся на основе двух строк, указанных пользователем:
; - Мастер-пароля – общего для всех программ / сайтов.
; - Строки-идентификатора – индивидуальной для каждой программы / сайта.
;
; и в соответствии с заданными, пользователем, правилами:
; - `Длина генерируемого пароля` от 8 до 64 символов.
; - `Количество циклов шифрования` от 1 до 9999. Для шифрования используется алгоритм AES256.
; В интерфейсе нет возможности выбора другого метода шифрования, но в коде скрипта его можно
; изменить (см. ниже по коду комментарии в функции `passgen`).
; - `Максимум символов подряд из одного набора`, от 0 до 4. Если указано 0, один и тот же набор
; может быть использован подряд неограниченное количество раз.
; - `Использовать каждый символ не больше` от 0 до 4. Если указано 0, один и тот же сим-вол
; может быть использован неограниченное количество раз.
; - Наборы символов, доступно 6 штук.
;
; Замечания:
; - Настройки с которыми стартует скрипт, можно изменить по своему вкусу. Сделать это можно
; в тексте скрипта, в секции `Настройки генератора по умолчанию`.
; - Если не выбран ни один набор, все настройки группы `Правила` будут неактивны.
; - Если выбран один любой набор, неактивной станет настройка: `Максимум символов под-ряд из
; одного набора`.
; - Если выбрано два и более набора, активны все настройки группы `Правила`.
; - В случае если ограничение `Использовать каждый символ не больше` действует, может возникнуть
; ситуация, когда в одном или нескольких алфавитах закончатся символы.
; Соответственно длина пароля может быть меньше, чем ожидалось.
;
; Пример 1:
; Выбранные наборы `_`
; `Длина генерируемого пароля` 8 символов
; `Максимум символов подряд из одного набора` неактивно, т.к. выбран один набор
; `Использовать каждый символ не больше` 1 раза
;
; Создан пароль длиной 1 символ `_`
;
; Пример 2
; Выбранные наборы `A-Z`, `_`
; `Длина генерируемого пароля` 8 символов
; `Максимум символов подряд из одного набора` 1 (т.е. наборы будут чередоваться)
; `Использовать каждый символ не больше` 1 раза
;
; Создан пароль длиной 3 (или 2) символа `A_B` (или `_A`)
; Так как наборы чередуются, то после 3 (2) символа, генератор должен переключиться на набор
; `_`, символы которого уже были использованы указанное кол-во раз.
;
; Пример 3
; Выбранные наборы `A-Z`, `0-9`, `_`
; `Длина генерируемого пароля` 32 символа
; `Максимум символов подряд из одного набора` 1 (т.е. наборы будут чередоваться)
; `Использовать каждый символ не больше` 1 раза
;
; Создан пароль длиной 22 символа ` A_0B1C2D3E4F5G6H7I8J9K`
; После того как символы набора `_` закончились, осталось ещё два набора. Далее аналогично
; 2ому примеру. Генератор переключается между наборами до тех пор, пока в них есть неисполь-
; зованные символы. С символом `9`, в наборе `0-9` заканчиваются все симво-лы, генератор
; переключается на набор `A-Z`. После чего должен переключиться на набор `0-9`, но там пусто.
;
; Исходя из примеров, если длина пароля не соответствует требованиям, нужно выбрать ещё один набор,
; либо увеличить значение параметра `Использовать каждый символ не больше` (либо снять ограничение).
#SingleInstance
#NoEnv
; >>> Настройки генератора по умолчанию менять здесь -----------------------------------------------
; !!! ВНИМАНИЕ: Если не указано, корректность вводимых значений не проверяется !!!
; Скрывать пароль или нет.
; допустимое значение: true (скрыть) / false (показать)
def_HidePass := true
; Длина генерируемого пароля.
; допустимое значение (проверяется через UpDown): целое число от 8 до 64.
def_LenPass := 8
; Количество циклов шифрования.
; допустимое значение (проверяется через UpDown): целое число от 1 до 9999.
def_Iteration := 1000
; Сколько раз подряд, будет использоваться один и тот же набор символов.
; допустимое значение (проверяется через UpDown): целое число от 0 до 4 (0 неограниченно).
def_LimitSet := 1
; Сколько раз в пароле будет использован один и тот же символ.
; допустимое значение (проверяется через UpDown): целое число от 0 до 4 (0 неограниченно).
def_LimitChar := 1
; Чекбоксы, активирующие тот или иной набор символов.
; допустимое значение: true (включение набора) / false (отключение набора).
def_UpCase := true ; A - Z
def_LowCase := false ; a - z
def_Num := true ; 0 - 9
def_ULine := true ; символ подчёркивания _
def_SpecSymbols := false ; спецсимволы ! @ # $ % ^ & * - +
def_Brackets := false ; скобки ( ) [ ] { } < >
; <<< Настройки генератора по умолчанию ------------------------------------------------------------
; >>> Настройки скрипта ----------------------------------------------------------------------------
script_name := "1Pass4All v0.02-6"
; Дефолтные ширина 454 и высота 146, главного окна. На основе этих значений расчитываются размеры
; контролов `Вкладки` (высота и ширина), `Мастер-пароль` (ширина), `Строка-Идентификатор` (ширина),
; `Новый пароль` (ширина), текста во вкладках `Помощь` и `О скрипте`.
m_width := 454, m_heigth := 146
; Для функции PBKDF2.
; Available hash algorithms and their length in bytes
aHashAlgid := {MD5: 0x8003, SHA1: 0x8004, SHA256: 0x800C, SHA384: 0x800D, SHA512: 0x800E}
aHashLength := {MD5: 16, SHA1: 20, SHA256: 32, SHA384: 48, SHA512: 64}
; <<< Настройки скрипта ----------------------------------------------------------------------------
; >>> GUI ------------------------------------------------------------------------------------------
; Всегда поверх всех окон.
Gui, +AlwaysOnTop hwndMainWin
; Шрифт для всего интерфейса.
Gui, Font, s8 w400, Tahoma
; --- GUI - Создание контрола Tab ------------------------------------------------------------------
tmp_w := m_width - 2, tmp_h := m_heigth - 3
Gui, Add, Tab2, x1 y3 w%tmp_w% h%tmp_h% vTabName gCalculatePass, Генератор||Настройки|О скрипте
; --- GUI - Вкладка "Генератор" --------------------------------------------------------------------
Gui, Tab, Генератор
Gui, Margin, 2, 4
tmp_w := m_width - 12
Gui, Add, Edit, x6 y28 w%tmp_w% h20 Section +Center Limit vMasterPass gCalculatePass hwndMP
SetEditCueBanner(MP, "Мастер-пароль")
Gui, Add, Edit, wp hp +Center Limit vStringID gCalculatePass hwndSID
SetEditCueBanner(SID, "Строка-идентификатор")
Gui, Add, Edit, wp hp +Center +ReadOnly vNewPass hwndNP
; Если длина конечного пароля скрывается, переменная `PHstate` не нужна.
PHstate := PlaceholderPass(NP)
; --- Прогресс-бар (ПБ) отображающий надёжность пароля.
; Стиль ПБ (Красный - Жёлтый - Зелёный).
PB_style=
(LTrim Join|
ff007f|ffff00|80ff00
)
; Рамка ПБ. Высота ПБ подобрана под 7 кегль гарнитуры Tahoma.
Gui, Add, Text, wp h11 0x8 +BackgroundTrans E0x20
; Контрол содержащий изображение ПБ.
Gui, Add, Picture, xp+1 yp+1 wp-2 hp-2 0x4E hwndPB_pic
; Информация о контроле Picture (координаты и размеры).
; - последний символ имени переменной говорит о том какую информацию нужно получить: x, y, w, h.
GuiControlGet, info_, Pos, %PB_pic%
; ? hBM - объект содержащий изображение ПБ. 3x1 размерность стиля ПБ.
hBM := CreateDIB(PB_style, 3, 1, info_w, info_h)
; Указание видимой части контрола Picture, расчитывается как процент от его ширины.
WinSet Region, 0-0 h9 w0, ahk_id %PB_pic%
; Текст с процентом надёжности пароля.
Gui, Font, s7 w1000
Gui, Add, Text, yp-1 wp h10 +Center +BackgroundTrans E0x20 vTxtPerc, % "0%"
Gui, Font, s8 w400
; Вывод изображения ПБ.
DllCall("SendMessage", UInt, PB_pic, UInt, 0x172, UInt, 0, UInt, hBM)
; --- Чекбокс `скрыть пароли`, кнопки копирования в буфер и завершения скрипта.
Gui, Add, CheckBox, xs+4 y+4 w100 h27 Checked%def_HidePass% Section vTogglePass gHideShowPass, Скрыть пароли
Gui, Add, Button, ys w234 hp gCopy2Buffer, Скопировать в буфер обмена
Gui, Add, Button, ys w100 hp vCloseApp gGuiClose, Выход
; --- GUI - Вкладка "Настройки" --------------------------------------------------------------------
Gui, Tab, Настройки
Gui, Margin, 2, 2
; --- Группа GUI настроек - 'Правила'.
Gui, Add, GroupBox, x5 y28 w310 h113, % " Правила"
Gui, Add, Text, xp+9 yp+21 w240 h20 Section, Длина генерируемого пароля
; Предотвращение ввода любых символов кроме цифр - `+Number`.
Gui, Add, Edit, x+0 yp-2 w52 h18 +Center +Number vToggleLen
; Значения забираются из `UpDown`, для предотвращение выхода значений за границы диапазона.
Gui, Add, UpDown, Range8-64 vLenPass, %def_LenPass%
Gui, Add, Text, xs w240 h20, Количество циклов шифрования
Gui, Add, Edit, x+0 yp-2 w52 h18 +Center +Number vToggleIter
Gui, Add, UpDown, Range1-9999 vIteration, %def_Iteration%
; Если указано 0, один и тот же набор будет использоваться подряд, неограниченное кол-во раз.
Gui, Add, Text, xs w240 h20, Максимум символов подряд, из одного набора
Gui, Add, Edit, x+0 yp-2 w52 h18 +Center +Number vToggleSet
Gui, Add, UpDown, Range0-4 vLimitSet, %def_LimitSet%
; Если указано 0, каждый символ допустимо использовать неограниченное кол-во раз.
Gui, Add, Text, xs w240 h20, Использовать каждый символ не больше
Gui, Add, Edit, x+0 yp-2 w52 h18 +Center +Number vToggleChar
Gui, Add, UpDown, Range0-4 vLimitChar, %def_LimitChar%
; --- Группа GUI настроек - 'Наборы символов'.
Gui, Add, GroupBox, x317 y28 w132 h113, % " Наборы символов"
Gui, Add, CheckBox, xp+9 yp+18 w58 h20 Section Checked%def_UpCase% vUpCase gLockGUI
, A...Z
Gui, Add, CheckBox, wp hp Checked%def_LowCase% vLowCase gLockGUI
, a...z
Gui, Add, CheckBox, ys wp hp Checked%def_Num% vNum gLockGUI
, 0...9
Gui, Add, CheckBox, wp hp Checked%def_ULine% vULine gLockGUI
, _
Gui, Add, CheckBox, xs w120 hp Checked%def_SpecSymbols% vSpecSymbols gLockGUI
, % "! @ # $ % ^ && * - +"
Gui, Add, CheckBox, wp hp Checked%def_Brackets% vBrackets gLockGUI
, % "( ) [ ] { } < >"
; --- GUI - Вкладка "О скрипте" --------------------------------------------------------------------
Gui, Tab, О скрипте
tmp_h -= 31
Gui, Add, Text, x6 y28 w%tmp_w% h%tmp_h%
, % "1Pass4All – генератор и анализатор надёжности паролей. Позволяет создавать слож-`n"
. "ные пароли, без необходимости запоминать их и хранить где-либо.`n`n"
. "Параметры группы 'Правила', сверху вниз (подробнее см.описание в тексте скрипта):`n"
. " - 1ый от 8 до 64.`n"
. " - 2ой от 0 до 4 (0 - неограниченно).`n"
. " - 3ий от 1 до 9999.`n"
. " - 4ый от 0 до 4 (0 - неограниченно)."
; --- GUI - Вывод интерфейса на экран --------------------------------------------------------------
Gui, Show, Center w%m_width% h%m_heigth%, %script_name%
; Установка фокуса на кнопку `Выход` сделан для того, чтобы при запуске скрипта, в полях для ввода
; мастер-пароля и строки-идентификатора были видны поясняющие надписи.
GuiControl, Focus, Выход
; см. описание к метке LockGUI. Здесь необходимо для деактивации элементов GUI, в зависимости от
; дефолтных настроек, сделанных пользователем.
goto LockGUI
Return
; --- GUI - Завершение работы скрипта --------------------------------------------------------------
GuiEscape: ; предопределённая метка, переход к которой происходит при нажатии клавиши ESC.
GuiClose: ; предопределённая метка, переход к которой происходит при закрытии окна скрипта.
ExitApp
; <<< GUI ------------------------------------------------------------------------------------------
Copy2Buffer:
if(calcpass != "")
Clipboard := calcpass
return
; --- Активация / Деактивация правил генератора в зависимости от количества наборов символов -------
; 0 - отключены все правила (пароль не генерируется)
; 1 - отключено ограничение на использование подряд одного и того же набора символов.
; 2 и более - все правила активны
LockGUI:
Gui, Submit, NoHide
; Перечисление наборов, которые будут использованы при создании пароля.
CheckedSet := [UpCase, LowCase, Num, ULine, SpecSymbols, Brackets]
; --- Подсчёт количества отмеченных наборов.
countSet := 0
while(countSet < 2 and A_Index <= checkedSet.length())
if(checkedSet[A_Index])
countSet++
; --- Активация / Деактивация правил генератора.
listControl := ["ToggleLen", "ToggleIter", "ToggleSet", "ToggleChar"]
if(countSet = 0)
toggle := [0, 0, 0, 0]
else if (countSet = 1)
toggle := [1, 1, 0, 1]
else
toggle := [1, 1, 1, 1]
loop % listControl.length()
GuiControl, % "Enable" . toggle[A_Index], % listControl[A_Index]
toggle := ""
; Необходимо для обновления состояния отображения, контролов `UpDown` на вкладке `Настройки`, при
; активации / деактивации группы настроек `Правила`.
WinSet, Redraw, , ahk_id %MainWin%
return
; --- Скрытие / Показ мастер-пароля и нового пароля ------------------------------------------------
HideShowPass:
Gui, Submit, NoHide
hide_pass(MP, TogglePass)
; Если нужно скрывать длину конечного пароля.
if(calcpass != "")
if(TogglePass)
{
hide_pass(NP, 1)
PlaceholderPass(NP, "БОЛЬШОЙСЕКРЕТ")
}
else
{
hide_pass(NP, 0)
PlaceholderPass(NP, calcpass)
}
else
{
hide_pass(NP, 0)
PlaceholderPass(NP)
}
; Если не нужно скрывать длину конечного пароля.
/*
if(!PHstate)
hide_pass(NP, TogglePass)
else
hide_pass(NP, 0)
*/
return
; --- Вычисление / Анализ пароля -------------------------------------------------------------------
CalculatePass:
Critical On
Gui Submit, NoHide
; Если нужно скрывать длину пароля.
if(TabName = "Генератор" and MasterPass != "" and StringID != "")
{
calcpass := passgen(MasterPass, StringID, Iteration, LenPass, CheckedSet, LimitSet, LimitChar)
pass_score := pwdmeter2(calcpass)
GuiControl, , TxtPerc, % pass_score . "%"
WinSet Region, % "0-0 h9 w" . info_w * pass_score // 100, ahk_id %PB_pic%
}
else
{
calcpass := ""
GuiControl, , TxtPerc, % "0%"
WinSet Region, 0-0 h9 w0, ahk_id %PB_pic%
}
; Если не нужно скрывать длину пароля.
/*
if(MasterPass != "" and StringID != "")
{
calcpass := passgen(MasterPass, StringID, Iteration, LenPass, CheckedSet, LimitSet, LimitChar)
PHstate := PlaceholderPass(NP, calcpass)
}
else
PHstate := PlaceholderPass(NP)
*/
goto HideShowPass
return
; >>> Функции --------------------------------------------------------------------------------------
; --- Функции - Свои -------------------------------------------------------------------------------
PlaceholderPass(hID, str = "")
; Текст подсказки и вывод готового пароля.
{
if(str = "")
{
Gui, Font, c0xA0A0A0
GuiControl, Font, %hID%
GuiControl, , %hID%, Ваш новый пароль
Gui, Font, cBlack
return true
}
else
{
Gui, Font, cBlack
GuiControl, Font, %hID%
GuiControl, , %hID%, %str%
return false
}
}
hide_pass(hID, state)
; Скрытие / Показ пароля.
{
; `9679` юникод символа `•` в гарнитуре Tahoma.
GuiControl, % state ? "+Password" . CHR(9679) : "-Password", % hID
WinSet, Redraw, , ahk_id %hID%
}
passgen(master, str_id, iter, len_p, sel_set, lim_set, lim_char)
; Функция, конвертирующая строку, состоящую из символов 16-ичной системы счисления - в строку,
; состоящую из символов, входящих в указанные наборы.
;
; master - мастер-пароль.
; str_id - строка идентификатор.
; iter - кол-во циклов шифрования.
; len_p - длина пароля.
; sel_set - выбранные наборы символов для создания пароля.
; lim_set - сколько раз подряд, допустимо использовать один и тот же набор символов, 0 - неограничено.
; lim_char - сколько раз допустимо использовать один и тот же символ, 0 - неограничено.
{
full_set := ["ABCDEFGHIJKLMNOPQRSTUVWXYZ"
, "abcdefghijklmnopqrstuvwxyz"
, "1234567890"
, "_"
, "!@#$%^&*-+"
, "()[]{}<>"]
; Наборы выбранные для создания пароля.
use_set := []
pass_out := ""
; --- Создание `рабочего` набора.
loop % sel_set.length()
if(sel_set[A_Index])
; `id_set` см. ниже, секцию комментариев `--- Символ найден`
use_set.Push(["id_set" . (use_set.length() + 1) , full_set[A_Index]])
; Если выбран хотя бы один набор - инициализация начальных значений, в противном случае - выход.
if(use_set.length())
{
; Информация о символах в пароле, необходима для исключения повторов символов.
char_in_pass := {}
; Остановка обработки пароля, если колво наборов равно 0 или
; если набор остался 1, а для формирования пароля было выбрано 2 и более.
stop_proc := false
; Расчёт `заготовки` пароля (строка - состоит из символов 16-ричной системы счисления).
; Допустимые значения алгоритма шифрования : MD5, SHA1, SHA256, SHA384, SHA512.
pass_in := PBKDF2(master, str_id, iter, len_p * 2, "SHA256")
; Снятие ограничений с наборов, если указано 0 или кол-во используемых наборов равно 1.
if(lim_set == 0 or use_set.length() == 1)
lim_set := len_p
; Снятие ограничений с символов, если указано 0
if(lim_char == 0)
lim_char := len_p
}
else
stop_proc := true
;--- Обработка пароля блоками по 4 символа.
while(A_Index <= len_p and !stop_proc)
{
block := SubStr(pass_in, A_Index * 4 - 3, 4)
; 1, 2 символы - номер набора.
cur_set := "0x" . SubStr(block, 1, 2)
; 3, 4 символы - номер символа в наборе.
cur_char := "0x" . SubStr(block, 3, 2)
char_found := false
while(!char_found and !stop_proc)
{
; Масштабирование номера набора и переход к следующему набору (+1), если текущий набор
; не подходит.
cur_set := Mod(cur_set, use_set.length()) + 1
if(cur_set != prev_set)
; Счётчик символов из одного и того же набора, если последовательность не прервана
; другим набором.
count_set := 0
if(count_set >= lim_set)
{
if(use_set.MaxIndex() <= 1)
stop_proc := true
}
else
{
; --- Символ найден.
char_found := true
prev_set := cur_set
count_set++
cur_char := SubStr(use_set[cur_set, 2], Mod(cur_char, StrLen(use_set[cur_set, 2])) + 1, 1)
pass_out .= cur_char
; `id_set` + #набора + #символа - необходимо для того, чтобы разтличать символы верхнего
; и нижнего регистра (т.к. ключи ассоциативного массива не чувствительны к регистру).
if(char_in_pass.HasKey(use_set[cur_set, 1] . cur_char))
char_in_pass[use_set[cur_set, 1] . cur_char]++
else
char_in_pass.Insert(use_set[cur_set, 1] . cur_char, 1)
if(char_in_pass[use_set[cur_set, 1] . cur_char] >= lim_char)
use_set[cur_set, 2] := StrReplace(use_set[cur_set, 2], cur_char)
if(StrLen(use_set[cur_set, 2]) == 0)
use_set.RemoveAt(cur_set)
if(use_set.length() == 0)
stop_proc := true
}
}
}
return pass_out
}
pwdmeter2(pass)
; AHK-реализация измерителя надёжности паролей - www.passwordmeter_com.
; версия: 0.02
; Отличия от оригинала, в оригинальной версии:
; 1. символ подчёркивания `_` не учитывается.
; - т.к. оригинал не учитывает символ подчёркивания.
; - неверно составлено условие проверок - (пароль `состоит только из букв` / `состоит только из цифр`).
; > как следствие для паролей состоящих из `A-Z` и `_` или `0-9` и `_`
; например FN_D_Y, 49_13_7
; может возникнуть ложное предположение о том, что пароль состоит только из букв или цифр.
; 2. не обнаруживаются последовательности xyz / zyx, из-за занижения на 1 в условии.
{
score := 0
if(StrLen(pass))
{
; --- Инициализация начальных значений -----------------------------------------------------
; Можно затолкать в массив, но удобнее использовать переменные со значащими именами.
test_UpCase := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
test_LowCase := "abcdefghijklmnopqrstuvwxyz"
test_Num := "0123456789"
test_Symbol := "!@#$%^&*()"
; Набор, к которому принадлежал предыдущий символ.
prev_testSet := ""
; --- Бонусы, процент надёжности растёт.
; Полная длина тестируемого пароля.
f_len_pass := StrLen(pass)
; В оригинальной версии из пароля удаляются не только пробелы.
pass := StrReplace(pass, A_Space)
; Длина пароля без пробелов.
ws_len_pass := StrLen(pass)
; Колво символов верхнего регистра A-Z.
count_UpCase := 0
; Колво символов нижнего регистра a-z.
count_LowCase := 0
; Колво цифр.
count_Num := 0
; Колво всех остальных символов.
count_Symbol := 0
; Колво символов + цифр в середине пароля, т.е 1ый и последний символы пароля, в счёт не идут.
count_MidNS := 0
; Какому количеству требований соответствует пароль:
; - минимальная длина 8 символов.
; - содержит любые символы верхнего регистра A-Z.
; - содержит любые символы нижнего регистра a-z.
; - содержит любые цифры.
; - содержит любые символы (не A-Z, a-z, 0-9), кроме ` `.
count_Req := 0
; --- Штрафы, процент надёжности падает.
; Если в пароле только символы верхнего и нижнего регистра, равно длине пароля.
coutn_OnlyLet := 0
; Если в пароле только цифры, равно длине пароля.
coutn_OnlyNum := 0
; Колво всех одинаковых символов.
count_RepChar := 0
; Разница расстояний между двумя идентичными символами, делённая на длину пароля.
; Суммируется когда встречает пару.
; ! чем дальше отстоят друг от друга символы, тем меньше штраф.
RepInc := 0
; Колво повторных, последовательных использований:
; - набора с символами верхнего регистра. (пример absdf, колво 4)
count_ConUpCase := 0
; - набора с символами нижнего регистра.
count_ConLowCase := 0
; - набора с цифрами.
count_ConNum := 0
; Колво символов A-Z, позиции которых (в алфавите) последовательно возрастают или убывают.
; (пример ABCDF, IHGFE).
; ! не чувствительно к регистру символов.
; ! учитываются последовательности длинной от 3х символов включительно.
count_SeqLetter := 0
; Аналогично для цифр.
count_SeqNum := 0
; Аналогично для символов сопоставленных цифрам 0-9, вверху клавиатуры.
count_SeqSym := 0
; --- Сбор информации о пароле - Подсчёт:
; колва символов `count_UpCase`, `count_LowCase`, `count_Num`, `count_Symbol`.
; колва последовательностей `count_ConUpCase`, `count_ConLowCase`, `count_ConNum`, `count_MidNS`.
; повторяющихся символов `count_RepChar`, `RepInc`.
loop, Parse, pass
{
if(InStr(test_UpCase, A_LoopField, true))
{
count_UpCase++
if(prev_testSet = "UpCase")
count_ConUpCase++
prev_testSet := "UpCase"
}
else if(InStr(test_LowCase, A_LoopField))
{
count_LowCase++
if(prev_testSet = "LowCase")
count_ConLowCase++
prev_testSet := "LowCase"
}
else if(InStr(test_Num, A_LoopField))
{
count_Num++
if(A_Index > 1 and A_Index < ws_len_pass)
count_MidNS++
if(prev_testSet = "Num")
count_ConNum++
prev_testSet := "Num"
}
else ;if(A_LoopField != "_") ; в оригинале присутствует.
{
count_Symbol++
if(A_Index > 1 and A_Index < ws_len_pass)
count_MidNS++
prev_testSet := "Symbol"
}
; --- Сбор информации о пароле - Повторы символов `count_RepChar` и штраф за повторы `RepInc`.
char_index := A_Index
char_value := A_LoopField
CharExists := false
loop, Parse, pass
if(char_value == A_LoopField and char_index != A_Index)
{
CharExists := true
RepInc += Abs(ws_len_pass / (A_Index - char_index))
}
if(CharExists)
{
count_RepChar++
UnqChar := ws_len_pass - count_RepChar
RepInc := UnqChar ? Ceil(RepInc / UnqChar) : Ceil(RepInc)
}
}
; --- Подсчёт `count_Req` скольким требованиям удовлетворяет пароль.
if(f_len_pass >= 8)
count_Req++
if(count_UpCase)
count_Req++
if(count_LowCase)
count_Req++
if(count_Num)
count_Req++
if(count_Symbol)
count_Req++
; --- Возрастающие / убывающие последовательности символов.
loop % StrLen(test_UpCase) - 2
{
forward_str := SubStr(test_UpCase, A_Index, 3)
backward_str := StrReverse(forward_str)
if(InStr(pass, forward_str) or InStr(pass, backward_str))
count_SeqLetter++
}
loop % StrLen(test_Num) - 2
{
forward_str := SubStr(test_Num, A_Index, 3)
backward_str := StrReverse(forward_str)
if(InStr(pass, forward_str) or InStr(pass, backward_str))
count_SeqNum++
}
loop % StrLen(test_Symbol) - 2
{
forward_str := SubStr(test_Symbol, A_Index, 3)
backward_str := StrReverse(forward_str)
if(InStr(pass, forward_str) or InStr(pass, backward_str))
count_SeqSym++
}
; --- Общий счёт - Бонусы.
score := f_len_pass * 4
if(count_UpCase > 0 and count_UpCase < f_len_pass)
score += (f_len_pass - count_UpCase) * 2
if(count_LowCase > 0 and count_LowCase < f_len_pass)
score += (f_len_pass - count_LowCase) * 2
if(count_Num > 0 and count_Num < f_len_pass)
score += count_Num * 4
score += count_Symbol * 6
score += count_MidNS * 2
if(count_Req > (f_len_pass >= 8 ? 3 : 4))
score += count_Req * 2
; --- Общий счёт - Штрафы.
; Если пароль состоит только из символов A-Z (регистр не важен).
count_OnlyLet := 0
if(count_UpCase + count_LowCase = f_len_pass)
{
score -= f_len_pass
count_OnlyLet := f_len_pass
}
; Если пароль состоит только из цифр.
count_OnlyNum := 0
if(count_Num = f_len_pass)
{
score -= f_len_pass
count_OnlyNum := f_len_pass
}
if(count_RepChar)
score -= RepInc
score -= count_ConUpCase * 2
score -= count_ConLowCase * 2
score -= count_ConNum * 2
score -= count_SeqLetter * 3
score -= count_SeqNum * 3
score -= count_SeqSym * 3
if(score < 0)
score := 0
if(score > 100)
score := 100
}
return score
}
StrReverse(str)
; Реверс строки.
{
loop, Parse, str
str_rev := A_LoopField . str_rev
return str_rev
}
; --- Функции - Сторонние --------------------------------------------------------------------------
SetEditCueBanner(hID, Cue)
; Текст-подсказка в контроле Edit
; - альтернатива (На ANSI версии не работает.)
; SendMessage, 0x1501, 0, "ТЕКСТ_ПОДСКАЗКИ",, ahk_id %ID_КОНТРОЛА%
{
Static EM_SETCUEBANNER := 0x1501
Return DllCall("User32.dll\SendMessageW", "Ptr", hID, "Uint", EM_SETCUEBANNER, "Ptr", True, "WStr", Cue)
}
CreateDIB(PixelData, W, H, ResizeW = 0, ResizeH = 0, Gradient = 1)
; Создание растровых изображений в контроле Picture.
; - автор: SKAN
; - ahkscript_org/boards/viewtopic.php?t=3203
{
WB := Ceil((W * 3) / 2) * 2, VarSetCapacity(BMBITS, WB * H + 1, 0)
P := &BMBITS
Loop, Parse, PixelData, |
P := Numput("0x" A_LoopField, P + 0) - (W & 1 && !Mod(A_Index * 3, W * 3) ? 0 : 1)
hBM := DllCall("CreateBitmap", Int, W, Int, H, UInt, 1, UInt, 24, UInt, 0)
hBM := DllCall("CopyImage", UInt, hBM, Int, 0, Int, 0, Int, 0, UInt, 0x2008)
DllCall("SetBitmapBits", UInt, hBM, UInt, WB * H, UInt, &BMBITS)
hBM := !Gradient ? DllCall("CopyImage", UInt, hBM, UInt, 0, Int, 0, Int, 0, Int, 8 ) : hBM
Return DllCall("CopyImage", UInt, hBM, Int, 0, Int, ResizeW, Int, ResizeH, Int, 0x200C, UInt)
}
; AutoHotkey Version: AutoHotkey 1.1
; Language: English
; Platform: Win7 SP1
; Author: Antonio Bueno <user atnbueno at Google's free e-mail service>
; Description: Implementation of PBKDF2 using MS-CAPI HMACs
; Last Modification: 2014-05-03
PBKDF2(sPassword, sSalt, nIterations = 10000, nLength = 0, sAlgo = "SHA1")
; Calculates PBKDF2 for a (password, salt) pair that can be either an UTF-8-encoded string or an hex
; string. Optional parameters are the number of iterations, the output length and the hash algorithm.
; It depends on the functions below (Wide2UTF8, Hex2Bin, RawPBKDF2, and Bin2Hex)
{
global aHashAlgid, aHashLength
; Basic error checking
If (nIterations <= 0)
Throw "PBKDF2 ERROR: Invalid number of iterations (" nIterations ")"
If (aHashAlgid[sAlgo] = "")
Throw "PBKDF2 ERROR: Unknown hash function (" sALgo ")"
; Prepares parameters for RawPBKDF2
If (nLength = 0)
nLength := aHashLength[sAlgo]
; sPassword and sSalt can be either an UTF-8-encoded string or an hex string
If (!RegExMatch(sPassword, "i)^([0-9A-F][0-9A-F])+$"))
nPassword := Wide2UTF8(sPassword, Password)
else
nPassword := Hex2Bin(sPassword, Password)
If (!RegExMatch(sSalt, "i)^([0-9A-F][0-9A-F])+$"))
nSalt := Wide2UTF8(sSalt, Salt)
else
nSalt := Hex2Bin(sSalt, Salt)
; Calculates PBKDF2
RawPBKDF2(Password, nPassword, Salt, nSalt, nIterations, Output, nLength, sAlgo)
; Outputs result in hexadecimal format
Return Bin2Hex(Output, nLength)
}
RawPBKDF2(ByRef Password, nPassword, ByRef Salt, nSalt, nIterations, ByRef Output, nOutput, sAlgo)
{
global aHashAlgid, aHashLength
; MS-CAPI constants used to do HMACs
CALG_HMAC := 0x8009
CALG_RC2 := 0x6602
CRYPT_IPSEC_HMAC_KEY := 0x0100
CRYPT_VERIFYCONTEXT := 0xF0000000
CUR_BLOB_VERSION := 0x02
HP_HASHVAL := 0x02
HP_HMAC_INFO := 0x05
PLAINTEXTKEYBLOB := 0x08
PROV_RSA_FULL := 0x01
; Reserves memory for hashing and XORing and storing the final result
VarSetCapacity(Hash, Ceil(aHashLength[sAlgo] / 8) * 8, 0)
VarSetCapacity(XORSum, Ceil(aHashLength[sAlgo] / 8) * 8, 0)
nBlockCount := Ceil(nOutput / aHashLength[sAlgo])
VarSetCapacity(Output, aHashLength[sAlgo] * nBlockCount, 0)
; If the output is not longer than the specified hash the following loop does a single iteration
Loop % nBlockCount
{
; The block count must be stored as an INT32_BE (the expression below is OK up to a block count of 255)
nHash := Hex2Bin(Bin2Hex(Salt, nSalt) "000000" Bin2Hex(Chr(A_Index), 1), Hash)
VarSetCapacity(HmacInfo, 4 * A_PtrSize, 0)
NumPut(aHashAlgid[sAlgo], HmacInfo, 0, "UInt") ; Selects hashing algorithm and default padding
nKeyBlobSize := 12 + nPassword
VarSetCapacity(keyBlob, nKeyBlobSize, 0)
NumPut(PLAINTEXTKEYBLOB, keyBlob, 0, "Char")
NumPut(CUR_BLOB_VERSION, keyBlob, 1, "Char")
NumPut(CALG_RC2, keyBlob, 4, "UInt")
NumPut(nPassword, keyBlob, 8, "Char")
DllCall("RtlMoveMemory", "UInt", &keyBlob + 12, "UInt", &Password, "Int", nPassword)
DllCall("advapi32\CryptAcquireContext", "UIntP", hProv, "UInt", 0, "UInt", 0, "UInt", PROV_RSA_FULL, "UInt", CRYPT_VERIFYCONTEXT)
DllCall("advapi32\CryptImportKey", "UInt", hProv, "UInt", &keyBlob, "UInt", nKeyBlobSize, "UInt", 0, "UInt", CRYPT_IPSEC_HMAC_KEY, "UIntP", hKey)
; Iteration zero
DllCall("advapi32\CryptCreateHash", "UInt", hProv, "UInt", CALG_HMAC, "UInt", hKey, "UInt", 0, "UIntP", hHmacHash)
DllCall("advapi32\CryptSetHashParam", "UInt", hHmacHash, "UInt", HP_HMAC_INFO, "UInt", &HmacInfo, "UInt", 0)
DllCall("advapi32\CryptHashData", "UInt", hHmacHash, "UInt", &Hash, "UInt", nHash, "UInt", 0)
DllCall("advapi32\CryptGetHashParam", "UInt", hHmacHash, "UInt", HP_HASHVAL, "UInt", &XORSum, "UIntP", aHashLength[sAlgo], "UInt", 0)
DllCall("advapi32\CryptDestroyHash", "UInt", hHmacHash)
DllCall("RtlMoveMemory", "UInt", &Hash, "UInt", &XORSum, "Int", aHashLength[sAlgo])
; End of iteration zero
Loop % nIterations-1
{
DllCall("advapi32\CryptCreateHash", "UInt", hProv, "UInt", CALG_HMAC, "UInt", hKey, "UInt", 0, "UIntP", hHmacHash)
DllCall("advapi32\CryptSetHashParam", "UInt", hHmacHash, "UInt", HP_HMAC_INFO, "UInt", &HmacInfo, "UInt", 0)
DllCall("advapi32\CryptHashData", "UInt", hHmacHash, "UInt", &Hash, "UInt", aHashLength[sAlgo], "UInt", 0)
DllCall("advapi32\CryptGetHashParam", "UInt", hHmacHash, "UInt", HP_HASHVAL, "UInt", &Hash, "UIntP", aHashLength[sAlgo], "UInt", 0)
DllCall("advapi32\CryptDestroyHash", "UInt", hHmacHash)
; XOR is done in 64-bit (8-byte) blocks (smaller blocks make the XORing significantly slower)
Loop % Ceil(aHashLength[sAlgo] / 8)
{
nOffset := (A_Index - 1) * 8
NumPut(NumGet(XORSum, nOffset, "Int64") ^ NumGet(Hash, nOffset, "Int64"), &XORSum, nOffset, "Int64")
}
}
DllCall("advapi32\CryptDestroyKey", "UInt", hKey)
DllCall("advapi32\CryptReleaseContext", "UInt", hProv, "UInt", 0)
DllCall("RtlMoveMemory", "UInt", &Output+(A_Index-1)*aHashLength[sAlgo], "UInt", &XORSum, "Int", aHashLength[sAlgo])
}
}
Wide2UTF8(sInput, ByRef Output)
{
nOutputSize := StrPut(sInput, "UTF-8")
VarSetCapacity(Output, nOutputSize)
StrPut(sInput, &Output, nOutputSize, "UTF-8")
Return nOutputSize-1
}
Bin2Hex(ByRef Input, nInput)
{
sIntegerFormat := A_FormatInteger
SetFormat Integer, H
Loop % nInput
sOutput .= SubStr(*(&Input + A_Index - 1) + 0x100, -1)
SetFormat Integer, % sIntegerFormat
Return sOutput
}
Hex2Bin(sInput, ByRef Output)
{
VarSetCapacity(Output, StrLen(sInput) // 2)
Loop % StrLen(sInput) // 2
NumPut("0x" . SubStr(sInput, 2 * A_Index - 1, 2), Output, A_Index - 1, "Char")
Return StrLen(sInput) // 2
}
; <<< Функции --------------------------------------------------------------------------------------