В данном тексте хотелось бы затронуть такую животрепещущую тему, как шифрование
файлов. Вообще нужно различать два вида шифрования файлов:

  • шифрование для себя (чтобы ваши файлы никто, кроме вас не "читал")
  • шифрование для других (чтобы ваши файлы "читал" только адресат)

Первый способ довольно актуальный для защиты собственной информации и для него
используются симметричные алгоритмы шифрования с секретным ключом. Так как
данный ключ будет доступен только тем, кому адресовано сообщение, в данном
случае только владельцу.

Во втором же способе необходимо использование ассиметричных алгоритмов, с
открытым и секретным ключом.

Блочные шифры используют симметричные алгоритмы и шифруют данные блоками.
Помимо блочных шифров существуют потоковые шифры, они часто применяются
военными для защиты каналов передачи информации. И имеют чаще всего аппаратную,
а не программную реализацию. Этим и объясняется довольно частое использование
в шифровании файлов блочных шифров. На блочных шифрах реализованы практически
все криптосистемы.

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

Годами зарекомендовавшими себя криптостойкими блочными шифрами являются:
IDEA, CAST, BlowFish, TwoFish, TEA, MARS, Serpent, Rijndael, ГОСТ 28147-89, Triple
DES, RC6.

В 80-х годах в США был принят стандарт симметричного криптоалгоритма для
внутреннего применения DES (Data Encryption Standard), который получил
достаточно широкое распространение в свое время. Но в данный момент он очень
сильно устарел. Все это побудило Американский институт стандартизации NIST - National 
Institute of Standards & Technology на объявление в 1997 году конкурса на
новый стандарт симметричного криптоалгоритма. Тем самым, победитель этого
соревнования, названного AES - Advanced Encryption
Standard, станет де-факто мировым криптостандартом на ближайшие 10-20 лет.
Алгоритм Rijandel в 2000 г. сменил предыдущий американский стандарт - алгоритм
DES. Победил же данный алгоритм на открытом конкурсе в конце которого
соревновался с MARS, TwoFish, Rijndael, RC6. Теперь Rijandel называется -
AES.

Для примера мы реализуем на паскале и ассемблере блочный шифр TEA
(Tiny Encryption Algorithm), разработанный в Кэмбридже в 1985 году.
Параметры шифра: длина блока - 64 бита, длина ключа - 128 бит.
Оптимизирован под 32 битные процессоры. Испытан временем и является довольно криптостойким.

В алгоритме использована сеть Фейштеля с двумя ветвями в 32 бита каждая.
Образующая функция F обратима. Сеть Фейштеля несимметрична из-за использования
в качестве операции наложения не исключающего "ИЛИ", а арифметического сложения.

Сеть Фейштеля является модификацией метода смешивания текущей части шифруемого
блока с результатом некоторой функции. Данная функция вычисляется от другой
не зависимой части блока. Этот метод часто используется, потому что обеспечивает
многократное использовании ключа и материала исходного блока информации.

Недостатком алгоритма является некоторая медлительность, вызванная
необходимостью повторять цикл Фейштеля 32 раза (это необходимо для тщательного
"перемешивания данных" из-за отсутствия табличных подстановок).

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

Рассмотрим листинг на паскале:

const Delta=$9E3779B9;

procedure EnCrypt(var y,z:longword; k0,k1,k2,k3:longword);
var a,sum:longword;
begin
sum:=0;
for a:=0 to 31 do
begin
inc(sum,Delta);
inc(y,((z shl 4)+k0) xor (z+sum) xor ((z shr 5)+k1));
inc(z,((y shl 4)+k2) xor (y+sum) xor ((y shr 5)+k3));
end;
end;

procedure DeCrypt(var y,z:longword; k0,k1,k2,k3:longword);
var a,sum:longword;
begin
sum:=Delta shl 5;
for a:=0 to 31 do
begin
dec(z,((y shl 4)+k2) xor (y+sum) xor ((y shr 5)+k3));
dec(y,((z shl 4)+k0) xor (z+sum) xor ((z shr 5)+k1));
dec(sum,Delta);
end;
end; 

Рассмотрим листинг на ассемблере:

; ;
; [TINY ENCRYPTION ALGORITHM] ;
; ;
; DEZIGNED BY SLON ;
; ;
; FOR MS WINDOWS ;
; ;
;---;
; BUFFER TO ENCRYPT -> EDX ;
; KEY TO ENCRYPT -> EAX ;
; SIZE OF BUFFER (div 4 = 0) -> ECX ;
;---;
total_encrypt:
pusha ;
Сохраняем всё в стеке

