Поточные шифры. Операция XOR и простейшее шифрование файлов Кодирование xor

The binary operation XOR (stands for eXclusive OR) is a binary operand (as are AND, OR, etc) from Boole algebra. This operand will compare two bits and will produce one bit in return. That bit will be equal to 1 if the two compared bits were different, 0 if they were equal. Xor encryption is commonly used in several symmetric ciphers (especially AES). A symetric cipher is simply a cipher in which the key is used for encryption and decryption process. The XOR operand is so applied to each bit between the text you want to encrypt and the key you"ll choose. Examples are better than words, let"s take the word "xor". We want to encrypt it with the key "cle". First we have to convert the input and the key in binary representation:

Then we compare each bit with the XOR operand. Which will give you this:

Xor: 01111000 01101111 01110010
cle: 01100011 01101100 01100101
00011011 00000011 00010111

If we wanted to go back to the original input ("xor"), we would just have to reapply the XOR between the output and the key. You can note that XOR is a commutative function, as multiplications. Now what do we do if the key is smaller than the input ? This is the case in most situations. If the key was the same length than the input, it wouldn"t be interesting because you would also have to communicate the key to the person you want reading the input. In contrast, when the key and the input have the same length, it is impossible for someone to crack the cipher. So, when the key is smaller than the input, you just reapply it until you reach the end of input. If by instance I wanted to encrypt the word "bonjour" with my key "cle", I would do it this way:

Bonjour: 01100010 01101111 01101110 01101010 01101111 01110101 01110010
cleclec: 01100011 01101100 01100101 01100011 01101100 01100101 01100011

You can see that we simply repeat the key. The smaller you key, the easiest it will be to crack your cipher (obviously). The XOR cracking often are based on frequency analysis. But for that matter, I suggest you to do some researches.

Согласно определению, двухместная однобитовая операция "исключающее ИЛИ" выполняет действия, показанные в табл. 19.1.

Таблица 19.1. Исключающее ИЛИ(ХОЯ)

Вход 1

Вход 2

Выход

Ее можно еще назвать "операция несовпадения"- на выходе логическая единица тогда, когда значения на входах не совпадают. Из этого определения легко вывести основное свойство этой операции: будучи применена дважды к одному и тому же операнду, она ничего не изменит, независимо от значения второго операнда, лишь бы он не менялся. Этим, в частности, широко пользуются в компьютерной графике: если приложить через операцию XOR к фону маску, состоящую из всех единиц (чисто белую), то изображение на этом месте инвертируется по цветам, при повторении того же действия все восстанавливается в неизменном виде (так, в частности, удобно производить выделение. см. главу 10).

Данное свойство и положено в основу практически всех алгоритмов шифрования, которые иногда могут быть очень навороченными, но мы не будем углубляться в этот вопрос, а просто попробуем применить этот метод в его изначальном виде. Для проверки можно использовать такую простейшую процедуру. Пусть мы хотим зашифровать некий текстовый файл. Так как мы дипломатические секреты не прячем, то нам хватит обычной в таких случаях длины ключа в 8 символов (64 бита)- этого достаточно, чтобы сделать взлом шифра методом перебора на обычном персональном компьютере задачей "с налета" нерешаемой. Для примера ключом будет служить слово "yvre- vich". Создавать такие ключи из своей фамилии на практике ни в коем случае нельзя, нельзя также употреблять любые словарные слова, даты, номера ге- лефонов- еще Вернам показал, что для эффективного шифрования ключ должен быть строго случайным, здесь это делается только в качестве примера (о том, как можно задавать случайный ключ, мы поговорим позже).

Создадим новый проект (в папке Glaval9\l) под названием ProbaCrypt, и разместим в той же папке некий файл на пробу. Я взял текст песни "Однажды мир прогнется под нас" из репертуара А. Макаревича (в текстовом же формате, файл mashinavremeni.txt) с аккордами, т. к. достаточно сложное форматирование этого текста сделает пример нагляднее 3 .

Поместим на форму компонент Memo, диалог OpenDialog и две кнопки Butt эл. В заголовке Buttoni напишем Зашифровать, в заголовке Buttoni - Расшифровать. Объявим такие переменные:

Forml: TForml ; fname,key:string; fi,fo:file of byte; i:integer; xb:byte;

При создании формы инициализируем ключ и диалог:

procedure TForml.FormCreate(Sender: TObject); begin key:=’yvrevich";

OpenDialogl.InitialDir:=ExtractFiieDir(Application.ExeName); end;

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

