<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<title type="html"><![CDATA[Серый форум &mdash; AHK: Генератор паролей, ревизия кода.]]></title>
	<link rel="self" href="https://forum.script-coding.com/extern.php?action=feed&amp;tid=10872&amp;type=atom" />
	<updated>2017-05-31T00:46:59Z</updated>
	<generator>PunBB</generator>
	<id>https://forum.script-coding.com/viewtopic.php?id=10872</id>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=116255#p116255" />
			<content type="html"><![CDATA[<p><strong>Stremin</strong><br />А чем дело закончилось? <br />Дописал скрипт или нет?</p><p>Открытых протоколов генерации паролей много... могу штук 5 - 7 дать, но проблема в том, что они открыты, а значит придется вспоминать(мне)/изучать <strong>криптологию</strong> и <strong>криптоанализ</strong>.</p><p>Я просто не хочу всё писать с &quot;нуля&quot;, но я так сказать лицо заинтересованное.</p>]]></content>
			<author>
				<name><![CDATA[Indomito]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=27285</uri>
			</author>
			<updated>2017-05-31T00:46:59Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=116255#p116255</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96518#p96518" />
			<content type="html"><![CDATA[<p><strong>Stremin</strong>, подобное общение с модератором уже не раз приводило к быстрому бану участника. Надеюсь, намёк понят, и ирония здесь отсутствует.</p>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2015-08-17T12:36:31Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96518#p96518</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96517#p96517" />
			<content type="html"><![CDATA[<p>Ещё раз, всем большое спасибо, за потраченное на меня время. В целом думаю на этом, обсуждение можно закруглить.</p><p>PS <strong>teadrinker</strong> согласно правилам данного ресурса п.2.1, 2.6, ваше сообщение никак не относится к обсуждаемой теме, т.е. является оффтопом. Вы сами себя забаните?</p>]]></content>
			<author>
				<name><![CDATA[Stremin]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=33282</uri>
			</author>
			<updated>2015-08-17T12:32:54Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96517#p96517</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96514#p96514" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>Stremin пишет:</cite><blockquote><p>Сожалею отсутствию у вас чувства иронии.</p></blockquote></div><p>Ну, ирония бывает разного качества, как и код. Особенно это заметно, когда человек пытается иронизировать на темы, в которых мало что понимает.</p>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2015-08-17T11:57:07Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96514#p96514</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96512#p96512" />
			<content type="html"><![CDATA[<p><strong>Irbis</strong><br />Огромное спасибо за весьма ценные конструктивные замечания.<br />Смена пароля, действительно `узкое место` данного решения. И хотя мне крайне не хотелось хранить пароли, в каком бы то ни было виде, без этого видимо не обойтись.</p><p><strong>teadrinker</strong><br />Сожалею отсутствию у вас чувства иронии. Её дефицит является серьёзным барьером для взаимопонимания.<br />За совет `заняться чем попроще`, спасибо. В благодарность хотел бы дать и вам совет: советую не советовать такие советы, особенно тогда, когда преследуемый результат получен. Чаще всего они пропадут втуне.</p>]]></content>
			<author>
				<name><![CDATA[Stremin]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=33282</uri>
			</author>
			<updated>2015-08-17T11:32:18Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96512#p96512</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96507#p96507" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>Stremin пишет:</cite><blockquote><p>скрипт писался в первую очередь для знакомства с AHK ...<br />То есть, если хендлы будут иметь размерность Ptr, не будет видно, что функции позаимствованы с офф.форума?</p></blockquote></div><p>Нет смысла начинать знакомиться с AHK с того, в чём не разобрались. Это всё равно, что начинать знакомиться с математикой с интегралов. Советую взяться за что-нибудь попроще.</p><p>Если размерность указана неверно, то нет гарантии, что всё сработает правильно на 64-битных версиях интерпретатора.</p>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2015-08-17T10:31:36Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96507#p96507</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96501#p96501" />
			<content type="html"><![CDATA[<p>Ну что же, раз звезды зажигают... (с).<br />Я, правда, потом отказался от развития программы, в пользу встроенного в браузер управления паролями. Несколько заметок по организации работы с программой, с точки зрения эргономики:<br /></p><ul><li><p>Так как мастер-пароль вводится один раз, можно не держать для него отдельное поле ввода, а забивать один раз при запуске скрипта.</p></li><li><p>Сбрасывать и требовать повторного ввода мастер-пароля - по команде/хоткею или по таймауту, если юзер больше нескольких минут Away from computer. (в целях безопасности).</p></li><li><p><em>Строка-идентификатор</em>, как я понимаю, чаще всего ассоциируется с названием сайта, поэтому лучше, если программа по хоткею будет из названия активной вкладки браузера извлекать строку вида www.***.com и вводить сгенерированный пароль в предназначенное для этого поле. Для остальных программ тоже подойдет. В таком случае не будет потребности вводить что-то каждый раз.</p></li><li><p>Некоторые сайты принудительно просят поменять пароль через определенное время, да и вообще это хорошее правило. Для каждого пароля можно задать время его жизни, и к примеру, раз в полгода напоминать о необходимости смены пароля.</p></li></ul><p>По поводу последнего пункта, получится не совсем чистый генератор &quot;на лету&quot;, так как сроки окончания паролей все равно надо хранить. Впрочем, их тоже можно зашифровать с помощью главного пароля.</p>]]></content>
			<author>
				<name><![CDATA[Irbis]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=27384</uri>
			</author>
			<updated>2015-08-17T07:34:08Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96501#p96501</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96499#p96499" />
			<content type="html"><![CDATA[<div class="quotebox"><cite>serzh82saratov пишет:</cite><blockquote><p>...зачем в принципе такой пароль, который потом и не нужен?...</p></blockquote></div><p>1. Затем, что снова введя те же мастер-пароль и строку-идентификатор, вы снова получите прежний пароль.<br />2. В приложении PWGen, есть схожий функционал `Инструменты &gt; Генератор мастер паролей`. Стало быть, если реализовано, значит кому-то нужно и кто-то пользуется.<br />3. www.pwdhash.com - схожая идея, академическая разработка Стенфордского университета.</p><p>Замечание к 2 и 3, нет аналогичных возможностей настраивать получаемый пароль.</p><div class="quotebox"><cite>teadrinker пишет:</cite><blockquote><p>...для достаточно сложного пароля, достаточно просто потыкать по клавиатуре...</p></blockquote></div><p>Вы потыкали по клавиатуре, и получили что-нибудь подобное `!y?G@v%)_POQ(+;%`, вы запомните такую комбинацию?...</p><p>В предлагаемом решении вы вводите:<br /></p><div class="codebox"><pre><code>Мастер-пароль - `СЕКРЕТНЫЙ_ПАРОЛЬ`.
Идентификатор - `СЕРЫЙ_ФОРУМ`.
Получаете - `#(h6&amp;AaWnI_]Y}kQ`.</code></pre></div><p>ИМХО, `СЕКРЕТНЫЙ_ПАРОЛЬ` и `СЕРЫЙ_ФОРУМ` запомнить гораздо легче. Впрочем, я согласен, такой вариант подойдёт не во всех ситуациях. Кроме того, касательно полезности, скрипт писался в первую очередь для знакомства с AHK. Полезность приложения стояла на втором плане.</p><div class="quotebox"><cite>teadrinker пишет:</cite><blockquote><p>...Хендлы в api-функциях должны иметь размерность Ptr, а не UInt, иначе видно, что всё просто передрано с постов офф. форума...</p></blockquote></div><p>Спасибо, за полезное замечание и за то что посмотрели код. Искренне, спасибо.<br />То есть, если хендлы будут иметь размерность Ptr, не будет видно, что функции позаимствованы с офф.форума? <img src="//forum.script-coding.com/img/smilies/smile.png" width="15" height="15" /></p><div class="quotebox"><cite>teadrinker пишет:</cite><blockquote><p>...Куда более полезно приложение для их хранения в зашифрованном виде и с организацией удобного доступа...</p></blockquote></div><p>Действительно, это так, и такие приложения к счастью уже существуют. Но, о них мне стало известно, только, во время&nbsp; написания генератора. Повторять функционал даже частично не имело смысла, но процесс уже пошёл и бросать его, мне не очень хотелось.</p>]]></content>
			<author>
				<name><![CDATA[Stremin]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=33282</uri>
			</author>
			<updated>2015-08-17T06:37:15Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96499#p96499</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96488#p96488" />
			<content type="html"><![CDATA[<p>Хендлы в api-функциях должны иметь размерность <em>Ptr</em>, а не <em>UInt</em>, иначе видно, что всё просто передрано с постов офф. форума времён ahk-basic. Кроме того, необходимость приложения, генерирующего пароли, имхо, стремится к нулю, т. к. для генерации достаточно сложного пароля достаточно просто потыкать по клавиатуре. Куда более полезно приложение для их хранения в зашифрованном виде и с организацией удобного доступа (по присвоенным меткам, с доп. информацией и т. п.).</p>]]></content>
			<author>
				<name><![CDATA[teadrinker]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=24515</uri>
			</author>
			<updated>2015-08-16T22:26:45Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96488#p96488</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[Re: AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96487#p96487" />
			<content type="html"><![CDATA[<div class="quotebox"><blockquote><p>Генератор позволяет создавать сложные пароли, без необходимости запоминать их и хранить где-либо.</p></blockquote></div><p>Не знаю зачем были те 2 темы, но зачем в принципе такой пароль, который потом и не нужен?</p>]]></content>
			<author>
				<name><![CDATA[serzh82saratov]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=27879</uri>
			</author>
			<updated>2015-08-16T20:50:31Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96487#p96487</id>
		</entry>
		<entry>
			<title type="html"><![CDATA[AHK: Генератор паролей, ревизия кода.]]></title>
			<link rel="alternate" href="https://forum.script-coding.com/viewtopic.php?pid=96486#p96486" />
			<content type="html"><![CDATA[<p>Приветствую завсегдатаев Серого Форума! Ради освоения AHK, написал генератор паролей. В целом, он является дальнейшим развитием генератора из <a href="http://forum.script-coding.com/viewtopic.php?id=7586">этой темы</a>. Прошу, кому не трудно, провести ревизию кода. Для выявления явных или не очень ошибок.</p><div class="codebox"><pre><code>
; Версия 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

; &gt;&gt;&gt; Настройки генератора по умолчанию менять здесь -----------------------------------------------
; !!! ВНИМАНИЕ: Если не указано, корректность вводимых значений не проверяется !!!

; Скрывать пароль или нет.
;    допустимое значение: 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        ; спецсимволы ! @ # $ % ^ &amp; * - +
def_Brackets := false            ; скобки ( ) [ ] { } &lt; &gt;

; &lt;&lt;&lt; Настройки генератора по умолчанию ------------------------------------------------------------

; &gt;&gt;&gt; Настройки скрипта ----------------------------------------------------------------------------
script_name := &quot;1Pass4All v0.02-6&quot;
; Дефолтные ширина 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}

; &lt;&lt;&lt; Настройки скрипта ----------------------------------------------------------------------------

; &gt;&gt;&gt; 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 - Вкладка &quot;Генератор&quot; --------------------------------------------------------------------
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, &quot;Мастер-пароль&quot;)

Gui, Add, Edit, wp hp +Center Limit vStringID gCalculatePass hwndSID
SetEditCueBanner(SID, &quot;Строка-идентификатор&quot;)

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, % &quot;0%&quot;
Gui, Font, s8 w400

; Вывод изображения ПБ.
DllCall(&quot;SendMessage&quot;, 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 - Вкладка &quot;Настройки&quot; --------------------------------------------------------------------
Gui, Tab, Настройки
Gui, Margin, 2, 2

; --- Группа GUI настроек - &#039;Правила&#039;.
Gui, Add, GroupBox, x5 y28 w310 h113, % &quot; Правила&quot;

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 настроек - &#039;Наборы символов&#039;.
Gui, Add, GroupBox, x317 y28 w132 h113, % &quot; Наборы символов&quot;

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
    , % &quot;! @ # $ % ^ &amp;&amp; * - +&quot;
Gui, Add, CheckBox, wp hp Checked%def_Brackets% vBrackets gLockGUI
    , % &quot;( ) [ ] { } &lt; &gt;&quot;

; --- GUI - Вкладка &quot;О скрипте&quot; --------------------------------------------------------------------
Gui, Tab, О скрипте

tmp_h -= 31
Gui, Add, Text, x6 y28 w%tmp_w% h%tmp_h%
        , % &quot;1Pass4All – генератор и анализатор надёжности паролей. Позволяет создавать слож-`n&quot;
        . &quot;ные пароли, без необходимости запоминать их и хранить где-либо.`n`n&quot;
        . &quot;Параметры группы &#039;Правила&#039;, сверху вниз (подробнее см.описание в тексте скрипта):`n&quot;
        . &quot;   - 1ый от 8 до 64.`n&quot;
        . &quot;   - 2ой от 0 до 4 (0 - неограниченно).`n&quot;
        . &quot;   - 3ий от 1 до 9999.`n&quot;
        . &quot;   - 4ый от 0 до 4 (0 - неограниченно).&quot;

; --- GUI - Вывод интерфейса на экран --------------------------------------------------------------
Gui, Show, Center w%m_width% h%m_heigth%, %script_name%
; Установка фокуса на кнопку `Выход` сделан для того, чтобы при запуске скрипта, в полях для ввода
;     мастер-пароля и строки-идентификатора были видны поясняющие надписи.
GuiControl, Focus, Выход

; см. описание к метке LockGUI. Здесь необходимо для деактивации элементов GUI, в зависимости от 
;    дефолтных настроек, сделанных пользователем.
goto LockGUI

Return

; --- GUI - Завершение работы скрипта --------------------------------------------------------------
GuiEscape:    ; предопределённая метка, переход к которой происходит при нажатии клавиши ESC.
GuiClose:    ; предопределённая метка, переход к которой происходит при закрытии окна скрипта.
ExitApp

; &lt;&lt;&lt; GUI ------------------------------------------------------------------------------------------

Copy2Buffer:

    if(calcpass != &quot;&quot;)
        Clipboard := calcpass

    return

; --- Активация / Деактивация правил генератора в зависимости от количества наборов символов -------
; 0 - отключены все правила (пароль не генерируется)
; 1 - отключено ограничение на использование подряд одного и того же набора символов.
; 2 и более - все правила активны
LockGUI:
    Gui, Submit, NoHide
    
    ; Перечисление наборов, которые будут использованы при создании пароля.
    CheckedSet := [UpCase, LowCase, Num, ULine, SpecSymbols, Brackets]
    
    ; --- Подсчёт количества отмеченных наборов.
    countSet := 0
    
    while(countSet &lt; 2 and A_Index &lt;= checkedSet.length())
        if(checkedSet[A_Index])
            countSet++

    ; --- Активация / Деактивация правил генератора.
    listControl := [&quot;ToggleLen&quot;, &quot;ToggleIter&quot;, &quot;ToggleSet&quot;, &quot;ToggleChar&quot;]
    
    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, % &quot;Enable&quot; . toggle[A_Index], % listControl[A_Index]
    
    toggle := &quot;&quot;

    ; Необходимо для обновления состояния отображения, контролов `UpDown` на вкладке `Настройки`, при
    ;    активации / деактивации группы настроек `Правила`.
    WinSet, Redraw, , ahk_id %MainWin%
    return

; --- Скрытие / Показ мастер-пароля и нового пароля ------------------------------------------------
HideShowPass:
    Gui, Submit, NoHide
    
    hide_pass(MP, TogglePass)
    
    ; Если нужно скрывать длину конечного пароля.
    if(calcpass != &quot;&quot;)
        if(TogglePass)
            {
            hide_pass(NP, 1)
            PlaceholderPass(NP, &quot;БОЛЬШОЙСЕКРЕТ&quot;)
            }
        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 = &quot;Генератор&quot; and MasterPass != &quot;&quot; and StringID != &quot;&quot;)
        {
        calcpass := passgen(MasterPass, StringID, Iteration, LenPass, CheckedSet, LimitSet, LimitChar)
        pass_score := pwdmeter2(calcpass)
        
        GuiControl, , TxtPerc, % pass_score . &quot;%&quot;
        WinSet Region, % &quot;0-0 h9 w&quot; . info_w * pass_score // 100, ahk_id %PB_pic%
        }
    else
        {
        calcpass := &quot;&quot;
        
        GuiControl, , TxtPerc, % &quot;0%&quot;
        WinSet Region, 0-0 h9 w0, ahk_id %PB_pic%
        }
    ; Если не нужно скрывать длину пароля.
    /*
    if(MasterPass != &quot;&quot; and StringID != &quot;&quot;)
        {
        calcpass := passgen(MasterPass, StringID, Iteration, LenPass, CheckedSet, LimitSet, LimitChar)
        PHstate := PlaceholderPass(NP, calcpass)
        }
    else
        PHstate := PlaceholderPass(NP)
    */
    
    goto HideShowPass
    
    return

; &gt;&gt;&gt; Функции --------------------------------------------------------------------------------------

; --- Функции - Свои -------------------------------------------------------------------------------
PlaceholderPass(hID, str = &quot;&quot;)
    ; Текст подсказки и вывод готового пароля.
    {    
    if(str = &quot;&quot;)
        {
        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 ? &quot;+Password&quot; . CHR(9679) : &quot;-Password&quot;, % 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 := [&quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;
                , &quot;abcdefghijklmnopqrstuvwxyz&quot;
                , &quot;1234567890&quot;
                , &quot;_&quot;
                , &quot;!@#$%^&amp;*-+&quot;
                , &quot;()[]{}&lt;&gt;&quot;]
    ; Наборы выбранные для создания пароля.
    use_set := []
    pass_out := &quot;&quot;

    ; --- Создание `рабочего` набора.
    loop % sel_set.length()
        if(sel_set[A_Index])
            ; `id_set` см. ниже, секцию комментариев `--- Символ найден`
            use_set.Push([&quot;id_set&quot; . (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, &quot;SHA256&quot;)
        
        ; Снятие ограничений с наборов, если указано 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 &lt;= len_p and !stop_proc)
        {
        block := SubStr(pass_in, A_Index * 4 - 3, 4)
        ; 1, 2 символы - номер набора.
        cur_set := &quot;0x&quot; . SubStr(block, 1, 2)
        ; 3, 4 символы - номер символа в наборе.
        cur_char := &quot;0x&quot; . 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 &gt;= lim_set)
                {
                if(use_set.MaxIndex() &lt;= 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] &gt;= 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. символ подчёркивания `_` не учитывается.
    ;    - т.к. оригинал не учитывает символ подчёркивания.
    ;    - неверно составлено условие проверок - (пароль `состоит только из букв` / `состоит только из цифр`).
    ;    &gt; как следствие для паролей состоящих из `A-Z` и `_` или `0-9` и `_`
    ;        например FN_D_Y, 49_13_7
    ;    может возникнуть ложное предположение о том, что пароль состоит только из букв или цифр.
    ;    2. не обнаруживаются последовательности xyz / zyx, из-за занижения на 1 в условии.
    {
    score := 0
    
    if(StrLen(pass))
        {
        ; --- Инициализация начальных значений -----------------------------------------------------
        ; Можно затолкать в массив, но удобнее использовать переменные со значащими именами.
        test_UpCase := &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;
        test_LowCase := &quot;abcdefghijklmnopqrstuvwxyz&quot;
        test_Num := &quot;0123456789&quot;
        test_Symbol := &quot;!@#$%^&amp;*()&quot;
        ; Набор, к которому принадлежал предыдущий символ.
        prev_testSet := &quot;&quot;
        
        ; --- Бонусы, процент надёжности растёт.
        ; Полная длина тестируемого пароля.
        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 = &quot;UpCase&quot;)
                    count_ConUpCase++
                
                prev_testSet := &quot;UpCase&quot;
                }
            else if(InStr(test_LowCase, A_LoopField))
                {
                count_LowCase++
                
                if(prev_testSet = &quot;LowCase&quot;)
                    count_ConLowCase++
                
                prev_testSet := &quot;LowCase&quot;
                }
            else if(InStr(test_Num, A_LoopField))
                {
                count_Num++
                
                if(A_Index &gt; 1 and A_Index &lt; ws_len_pass)
                    count_MidNS++
                
                if(prev_testSet = &quot;Num&quot;)
                    count_ConNum++
                
                prev_testSet := &quot;Num&quot;
                }
            else ;if(A_LoopField != &quot;_&quot;) ; в оригинале присутствует.
                {
                count_Symbol++
                    
                if(A_Index &gt; 1 and A_Index &lt; ws_len_pass)
                    count_MidNS++
                                
                prev_testSet := &quot;Symbol&quot;
                }
            
            ; --- Сбор информации о пароле - Повторы символов `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 &gt;= 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 &gt; 0 and count_UpCase &lt; f_len_pass)
            score += (f_len_pass - count_UpCase) * 2
        
        if(count_LowCase &gt; 0 and count_LowCase &lt; f_len_pass)
            score += (f_len_pass - count_LowCase) * 2
        
        if(count_Num &gt; 0 and count_Num &lt; f_len_pass)
            score += count_Num * 4
        
        score += count_Symbol * 6
        score += count_MidNS * 2
        
        if(count_Req &gt; (f_len_pass &gt;= 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 &lt; 0)
            score := 0
        
        if(score &gt; 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, &quot;ТЕКСТ_ПОДСКАЗКИ&quot;,, ahk_id %ID_КОНТРОЛА%
    {
    Static EM_SETCUEBANNER := 0x1501
    Return DllCall(&quot;User32.dll\SendMessageW&quot;, &quot;Ptr&quot;, hID, &quot;Uint&quot;, EM_SETCUEBANNER, &quot;Ptr&quot;, True, &quot;WStr&quot;, 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 := &amp;BMBITS
    
    Loop, Parse, PixelData, |
        P := Numput(&quot;0x&quot; A_LoopField, P + 0) - (W &amp; 1 &amp;&amp; !Mod(A_Index * 3, W * 3) ? 0 : 1)
    
    hBM := DllCall(&quot;CreateBitmap&quot;, Int, W, Int, H, UInt, 1, UInt, 24, UInt, 0)    
    hBM := DllCall(&quot;CopyImage&quot;, UInt, hBM, Int, 0, Int, 0, Int, 0, UInt, 0x2008) 
    DllCall(&quot;SetBitmapBits&quot;, UInt, hBM, UInt, WB * H, UInt, &amp;BMBITS)
    hBM := !Gradient ? DllCall(&quot;CopyImage&quot;, UInt, hBM, UInt, 0, Int, 0, Int, 0, Int, 8 ) : hBM
    
    Return DllCall(&quot;CopyImage&quot;, UInt, hBM, Int, 0, Int, ResizeW, Int, ResizeH, Int, 0x200C, UInt)
    }

; AutoHotkey Version: AutoHotkey 1.1
; Language:           English
; Platform:           Win7 SP1
; Author:             Antonio Bueno &lt;user atnbueno at Google&#039;s free e-mail service&gt;
; Description:        Implementation of PBKDF2 using MS-CAPI HMACs
; Last Modification:  2014-05-03

PBKDF2(sPassword, sSalt, nIterations = 10000, nLength = 0, sAlgo = &quot;SHA1&quot;)
; 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 &lt;= 0)
        Throw &quot;PBKDF2 ERROR: Invalid number of iterations (&quot; nIterations &quot;)&quot;
    If (aHashAlgid[sAlgo] = &quot;&quot;)
        Throw &quot;PBKDF2 ERROR: Unknown hash function (&quot; sALgo &quot;)&quot;
    ; 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, &quot;i)^([0-9A-F][0-9A-F])+$&quot;))
        nPassword := Wide2UTF8(sPassword, Password)
    else
        nPassword := Hex2Bin(sPassword, Password)
    If (!RegExMatch(sSalt, &quot;i)^([0-9A-F][0-9A-F])+$&quot;))
        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) &quot;000000&quot; Bin2Hex(Chr(A_Index), 1), Hash)
        VarSetCapacity(HmacInfo, 4 * A_PtrSize, 0)
        NumPut(aHashAlgid[sAlgo], HmacInfo, 0, &quot;UInt&quot;) ; Selects hashing algorithm and default padding
        nKeyBlobSize := 12 + nPassword
        VarSetCapacity(keyBlob, nKeyBlobSize, 0)
        NumPut(PLAINTEXTKEYBLOB, keyBlob, 0, &quot;Char&quot;)
        NumPut(CUR_BLOB_VERSION, keyBlob, 1, &quot;Char&quot;)
        NumPut(CALG_RC2, keyBlob, 4, &quot;UInt&quot;)
        NumPut(nPassword, keyBlob, 8, &quot;Char&quot;)
        DllCall(&quot;RtlMoveMemory&quot;, &quot;UInt&quot;, &amp;keyBlob + 12, &quot;UInt&quot;, &amp;Password, &quot;Int&quot;, nPassword) 
        DllCall(&quot;advapi32\CryptAcquireContext&quot;, &quot;UIntP&quot;, hProv, &quot;UInt&quot;, 0, &quot;UInt&quot;, 0, &quot;UInt&quot;, PROV_RSA_FULL, &quot;UInt&quot;, CRYPT_VERIFYCONTEXT)
        DllCall(&quot;advapi32\CryptImportKey&quot;, &quot;UInt&quot;, hProv, &quot;UInt&quot;, &amp;keyBlob, &quot;UInt&quot;, nKeyBlobSize, &quot;UInt&quot;, 0, &quot;UInt&quot;, CRYPT_IPSEC_HMAC_KEY, &quot;UIntP&quot;, hKey)
        ; Iteration zero
        DllCall(&quot;advapi32\CryptCreateHash&quot;, &quot;UInt&quot;, hProv, &quot;UInt&quot;, CALG_HMAC, &quot;UInt&quot;, hKey, &quot;UInt&quot;, 0, &quot;UIntP&quot;, hHmacHash)
        DllCall(&quot;advapi32\CryptSetHashParam&quot;, &quot;UInt&quot;, hHmacHash, &quot;UInt&quot;, HP_HMAC_INFO, &quot;UInt&quot;, &amp;HmacInfo, &quot;UInt&quot;, 0)
        DllCall(&quot;advapi32\CryptHashData&quot;, &quot;UInt&quot;, hHmacHash, &quot;UInt&quot;, &amp;Hash, &quot;UInt&quot;, nHash, &quot;UInt&quot;, 0)
        DllCall(&quot;advapi32\CryptGetHashParam&quot;, &quot;UInt&quot;, hHmacHash, &quot;UInt&quot;, HP_HASHVAL, &quot;UInt&quot;, &amp;XORSum, &quot;UIntP&quot;, aHashLength[sAlgo], &quot;UInt&quot;, 0)
        DllCall(&quot;advapi32\CryptDestroyHash&quot;, &quot;UInt&quot;, hHmacHash)
        DllCall(&quot;RtlMoveMemory&quot;, &quot;UInt&quot;, &amp;Hash, &quot;UInt&quot;, &amp;XORSum, &quot;Int&quot;, aHashLength[sAlgo])
        ; End of iteration zero
        Loop % nIterations-1
            {
            DllCall(&quot;advapi32\CryptCreateHash&quot;, &quot;UInt&quot;, hProv, &quot;UInt&quot;, CALG_HMAC, &quot;UInt&quot;, hKey, &quot;UInt&quot;, 0, &quot;UIntP&quot;, hHmacHash)
            DllCall(&quot;advapi32\CryptSetHashParam&quot;, &quot;UInt&quot;, hHmacHash, &quot;UInt&quot;, HP_HMAC_INFO, &quot;UInt&quot;, &amp;HmacInfo, &quot;UInt&quot;, 0)
            DllCall(&quot;advapi32\CryptHashData&quot;, &quot;UInt&quot;, hHmacHash, &quot;UInt&quot;, &amp;Hash, &quot;UInt&quot;, aHashLength[sAlgo], &quot;UInt&quot;, 0)
            DllCall(&quot;advapi32\CryptGetHashParam&quot;, &quot;UInt&quot;, hHmacHash, &quot;UInt&quot;, HP_HASHVAL, &quot;UInt&quot;, &amp;Hash, &quot;UIntP&quot;, aHashLength[sAlgo], &quot;UInt&quot;, 0)
            DllCall(&quot;advapi32\CryptDestroyHash&quot;, &quot;UInt&quot;, 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, &quot;Int64&quot;) ^ NumGet(Hash, nOffset, &quot;Int64&quot;), &amp;XORSum, nOffset, &quot;Int64&quot;)
                }
            }
        DllCall(&quot;advapi32\CryptDestroyKey&quot;, &quot;UInt&quot;, hKey)
        DllCall(&quot;advapi32\CryptReleaseContext&quot;, &quot;UInt&quot;, hProv, &quot;UInt&quot;, 0)
        DllCall(&quot;RtlMoveMemory&quot;, &quot;UInt&quot;, &amp;Output+(A_Index-1)*aHashLength[sAlgo], &quot;UInt&quot;, &amp;XORSum, &quot;Int&quot;, aHashLength[sAlgo])
        }
    }
    
Wide2UTF8(sInput, ByRef Output)
    {
    nOutputSize := StrPut(sInput, &quot;UTF-8&quot;)
    VarSetCapacity(Output, nOutputSize)
    StrPut(sInput, &amp;Output, nOutputSize, &quot;UTF-8&quot;)
    Return nOutputSize-1
    }

Bin2Hex(ByRef Input, nInput)
    {
    sIntegerFormat := A_FormatInteger
    SetFormat Integer, H
    Loop % nInput
        sOutput .= SubStr(*(&amp;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(&quot;0x&quot; . SubStr(sInput, 2 * A_Index - 1, 2), Output, A_Index - 1, &quot;Char&quot;)
    Return StrLen(sInput) // 2
    }

; &lt;&lt;&lt; Функции --------------------------------------------------------------------------------------
</code></pre></div>]]></content>
			<author>
				<name><![CDATA[Stremin]]></name>
				<uri>https://forum.script-coding.com/profile.php?id=33282</uri>
			</author>
			<updated>2015-08-16T20:32:15Z</updated>
			<id>https://forum.script-coding.com/viewtopic.php?pid=96486#p96486</id>
		</entry>
</feed>
