Шифрование в DELPHI

Материал из DRKB


Шифрование в DELPHI

Данные надо беречь. Сам посуди, обидно, если открытие ценой в сто миллионов енотов или рецепт безалкогольной водки, над которым ты корпел три вечера в мрачном подвале нелегального компьютерного клуба, уплывет к злостному ленивому конкуренту, который, пользуясь твоим похмельем, наложил грязную лапу на приватные дискеты с ценнейшей инфой?! Дальше можно не продолжать. Шифруем, шифруем, шифруем!..

Добрый дядюшка borland предоставил нам несколько занятных функций для работы со строками, о которых не все знают. Сосредоточены они в модуле strutils.pas.

Такие функции, как RightStr(), LeftStr() совмещают стандартные команды Copy() и Delete(): так, LeftStr() возвращает значение левой части строки до указанной вами позиции (что вытворяет RightStr(), догадайся сам), а функция ReverseString() и вовсе делает зеркальное отображение данной строки: 321 вместо 123. Используем ее в особенности, чтобы осложнить жизнь хитрому дешифровщику.

Алгоритм шифрования будет прост, как win 3.1. С каждым символом кодируемого документа проделаем следующее:

1. Преобразуем символ в число командой Ord.
2. Преобразуем каждый символ пользовательского пароля в число и сумму этих чисел прибавим к полученному в пункте 1.
3. От результата отнимаем число, равное позиции данного символа. То есть буковки будут шифроваться по-разному в зависимости от их позиции в строке :).
4. То, что получилось, запишем обратно из чисел в символы командой Chr. Как видишь, после всех наших манипуляций этот символ уже будет другим.
5. Запишем всю строку навыворот командой ReverseString.

Дешифровка, как ты догадываешься, будет производиться в обратном порядке.

Теперь, когда алгоритм намертво засел в голове, реализуем соответствующую программу.

Внимание! Не исключено, что это будет первая твоя программа с настоящим синтаксисом команд:

<команда> <путь> <пароль>

- так будет выглядеть он в консоли нашего приложения (да, оно будет консольным!). Команд всего две: crypt и decrypt соответственно зашифровать и дешифровать файл, путь к которому указывается после пробела, а затем - твой пароль. НЕ ЗАБУДЬ ЕГО! Предупреждаю совершенно серьезно. Запомнил? В бой!

crypt c:\file.txt linuxmustsurvive

- закодируем file.txt.

Результат (зашифрованный текст) сохраниться в той же директории, что и исполняемый файл нашего приложения под именем translated_file.txt.

decrypt c:\translated_file.txt linuxmustsurvive

- дешифровка.

Реализовывается это вот как:

program crypter;

{$apptype console}

uses
  sysutils,
  strutils; //!!

var
  f, // входящий файл
  f1: TextFile; // результат (файл с переводом)
  todo, Filename, passw, line, TranslatedFile: string;
  Position, IsCrypt: Integer;

// находим сумму числовых значений символов пароля
function Password(psw: string): Integer;
var
  i: Integer;
begin
  Result := 0;
  for i:=1 to Length(psw) do
    Result  := Result + Ord(psw[i]);
end;

function Crypt(CryptStr: string): string;
var
  s: string;
  i: Integer;
begin
  Result := '';
  if CryptStr = EmptyStr then Exit;
  for i := 1 to Length(CryptStr) do
  begin
    s := LeftStr(CryptStr, 1);
    CryptStr := RightStr(CryptStr, Length(CryptStr)-1);
    // ШИФРОВКА:
    s := Chr(Ord(s[1]) + Password(passw)-i);
    Result := Result + s;
  end;
  Result := ReverseString(Result);
end;

function Decrypt(DecryptStr: string): string;
var
  i: Integer;
  s: string;
begin
  Result := '';
  DecryptStr := ReverseString(DecryptStr);
  if DecryptStr = EmptyStr then Exit;

  for i := 1 to Length(DecryptStr) do
  begin
    s := LeftStr(DecryptStr, 1);
    DecryptStr := RightStr(DecryptStr, Length(DecryptStr)-1);
    // ДЕШИФРОВКА:
    Result := Result + Chr(Ord(s[1]) - Password(passw)+i);
  end;
end;

begin
  while True do
  begin
    IsCrypt := 0;
    WriteLn(#10 + 'crypter >' + #10);
    // Какую команду ввел юзер?
    ReadLn(todo);
    if LowerCase(todo) = 'exit' then exit;
    if AnsiContainsText(todo, 'decrypt') then
      IsCrypt := 1
    else if AnsiContainsText(todo, 'crypt') then
      IsCrypt := 2;
    // прочитав команду, удаляем ее из строки и читаем дальше
    Position := Pos(' ', todo);
    if Position > 0 then
      todo := RightStr(todo, Length(todo) - Position);
    // Читаем путь к файлу
    Position := Pos(' ', todo);
    if Position > 0 then
      FileName := LeftStr(todo, Position-1);
    // Читаем пароль
    passw := RightStr(todo, Length(todo) - Position);
    // Всё правильно? Начинаем!
    if (IsCrypt <= 0) or (passw = EmptyStr)
    or (not FileExists(FileName)) then
      WriteLn('wrong command')
    else
    begin
      TranslatedFile := ExtractFilePath(ParamStr(0)) +
        'translated_' + ExtractFileName(FileName);
      // соединяемся с файлами
      AssignFile(f, FileName);
      AssignFile(f1, TranslatedFile);
      // переходим в начало файла
      Rewrite(f1);
      Reset(f);
      // читаем строки, пока не дойдем до конца файла
      while not Eof(f) do
      begin
        // читаем из переводимого файла
        ReadLn(f, line);
        if IsCrypt = 1 then line := Decrypt(line);
        if IsCrypt = 2 then line := Crypt(line);
        // записываем в файл с переводом
        WriteLn(f1, line);
      end;
      // отсоединяемся от файлов
      CloseFile(f);
      CloseFile(f1);
    end;
  end;
end.


Вот, собственно, и всё. Еще раз напоминаю, что результат (файл с переводом) сохранится В ТОЙ ЖЕ ДИРЕКТОРИИ, что и наше приложение, а не в той, где лежит исходный файл. В заключение процитирую отрывок из статьи «Криптография в c++» в номере 3.03 журнала «Хакер»:

//(с) Николай «gorlum» Андреев

Но я хочу тебя предупредить: в нашей стране, согласно указу № 334 от 1995 года, производить и распространять любые шифрующие средства можно, только имея лицензию ФАПСИ. Соответственно, шифровать нельзя :). Поэтому пиши программы только для личного пользования и только в познавательных целях.


Author: Трофим Роцкий
ID: 03983