Криптовелосипед своими руками

от автора


Всем привет!
Однажды ко мне пришла идея защитить свои программы паролем. После недолгих размышлений было решено хранить пароль в файле рядом с исполняемым файлом программы. Доступа в интернет у меня в тот момент не было, других источников информации по криптографии тоже. А все мои знания по алгоритмам шифрования ограничивались шифром Цезаря, про который рассказывали в школе. Поэтому алгоритм шифрования придумал на коленке сам. Хочу рассказать о том что получилось.

Требования

-Реализовать алгоритм на 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *