
Всем привет!
Однажды ко мне пришла идея защитить свои программы паролем. После недолгих размышлений было решено хранить пароль в файле рядом с исполняемым файлом программы. Доступа в интернет у меня в тот момент не было, других источников информации по криптографии тоже. А все мои знания по алгоритмам шифрования ограничивались шифром Цезаря, про который рассказывали в школе. Поэтому алгоритм шифрования придумал на коленке сам. Хочу рассказать о том что получилось.
Требования
-Реализовать алгоритм на Delphi и для программ соответственно на нём же.
-приложение доступно только при правильном пароле
-пароль можно менять
-пароль не должен явно выделятся из файла, в котором хранится
Что получилось:
-Запуск приложения предваряет форма запроса пароля. После ввода пароля, пароль дешифровывается из файла и сравнивается с введённым. Если они совпадают, то загружается приложение.
-Файл с зашифрованным паролем хранится в папке с exe-файлом программы. При отсутствии этого файла, приложение ругается на его отсутствие и не принимает никакого пароля.
-Для себя оставил лазейку в виде админ-пароля, который сбрасывает значение пароля на дефолтное.
Алгоритм
Поскольку больше ничего в активе не было, за принципиальную основу был взят вышеупомянутый шифр, который я усовершенствовал. В начале создавалась строка, которая заполнялась 12-ю рандомными числами от 0 до 999. Строка считывалась в массив чисел. Далее бралось 2-е число массива и определялся номер строки, которую я назвал управляющей.
controlString:=xArr[2];
Очевидно, что расположение управляющей строки в файле от пароля к паролю будет разным.
Чтобы уменьшить объём файла, позиция управляющей строки при необходимости нехитрыми преобразованиями уменьшается на 1-2 порядка.
if controlString >= 100 then controlString:=controlString div 100; if controlString > 30 then controlString:=controlString div 10;
Пространство от первой до управляющей строки заполняется мусорными строками, заполненными ничего не значащими случайными числами:
if controlString<>1 then for ii:=1 to controlString-1 do M.Lines.Add(AddRandString(1000));
Далее формируется управляющая строка. Первое число — рэндомное. Второе — номер строки с первым символом пароля:
s:=inttostr(random(1000))+' '; //first symbPass1_str:=random(50)+controlString; s:=s+inttostr(symbPass1_str)+' ';//second
Как видите, строка с первым символом пароля тоже случайна, хотя и имеет зависимость от случайного же номера управляющей строки. В следующем числе кодируем номер позиции символа пароля в строке.
symbPass1_pos:=random(12)+1; s:=s+inttostr(symbPass1_pos+(random(9)+1)*100)+' ';//third
писать позицию (1..12) в явном виде — слишком очевидно, поэтому номер позиции преобразовывается в трёхзначное число. Два следующих числа — начальное приращение кода символа пароля и приращение к приращению:
firstAdd:=random(151)+50; s:=s+inttostr(firstAdd)+' '; nextAdd:=random(21)+10; s:=s+inttostr(nextAdd+(random(9)+1)*100)+' ';
Последнее информационное число — длина пароля. Сделано для того, чтобы при проверке пароля для начала сравнивалась длина, и если не совпадает, то дальнейшее восстановление правильного пароля из шифра бессмысленно.
passLeng:=length(str); s:=s+inttostr(passLeng+(random(9)+1)*100)+' ';
Оставшиеся позиции в строке заполняются случайными числами.
Далее файл до строки с символом пароля (symbPass1_str) заполняется мусорными строками. А пароль превращается в массив ansi-кодов своих символов:
for ii:=1 to passLeng do pas[ii]:=ord(str[ii]);
и шифруется:
isp:=1; //номер символа пароля stroka:=symbPass1_str; //строка, куда запишется этот символ pos_sp:=symbPass1_pos; //позиция в этой строке for jj:=1 to passLeng do begin m.Lines.Add(AddCoStringPas(1000,pas[isp]+firstAdd+(jj-1)*nextAdd,pos_sp)); NextAftPas(s,stroka,pos_sp); m.Lines.Add(s); for ii:=m.Lines.Count-1 to stroka-2 do M.Lines.Add(AddRandString(1000)); inc(isp); end;
К коду символа пароля прибавляется начальное приращение и приращение приращения, умноженное на счётчик. В следующей строке (NextAftPas) записывается информация о следующем символе пароля: номер строки (текущий
номер + 6..16) и позиция в строке (1..12).
И так далее, пока не кончатся символы пароля. После последней значимой строки файл заполняется случайным (10..40) количеством мусорных строк.
Для дешифрования всё идёт почти в таком же порядке: считывание первой строки, восстановление из неё номера управляющей строки, восстановление информации из управляющей строки, восстановление первого символа пароля, восстановление информации о местоположении второго символа пароля… восстановление последнего символа пароля, восстановление парольной строки и сравнение с введённой строкой.
Послесловие
Я остался доволен своим детищем. Используя такой же алгоритм, начинал делать шифратор, который шифровал текстовую информацию, но на выходе получались большие объёмы, поэтому не прижилось, а потом я отвлёкся на что-то другое.
При написании статьи во многих местах думал «тут можно ещё закрутить, усложнить», но сути алгоритма это не меняет.
Из минусов могу выделить следующие:
-большой объём файла с паролем;
-имея файл с известным паролем, можно открыть программу путём подмены файла;
-если изучить исходники и/или узнать точный алгоритм шифрования, можно восстановить пароль по файлу;
-неидеальность рэндома (с этим не уверен, в данном случае, возможно, это не влияет).
Из плюсов:
-сложность выуживания пароля из файла не зная алгоритма
-один и тот же пароль в зашифрованном виде будет выглядеть каждый раз по-разному
С благодарностью приму критику, замечания и предложения.
ссылка на оригинал статьи http://habrahabr.ru/post/204482/
Добавить комментарий