Поехали!
Первым делом прикинем в голове общий план будущей программы: первое - это возможность шифровать файл с помощью 2-х методов: 1) по ключу; 2) с помощью ключевого файла. На выбор пользователя.
Теперь внимание на форму программы:
3 edit'a, 4 button'a, 1 richedit и 2 radiobutton'а.
Надо понимать, что XOR (а именно он и шифрует) использует ключ (что и есть пароль) и шифрует файл непосредственно с помощью него. Для первого варианта шифровки ключ обязателен, ведь шифрование идёт напрямую связанное с паролем.
Скелет в шкафу номер 1.
Дело в том, что считывая байты программы, которую собираемся шифровать, мы получаем огромное количество символов и букв, заключённых в массив. Сначала я , использую публичную функцию криптовки XOR'ом, задавал огромный ключ и радовался тому, что программа ничерта не работала. Но потом мне объяснили, что т.к. каждый байт состоит из 2-х символов, его нельзя шифровать ключём более 2-х символов! Но какая-же это тогда шифровка? Тогда и ключ будет вычислить несложно, скажешь ты. И будешь прав, поэтому единственный целесообразный способ зашифровать массив длинным ключём - это разграничить каждый байт массива (помним, что это 2 символа) и каждые 2 символа ключа, и зашифровать их друг с другом:
Т.е. каждые 2 символа массива шифруются попарно с каждыми двумя символами ключа. Вот и весь процесс. Тогда и ключ можно будет задать длинный (32, 64, 128 бит) и достать его будет сложней. Но что же будет, если ключ неожиданно закончится, а массив ещё продолжается? Не шифровать же половину массива? Конечно нет. Если ключ закончится - его мы начнём с начала. Что бы всё это реализовать - достаточно несколько строчек кода и несколько переменных:
var
CryptFilePath : string; // переменная пути файла который шифруется
KeyFilePath : string; //переменная пути ключевого файла
USerKey : string; // ключ, генерированный программой
fCrypt, fKey: file; // переменный файла который шифруется и ключевого файла
arr, arrKeyFile: array of Byte; // переменный массивов, куда считываются байты из файлов.
Size, pos1, pos2, _key, sizekeyFile, t: longint;
_StrKey : string ;
// Сразу приведу функцию, которая будет сохранять массив байтов в файл:
function SaveBinArrayToFile(AFileName:string; ABuf:array of byte):boolean;
var
fs:TFileStream;
n:integer;
begin
fs:=TFileStream.Create(AFileName, fmCreate);
try
fs.Position := 0;
n := Length(ABuf);
fs.Write(ABuf, n);
finally
fs.Free;
end;
end;
// Процедура генерации 32-х битного ключа:
procedure TForm1.Button2Click(Sender: TObject); // тут всё понятно
var
i: integer;
begin
randomize;
txtKey.Clear;
for i := 1 to 32 do
txtKey.Text:=txtKey.Text+IntToStr(random(9));
end;
// Открытие файла, который будем шифровать:
AssignFile(fCrypt,CryptFilePath); // привязка переменной к пути и имени файла
Reset(fCrypt,1); // разрешаем файл для чтения и редактирования с блоком чтения в 1 байт
size:= FileSize(fCrypt); // в переменную size ложится размер файла (кол-во байт)
SetLength(arr,size); // присваивание массиву ARR данного размера
BlockRead(fCrypt,arr[0],size); // читаем байты из файла FCrypt, ложим в массив ARR, начиная с [0]-ого элемента, читаем количество байт равное SIZE
CloseFile(fCrypt); // закрываем файл после чтения
Процедура Шифрования файла по ключу:
procedure TForm1.EncryptedKey;
var i: integer;
begin
UserKey:= txtKey.Text; // Userkey - переменная типа String, куда ложится ключ генерированный программой
Pos1:=1; // Переменная позиции (будет определять позицию символа в ключе)
//Шифрование файла по ключу
for i := 1 to length(arr) do // перебираем байты файла который будет зашифрован
begin
if pos1>= length(UserKey) then pos1:=1; // если позиция символа в ключе меньше или равна длине ключе (т.е. достигла конца ключа, то позиция равна 1, т.е. начинается с начала)
_StrKey:= UserKey[pos1]+UserKey[pos1+1] ; // _StrKey = символу ключа pos1 и следующему символу (pos1+1)
_key:=StrToInt(_StrKey); // _key = 2-м символам взятым выше
arr[i]:=arr[i] xor _key; // шифруется i-товый байт массива (2 символа) и 2 символа ключа
pos1:=pos1+2; // позиция перескакивает на 2 следующих символа.
end;
if not SaveDialog1.Execute then exit; // если диалог1 не открыт, то выходим
SaveBinArrayToFile(SaveDialog1.FileName, arr); // процедура сохранения массива байт в файл
end;
По-такому принципу будет происходить шифрование файла. Теперь процедура шифрования файла по ключевому файлу. Если подумать, то всё аналогично с ключём, разница лишь в том, что ключевой файл мы считываем в массив и шифруем так же по-парно:
procedure TForm1.EncryptedKeyFile;
var I: integer;
v: TSaveDialog;
begin
v:= TSaveDialog.Create(SaveDialog2);
//Открытие ключевого файла
AssignFile(fKey,OpenDialog2.FileName); // всё аналогично, не комментирую. только тут открываем уже ключевой файл
Reset(fKey,1);
sizekeyFile:= FileSize(fKey);
SetLength(arrKeyFile,sizekeyFile);
BlockRead(fKey,arrKeyFile[0],sizekeyFile);
CloseFile(fKey);
// Шифрование по ключевому файлу
pos2:=0;
for i := 1 to length(arr) do
begin
if pos2 >= length(arrkeyFile) then pos2:=1;
arr[i]:= arr[i] xor arrkeyFile[pos2];
pos2:= pos2+1;
end;
if not v.Execute then exit;
SaveBinArrayToFile(v.FileName, arr);
end;
Что бы вызвать процедуры, на событие onclick у кнопки Crypt пишем такой код:
if form1.RadioButton1.Checked=true then EncryptedKey else
if form1.RadioButton2.Checked=true then EncryptedKeyFile;
Так же при открытии файла желательно создать бэкап, что делается одной строчкой:
CopyFile (PChar(Opendialog1.FileName), PChar(OpenDialog1.FileName + '.bak'), true);
Всё, шифратор файлов готов. Соответственно можно прикрутить лог событий и прочие ненужные вещи :) Спасибо за внимание.