27 апреля 2012 г.

Сеть Фейштеля

Иной раз необходимо зашифровать какойнить кусочек, причем желательно не банальным XOR, так как он расшифровывается без проблем частенько даже при наличии бумажки с ручкой, а чем нибудь более стоящим. Посложнее XOR но полегче и попроще чем AES или MD5.
Для этого один из американских ученых по фамилии Фейштель разработал алгоритм, в последствии который стал называться сетью Фейштеля. Он до сих пор используется в в качестве основного движка во многих алгортмах шифрования, да хотябы в том же MD5. Я рассмотрю основной движек, без навороченных навесок типа перемешивания и прочего.
Смысл его в чем:



У нас есть сообщение которое мы хотим зашифровать, например изречение Конфуция
"It does not matter how slowly you go so long as you do not stop." и ключ которым будем шифровать "konf".

1. Берем исходное сообщение и разбиваем его на куски по 32бита. Тоесть по 4 буквы.
2. Берем первые 2 части по 32 бита. В 16ричном выглядят они так "49742064" и "6F657320". Одну часть называем левой, вторую правой.
3. Теперь берем ключ konf. - 66 6E 6F 6B
4. Сдвигаем по кругу на 1 бит в право. Это так называемая функция F. Которая важна чтобы не получить закономерности.
5. Делаем XOR c левой части с ключем.
6. Делаем XOR результата предыдущей функции с с правой частью.
7. Меняем местами левую и правую часть - и снова переходим на первый пункт. Повторить до получения удовлетворения.

В картинках это выглядит следующим образом:

Вообщем ничего сложного в этом нет,  а теперь посмотрим как это выглядит на ассембелере:


.386
.model flat, stdcall
option casemap:none
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib

code     proto:DWORD, :DWORD, :DWORD, :DWORD, :DWORD ; прототип функции

.data
clear_text     db "It does not matter how slowly you go so long as you do not stop." ; строка которую шифруем
msg_l        dd 40h ; длинна строки
key            dd "konf" ; ключ которым шифруем
code_repeat dd 20h ; сколько раз будем повторять

.data?
code_text db 40h DUP (?) ; выходная строка

.code
start:

    invoke     code, ADDR clear_text, ADDR key, ADDR code_text, code_repeat, msg_l ; шифруем строку
    
    shl        code_repeat,1 ; умножим количество раундов в 2 раза для расшифровки
    invoke     code, ADDR code_text, ADDR key, ADDR code_text, code_repeat, msg_l ; расшифровывем


    invoke    ExitProcess,0 ; корректно выходим из программы
    
code proc uses ebx edi edx ecx c_msg:DWORD, c_key:DWORD, c_ctext:DWORD, c_rep:DWORD, c_msg_l:DWORD
local buf_l:DWORD ; буфер для левой части
local buf_r:DWORD ; буфер для правой части

    mov        edi, c_msg ; кладем в edi начало не зашифрованной строки
    mov        edx, c_ctext ; кладем в edx куда будем писать зашифрованные данные 

next_part:    
    mov        eax, DWORD PTR [edi] ; читаем первые 4 байта сообщения
    mov        buf_l,     eax ; кладем их в левый буфер
    mov        eax, DWORD PTR [edi+4] ; читаем следующие 4 байта
    mov        buf_r, eax ; кладем в правую часть
    
    mov        eax, c_key ; в eax помещаем адрес ключа
    mov        eax, [eax] ; в eax помещаем сам ключ
    mov        ecx, c_rep ; в ecx - сколько раз повторить процесс

pov:
    mov        ebx, DWORD PTR [buf_l] ; в ebx кладем левую часть 
    ror        eax, 1 ; сдвигаем на 1 бит в право ключ
    xor        ebx, eax ; ксорим левую часть с ключем, это и есть функция F
    xor        DWORD PTR [buf_r], ebx ; получившееся ксорим с правой частью
    
    push    DWORD PTR [buf_l] ; кидаем в стек левую часть
    push    DWORD PTR [buf_r] ; кидаем в стек правую часть
    
    pop        DWORD PTR [buf_l] ; поднимаем данны из стека в левую часть
    pop        DWORD PTR [buf_r] ; поднимаем данны из стека в правую часть
    loop    pov ; повторить пока не закончится ecx
    
    mov        eax, DWORD PTR [buf_l] ; поместить в eax левый буфер
    mov        DWORD PTR [edx], eax ; записать в хранилище зашифрованного сообщения
    mov        eax, DWORD PTR [buf_r] ; поместить в eax правый буфер
    mov        DWORD PTR [edx+4], eax ; записать в хранилище зашифрованного сообщения
    
    add        edi, 8h ; сдвинуть позицию в незашифрованной строке
    add        edx, 8h ; сдвинуть позицию в зашифрованной строке
    sub        c_msg_l,8h ; уменьшить количество символов в оставшейся строке на 8
    cmp        c_msg_l, 0 ; сравнить с нулем
    jz        end_fest ; если равно нулю - закончить шифрование
    jmp        next_part

end_fest:
    mov        eax, c_ctext
    
    Ret
code EndP
    
end start

Комментариев нет:

Отправить комментарий