procedure TForml.ButtonlClick(Sender: TObject); begin /Зашифровать/ OpenDialogl. FileName:?= 11 ; (очистим) OpenDialogl.Filter:=”; if OpenDialogl.Execute then fname:=OpenDialogl.FileName else exit; assignfile(fi,fname); {задали исходный файлI try

reset(fi); {открыли исходный) except

exit; {если не открывается – на выход) end;

assignfile(fo,ChangeFileExt(fname, 1 .sec’)) ; rewrite(fo);

read(fi,xb); {прочли первый байт)

Forml.Caption:=’ProbaCrypt: ‘+ExtractFileName(fname);

/название файла – в заголовок) Memol.Lines.Clear; Memol.Lines.Add(‘Подождите…’);

Application.ProcessMessages; Memol.Lines.Clear; while not eof(fi) do begin

xb:=xb xor ord(key[i]); {шифруем)

Memol.Text:=Kemol.Text+chi(xb); {выводим в Memo)

write(fo,xb); (записываем в файл)

read(fi,xb); {если конец файла – выходим) except break; end; end; end;

closefile(fi) ;

erase(fi); {уничтожаем исходник)

closefile(fo);

{зашифровали) end;

Тут мы складываем через операцию XOR каждый байт исходного файла с байтами ключа по очереди; когда ключ заканчивается, мы опять начинаем с его первого символа. Результаты пишем в файл с расширением sec (от "security") и выводим в Memoi. В точности ту же операцию мы производим при расшифровке, только уже с зашифрованным файлом, в результате чего исходный файл восстанавливается полностью:

procedure TForml.Buttor.2Click(Sender: TObject); begin {Pa оцифровать j OpenDialogl.FileName:=”; {очистим/ OpenDialogl.Filter: = ‘№4>poBaHHbie файлы| *.sec’ ; if OpenDialogl.Execute then fname:OpenDialogl.FileName else exit; assignfile(fi, fname); {открыли шифрованный) try

reset(fi); except exit; end;

assignfile(fo,ChangeFileExt(fname, ‘.txt’)); rewrite(fo); {перезаписываем старый) read(fi,xb);

Forml.Caption:=’ProbaCrypt: ‘+ExtractFileNajne (fname) ;

!название файла – в заголовокj

Memol.Lines.Clear;

Memol.Lines.Add(1 Подождите…’);

Application.ProcessMessages; {чтобы увидеть предупреждение) Memol.Lines.Clear; while not eof(fi) do begin /асе без изменений, как выше} for i:=l to length(key) do begin

xb:=xb xor ord(keyU));

Memol.Text:=Memol.Text+chr(xb);

write(fo,xb);

read(fi,xb); except break; end; end; end;

closefile(fi); closefile(fo); {pa сшифровали) end;

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

Есть тонкий момент, связанный с уничтожением оригинала - как известно, при уничтожении дискового файла он не стирается, подобно музыкальной записи на магнитной ленте, а просто в заголовочных структурах FAT место, которое ои занимает, помечается, как свободное (примерно также происходит это и в NTFS). Именно с этой особенностью была связана работа DOS- программы Unerase (если кто помнит, что это такое). Поэтому, если вы даже удалите файл из Корзины (удаленный из нашей программы файл в Корзину, правда, итак не попадает), на диске останется его содержание до тех пор, пока туда не будет записано что-то еще. Поэтому для особо параноидальных личностей продвинутые программы шифрования предлагают опцию, при которой файлы после стирания уничтожаются гарантированно- на их место записываются нули. В нашем случае для этого в принципе достаточно не закрывая файл, заполнить его байтами с нулевым значением (или любым другим, но не увеличивая и не уменьшая размер файла), записать это на диск (закрыв файл), а потом уже его уничтожать. Правда, в Windows стопроцентной гарантии, что он запишется в точности на то же место, я дать не могу, поэтому лучше в таких случаях применять все же "официальные" программы, которые, кстати, уничтожают следы исходника не только в той области диска, где он хранился, но и SWAP-файле Windows, если они там остались.

Что касается генерации случайных ключей, то вот один из способов. I Указывать реализацию полностью я не буду, так как она проста. Генератор псевдослучайных чисел в Delphi (и не только в Delphi) устроен следующим образом: через переменную RandSeea задается начальное число генератора (но умолчанию оно равно 0). Тогда функция Random при последовательном обращении к ней всегда будет возвращать один и гот же набор чисел, независимо от того, в какой программе и когда мы ее используем. Отсюда и способ- вы устанавливаете в программе такой генератор и на его основе генерируете ключ, например. вот так можно сгенерировать случайный 16-байтный (128-битный) набор символов, который будет зависеть только от величины начального смещения генератора init:

:

init:integer; st:string;

st:=”;

RandSeed:=init; {начальное смещение} while length(st)<16 do begin xb:=Random(255); if xb>31 then st:=st+chr(xb); end;

