Шифровка с помощью пароля. Улучшаем алгоритм шифрования
Доброго времени суток. Наверно все читали мою предыдущую статью «Шифруем файл с помощью пароля» (рекомендую прочитать перед прочтением этой статьи). В ней я описал методику шифрования файлов с помощью пароля. Это конечно довольно-таки простая методика. В этой статье я расскажу про более сложную методику шифрования с помощью пароля. Итак, приступим.
В чём уязвимость старого алгоритма? Допустим в файле будет некоторая последовательность одинаковых байт. После шифрования будет видно повторение одной и той же последовательности, которая имеет длину равную длине пароля. Будет видно, на сколько отличаются символы в пароле (например, второй символ на 3 «больше» чем первый, третий на 20 «меньше» чем второй и т.д.). После этого нам только останется перебрать все 256 вариантов пароля, и в итоге файл будет расшифрован в считанные минуты.
Отсюда вывод: не надо обрабатывать данные в файле «данными» пароля, т.е. при шифровании не надо использовать пароль в чистом виде. Один из множества выходов заключается в том, что бы использовать при шифровании некую контрольную сумму пароля. В качестве контрольной суммы будем использовать CRC32 пароля. CRC32 — это урезанный вариант «хеша», который имеет размер не 16 байт, а 4 байта. Следовательно, шаг у нас будет на 1 байт как в прошлом случае, а 4 байта. Вместо прибавления/убавления, по-моему, использовать взаимно обратную логическую операцию XOR (это только моё мнение, возможно, она мне понравилась из-за того, что для неё не надо писать дешифратор, поскольку шифратор также является дешифратором). Использовать одну и ту CRC32 слишком просто, потому что можно подобрать такое слово, у которого CRC32 будет такой же что и у пароля. Поэтому надо будет видоизменять пароль после очередной операции XOR. У видоизменённого пароля CRC32 будет уже совсем другим. Правило изменения пароля будет таким:
1. Текущее смещение в файле делится 4, и делится на длину пароля -1, остаток от деления будет числом K.
2. Символ в пароле, который находится на позиции K, перемещается в конец пароля.
Довольно-таки незамысловатое правило. Но если следовать этому правилу, мы получим исходный пароль после N*(N-1) модификаций. Если использовать пароль длиной 8 символов (средняя длины пароля) то количество модификаций будет 56. Подобрать слово такой же длины, у которого все 56 модификаций имеют такую же CRC32 почти невозможно. Если длина файла не кратна 4 то остаток (1,2 или 3 байта), «ксорится» побайтово с CRC32 текущей модификации пароля.
Теория закончилась, приступим к практике. Сначала напишем функцию, которая будет шифровать некоторую область данных в памяти с помощью пароля. Я реализую её на ассемблере и засуну в DLL (будет использован компилятор FASM). Тем кому это не интересно могут пропустить эту часть. Функция получения CRC32 некоторого блока:
GET_CRC32:
; IN>
; ESI = block offset
; EDI = block size
; OUT
; EAX = CRC32
push esi
push edi
push ecx
push ebx
push edx
cld
xor ecx,ecx
dec ecx
mov edx,ecx
.NextByteCRC:
xor eax,eax
xor ebx,ebx
lodsb
xor al,cl
mov cl,ch
mov ch,dl
mov dl,dh
mov dh,8
.NextBitCRC:
shr bx,1
rcr ax,1
jnc .NoCRC
xor ax,08320h
xor bx,0EDB8h
.NoCRC:
dec dh
jnz .NextBitCRC
xor ecx,eax
xor edx,ebx
dec edi
jnz .NextByteCRC
not edx
not ecx
mov eax,edx
rol eax,16
mov ax,cx
pop edx
pop ebx
pop ecx
pop edi
pop esi
ret
Теперь функция модификации пароля
NextPasswordMod:
;IN
; ESI offset ZS of password
; EAX ordinal number ((текущее смещение в файле)/4)
; EDI password length
pushad
dec edi
xor edx, edx
div edi
add esi, edx
mov bh, [esi]
mov ecx, edi
sub ecx, edx
.next:
mov bl, [esi+1]
mov [esi], bl
inc esi
loop .next
mov [esi], bh
popad
ret
Едем далее, теперь сама функция:
proc CSCA1 DataAddress, DataSize, Password
; DataAddress — data offset
; DataSize — data size
; Password — offset ZS of password
local PasswordCp:DWORD
local PasswordLength:DWORD
pushad
mov edi, [Password]
call GetZSLength
mov [PasswordLength], eax
stdcall [VirtualAlloc],0,eax, MEM_COMMIT+MEM_RESERVE,
PAGE_READWRITE
mov edi, eax ; eax = password offset
mov esi, [Password]
mov ecx, [PasswordLength]
rep movsb
mov [PasswordCp], eax
Мы получили длину пароля. Выделили память и скопировали туда пароль, чтобы можно было без всякого «страха» модифицировать пароль.
xor ecx, ecx
.next: ; ecx
mov esi, [PasswordCp]
mov edi, [PasswordLength]
mov eax, ecx
call NextPasswordMod
mov esi, [PasswordCp]
mov edi, [PasswordLength]
call GET_CRC32 ;eax = CRC32 of current password mod
mov edi, [DataAddress]
imul edx, ecx,4 ;edx = current position
add edi, edx ; edi = current offset
mov ebx, [DataSize]
sub ebx, edx
cmp ebx, 0
jz .end
cmp ebx, 4
jl .not_full_xor
Здесь мы модифицируем пароль, получаем его CRC32, и смотрим в конце ли мы, если в конце, прыгаем в конец, если осталось меньше чем 4 байта, прыгаем в завершающую стадию шифрования.
.full_xor:
xor [edi], eax
inc ecx
jmp .next
.not_full_xor:
mov ecx, ebx
.rep:
dec ecx
add edi, ecx
mov dl, [edi]
xor dl, al
mov [edi], dl
sub edi, ecx
inc ecx
shr eax, 8
loop .rep
.end:
stdcall [VirtualFree],[PasswordCp],0, MEM_RELEASE
popad
ret
endp
Полностью исходник DLL и сама DLL есть в архиве с примером. Как эту DLL можно использовать? Приведу пример на Delphi:
procedure CSCA1(DataAddress:pointer; DataSize:DWORD; Password:PChar); stdcall; external ‘CSCA1.DLL ‘;
procedure TForm1.Button1Click(Sender: TObject);
var
FH,FMH:THandle;
DataAddr:pointer;
FSize:DWORD;
begin
if not OpenDialog1.Execute then exit;
FH:=CreateFile(pchar(OpenDialog1.FileName), GENERIC_ALL, FILE_SHARE_READ,0, OPEN_EXISTING, 0, 0);
FSize:=GetFileSize(FH,nil);
FMH:=CreateFileMapping(FH,0,PAGE_READWRITE,0,FSize,»);
DataAddr:=MapViewOfFile(FMH,FILE_MAP_WRITE,0,0,FSize);
CSCA1(DataAddr,FSize,pchar(Edit1.Text));
UnmapViewOfFile(DataAddr);
CloseHandle(FMH);
CloseHandle(FH);
end;
При первом нажатии на кнопку файл шифруется и при втором файл дешифруется.
Вот наверно и всё. Чуть не забыл. Почему функция так называется? Я назвал алгоритм так Control Sum Cript Algorithm v1.0, т.е. CSCA1. Качаем пользуемся. В архиве исходник DLL (FASM), сама DLL и пример её использования.
просто и со вкусом… больше слов здесь не нужно…
рад, что хоть кому-то понравилась эта статья, и этот алгоритм……
Алгоритм суперский! Аффторору зачёт и огромное спасибо 😉
Будет вообще суперски если аффтор сделает просто модуль, без dll 🙂 У мну плохо с асмом… ))
если ты используешь Dll тебе не надо знать асм, ты просто вызываешь функцию из этой Dll и тебе не важно на чём она написана. Я специально засунул этот алгоритм в Dll Ин аписал его на асме для максимальной скорости обработки файлов.
Ой, извиняюсь, не правильно выразился… действительно можно подумать что из-за незнания асма у мну проблемы использования функции из dll :))). Я хотел сказать что не есть гуд с собой библиотеку тягать, легче сделать одним модулем со вставками на асме. В принципе я уже даже реализовал это всё в виде компонента, но dll так и мозолит глаза… :)) Асм конечно рулит всегда )))
Угу, ценный алгоритм, за сутки не вскрывается; правда за пару-тройку суток запросто, особенно если есть dll для игры паролями и файлами для шифрования.
Основная проблема: сложность шифрования (скорее кодирования, но не суть) в большей степени зависит от пароля. Например, текстовый файл, зашифрованный паролем 1111111 (или паролем длины
продолжение статьи — http://pblog.ru/?p=103, в ней как раз исправлена ситуация с паролем состоящим из одинаковых символов.
супер статья
Алгоритм — совсем для начинающих. Линейность преобразования пароля и линейность CRC32 не дают основания говорить о хоть какой-то стойкости. Не занимайтесь ерундой — читайте нормальные статьи по серьезной криптографии, если хотите сделать что-то стоящее.
О предыдущей статье: алгоритм — для 5 класса, а то и младше, слово «шифровать» по-английски пишется «crYpt», а не «cript».