mov esi,eax ; Кладём в esi - eax
mov edi,edx ;
Кладём в edi - edx
work__:
pusha ;
Сохраняем всё в стеке
call Encrypt ;
Шифруем первые 64 бита данных
popa ;
Восстанавливаем из стека

add edi,8 ; Добавляем к edi - 8 
sub ecx,7 ;
Отнимаем от ecx - 7
loop work__ ;
Продолжаем шифровать

popa ;
Восстанавливаем из стека
ret ;
Возврат из подпрограммы
;---;
; BUFFER TO DECRYPT -> EDX ;
; KEY TO DECRYPT -> EAX ;
; SIZE OF BUFFER (div 4 = 0) -> ECX ;
;---;
total_decrypt:
pusha ;
Сохраняем всё в стеке

mov esi,eax ; Кладём в esi - eax
mov edi,edx ;
Кладём в edi - edx
work2__:
pusha ;
Сохраняем всё в стеке
call decrypt ;
Шифруем первые 64 бита данных
popa ;
Восстанавливаем из стека

add edi,8 ; Добавляем к edi - 8 
sub ecx,7 ;
Отнимаем от ecx - 7
loop work2__ ;
Продолжаем шифровать

popa ; Восстанавливаем из стека
ret ;
Возврат из подпрограммы
;---;
Encrypt:
push edi ;
Сохраняем edi в стэке
mov ebx,v0 ;
Кладём в ebx первые 32 бита данных
mov ecx,v1 ;
В ecx кладём вторые 32 бита данных
xor eax,eax ;
Обнуляем eax
mov edx,9e3779b9h ;
В edx ->
sqr(5)-1 * 2^31

mov edi,32 ;
Кладём в edi - 32
ELoopR:
add eax,edx ;
Добавляем к eax - edx
mov ebp,ecx ;
Кладём в ebp - ecx
shl ebp,4 ;
Сдвиг ebp на 4 бита влево
add ebx,ebp ;
Добавляем к ebx - ebp
mov ebp,k0 ;
Кладём в ebx первые 32 бита ключа
xor ebp,ecx ;
XOR'им их вторыми 32 битами данных
add ebx,ebp ;
Добавляем к 1-и 32 битам данных р-т
mov ebp,ecx ;
Кладём в ebp - ecx
shr ebp,5 ;
Делим ebp на 32
xor ebp,eax ;
XOR'им ebp - eax'ом
add ebx,ebp ;
Добавляем к ebx - ebp
add ebx,k1 ;
Добавляем к ebx - 2-е 32 бита ключа
;
mov ebp,ebx ;
Кладём в ebp - ebx
shl ebp,4 ;
Сдвиг ebp на 4 бита влево
add ecx,ebp ;
Добавляем к ecx - ebp
mov ebp,k2 ;
Кладём в ebp 3-и 32 бита ключа
xor ebp,ebx ;
XOR'им ebp - ebx'ом
add ecx,ebp ;
Добавляем к ecx - ebp
mov ebp,ebx ;
Кладём в ebp - ebx
shr ebp,5 ;
Сдвиг ebp вправо на 5 бит
xor ebp,eax ;
XOR'им ebp - eax'ом
add ecx,ebp ;
Добавляем к ecx - ebp
add ecx,k3 ;
Добавляем к ecx - 4-е 32 бита ключа
dec edi ;
Уменьшаем edi на единицу
jnz ELoopR ;
Шифруем дальше

pop edi ; Вынимаем из стека edi
mov v0,ebx ;
Кладём результаты шифрования
mov v1,ecx ;
В отведённое для них место
ret ;
Возврат из подпрограммы
;---;
Decrypt:
push edi ;
Сохраняем edi в стэке
mov ebx,v0 ;
Кладём в ebx первые 32 бита данных
mov ecx,v1 ;
В ecx кладём вторые 32 бита данных
mov edx,9e3779b9h ;
В edx ->
sqr(5)-1 * 2^31