При этом вы передаете вашему корреспонденту не сам ключ, а величину ir.j .. У него будет сгенерирован по идентичной процедуре в точности тот же ключ. Можно придумать, разумеется, и более хитрые механизмы реализации этого метода.

Хочу заметить, чтобы не затемнять суть дела, ранее в программе я использовал традиционное побайтное чтение из дискового файла. Резко ускорить процедуру можно при использовании одного из механизмов предварительного чтения файла в память- file mapping, как в главе 14, потокового чтения или любого другого способа организации динамических массивов в памяти (см. главу 21). В примере с использованием стеганографии, к которому мы сейчас приступим, частично положение будет исправлено.

Thus, when executing an exclusive OR, there will always be a zero value if the variables have the same values.

The peculiarity of XOR is that one and the same function can both encrypt data and decrypt it. This is a simple method of data encryption, which can be hacked quickly enough if there is a large enough encrypted text, or a large password dictionary. But nevertheless, this can already be used for small initial data protection.

In the context of Qt, the use of XOR is no different from how the program was written without using Qt. The question here is how to extract data for encryption from QString objects, for example, if the text was entered in QTextEdit.

To do this, write a program that contains:

  • QTextEdit, In which the text will be entered, which will be encrypted.
  • QLineEdit, In which the encryption key will be entered.
  • QPushButton, In the slot of the click handler of which, data encryption / decryption will be performed. Again, I note that the method will be used the same.

The program will look like this:

Project structure

The project is written using CMake, so the structure will be as follows:

  • CMakeLists.txt
  • main.cpp
  • EncoderWidget.h
  • EncoderWidget.cpp

Encryption / decryption function

To implement encryption / decryption it is necessary:

  • The presence of a char array with the original data
  • Length of the array with the original data
  • Key as array char
  • Length of key
  • And also an array with output data.
const char* input; int inputLength; const char* key; int keyLength; char output; for (int i = 0; i < inputLength + 1; ++i) { output[i] = input[i] ^ key; }

Slot handler for encryption

As already mentioned, to encrypt the text, you need to correctly extract data from the input fields. To do this, you need to translate the text in the form of a QString string into a QByteArray from which to extract the data in the form of const char *. And also take the length of this data.

There is one point. This from QString in QByteArray is translated using the toLatin1 () method, which will result in data to the ASCII table, which will lead to data corruption if the text was written in Cyrillic. That is, this approach to encryption will be relevant if only symbols from the ASCII table are used, for example, for the login and password.

Void EncoderWidget::encodeDecode() { const char* input = m_textEdit->toPlainText().toLatin1().data(); int inputLength = m_textEdit->toPlainText().toLatin1().length(); const char* key = m_keyLineEdit->text().toLatin1().data(); int keyLength = m_keyLineEdit->text().toLatin1().length(); char output; for (int i = 0; i < inputLength + 1; ++i) { output[i] = input[i] ^ key; } m_textEdit->setText(QString::fromLatin1(output, inputLength)); }

Однажды, при разработке сайта, появилась необходимость передавать данные в зашифрованном виде используя PHP . Конечно же сразу пришла мысль использовать mcrypt который уже есть на PHP ... Но эта идея сразу же отпала, поскольку не на всех хостингах этот модуль установлен.

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

Немного расскажу как вообще работает XOR :

XOR - это побитовое сложение по модулю (с инвертированием при переполнении), например, 1+1=0 т.к. 1 - максимальное значение.
Все варианты:
0+0=0
0+1=1
1+1=0

Уникальность сложения по модулю состоит в его обратимости! Т.е. если придумать некоторое слово-код (назовем его гаммой) и выполнить XOR 2 раза к открытому тексту - то получим тот же открытый текст.

Пример работы XOR

Допустим, у нас есть открытый текст - "denik.od "
Придумаем для него гамму: "12345678 " (гамма должна быть равной длине текста, т.к. мы весь текст хотим зашифровать)

Конкретный пример рассмотрим на первых 2-х байтах "de " (представим их в двоичной системе):

Для расшифровки, просто применим XOR еще раз:

В результате мы получили наши первые 2 байта (de ). Точно так же делается со всем текстом.

Все остальные усложнения уже заложены в методах генерации этой самой гаммы. Есть много способов ее генерации, но в основу своего способа, я заложил функцию sha1 (создание HEX хеша).

Логика проста, мы составляем гамму длиной в кодируемый текст примерно так:

$gamma .= sha1($passw . $gamma );

Полный пример для PHP:

function strcode($str , $passw ="" ) { $salt = "Dn8*#2n!9j" ; $len = strlen($str ); $gamma = "" ; $n = $len >100 ? 8 : 2 ; while (strlen($gamma )<$len ) { $gamma .= substr(pack("H*" , sha1($passw .$gamma .$salt )), 0 , $n ); } return $str ^$gamma ; }