Суббота, 04.05.2024
Королевство Delphi
Главное меню
Статьи
Наш опрос
Нужен форум на сайте?
Всего ответов: 90
Статистика
Онлайн всего: 1
Гостей: 1
Пользователей: 0
Форма входа
Главная » Статьи » Защита » Шифрование

Шифруем файл с помощью другого файла

Здравствуйте, уважаемые читатели моей очередной статьи.

В прошлой статье я вам рассказывал, как можно зашифровать файл с помощью пароля. Разумеется, чем длиннее пароль, тем труднее расшифровать файл. Давайте попробуем сосчитать, сколько времени нам потребуется на расшифровку такого файла. Допустим, что если пароль имеет размер 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:D9D8F57C3274EF3A6E7C5D5B27ADCF0.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 КВ. И потеряв файл-пароль мы теряем и зашифрованный файл потому расшифровать такой файл почти невозможно.

Вот и всё!

скачать исходик

Получить ссылку на материал

Категория: Шифрование | Добавил: Барон (10.12.2011)
Просмотров: 1534 | Теги: файл | Рейтинг: 0.0/0
[ Пожертвования для сайта ] [ Пожаловаться на материал ]

Если вам помог материал сайта кликните по оплаченной рекламе размещенной в центре

Поиск
Категории раздела
Бомберы [0]
Трояны [0]
Робота с паролем [4]
Delphi и Хакинг [2]
Шифрование [6]
Разные [25]
Королевство Delphi © 2010-2024
Яндекс цитирования