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

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

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

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

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

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

Годами зарекомендовавшими себя криптостойкими блочными шифрами являются:
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.

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

Оставить мнение

Check Also

Ugears. Новые модели подвижных конструкторов из дерева

Услышав слова «деревянный конструктор», ты, наверное, представляешь себе этакий Lego для с…