Задания к лабам / 2 / itzi02 / Журнал Программист
.htmЖурнал "Программист" Вышел 2-й номер журнала за 2002 год. Анонсы номера и статьи размещены на сайте.
“Программист” Подписка 2002 Агентство “Роспечать” Каталог “Газеты. Журналы. Книги. Учебные пособия. Товары.” (Россия и СНГ) Индекс: 80467
“Программист” Подписка 2002 Объединенный каталог “Почта России 2001” (Россия) Индекс: 45775
В Москве на “Программист” можно подписаться через агентство “Интер-почта”
“Интер-почта” Удобно и выгодно! Не выходя из офиса! Подписка на профессиональный журнал “Программист” В Москве и регионах. Тел. (095) 921-1138, 921-1142, 925-07-94
Вы также можете:
ЗАКАЗАТЬ любой номер журнала с доставкой по Москве Стеганография: скрытие информации Андрей Беляев
nikolsk@mail.ru
Стеганография - очень близкая к криптографии, но все-таки независимая отрасль computer science. Ее задача - сокрытие конфиденциальной информации от посторонних глаз в самых обычных почтовых отправлениях, файлах, картинках и т.п. Сам этот термин переводится как "тайнопись".
Основные определения Задача любой стеганографической программы - разместить исходный блок данных (стеганограмму или просто стего) в некоем вспомогательном носителе - контейнере. Контейнером может служить любой файл или поток данных. Его содержимое безразлично как отправителю, так и получателю секретного сообщения - их интересует только сама стеганограмма. Здесь важно, что любой посторонний человек, взглянув на файл-контейнер, не должен заметить ничего особенного кроме основного содержания контейнера. А значит - во-первых, сам факт отправки файла-контейнера от автора к получателю не должен выглядеть странным (зачем, скажем, пересылать по почте в другой город таблицу Менделеева?) Во-вторых, стегопреобразования должны быть настолько незаметными, чтобы даже искушенный наблюдатель не заметил в файле броских отличий от нормы.
Немало примеров стеганографических посланий можно найти в приключенческой литературе. Так, классический двоичный сигнал "да/нет", "хорошо/плохо" - это поставленная в конце предложения точка или нарочно пропущенная запятая. При этом сам текст абсолютно никакой роли не играет - лишь бы он был осмысленным и укладывался в окружающую ситуацию.
Но настоящую жизнь вдохнула в стеганографию эра компьютерных технологий - появилась возможность преобразовывать сообщения молниеносно, а главное, автоматически. Сам двоичный код - уже предоставляет хороший потенциал для сокрытия данных. А уж огромное множество форматов данных и сообщений дало благодатную почву для развития этой отрасли.
Практически все существующие стегоалгоритмы можно разбить на 4 основные категории:
1) преобразования текста;
2) метод незначащих бит;
3) использование неотображаемых областей форматов файлов;
4) незначимое преобразование форматов файлов.
Преобразования текста Этот класс методов является самым старым, он появился еще в "довиртуальную" эпоху и был просто перенесен на компьютеры с учетом их особенностей и возможностей. Данной категории принадлежит очень много алгоритмов. К полностью автоматическим относится, например, форматирование текста количеством пробелов отличным от единицы. Скажем, один пробел соответствует биту "0", а два - "1" (рис.1). Программа получает произвольный текст в качестве контейнера и внедряет в него какое-либо стегосообщение. Из полуавтоматических алгоритмов можно отметить метод переменной длины слов и метод первой буквы. В этих случаях работа не автоматическая; программа кодирования работает в режиме подсказки: после того как ей передали стегосообщение, она предлагает оператору начать набор текста, но накладывает на вводимые слова ограничения, несущие, собственно, информацию.
В методе переменной длины слова, набираемые создателем стеганограммы, должны соответствовать длине, которую укажет программа - обычно в одно слово кодируется два бита информации из стегосообщения. Например, слова длиной в 4 и 8 символов могут означать комбинацию бит "00", длиной в 5 и 9 - "01", 6 и 10 - "10", 7 и 11 букв - "11". Слова короче 4 и длиннее 11 букв можно вставлять где угодно для лексической и грамматической связки слов в предложении - программа-декодер будет просто игнорировать их (рис.2).
Метод первой буквы может передавать еще больше стегоинформации в одном слове: обычно это три или четыре бита. Программа-помощник в этом методе накладывает ограничение уже не на длину слова, а на первую (можно на вторую) букву. Обычно одну и ту же комбинацию могут кодировать несколько букв, например, комбинацию "101" означают слова, начинающиеся с "А", "Г" или "Т". Это дает большую свободу выбора оператору, придумывающему стегосообщение, и текст не становится нелепым (рис.3).
Существует и множество других методов преобразования текста. В любом случае, необходимо искать золотую середину: контейнер должен быть "плотно" насыщен стегоинформацией и при этом совершенно не должен выделяться из обычной общей массы файлов такого же формата и наполнения.
Метод незначащих бит Данный класс алгоритмов весьма интересен и широко используется на практике. Он основан на том факте, что в некоторых форматах файлов (в большинстве случаев - мультимедиа данные) младшие биты значений хотя и присутствуют в файле, но не влияют на восприятие звука или изображения человеком. Кстати, на этом же принципе основано и сжатие с потерями (JPEG, MP3, MP4 и т.п.). Именно в таких "неиспользуемых" местах в файлах можно хранить стегосообщения. Наиболее часто контейнерами служат графические форматы с прямым цветокодированием в 24 и более бит на пиксел (BMP, TIFF). Реже - звуковые файлы с абсолютным кодированием амплитуды аудиосигнала (WAV). При разумном наполнении контейнера исходный файл не отличит от заполненного без специального анализа даже опытный специалист.
Кстати, в цветных графических изображениях заменять младшие биты можно у каждой из составляющих (R, G, B или C, M, Y, K). И еще одно соображение: если вы предполагаете, что кто-то заподозрит в вашем файле стегосообщение - в качестве контейнера нужно выбирать не искусственно созданные картинки (стего в них обманет только неискушенного пользователя), а отсканированные фотоизображения. Только в них присутствуют шумы квантования - случайное заполнение младших бит, под которые и маскируются кусочки стегосообщения. Необходимо избегать фотографий с большими областями очень ярких и черного цветов. На таких картинках большие области в исходном файле имеют цветовые составляющие 255 и 0, соответственно и стегобайты будут характерно выделяться при просмотре файла в кодах своими 254 и 1.
Ниже приведена основная часть алгоритма, записывающего и считывающего стегосообщение. Контейнером служит 24-битный BMP-файл (полный текст программы и рабочий проект с примером стегосообщения можно найти на сайте журнала). В примере в каждом байте используется только 1 младший бит. Длина сообщения записывается не прямым 16-битным кодом, а в два этапа - это позволяет избежать подозрительной последовательности нулей в начале сообщения, если его длина мала. Сначала в 4 битах записывается N - "длина длины" сообщения, затем в N последующих битах собственно длина стего-сообщения в битах (старший (N+1)-ый бит считается установленным). Максимальная длина стегосообщения - 8 килобайт.
procedure AddLSBStego(const ContainerFileName:string; const Stego; BitCnt:integer);
var
Header:TBMPHeader; F:TFileStream;
Buffer:array[0..$103FF] of byte;
Ps,i,x,CntLen,BytesInLine,BytesRead:integer;
procedure AddLeastBit(Bit:integer);
begin
if Header.Width*3 <= Ps mod BytesInLine then
// перепрыгиваем выравнивание BMP-строк по границе dword
inc(Ps,BytesInLine-Header.Width*3);
Buffer[Ps]:=((Buffer[Ps]) and $FE) or (Bit and $01);
inc(Ps)
end;
begin
if (BitCnt<=$FFFF) and FileExists(ContainerFileName) then
begin
F:=TFileStream.Create(ContainerFileName,fmOpenReadWrite or fmShareExclusive);
F.Read(Header,sizeof(TBMPHeader));
if (Header.Signature=$4D42) and (Header.BMOffset=sizeof(TBMPHeader)) and (Header.ColorDepth=24) and (Header.Width*Header.Height*3>BitCnt) then
begin
BytesInLine:=(((Header.Width*3)+3) div 4)*4;
BytesRead:=F.Read(Buffer,sizeof(Buffer)); Ps:=0;
x:=BitCnt; CntLen:=0;
while x>0 do // определяем "длину длины"
begin x:=x shr 1; inc(CntLen) end;
for i:=0 to 3 do // записываем "длину длины"
AddLeastBit(CntLen shr (3-i));
for i:=0 to CntLen-2 do // записываем длину
AddLeastBit(BitCnt shr (CntLen-2-i));
for i:=0 to BitCnt-1 do // записываем саму стеганограмму
AddLeastBit(TByteArray(Stego)[i div 8] shr (7-(i mod 8)));
// возвращаемся и записываем измененный буфер на место
F.Seek(sizeof(TBMPHeader),soFromBeginning);
F.Write(Buffer,BytesRead);
end;
F.Free;
end;
end;
procedure ReadLSBStego(const ContainerFileName:string; var Stego; var BitCnt:integer);
var
Header:TBMPHeader; F:TFileStream;
Buffer:array[0..$103FF] of byte;
Ps,i,x,CntLen,BytesInLine:integer;
function ReadLeastBit:integer;
begin
if Header.Width*3 <= Ps mod BytesInLine then
// перепрыгиваем выравнивание BMP-строк по границе dword
inc(Ps,BytesInLine-Header.Width*3);
Result:=Buffer[Ps] and $01; inc(Ps)
end;
begin
if FileExists(ContainerFileName) then
begin
F:=TFileStream.Create(ContainerFileName,fmOpenRead or fmShareExclusive);
F.Read(Header,sizeof(TBMPHeader));
if (Header.Signature=$4D42) and (Header.BMOffset=sizeof(TBMPHeader)) and (Header.ColorDepth=24) then
begin
BytesInLine:=(((Header.Width*3)+3) div 4)*4;
F.Read(Buffer,sizeof(Buffer)); Ps:=0;
CntLen:=0; // определяем "длину длины"
for i:=0 to 3 do
CntLen:=(CntLen shl 1) or ReadLeastBit;
if CntLen=0 then CntLen:=16;
BitCnt:=1; // определяем длину
for i:=0 to CntLen-2 do
BitCnt:=(BitCnt shl 1) or ReadLeastBit;
x:=0; // считываем стеганограмму
for i:=0 to BitCnt-1 do
begin
x:=(x shl 1) or ReadLeastBit;
if i mod 8 = 7 then
begin TByteArray(Stego)[i div 8]:=x; x:=0 end;
end;
// "досмещение" и запись последнего неполного байта (если он был)
if BitCnt mod 8 <> 0 then
begin
x:=x shl (8-(BitCnt mod 8));
TByteArray(Stego)[BitCnt div 8]:=x;
end
end;
F.Free;
end;
end;
Какие же есть средства обнаружения стеганограмм? Мы уже говорили о том, что изменения младших бит несложно обнаружить в очень темных и очень ярких областях картинок. Более тонкий способ - анализ спектра младших бит - как статически на некоторой области файла, так и динамически по его ходу. Подобные программы сравнивают вычисленные показания с прогнозируемыми теорией вероятности для настоящих шумов квантования в целом и для данной картинки (а значит и для данного сканера) в частности. Например, если на вход алгоритма в качестве стеганограммы подан обычный ASCII-текст сообщения, то на анализаторе спектра сразу поднимутся значения амплитуд на частотах кратных 8 по сравнению с "нормальным" пустым контейнером. Если же стегоинформация распределена не по всему файлу, а только по некоторой его части, то спектр амплитуд младших бит заполненной и незаполненной частей будет более или менее отличаться - это еще один, более тонкий, но тоже реализуемый автоматический анализ файла на стегоначинку.
Отсюда еще два правила для стегоалгоритмов. Во-первых, лучше подавать на вход "смешивателя" данные с хорошей статистической распределенностью. Для этого используется либо кодирование, либо полноценное шифрование (ведь результат любых стойких криптопреобразований тоже имеет очень хорошие случайные характеристики, да и отсутствие ключа у третьей стороны не даст ей возможность даже свидетельствовать о самом факте наличия стего). В качестве кодера для первого способа можно применять наложение по "исключающему ИЛИ" (XOR) исходной стеганограммы с потоком, порождаемым генератором псевдослучайных чисел приемлемой разрядности. Естественно, начальное заполнение ГПСЧ должно быть известно принимающей стороне. Кстати, сообщения можно сжимать, так мы убиваем двух зайцев: объем стего уменьшается, а его "случайность" повышается.
Второе правило: стегосообщение лучше распределять равномерно по всей длине контейнера. Если в контейнере слишком много "свободных" бит - можно модифицировать не все подряд, а только каждый второй или третий. С точки зрения маскировки спектральных составляющих - лучше всего вообще динамически генерировать длины подобных "прыжков", например, с помощью того же ГПСЧ - "модифицируем бит, пропускаем 1, модифицируем бит, пропускаем 4 и т.д.".
Метод неотображаемых областей форматов файлов Эти алгоритмы размещают стего в виде непрерывной области данных внутри известных файловых форматов. Не секрет, что многие форматы имеют зарезервированные и неиспользуемые поля и области переменной длины. Многие форматы имеют многоблочную структуру с идентификаторами типа данных, записанными в начале каждого блока.
Программы просмотра обычно игнорируют все блоки с неизвестными им идентификаторами, что собственно нам и нужно. В качестве примера - HTML с его тегами: несуществующие теги не отображаются практически всеми браузерами. Наберите в тексте HTML-страницы <x value="торт готов"> и запустите ее на просмотр браузером…
При своей простоте подобное стегопреобразование довольно трудно скрыть от специалиста - если вы знаете формат данного файла, то и лицо, занимающееся поиском стегосообщений тоже, скорее всего, его знает. Выход - искать редко публикуемые и сложные форматы данных и тщательно маскировать стегосообщение под общий вид файла-контейнера в этом его месте.
Метод незначимых преобразований форматов файлов Интересный и перспективный, но довольно сложный и немногочисленный пока класс алгоритмов. Он основан на изменении структуры или содержания формата по стегозакону, но так, чтобы для программ просмотра файлов, написанных по стандартным рекомендациям, подобные изменения были бы безразличны.
В качестве примера приведу часть программы, которая используется для изменения порядка цветов в 256-цветной палитре BMP-файла. Перестановка цветов в палитре никак не сказывается на виде файла и только с небольшой долей вероятности может быть заподозрена как стегоконтейнер. При этом она позволяет гарантированно передавать около 200 байт даже в совсем небольшой картинке. С использованием алфавитного сжатия это дает стеготекст длиной в 400 символов - например, данный абзац. Данный исходный код и проект для его тестирования также размещен на сайте журнала.
Type
TPTPStego=array[0..191] of byte;
TTransposition=array[0..255] of byte;
procedure EncodeTransposition(const Stego:TPTPStego; var TP:TTransposition);
var Src:TTransposition; i,part,bit,value,InPs,OutPs:integer;
begin
for i:=0 to 255 do Src[i]:=i;
OutPs:=0; InPs:=0;
for bit:=7 downto 1 do
for part:=0 to (1 shl bit)-1 do
begin
value:=0;
for i:=0 to bit-1 do
begin
value:=(value shl 1) or ( (Stego[InPs shr 3] shr (7-(InPs and 7))) and 1 );
inc(InPs)
end;
TP[OutPs]:=Src[value]; inc(OutPs);
move(Src[value+1],src[value],255-value)
end;
TP[254]:=Src[0]; TP[255]:=Src[1];
end;
procedure DecodeTransposition(const TP:TTransposition; var Stego:TPTPStego);
var Src:TTransposition; i,part,bit,value,InPs,OutPs:integer;
begin
for i:=0 to 255 do Src[i]:=i;
FillChar(Stego,sizeof(Stego),0);
bit:=7; part:=0; OutPs:=0;
for InPs:=0 to 253 do
begin
value:=0;
while Src[value]<>TP[InPs] do inc(value);
move(Src[value+1],src[value],255-value);
for i:=0 to bit-1 do
begin
Stego[OutPs shr 3]:=Stego[OutPs shr 3] or ( ((value shr (bit-1-i)) and 1) shl (7-(OutPs and 7)) );
inc(OutPs)
end;
inc(part);
if part=(1 shl bit) then
begin
dec(bit); part:=0
end;
end;
end;
Эти процедуры производят только кодирование стеганограммы в перестановку из 256 элементов и обратно. В самой программе вам потребуется:
а) при кодировании отсортировать палитру по полученному из стеганограммы закону перестановок,
б) при декодировании определить из палитры закон ее перестановки, а затем с помощью DecodeTransposition извлечь из нее стего.
Не забывайте проверять перед использованием BMP-файла наличие в его палитре 256 разных (!) цветов (хотя для отсканированных фотографий, переведенных в 256-цветную палитру, это выполняется практически всегда).
Заключение В небольшой статье невозможно рассказать обо всех существующих стегоалгоритмах. Стеганография отличается от многих областей computer science тем, что зачастую метод, придуманный самостоятельно, может успешно конкурировать с известными и распространенными схемами. Основные принципы этой отрасли: 1) скрытность превыше всего, и 2) не надо недооценивать противника.
СКАЧАТЬ ИСХОДНИК К СТАТЬЕ
В начало
Что такое программирование?
искусство
наука
ремесло
не знаю
Результаты предыдущих голосований
обсуждение журнала/ общение с редакцией
web-дизайн/ программи- рование
windows программирова- ние
unix программирование
3D графика
Hardware
Подпишитесь на нашу почтовую рассылку. подписаться
отписаться
125047, г. Москва, ул. Бутырский вал д.20 тел.: 250-3801 факс: 250-2121 e-mail: info@programme.ru
© ПРОГРАММИСТ 2000. Все права сохранены
Перепечатка материалов без письменного разрешения редакции запрещена.
Поддержка: mailto:webmaster@programme.ruДизайн: NETOFFICE-DESIGN u="u1162.68.spylog.com";d=document;nv=navigator;na=nv.appName;p=0;j="N"; d.cookie="b=b";c=0;bv=Math.round(parseFloat(nv.appVersion)*100); if (d.cookie) c=1;n=(na.substring(0,2)=="Mi")?0:1;rn=Math.random(); z="p="+p+"&rn="+rn+"&c="+c;if (self!=top) {fr=1;} else {fr=0;} sl="1.0"; pl="";sl="1.1";j = (navigator.javaEnabled()?"Y":"N"); sl="1.2";s=screen;px=(n==0)?s.colorDepth:s.pixelDepth; z+="&wh="+s.width+'x'+s.height+"&px="+px; sl="1.3" y="";y+=""; y+=""; y+=""; d.write(y);if(!n) { d.write("