Последние записи
- Преобразовать массив байт в вещественное число (single)
- TChromium (CEF3), сохранение изображений
- Как в Delphi XE обнулить таймер?
- Изменить цвет шрифта TextBox на форме
- Ресайз PNG без потери прозрачности
- Вывод на печать графического файла
- Взаимодействие через командную строку
- Перенести программу из Delphi в Lazarus
- Определить текущую ОС
- Автоматическая смена языка (раскладки клавиатуры)
Интенсив по Python: Работа с API и фреймворками 24-26 ИЮНЯ 2022. Знаете Python, но хотите расширить свои навыки?
Slurm подготовили для вас особенный продукт! Оставить заявку по ссылке - https://slurm.club/3MeqNEk
Online-курс Java с оплатой после трудоустройства. Каждый выпускник получает предложение о работе
И зарплату на 30% выше ожидаемой, подробнее на сайте академии, ссылка - ttps://clck.ru/fCrQw
29th
Авг
Шифруем файл с помощью другого файла в delphi
Posted by admin under Исходники, Статьи
В прошлой статье я вам рассказывал, как можно зашифровать файл с помощью пароля . Разумеется, чем длиннее пароль, тем труднее расшифровать файл. Давайте попробуем сосчитать, сколько времени нам потребуется на расшифровку такого файла. Допустим, что если пароль имеет размер 10 символов и допустим, что если мы попробовали расшифровать файл с верным паролем, то мы сразу поймём что это файл оригинальный (хотя это условие не обязательно потому что, расшифровывая файл мы не знаем что должно быть в оригинале, но в данном случае
мы знаем что в оригинале и нам надо узнать только пароль).
Сосчитаем:
Один символ пароля может принимать примерно 160 значений это примерно столько значений, сколько мы можем ввести с клавиатуры (26 +26 английский алфавит, 33+33 русский алфавит + ~22 дополнительный символы+10 цифр).
Следовательно, количество попыток равно 160 в степени 10 это число 5766503906250000000000, и если за одну секунду делается 10 попыток, то нам потребуется 24610789412122 лет чтобы узнать пароль и это с тем учётом, что мы знаем длину пароля. Почти невозможно…. Это только, кажется что сложно. Но даже если пароль имеет 30 символов, а файл 1 МВ, то, имея некоторую сноровку можно заметить повторы через каждые 30 байт, а там и найти пароль нетрудно. >
Единственный выход это увеличивать длину пароля. А что если пароль будет представлять собой файл длиной несколько сотен килобайт. Объясняю для тех, кто не понял. Символы для пароля мы брать из файла, и теперь уже каждый символ пароля будет принимать не только 160 значений, а все от 0 до 255, т.е. 256 значений, а длина пароля будет равна размеру файла в байтах.
Итак, перейдём к практике. В процедурах шифровки расшифровки я буду использовать технику файлового мэпинга. Мы все знаем что когда программы используют слишком больше памяти чем есть на компьютере, то система сбрасывает лишнюю память на диск в файл подкачки. А когда происходит попытка обращения к сброшенной памяти, то система загружает с диска память обратно, а другую память, которая давно не использовалась, скидывает на диск. А при использовании техники мэпинга, мы как будто говорим системе, что данную область памяти не надо выгружать в файл подкачки, а
надо выгружать в нужный нам файл. При создании такой области памяти мы файл полностью отображается на память, и при изменении этой области памяти изменяется файл.
Для увеличения скорости работы процедуры шифровать (и расшифровывать) я буду в ассемблерных вставках. А работать с файлами используя ассемблер очень трудно, поэтому я и использую мэпинг потому что файлы отображаются на память. А работать с памятью на ассемблере легче.
Чтобы создать область памяти надо сначала создать mapped объект с помощью функции CreateFileMapping. Вот описание функции из MS SDK
HANDLE CreateFileMapping(
HANDLE hFile,// хендл файла для мэпинга
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,//атрибуты безопасности
DWORD flProtect,//флаги доступа к объекту
DWORD dwMaximumSizeHigh,//максимальный размер (старший)
DWORD dwMaximumSizeLow,//максимальный размер (младший)
LPCTSTR lpName //имя объекта
);
Для того чтобы отобразить файл на память используется функция MapViewOfFile
LPVOID MapViewOfFile(
HANDLE hFileMappingObject,//хендл созданного объекта
DWORD dwDesiredAccess,// уровень доступа
DWORD dwFileOffsetHigh,//смещение начала проецирования (старшее)
DWORD dwFileOffsetLow,// смещение начала проецирования (младшее)
DWORD dwNumberOfBytesToMap// размер проецирования
);
Эта функция возвратит начальный адрес мэпинга, т.е. возвратит адрес первого байта файла в памяти. Короче смотрим всё на примере.
Function FlCriptFile(
SourceFile:string;
DestFile:string;
PSWFileName:string;
Flags:DWORD
):boolean;
var
DestHFile,SourceHFile,PSWHFile,BackupHFile:THandle;
SourceMH,PSWMH:THandle;
SourceFileSize,PSWSize:DWORD;
SourceMMFAddr,PSWMMFAddr:pointer;
begin
Result:=False;
ACF_AutoRename :=(Flags and CF_AutoRename) = CF_AutoRename;
ACF_DeleteSource :=(Flags and CF_DeleteSource) = CF_DeleteSource;
ACF_Dest_NOT_CREATE:=(Flags and CF_Dest_NOT_CREATE)= CF_Dest_NOT_CREATE;
ACF_ShowProgress :=(Flags and CF_ShowProgress) = CF_ShowProgress;
//пользуемся теми же флагами что в предыдущей статье
if ACF_AutoRename then
begin
DestFile:=SourceFile+’.cript’;
ACF_Dest_NOT_CREATE:=false;
end;
if ACF_Dest_NOT_CREATE then
begin
DestFile:=’D:\3D9D8F57C3274EF3A6E7C5D5B27ADCF0.dat’;
ACF_DeleteSource:=false;
end; //думаю что это понятно
SourceHFile:=CreateFile(pchar(SourceFile),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
if SourceHFile=INVALID_HANDLE_VALUE then Exit;
SourceFileSize:=GetFileSize(SourceHFile,nil);
CloseHandle(SourceHFile);
{открываем, получаем размер исходного файла, закрываем файл}
PSWHFile:=CreateFile(pchar(PSWFileName),GENERIC_READ,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
if PSWHFile=INVALID_HANDLE_VALUE then Exit;
PSWSize:=GetFileSize(PSWHFile,nil);
DeleteFile(BackupFileName);
{удаляем промежуточный файл если он есть и копируем исходный файл в него, задайте имя исходного файла в разделе const}
CopyFile(pchar(SourceFile),pchar(BackupFileName),False);
BackupHFile:=CreateFile(pchar(BackupFileName),GENERIC_READ+GENERIC_WRITE,FILE_SHARE_READ,nil,OPEN_EXISTING,0,0);
if BackupHFile=INVALID_HANDLE_VALUE then Exit;
{открываем промежуточный файл}
///—————
Далее создаём объекты мэпинга и проецируем файлы на память. Обратите внимание на атрибуты доступа, давать слишком много доступа тоже не очень хорошо. Имена для объектов мы не задаём т.к. нам не надо что бы этим объектом не пользовались другие процессы. Это не опечатка, используя файловый мэпинг разные процессы могут общаться между собой. Открыв объект с помощью функции OpenFileMapping передав ей, имя объекта и атрибуты доступа, процессы разделяют между собой одну память, при этом, если один процесс изменяет эту память у себя она автоматически изменяется у другог
о процесса (но не увлекайтесь этой возможностью, потому что без синхронизации процессы быстро зависнут).
SourceMH:=CreateFileMapping(BackupHFile,0,PAGE_READWRITE,0,SourceFileSize,”);
if SourceMH=0 then exit;
PSWMH:=CreateFileMapping(PSWHFile,0,PAGE_READONLY,0,PSWSize,”);
if PSWMH=0 then exit;
SourceMMFAddr:=MapViewOfFile(SourceMH,FILE_MAP_ALL_ACCESS,0,0,SourceFileSize);
if DWORD(SourceMMFAddr) = 0 then exit;
PSWMMFAddr:=MapViewOfFile(PSWMH,FILE_MAP_READ,0,0,PSWSize);
if DWORD(PSWMMFAddr) = 0 then exit;
asm
pushad // сохраняем все регистры в стеке
mov esi, SourceMMFAddr
mov edi, PSWMMFAddr
mov ecx, SourceFileSize
mov ebx, PSWSize
add ebx, edi
xor edx, edx // edx=0
@_loop:
mov al, byte ptr [edi]
xor byte ptr [esi], al
inc edi//увеличиваем позицию в пароле
cmp edi, ebx
{если мы вышли за границу пароля, то возвращаемся к началу пароля}
jl @_next
mov edi, PSWMMFAddr
@_next:
inc esi
loop @_loop
Popad // возвращаем регисры
end;
UnmapViewOfFile(PSWMMFAddr);//анмэпим
UnmapViewOfFile(SourceMMFAddr); //анмэпим
{закрываем хендлы, но главное не нарушить порядок}
if not CloseHandle(SourceMH) then exit;
if not CloseHandle(PSWMH) then exit;
CloseHandle(BackupHFile);
CloseHandle(PSWHFile);
Заметьте, для того чтобы закрыть хендлы надо сначала анмепить память, в которую мы спроецировали наши файлы. Для этого надо передать функции UnmapViewOfFile базовый адрес мэпинга. Во время работы с промэпированной памятью файл может и не измениться, потому что эта область памяти может ни разу не выгрузиться на диск. Функция UnmapViewOfFile полностью выгружает эту память в файл и высвобождает её. Далее идёт копирование промежуточного файла в файл, который был передан нашей функции через параметр DestFile и его последующее удаление. Потом файлы обрабатыва
ют согласно переданным флагам.
///—————
CopyFile(pchar(BackupFileName),pchar(DestFile),false);
DeleteFile(BackupFileName);
if ACF_DeleteSource then
DeleteFile(pchar(SourceFile));
if ACF_Dest_NOT_CREATE then
begin
if not DeleteFile(pchar(SourceFile))then exit;
CopyFile(pchar(DestFile),pchar(SourceFile),false);
if not DeleteFile(pchar(DestFile)) then exit;
end;
Result:=true;
End;
У данной методики есть некоторые ограничения. Так как в Windows каждому процессу дается область памяти в диапазоне 10000h-7FFFFFFFh, это примерно 2047 МВ, минус ту память, которую занимают системные DLL и сама программа, в среднем 20 МВ. Размер файла-пароля плюс размер исходного файла не должны превышать ~2020 МВ.
Функция дешифрования почти полностью идентичная за некоторым отличием обработки флагов. Вот описание функции:
Function FlDeCriptFile(
SourceFile:string;
DestFile:string;
PSWFileName:string;
Flags:DWORD
):boolean;
Полностью код этой функции смотрите в исходнике FileCript.pas там же есть функции шифровки файла с помощью пароля. Кидаем этот модуль в “расшаренную” для Delphi папку и пользуемся модулем на здоровье.
На последок расскажу о преимуществах данной методики над методикой шифровки файла с помощью пароля. Любой пароль можно запомнить каким бы он и был (например, пароль с рожицей в центре: P@S:-|sVVorDdD), пароль можно записать на бумажке. А файл мы никогда не сможем записать на бумажке тем более если он имеет размер ~800 КВ. И потеряв файл-пароль мы теряем и зашифрованный файл потому расшифровать такой файл почти невозможно.
Вот и всё!
Руслан Аблязов E-mail
Похожие статьи
Купить рекламу на сайте за 1000 руб
пишите сюда - alarforum@yandex.ru
Да и по любым другим вопросам пишите на почту
пеллетные котлы
Пеллетный котел Emtas
Наши форумы по программированию:
- Форум Web программирование (веб)
- Delphi форумы
- Форумы C (Си)
- Форум .NET Frameworks (точка нет фреймворки)
- Форум Java (джава)
- Форум низкоуровневое программирование
- Форум VBA (вба)
- Форум OpenGL
- Форум DirectX
- Форум CAD проектирование
- Форум по операционным системам
- Форум Software (Софт)
- Форум Hardware (Компьютерное железо)