Шифруйся сам! Alek Silverstone Xakep, номер #065, стр. 065-110-1 (AlekSi@pisem.net) Шифруем и хешируем без чужих компонентов Сейчас модно говорить о криптографии: таинственные слова "IDEA", "BlowFish", "MD5" можно слышать достаточно часто. Однако большая часть людей знает только, что это такое, и не знает, как это сделано. Поэтому все начинающие кодеры, столкнувшиеся с проблемой защиты информации, начинают либо изобретать колесо (xor с ключом, битовый сдвиг и т.п. - все это вызывает у профессионалов лишь кривую ухмылку), либо использовать чужие компоненты. В этой статье мы разберем два простых алгоритма, необходимых в любой программе защиты информации. Первый - алгоритм шифрования, второй - функция хеширования (о том, что это такое, прочитай в статье «Надери задницу хацкерам» этого же номера). Шифруемся! Рассмотрим алгоритм шифрования RC4 (Ron's Code 4 или Rivest's Cipher 4, если интересно). Я взял его, во-первых, из-за крайне простой реализации, а во-вторых, из-за высокой стойкости к атакам. Он был разработан Роном Ривестом (Ron Rivest, один из самых известных людей в мире криптографии - буква "R" в аббревиатуре RSA принадлежит именно ему) в 1987 году, и с тех пор не известно ни одного случая успешной атаки на него. Есть и третья причина - этот алгоритм является поточным шифром. Что это значит? Опять рассмотрим пример. Допустим, нам необходимо шифровать поток информации. Как работают блочные шифры, такие как DES, IDEA и BlowFish? Им на вход подается текст фиксированного размера (в случае DES - 64 байта), на выходе получается тот же объем. То есть в нашем примере нам придется ждать получения 64 байт, потом шифровать их и выплевывать. Но ведь поток надо шифровать в режиме реального времени! А если блоки идут по нескольку байт? Вот и выходит облом... Потоковые же шифры обрабатывают текст по одному биту (в данной реализации RC4 - по одному байту). RC4 входит в спецификацию стандарта CDPD (сотовая пакетная передача данных), а также в "туннельный" протокол "точка-точка" PPTP (защищенный PPP). Такие солидные стандарты не выбрали бы что-то плохое :). Для алгоритма нам понадобятся три глобальные переменные - rc4i и rc4j типа byte и массив rc4s:array[0..255] of byte. Сначала надо заполнить массив: Заполняем массив procedure RC4Init(key:shortstring); var k: array[0..255] of byte; i, j, t : byte; begin rc4i:=0; rc4j:=0; for i:=0 to 255 do rc4s[i]:=i; j:=0; t:=length(key); for i:=0 to 255 do begin inc(j); k[i]:=Byte(key[j]); if j=t then j:=0; end; j:=0; for i:=0 to 255 do begin j:=(j+k[i]+rc4s[i]) mod 256; t:=rc4s[i]; rc4s[i]:=rc4s[j]; rc4s[j]:=t; end; end; Вот и все! Сложно? Да ладно! Все остальные алгоритмы намного сложнее! :) Теперь напишем функцию для получения шифрованного байта: Шифранем байты function RC4GetCryptoByte(ch:byte):byte; var t:byte; begin rc4i:=(rc4i+1) mod 256; rc4j:=(rc4j+rc4s[rc4i]) mod 256; t:=rc4s[rc4i]; rc4s[rc4i]:=rc4s[rc4j]; rc4s[rc4j]:=t; t:=(rc4s[rc4i]+rc4s[rc4j]) mod 256; RC4GetCryptoByte:=rc4s[t] xor ch; end; В первой строчке мы циклически увеличиваем значение rc4i на 1. Если значение стало равным 255, то оно обнуляется. Второй строчкой мы изменяем значение счетчика rc4j в зависимости от массива rc4s (который, в свою очередь, зависит от ключа). Потом мы меняем местами элементы с порядковыми номерами rc4i и rc4j в этом массиве. Далее мы определяем номер элемента, который складывается по модулю 2 (это такое хитрое название xor'а) с байтом исходного текста. Этот шифр является симметричным, поэтому дешифрование выполняется аналогично шифрованию - на вход подаем зашифрованный байт и получаем дешифрованный. Скорость его примерно в 11 раз выше, чем у известного DES’а (проверенно мной). |