mov eax,edx ;
Кладём в eax - edx
shl eax,5 ;
Сдвиг eax в лево на 5 бит
mov edi,32 ;
Кладём в edi - 32
DLoopR:
mov ebp,ebx ;
Кладём в ebp - ebx
shl ebp,4 ;
Сдвиг ebp на 4 бита влево
sub ecx,ebp ;
Отнимаем от ecx - ebp
mov ebp,k2 ;
Кладём в ebp 3-и 32 бита ключа
xor ebp,ebx ;
XOR'им ebp - ebx'ом
sub ecx,ebp ;
Отнимаем от ecx - ebp
mov ebp,ebx ;
Кладём в ebp - ebx
shr ebp,5 ;
Сдвиг ebp вправо на 5 бит
xor ebp,eax ;
XOR'им ebp - eax'ом
sub ecx,ebp ;
Отнимаем от ecx - ebp
sub ecx,k3 ;
Отнимаем от ecx - 4-е 32 бита ключа
;
mov ebp,ecx ;
Кладём в ebp - ecx
shl ebp,4 ;
Сдвиг ebp на 4 бита влево
sub ebx,ebp ;
Отнимаем от ebx - ebp
mov ebp,k0 ;
Кладём в ebx первые 32 бита ключа
xor ebp,ecx ;
XOR'им ebp - eсx'ом
sub ebx,ebp ;
Отнимаем от ebx - ebp
mov ebp,ecx ;
Кладём в ebp - ecx
shr ebp,5 ;
Сдвиг ebp вправо на 5 бит
xor ebp,eax ;
XOR'им ebp - eax'ом
sub ebx,ebp ;
Отнимаем от ebx - ebp
sub ebx,k1 ;
Отнимаем от ebx - 2-е 32 бита ключа
sub eax,edx ;
Отнимаем от eax - edx
dec edi ;
Уменьшаем edi на единицу
jnz DLoopR ;
Дешифруем дальше

pop edi ; Вынимаем из стека edi
mov v0,ebx ;
Кладём результаты шифрования
mov v1,ecx ;
В отведённое для них место
ret ;
Возврат из подпрограммы
;---;
v0 equ dword ptr [edi]
v1 equ dword ptr [edi+4]
k0 equ dword ptr [esi]
k1 equ dword ptr [esi+4]
k2 equ dword ptr [esi+8]
k3 equ dword ptr [esi+12]
;-8<---[tea_128.asm]---8<-;
Как вы могли заметить, алгоритм довольно таки простой и легко реализуем на
ассемблере. Теперь на базе данного алгоритма разработаем утилиту для шифрования
файлов, ориентированную на ОС Windows.

Рассмотрим листинг:

;-8<---[fencu.asm]---8<-;
; ;
;xxx;
; ;
; [FILE ENCRYPTION UTILITE] ;
; ;
; DEZIGNED BY SLON ;
; ;
; FOR MS WINDOWS ;
; ;
;xxx;
.386 
.model flat, stdcall 

callx macro x ;
extrn x:proc ;
Макрос для упрощения
call x ;
использования WIN API
endm ; 

.data 
start: 
;---;
push offset usage__ ;
callx printf ;
Выводим сообщение об использовании
add esp,4 ;
данной программы

callx GetCommandLineA ; Получаем командную строку
mov esi,eax ;
Помещаем указатель на
;
командную строку в esi
call t__ ;
Получаем указатель на первый параметр

lodsw ;
Загружаем параметр в ax
cmp ax,'E-' ;
Проверяем мы будем шифровать?
jne d__ ;
Нет, идём на следующую проверку
mov flag,1 ;
Устанавливаем флаг в 1
jmp w__ ;
И переходим к шифрованию
d__: ;
cmp ax,'D-' ;
Проверяем мы будем дешифровать?
jne ex__ ;
Нет, идём на выход
mov flag,2 ;
w__:
call f_open ;
Работаем с файлом
ex__: 
mov al,flag ;
Помещаем в al - флаг
test al,al ;
Проверяем его
jnz ex2__ ;
Если всё нормально, то на выход

push offset invalid1_ ;
callx printf ;
Выводим сообщение, об ошибке
add esp,4 ;
ex2__:
push 0 ;
callx ExitProcess ;
Завершение процесса
;---;
t__: ;
lodsb ;
Проверяем все символы на
cmp al,20h ;
равенство пробелу
jne t__ ;
Если нашли пробел, то 
;
теперь esi указывает на
;
argv[1]
ret
;---;
f_open:
pusha ;
Сохраняем всё в стэке
call t__ ;
Находим имя файла
push esi ;
Сохраняем указатель в стэке
call t__ ;
Находим следующий параметр
dec esi ;
Переходим на разделяющий пробел
mov byte ptr[esi],0 ;
И заменяем его нулём
pop esi ;
Восстанавливаем указатель из стека
push esi ;
И тут же кладём его обратно в стек

