» Шифровка с помощью пароля. Улучшаем алгоритм шифрования Assembler. Win Api. . Блог программистов


Блог программистов






20073 Сен

Шифровка с помощью пароля. Улучшаем алгоритм шифрования

    Доброго времени суток. Наверно все читали мою предыдущую статью «Шифруем файл с помощью пароля» (рекомендую прочитать перед прочтением этой статьи). В ней я описал методику шифрования файлов с помощью пароля. Это конечно довольно-таки простая методика. В этой статье я расскажу про более сложную методику шифрования с помощью пароля. Итак, приступим.

    В чём уязвимость старого алгоритма? Допустим в файле будет некоторая последовательность одинаковых байт. После шифрования будет видно повторение одной и той же последовательности, которая имеет длину равную длине пароля. Будет видно, на сколько отличаются символы в пароле (например, второй символ на 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 и пример её использования.

Исходник алгоритма шифрования CSCA1 и пример использования

Комментарии

  1. D-fyz
    3 сентября, 2007 | 22:37

    просто и со вкусом… больше слов здесь не нужно…

  2. rpy3uH
    4 сентября, 2007 | 19:17

    рад, что хоть кому-то понравилась эта статья, и этот алгоритм……

  3. Romik©
    18 сентября, 2007 | 22:13

    Алгоритм суперский! Аффторору зачёт и огромное спасибо 😉

  4. Romik©
    18 сентября, 2007 | 22:19

    Будет вообще суперски если аффтор сделает просто модуль, без dll 🙂 У мну плохо с асмом… ))

  5. rpy3uH
    20 сентября, 2007 | 19:11

    если ты используешь Dll тебе не надо знать асм, ты просто вызываешь функцию из этой Dll и тебе не важно на чём она написана. Я специально засунул этот алгоритм в Dll Ин аписал его на асме для максимальной скорости обработки файлов.

  6. Romik©
    23 сентября, 2007 | 12:12

    Ой, извиняюсь, не правильно выразился… действительно можно подумать что из-за незнания асма у мну проблемы использования функции из dll :))). Я хотел сказать что не есть гуд с собой библиотеку тягать, легче сделать одним модулем со вставками на асме. В принципе я уже даже реализовал это всё в виде компонента, но dll так и мозолит глаза… :)) Асм конечно рулит всегда )))

  7. QuAlex
    4 октября, 2007 | 11:40

    Угу, ценный алгоритм, за сутки не вскрывается; правда за пару-тройку суток запросто, особенно если есть dll для игры паролями и файлами для шифрования.
    Основная проблема: сложность шифрования (скорее кодирования, но не суть) в большей степени зависит от пароля. Например, текстовый файл, зашифрованный паролем 1111111 (или паролем длины

  8. rpy3uH
    15 февраля, 2008 | 18:03

    продолжение статьи — http://pblog.ru/?p=103, в ней как раз исправлена ситуация с паролем состоящим из одинаковых символов.

  9. Димон
    11 апреля, 2008 | 21:33

    супер статья

  10. Serb
    15 июня, 2010 | 15:40

    Алгоритм — совсем для начинающих. Линейность преобразования пароля и линейность CRC32 не дают основания говорить о хоть какой-то стойкости. Не занимайтесь ерундой — читайте нормальные статьи по серьезной криптографии, если хотите сделать что-то стоящее.

  11. Serb
    15 июня, 2010 | 15:46

    О предыдущей статье: алгоритм — для 5 класса, а то и младше, слово «шифровать» по-английски пишется «crYpt», а не «cript».