Секреты Джеймса БондаСергей «John Frost» Колесник Хакер, номер #104, стр. 106 (John-Frost@yandex.ru) Передаем скрытые сообщения в файлах формата *.txt В последнее время интерес к стеганографии начинает превышать интерес к криптографии, и это понятно, ведь скорость взлома шифрованной информации зависит только от мощности вычислительных ресурсов взломщика. Стеганография же предоставляет возможность скрыть сам факт передачи скрытых данных. Что это такое и с чем его едят Слово «стеганография» происходит от греческих слов steganos (тайна) и graphy (запись) и означает «тайнопись». Получается, что главной задачей стеганографии является скрытие факта передачи секретной информации. Поискав в интернете стеганографический софт, можно обнаружить большое количество программ от самых разных разработчиков: от продукции крупных компаний, занимающихся безопасностью, до всяческих «Суперскрывателей Текста В КартинГах», основанных на могучем алгоритме Василия Пупловенко, предположительно похищенном им из секретной лаборатории ГРУ :). К большинству программ даже прилагаются исходники. Но, просмотрев пару-другую таких «шедевров» программерской мысли, мы погружаемся в дежавю: большинство авторов использует примерно один и тот же алгоритм (LSB,DCT и др.). Кто-то даже переделывает алгоритм под себя, что делает скрытие данных более устойчивым к вскрытию, а кто-то просто берет известную идею, прикрепляет к ней графические навороты и начинает продавать эту шпионскую софтину по заоблачным ценам. Ладно, оставим рассуждения преподавателям информатики и политикам (они за это деньги получают), а сами перейдем к делу. О вредности известных алгоритмов В настоящее время самыми популярными контейнерами, применяемыми для скрытия информации, являются графические, звуковые и видеофайлы. Причиной тому является несовершенство человеческий органов чувств: не каждый заметит небольшое изменение палитры изображения, очень трудно отличить звук CD-качества от его mp3-варианта с очень высоким битрейтом. Из этого следует, что в таких данных содержится избыточность, которую можно использовать для своих целей. Эти способы всем хороши, только все основные алгоритмы достаточно известны, и выудить скрытое послание не так уж сложно. Единственным выходом является написание своего метода скрытия информации, чем мы сейчас и займемся. Вперед к новым тайнам Итак, мы пришли к выводу, самой лучшей идеей будет создание своего собственного алгоритма для скрытия информации. Но перед тем как приступить к ее реализации, должны ответить на несколько вопросов: 1) Какой формат файлов мы используем для скрытия? 2) Какие требования мы предъявим к файлу? 3) Изменится ли размер файла? 4) Будет ли алгоритм изменяемым, чтобы его можно было переделать под себя? Поразмыслив немного, я ответил следующим образом: 1) Мы будем использовать обычные текстовые файлы формата txt. Почему именно txt? Да потому что этот формат у большинства не вызывает подозрений, ведь он не содержит управляющих и служебных символов. Что написано текстом, то и есть на самом деле. Имеется и неплохой способ проверки - в ANSI-кодировке каждый символ занимает один байт, т.е. сколько символов текста, столько байт и должен занимать файл (юникод символ занимает два байта). 2)В нашем случае требования будут предъявляться только к объему файла (скоро узнаешь, почему). 3) Алгоритм не будет изменять оригинальный файл ни на байт и будет обладать неплохой изменяемостью. Так, вроде бы с предварительной подготовкой мы закончили, перейдем к описанию самого алгоритма, а затем и непосредственно к кодингу. Рождение идеи, или как это работает Посмотри на рисунок с изображенными на нем хитрыми буковками. На первый взгляд, в нем нет ничего необычного и напоминает он открытый в стандартном виндовом редакторе файл шрифтов с сакраментальным «Съешь еще этих мягких французских…». Казалось бы, на нем изображен один и тот же текст, просто в разных строчках. Но зачем тогда слова english и russian? Конечно же, на этой картинке изображены буквы латинского и русского алфавита, имеющие одинаковое начертание. Заметить разницу можно только при переходе со стандартного шрифта на какой-нибудь покрасивее, но поскольку в файлах формата txt не хранится информация о шрифте и прочих красивостях, файл будет открываться со стандартным начертанием и, следовательно, никто не ничего не заподозрит (вряд ли кто-то, открывая readme.txt, сразу будет изменять шрифты). Все привыкли к тому, что в обычном txt-файле не может ничего содержаться - ни скрытых данных, ни вредоносных программ - только видимый текст, а привычка, как известно, великая сила. Этим мы и воспользуемся :). Итак, мы получили в свое распоряжение 16 букв (10 больших и 6 маленьких), теперь наметим примерный алгоритм: берем какой-нибудь файл с русским текстом (можно книгу), просматриваем все символы и меняем русские символы на латинские только нам известным способом. А вот каков он будет, зависит лишь от твоей, дорогой читатель, фантазии. Я, к примеру, сделал так, что следующая буква после замененного символа становится буквой скрытого текста. Ты же можешь придумать что-нибудь свое. Начинаем кодить Сейчас мы напишем программу, реализующую мой алгоритм замены, а ты потом легко переделаешь ее под себя, так что даже если кто-то и обнаружит факт скрытия информации, прочесть ее он все равно не сможет, поскольку не знает твой алгоритм кодирования. Запускай Visual Studio .Net, выбирай новый проект, в качестве языка выбирай С# (алгоритм не зависит от языка и может быть легко перенесен на любой другой). На появившиеся окно кидай TextBox в количестве двух штук, три Button и два label. Один TextBox мы будем использовать для отражения содержимого текстового файла, второй - для скрытого послания. Одна кнопка будет служить для открытия нужного файла, вторая, соответственно, будет сохранять, ну а третья - выводить инфу о разработчике (то есть о тебе). В результате у тебя должно получиться нечто похожее на то, что изображено на рисунке (конечно, необязательно делать такой убогий дизайн) Как известно, прежде чем что-то считывать из файла, надо туда что-то записать, следовательно, мы должны научить нашу прогу анализировать текст, подставлять туда нужные символы и сохранять это чудо в файл. Алгоритм сохранения будет таков: 1) считываем с TextBox'а (в котором хранится обычный текст) подряд все буквы, сравниваем каждую из них с буквой из другого TextBox'а (в котором хранится секретный текст); 2) если они совпадают, то смотрим предыдущую букву (из обычного текста), и если она совпадает с одной из букв, которые имеют одинаковое написание в разных алфавитах, то заменяем ее русский вариант англоязычный аналогом; 3) записываем полученный текст в файл; Этот алгоритм в реализации на си шарп ты можешь увидеть в блок-врезке (полный вариант - на нашем диске). Теперь поговорим об алгоритме считывания скрытого текста из нашего файла. Тут все намного проще: открываем файл, если встречается англоязычный вариант нужной буквы, то записываем в секретный текст идущий слева от нее символ. Но как же быть, если там есть настоящий английский текст? Просто очень сложно найти текст полностью на русском. Думаем, ведь текст - это набор символов, значит, если это текст, то справа или/и слева должны стоять тоже английские буквы. Проблема решена: если рядом с найденным символом справа или слева будут стоять тоже английские буквы, то это текст и дешифровать его не надо. Не очень эффективно, но зато поможет, если в тексте есть небольшие английские слова. Посмотрим на функцию, решающую все эти проблемы и выдирающую секретный текст: private string GetSecretSymbols(string text) { // для проверки, английский этот текст или всего лишь символ bool beng=false; //английский алфавит string seng = "qwertyuiopasdfghjklzxcvbnm"; //строка, куда будут помещены секретные символы string secrets=""; // перебираем все символы переданного нам текста for (int i = 0; i < text.Length-1; i++) { switch (text[i]) { //и если это один из наших замененных вариантов case 'A': case 'B': case 'C': case 'E': case 'H': case 'M': case 'O': case 'P': case 'T': case 'X': case 'a': case 'c': case 'e': case 'o': case 'p': case 'x': // проверяем текст на англоязычность for (int j = 0; j < seng.Length; j++) { if ((text[i - 1].ToString().ToUpper() == seng[j].ToString().ToUpper()) || (text[i + 1].ToString().ToUpper() == seng[j].ToString().ToUpper())) beng = true; } if (!beng) //если текст не английский { secrets += text[i + 1]; } beng = false; break; } } return secrets; //возвращаем секретный текст } Конец игры, Бонд Подытожим, что же у нас получилось. А получилось у нас то, что нам и хотелось, - прога, которая неплохо скрывает текст в файлах формата *.txt. Да, при слишком большом объеме скрываемого сообщения она не подойдет. Зато, если переделать алгоритм под конкретные нужды, можно добиться неплохой производительности и результативности, а то, что софтина не изменяет размер модифицированного файла, - это большой плюс. Не нужно быть гением, чтобы догадаться, что можно скрыть больше текста, если исходный текст был набран в верхнем регистре. CD На диске ты найдешь исходник нашей программы, а также несколько текстовых файлов, в которых содержится скрытая информация и один оригинальный файл, который ты можешь использовать для кодирования своего текста. INFO Первое упоминание о стеганографических методах в литературе принадлежит Геродоту, описавшему случай передачи сообщения Демартом, который соскабливал воск с дощечек, писал письмо прямо на дереве, а потом заново покрывал дощечки воском. Другой эпизод, который относят к тем же временам, - передача послания с использованием головы раба. Для передачи тайного сообщения голову раба обривали, наносили на кожу татуировку и, когда волосы отрастали, отправляли с посланием. Функция, реализующая сохранение скрытого текста в обычном private void bSaveFile_Click(object sender, EventArgs e) { // для хранения номера считанного символа обычного текста int number2 = 0; // текущий номер символа секретного текста int number1 = 0; // для хранения промежуточных расчетов string temp = "";
for (int j = 0; j < tbVisibleText.Text.Length-1; j++) //перебираем все символы обычного текста { // если текущий элемент секретного текста равен // элементу обычного текста, то... if ((tbHiddenText.Text[number1].ToString().ToUpper() == tbVisibleText.Text[j].ToString().ToUpper())) { switch (tbVisibleText.Text[j - 1]) //проверяем предыдущий символ { case 'А'://если это русская буква А temp = temp.Substring(0, temp.Length - 1); temp += "A"; //заменяем англоязычным вариантом // теперь записываем следующие три символа // во избежание совпадения с заменяемыми temp += tbVisibleText.Text[j]; temp += tbVisibleText.Text[j+1]; temp += tbVisibleText.Text[j+2]; number1++; //записали на один скрытый символ больше j+=2; //перепрыгиваем сразу на два символа break;
... //здесь такой же кусок кода, только другие буквы default: temp += tbVisibleText.Text[j]; // если ни одна буква не совпадает, // просто записываем один символ break; } } else temp += tbVisibleText.Text[j]; //иначе просто прибавляем его }
... //добавляем оставшийся кусок текста после манипуляций temp += tbVisibleText.Text.Substring(number2); //теперь записываем весь этот текст в текстбокс tbVisibleText.Text = temp; if (saveFileDialog1.ShowDialog() == DialogResult.OK) //и сохраняем результат в файл { FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create); byte[] barray = Encoding.Unicode.GetBytes(tbVisibleText.Text); fs.Write(barray, 0, barray.Length); fs.Close(); } } От редактора Лозовский Александр В принципе технология интересная. Но! Одно дело использовать ее, посылая письма молодой и симпатичной даме через TheBat (в формате plain text) так, чтобы ее бдительный бойфренд, перлюстрирующий почту, не смог ничего запалить :), и совсем другое – использовать для передачи действительно секретной информации. Алгоритм, в его нынешнем понимании, даже для студента-технаря представляет проблем не больше, чем знаменитый шифр Юлия Цезаря (да-да, тот самый «симетричний алгоритм шифрування підстановками» :)). |