xor eax,eax ;
push eax ;
push 00000080h ;
push 3 ;
push eax ;
push 00000001h OR 00000002h ;
push 40000000h OR 80000000h ;
push esi ;
Открываем существующий
callx CreateFileA ;
файл
(esi)

inc eax ;
test eax,eax ;
Если возникла ошибка, то
jnz g__ ;
переходим на error_
push offset file_err_ ;
и выводим
callx printf ;
Сообщение
add esp,4 ;
g__:
dec eax ;
Уменьшаем eax на 1

mov fHnd,eax ; Сохраняем хэндл файла

push s2read ;
push eax ;
callx GetFileSize ; П
олучаем его размер
mov sz_,eax ;
и сохраняем его в sz_

; выделяем память
push 0 ;
имя файла хэндл = 0
push sz_ ;
макс. размер = memory
push 0 ;
минимальный размер = 0
push 4 ;
доступ чтение/запись
push 0 ; 
push fHnd ;
callx CreateFileMappingA ;

mov mHnd,eax ; Сохраняем хэндл памяти
or eax,eax ;
если ошибка, то на выход
jz error2_ ;

push sz_ ; количество памяти 
;
для работы
push 0 ; 
push 0 ; 
push 2 ;
Режим записи
push eax ;
хэндл
callx MapViewOfFile ;
Вызываем функцию

test eax,eax ; Если ошибка, то
je error3_ ;
На выход

mov mHnd2,eax ; Сохраняем указатель на память

cmp flag,1 ;
je d2__ ;
lea ebx,total_decrypt ;
Проверяем какая нам функция нужна
jmp d3__ ;
Шифровки или дешифровки
d2__: ;
и кладём её смещение в ebx
lea ebx,total_encrypt ;
d3__:
pop esi ;
Получаем указатель на
call t__ ;
наш 128 битный ключ

mov edx,mHnd2 ; Дешифруем данные
mov eax,esi ;
Нашим ключом (128 бит)
mov ecx,sz_ ;
sz_ байт - длина данных
call ebx ;

push mHnd2 ;
callx UnmapViewOfFile ;
Закончиваем изменение 
;
файла в памяти и ложим
;
его обратно
error3_: 
push mHnd ;
callx CloseHandle ;
Закрываем память
error2_:
push fHnd ;
callx CloseHandle ;
Закрываем файл
error_:
popa ;
Вынимаем всё из стэка
ret ;
Возврат из подпрограммы
;---;
fHnd dd 0 ;
sz_ dd 0 ;
mHnd dd 0 ;
s2read dd 0 ;
Данные
mHnd2 dd 0 ;
flag db 0 ;

usage__:
db '|----------------------------------------------------------------|',0ah,0dh
db '| [FILE ENCRYPTION UTILITE (BASED ON TEA) BY SLON] |',0ah,0dh
db '|----------------------------------------------------------------|',0ah,0dh
db '| USAGE: FENCU.EXE [-D OR -E] [FILENAME] [128 BIT KEY] |',0ah,0dh
db '| -D : DECRYPT FILE |',0ah,0dh
db '| -E : ENCRYPT FILE |',0ah,0dh
db '| EXAMPLE: FENCU.EXE -E HELLO.TXT 1234567890abcdef |',0ah,0dh
db '|----------------------------------------------------------------|',0ah,0dh
db 0ah,0dh,0

invalid1_:
db '[INVALID PARAMETER, EXITING ...]',0ah,0dh,0 
file_err_:
db '[FILE ERROR, EXITING ...]',0ah,0dh,0
;---;
include tea_128.asm
;---;
.code
nop
end start 
end 

;-8<---[fencu.asm]---8<-;

Исходники

Итак, к чему мы пришли в итоге: мы смогли написать утилиту, которая шифрует
файлы по алгоритму TEA на основе 128 битного ключа. Вскрытие таких файлов нельзя
назвать невозможным, но можно назвать крайне трудоёмким и
долгим по временм.

Данную утилиту можно было бы оптимизировать следующим образом:

  • чтобы все ключи с именами файлов хранились на дискете (не нужно будет помнить все ключи)
  • случайно генерировать ключ для шифрования файла (не возможность атаки по словарю)

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

На совести читателя остаётся изучение и разработка, таких алгоритмов, как:
IDEA, CAST, BlowFish, TwoFish, MARS, Serpent, Rijndael.

Освоение данной области криптографии открывает громадные перспективы перед
нами.

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии