|
Программирование >> Рекурсивные объекты и фрактальные узоры
MinBX = min(c->first, MinBX); MaxBX = max(c->first, MaxBX); MinBY = min(c->second, MinBY) MaxBY = max(c->second, MaxBY) найти крайние точки линии рисунка в пределах текущей клетки С++; перейти к следующей точке рисунка если линия проходит по существенной части клетки, добавить клетку к записи if(MaxBX - MinBX + 1 > BlockW /2 11 MaxBY - MinBY + 1 > BlockH /2) Path.push back(CurBlock); while(с != CurrentDrawing->end()); пока рисунок не кончился в режиме записи if(Mode == RECORD) ввести название жеста lsRecords->Items->Strings[lsRecords->ItemIndex] = InputBox(, Название жеста , ); записать фигуру в вектор Records Records[lsRecords->ItemIndex] = Path; в режиме распознавания else if(Mode == RECOGNITION) { найти в векторе Records объект, равный текущей записи (Path) for(unsigned i = 0; i < Records.size(); i++) if(Records[i] == Path) если объект найден, сообщить об успешном распознавании Application->MessageBox( lsRecords->Items->Strings[i].c str(), 0); return; сообщить о неудаче Application->MessageBox( Не распознано , 0); 9.3. СТЕГАНОГРАФИЯ, ИЛИ МАСКИРОВКА НАЛИЧИЯ ПРИСУТСТВИЯ 9.3.1. Стеганография в тексте Пересылка секретных сообщений Передача секретных сообщений - задача давно известная и по-прежнему актуальная. В новостях регулярно сообщается как об изобретении новых криптографических алгоритмов, так и о нахождении уязвимостей в существующих. Однако криптография - не единственный метод защиты секретной информации от посторонних глаз. С давних пор популярна также стеганография, то есть сокрытие самого факта наличия секретного сообщения. Если вЫ посылаете другу письмо, состоящее из непонятных цифр, словесной абракадабры и странных крючков, перехвативщий его злоумышленник сразу поймёт, что имеет дело с шифровкой (и, вероятно, приложит все усилия для её разгадывания). Если же в письме сообщается о здоровье вашей тётушки и её небывалых успехах в деле выращивании редиски, потенциальный злоумышленник вряд ли заподозрит что-нибудь. А просветить письмо void fastcall TMainForm::DrawingAreaMouseUp(TObjееt *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) выйти из режима рисования IsMouseDown = false; определить границы (MinX, MinY, МахХ, MaxY) рисунка int MinX = min element(CurrentDrawing->begin{), CurrentDrawing->end(), LessX)->first; int MinY = min element(CurrentDrawing->begin{), CurrentDrawing->end(), LessY)->second; int MaxX = max elenient (CurrentDrawing->begin{) , CurrentDrawing->end(), LessX)->first; int MaxY = max eleinent (CurrentDrawing->begin () , CurrentDrawing->end(), LessY)->second; ширина и высота клеток получившейся сетки int BlockW = (МахХ - MinX + 1) /3, BlockH = (MaxY - MinY + 1) / 3; сжатая запись фигуры vector<pair<int, int> > Path; vector<pair<int, int> >::iterator с = CurrentDrawing->begin() do { определить клетку очередной точки рисунка pair<int, int> CurBloclc = GetBlock(*c, MinX, MaxX, MinY, MaxY) int MaxBX = MinX, MinBX = MaxX, MaxBY = MinY. MinBY = MaxY; пока мы находимся в той же самой клетке и рисунок не кончился while(GetBloclc(*c, MinX, МахХ, MinY, MaxY) == CurBlock && с != CurrentDrawing->endО) В режиме декодирования (команда d) из переданного на вход письма извлекается секретное сообщение и записывается в файл decoded.txt: steganograph.exe d <файл письма> Таким образом, функция main () вызывает в зависимости от переданной команды либо функцию кодирования, либо функцию декодирования: int main(int argc, char* argv[]) { if(argv[l][0] == e) Encode(argv[2], argv[3]); else if(argv[l][0] == d) Decode(argv[2]); return 0; Рассмотрим сначала процесс кодирования. Необходимо предварительно вычислить длину кодируемого сообщения и выяснить, достаточен ли размер письма для его хранения. В этом нам помогут функции CountChars () и CountSpaces(). Функция CounrtChars () определяет количество символов в переданном входном файле. Мы не можем пользоваться для этой цели встроенной функцией istream: :tellg(), возвращающей длину файла в байтах, поскольку символ возврата каретки / перевода строки занимает два байта и, следовательно, для файла из нескольких строк функция tellgO будет возвращать неправильный результат. int CountChars(char *filename) { ifstream in(filename); int Count = 0; char c; while(in.get(c)) пока из файла можно считать очередной символ Count++; return Count; Функция CountSpaces () возвращает количество пробелов (точнее, промежутков между словами, состоящих из одного или более пробельных символов) в переданном файле: int CountSpaces(char *fname) { количество пробелов равно количеству слов минус единица int Spaces = -1; string temp; ifstream letter(fname); ультрафиолетовыми лучами, чтобы увидеть написанное на полях, надо ещё догадаться. Стеганография в электронных документах тоже возможна. В качестве письма о тётущке , в котором скрывается истинное секретное сообщение, может выступать обычный текстовый документ, изображение или шрЗ-файл. В этой задаче предлагается спрятать сообщение внутри текстового файла. Как это сделать? Например, можно использовать систему один пробел/ два пробела . Каждая пара соседних слов исходного файла будет кодировать один бит секретного сообщения. Если между словами находится один пробел, то этот бит равен нулю, если два - единице. Так, фраза в * огороде моейтётушки * растёт * огромная* редиска! скрывает двоичное число 010001 (пробелы обозначены символами °). Таким образом, восемь пар слов позволяют закодировать один байт информации. Итак, задача заключается в программировании системы стеганографии. Система работает в двух режимах: кодирование и декодирование. В режиме кодирования на вход программе подаются два текстовых файла: секретное сообщение и подставное письмо. Первым делом система определяет, достаточен ли размер подставного письма для кодирования секретной информации. Если недостаточен, пользователю предлагается выбрать файл побольше. Затем производится кодирование, и на выходе генерируется письмо с внедрённым секретным сообщением. Обратите внимание, что первым делом следует закодировать размер сообщения, иначе на этапе декодирования вы не сможете определить, что все данные уже извлечены, и процесс пора прекратить. В режиме декодирования на вход поступает лишь письмо с внедрёнными данными. Программа его анализирует и печатает на экране секретное сообщение. Решение Общая идея решения уже была описана в формулировке задачи, так что мне остаётся лишь привести реализацию с комментариями. Программа будет работать в двух различных режимах. В режиме кодирования (команда е) текст сообщения внедряется в текст подставного письма, и результат выводится в файл encoded.txt: steganograph.exe е <файл письма> <файл секретного сообщения> letter s; outfile s if(c & 1) outfile с = 1 ; считать очередное слово письма вывести слово с одним пробелом если очередной бит байта с равен единице вывести и второй пробел перейти к следующему биту Значение выражения (с & 1) равно единице тогда и только тогда, когда младший бит байта с установлен; если же бит сброшен, результат операции равен нулю. Теперь займёмся функцией Encode (),.внедряющей в текст письма длину и тело сообщения: void Encode(char *let fn, char *rasg fn) { количество пробелов в письме int Spaces = CountSpaces(let fn); размер сообщения int msg size = CountChars(msg fn); считается, что длина сообщения не превышает 65535 символов и может быть закодирована двумя байтами таким образом, количество пробелов в письме должно быть не меньше msg size * 8 (размер сообщения в битах) плюс 2*8 бит для кодирования длины if(msg size * 8 + 2 * 8 > Spaces) { cout Message too long endl; exit(O); } ifstream letter(let fn), message(msg fn); ofstream outfile( encoded.txt*); вывести старший и младший байт длины кодируемого сообщения OutByte(msg size / 256, letter, outfile); OutByte(msg size % 256, letter, outfile); char c; вывести сообщение while(message.get(с)) OutByte(c, letter, outfile); в оставшемся фрагменте письма расставить пробелы случайным образом (в противном случае окончание сообщения очень хорошо заметно в закодированном файле) randomize(); string s; вывести очередное слово, затем один или два пробела while(letter s) outfile s (random(2) == 0 ? : ); lla этом разработка кодировщика заканчивается, можно приступать к блоку декодирования. Алгоритм декодирования использует служебную функцию InByte () для извлечения очередного закодирова1П10го во входном файле символа: unsigned char InByte(ifstreams letter) { unsigned char result = 0; for(int i = 0; i < 8; i++) { char c; while(letter.get(c) && с != letter.get(c); int к = (с == ) result = 1; result 1= (12B*k); return result; ) найти очередной пробел во входном файле считать следующий символ если считан пробел, к = 1, иначе к = О перейти к следующем/ разряду результата записать в старший бит значение к На каждом шаге в переменную result записывается значение операции (result I 128) или (result О). Наложение нуля не меняет значения result, а наложение числа 128(двоичное 10000000) приводит к установке старшего бита. Запись битов каждого числа в закодированный файл производилась от младшего к старшему. При чтении осуществляется обратный процесс. while(letter temp) Spaces++; return Spaces; Основную работу по выводу закодированного файла выполняет функция OutByte (). Она считывает очередные восемь слов из входного файла letter, расставляет между ними пробелы в соответствии с содержимым байта с и выводит результат в выходной файл outfile: void OutByte (unsigned char с, ifstreamSc letter, of streams outfile) { for(int i = 0; i < 8; i++) { string s;
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |