Форум программистов, компьютерный форум, киберфорум
Наши страницы

C++ Builder

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 482, средняя оценка - 4.80
Erravielle
337 / 48 / 1
Регистрация: 27.04.2009
Сообщений: 36
#1

Стеганография в BMP. Полное руководство - C++ Builder

11.03.2010, 21:54. Просмотров 67529. Ответов 56
Метки нет (Все метки)

СТЕГАНОГРАФИЯ в BMP ИЗОБРАЖЕНИЯХ

Данная статья содержит готовый проект с подробным описанием алгоритма реализации шифрования текстового сообщения в графический файл формата *.BMP

I. Теоретические предпосылки, или что нужно знать для начала работы . . .

Пиксел изображения в 24-х битном .BMP формате занимает 3 Байта (24 бита) памяти (соответственно по 1 байту на каждый канал - Red, Green, Blue (RGB))

Один символ текста занимает 1 Байт (8 бит) дискового пространства.

Если заменять Байт изображения Байтом текста, то мы получим обсалютно другой цвет пиксела, и, как следствие, сильное искажение изображения.
Поэтому наиболее удобно заменять только 1 бит одного из каналов Пиксела на 1 бит Текста. Такая подмена будет незаметна для человеческого глаза. (При желании можно заменять последний бит КАЖДОГО из каналов... Алгоритм изменится незначительно).

Таким образом, один символ текста будет кодироваться в 8 пикселов изображения.

Разумно задать следующий вопрос: "а какой бит заменять то?"

Рассмотрим пример:

Возьмем пиксел со значениями кодируемого канала: Red = 255;

BYTE R = 255; // 11111111


Предположим нам нужно заменить один бит этого канала на бит символа, равный '0'.
Если мы заменим первый бит Байта R, то получим:

BYTE R = 11111110; // теперь R = 127
(отсчет идет справа налево, а не слева направо!!! Вожно это знать!)
- согласитесь, разница значений очень велика!

Теперь попробуем заменить последний бит Пиксела:

BYTE R = 01111111; // теперь R = 254
т.о. оттенок цвета изменится незначительно.

Итак, решено - МЕНЯЕМ ПОСЛЕДНИЙ БИТ ПИКСЕЛА.

II. АЛГОРИТМ РАБОТЫ ПРОГРАММЫ . . .

ШИФРОВАНИЕ
1. Загружаем изображение
2. Определяем колличество пикселов, из которого оно состоит
3. Делим полученное значение на 8 и получаем максимальный размер текстового сообщения
3. Вводим шифуемый текст
4. Определяем размер текста и сопоставляем его с максимально допустимым
6. Определяем шаг продвижения по Битмапу
5. Организуем два цикла:
- Внешний: обход по символам
- Внутренний: обход по битам символа
6. В циклах заменяем биты изображения битами текста, двигаясь по изображению с заданным шагом
7. Сохраняем полученный результат
8. Записываем в файл "ключ", который позволит расшифровать сообщение

! Ключ содержит две переменных: ШАГ и РАЗМЕР ТЕКСТА

ДЕШИФРОВКА
1. Загружаем изображение
2. Загружаем ключ
3. Организуем два цикла:
- Внешний: обход по символам
- Внутренний: обход по битам символа
4. В циклах считываем с шагом, указанным в ключе, значения последних битов пикселов; Группируем биты в символы и формируем из символов Текстовую строку

III. РЕАЛИЗАЦИЯ . . .

1. Объявим глобальные переменные, которые позволят нам продолжить работу:

C++
1
2
3
4
5
6
7
8
9
10
Graphics::TBitmap *Bmp; // переменная для хранения BMP изображения
 
bool ERR_OPEN_BMP = true;  // переменные для отслеживания ошибок
bool ERR_OPEN_KEY = true;
bool ERR_NO_TEXT = true;
bool ERR_TEXT_LENGTH = false;
 
unsigned int IMAGE_SIZE = 0; // дополнительные переменные
unsigned int TEXT_SIZE = 0;
unsigned int MAX_TEXT_SIZE = 0;
2. Напишем функции для работы с Текстом и изображением:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
TPoint GetPosition(TPoint Point, int Shag, int Width)
/* Функция оперделяет следующую координату пиксела, который будет кодироваться
   TPoint Point - предыдущая координата
   Shag - шаг кодирования
   Width - ширина Битмапа
*/
{  TPoint REZ;
   REZ.y += Point.y;
 
int BUF = Width - Point.x - Shag;
 
if (BUF <= 0) {
                REZ.y++;  BUF = abs(BUF);
                while (BUF >= Width)
                {BUF -= Width; REZ.y++;}
              }
              else BUF = REZ.x + Width - BUF;
REZ.x = BUF;
 
return REZ;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
BYTE BinaryToByte (int *mass)
/* Собирает из массива битов один целый байт и возвращает его.
   Входной параметр: массив из восьми элементов, соответсвтующих
   битам Байта
*/
{
            BYTE Mask   = 00000001;
            BYTE Result = 00000000;
            BYTE Mask2;
 
            int j = 0;
            for (int i = 7; i > -1; i--, j++)
            {
              if (mass[i] == 1)  {Mask2 = (Mask << (j));
                                  Result = Result|Mask2;
                                  }
            }
            return Result;
}
C++
1
2
3
4
5
6
7
8
9
10
11
int GetBitValue(BYTE B, int N)
/* Получает значение N-ого бита в байте B
   Возвращает 1 или 0 (в зависимости от значения Бита)
*/
{ int k = 256;
 
      for (int i = 0; i < N; i++) k /= 2;
 
      if ((B & k) != 0) return 1;
      else return 0;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
BYTE ReadBitToByte (int Bit, BYTE B)
/* Записывает в байт B на последнюю позицию бит Bit
*/
{
     BYTE A = 00000001;
     BYTE Result = B;
 
     if (Bit == GetBitValue(B,8)) return B;
        else if (Bit == 1) return Result = Result|A;
             else if (Bit == 0) return B - A;
 
             return NULL;
}
Следующие функции не используются в проекте, но могут представлять для вас интерес:

C++
1
2
3
4
5
6
7
8
9
10
11
int BinaryToDec (BYTE val)
/* Переводит Байт из двоичной системы в десятичную
*/
{   int Result = 0;
 
    for (int t = 1, i = 0; t < 129; t *= 2, i++)
            {
                if ((val & t) != 0) Result += pow(2,i);
            }
 return Result;
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int *ByteToBinary (BYTE val)
/* Разбивает исходный Байт на биты. Возвращает массив из восьми элементов
   Каждый Nй элемент соответствует Nму биту.
   Принимает значения 1 или 0
*/
{           int *mass = new int[8];
            int t, i;
            for (t = 128, i = 0; t > 0; t /= 2, i++)
            {
                if ((val & t) != 0) mass[i] = 1;
                else if ((val & t) == 0) mass[i] = 0;
            }
  return mass;
}
К сожалению из за катастрофической нехватки времени не могу подробно описать как работает каждая из функций ((( возможно сделаю это чуть позже. . .

3. Подготавливаем изображение для работы и определяем дополнительные переменные:

C++
1
2
3
4
5
6
Bmp = new Graphics::TBitmap;
    Bmp->LoadFromFile(FileName); // копируем изображение в Bmp
    Bmp->PixelFormat = pf24bit; // устанавливаем глубину цвета в 24 bit (стандарт без Альфа канала)
 
IMAGE_SIZE = WIDTH*HEIGHT;
MAX_TEXT_SIZE = IMAGE_SIZE/8;
4. Введем шифруемый текс:

Для этого я использовал компонент TRichEdit. Создаем свойство OnChange и пишем туда приблизительно такой код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
TEXT_SIZE = RichEdit1->Text.Length();
 
if (TEXT_SIZE != 0) ERR_NO_TEXT = false;
  else ERR_NO_TEXT = true;
 
if (TEXT_SIZE > MAX_TEXT_SIZE)
    {
       ERR_TEXT_LENGTH = true;
       Label9->Font->Color = clRed;
       Label12->Font->Color = clRed;
    }
    else
       {
         ERR_TEXT_LENGTH = false;
         Label9->Font->Color = clWhite;
         Label12->Font->Color = clWhite;
       }
Теперь при вводе символов в RichEdit1 программа будет самостоятельно высчитывать интересующие ее значения.

5. Шифруем сообщение :

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
int Shag = MAX_TEXT_SIZE/TEXT_SIZE;
char *String = new char[RichEdit1->Text.Length()+1];// создаем переменную для хранения кодируемого текста
strcpy(String,RichEdit1->Text.c_str()); // копируем в нее кодируемый текст
 
 TPoint Next;    // позиция следующего кодируемого пиксела
 TPoint First;   // позиция кодированного пиксела
 BYTE TextByte;  // переменная для хранения символа
 
//---------------- ШИФРУЕМ СООБЩЕНИЕ -----------------//
 for (int i = 0; i < TEXT_SIZE; i++)  // перебор символов
    {
         TextByte = String[i]; // загоняем очередной символ
 
         for (int j = 0; j < 8; j++) // перебор битов символа
            {
             Next = GetPosition(First, Shag, WIDTH);
 
             TColor COLORR = Bmp->Canvas->Pixels[First.x][First.y];
 
             BYTE R=GetRValue(COLORR);    //
             BYTE G=GetGValue(COLORR);    // получили каналы
             BYTE B=GetBValue(COLORR);    //
 
             int bit = GetBitValue(TextByte, j+1); // получили записываемый бит
             R = ReadBitToByte (bit, R);         // записали jй бит в канал
 
             Bmp->Canvas->Pixels[First.x][First.y] = RGB(R,G,B);  // переопределили цвет
 
             First = Next;
            }
    }
//------------------ ЗАШИФРОВАЛИ ---------------------//


6. Сохраняем полученное изображение и ключ в файлы:

C++
1
2
3
4
5
6
7
Bmp->SaveToFile(SavePictureDialog1->FileName); // изображение
 
  ofstream READ;
  READ.open(FileName);
// ключ
  READ<<StrToInt(Shag)<<endl;
  READ<<StrToInt(TEXT_SIZE);
ШИФРОВАНИЕ ГОТОВО!!!!

Теперь ДЕШИФРОВКА:

... как открыть файл мы теперь знаем ...

1. Считываем коюч:

C++
1
2
3
4
  ifstream OPEN;
  OPEN.open(Stego->OpenDialog1->FileName.c_str());
 
  OPEN>>SHAG>>KOL;
2. Собственно дешифруем и выводим результат:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
TPoint Next;    // позиция следующего кодируемого пиксела
 TPoint First;   // позиция кодированного пиксела
 BYTE TextByte;  // переменная для хранения символа
 
 char *result = new char[KOL+1];
 strset(result, '\0');
 int *BitMass = new int[8]; // массив для хранения битов
 
    for (int i = 0; i < KOL; i++)  // перебор символов дешифруемого сообщения
        {
         for (int j = 0; j < 8; j++) // перебор битов символа
            {
             Next = GetPosition(First, SHAG, WIDTH);
 
             long COLORR = GetPixel(Bmp->Canvas->Handle,First.x,First.y);  // получили цвет
             BYTE R=GetRValue(COLORR);    //
             //BYTE G=GetGValue(COLORR);    // получили каналы
             //BYTE B=GetBValue(COLORR);    //
 
             BitMass[j] = GetBitValue(R, 8);
 
             First = Next;
            }
          result[i] =  BinaryToByte (BitMass);
          for (int k = 0; k < 8; k++) BitMass[k] = 0;
        }
 
 RichEdit1->Clear();
 result[KOL] = '\0';
 RichEdit1->Text = result;
Вот и Все, друзья... Во вложении вы найдети исходиники (среда разработки - C++ Builder 2009), краткую инструкцию по применению и примерчик....

Удачи в ваших начинаньях!!!
29
Вложения
Тип файла: rar Program.rar (1.65 Мб, 4533 просмотров)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
11.03.2010, 21:54
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Стеганография в BMP. Полное руководство (C++ Builder):

Стеганография в BMP попробуем вместе разложить все по полочкам - C++ Builder
Здравствуйте уважаемые форумчане! Столкнулся с задачей написать программный продукт, реализующий стеганографический метод. ...

Стеганография.Работа с изображением - C++ Builder
Здравствуйте! Есть следующее задание - нужно реализовать метод наименьшего значащего бита для BMP файлов . Метод заключается в следующем -...

Руководство по libxml2 - C++
Доброго дня! Подскажите пожалуйста, где можно почитать о библиотеке libxml2? Какие функции, как использовать - если есть с примерами...

Руководство по C++ Builder X2 Embarcadero - C++ Builder
Может ли кто нибудь помочь с руководством пользователя для C++ Builder X2 Embarcadero лучше на русском но можно на английском с уклоном в...

Руководство на русском по GCC и g++ - C++
Подскажите по сабжу - надо разобраться с ключами, режимами и понять общую схему работы компиляторов и линковщика. Добавлено через 3...

Borland C++ Builder 6 руководство разработчика - C++ Builder
Подсказали книгу по С++ (сказали что хорошая) Посмотрел уж больно дорогая она( Попробовал найти в нете не получается( Может тут подскажите...

56
Erravielle
337 / 48 / 1
Регистрация: 27.04.2009
Сообщений: 36
12.03.2010, 07:50  [ТС] #2
Вот выложил исходники. . .

! И еще одно замечание - BMP-файл можно представить в виде вектора, размерностью [width*height*3] что упростит продвижение по изображению и сделает ненужной функцию GetPixel. Но учтите, перевод BMP файла в вектор потребует определенные затраты времени. . .
7
Evg
Эксперт CАвтор FAQ
18239 / 6364 / 435
Регистрация: 30.03.2009
Сообщений: 17,583
Записей в блоге: 28
12.03.2010, 14:15 #3
Вот тут у нас поднялся вопрос о том, как засунуть информацию в *.jpg. Ибо передача файла *.bmp уже наводит на мысль о том, что там что-то спрятано. Поэтому кодирование информации в изображения с форматами бес сжатия - не есть интересно. Ты владеешь вопросом в части *.jpg?
3
Xdron
13 / 13 / 0
Регистрация: 21.02.2010
Сообщений: 45
01.06.2010, 21:25 #4
вот такой вопрос а можно в этой проге ключ убрать?????
0
Evg
Эксперт CАвтор FAQ
18239 / 6364 / 435
Регистрация: 30.03.2009
Сообщений: 17,583
Записей в блоге: 28
01.06.2010, 21:36 #5
Про какой ключ идёт речь?
0
Xdron
13 / 13 / 0
Регистрация: 21.02.2010
Сообщений: 45
01.06.2010, 21:39 #6
ну в нутри есть программа она использует ключ для шифрации а можно как нить без него просто изображение сохраять!!????????
0
Evg
Эксперт CАвтор FAQ
18239 / 6364 / 435
Регистрация: 30.03.2009
Сообщений: 17,583
Записей в блоге: 28
01.06.2010, 21:45 #7
Цитата Сообщение от Xdron Посмотреть сообщение
ну в нутри есть программа она использует ключ для шифрации а можно как нить без него просто изображение сохраять!!????????
Ах вот но что Тебе что конкретно надо? Самодельную программу, которая записывает файл bmp или тебе нужно просто записать bmp (например, посредством библиотечных функций)?
0
Xdron
13 / 13 / 0
Регистрация: 21.02.2010
Сообщений: 45
01.06.2010, 21:51 #8
мне нужно просто шифровать текст в изображение BMP но без ключа ......

Добавлено через 55 секунд
текст нужно зашифровать в BMP...
как я примерно понял нужно разбить картинку на куски (по 8 пикселей) и в одном таком куске будет храниться 1 буква через двоичный код (тиипа 00010101)...

Добавлено через 2 минуты
а при зашифровке и расшифровке чтобы не выскакивал сохранить и заагрузить ключ а что бы он просто сразу загружал изображение и расшифровывал то что есть в изображении......т.е.текст!!!!!!!
0
Evg
Эксперт CАвтор FAQ
18239 / 6364 / 435
Регистрация: 30.03.2009
Сообщений: 17,583
Записей в блоге: 28
01.06.2010, 22:36 #9
Я так понимаю, что тебе нужно исходники вот этой программы? Ну дык попроси автора да и всё. В этой теме тоже исходник лежит - бери его, да убирай ключ. Автор тут, можешь его спросить если что. Или ты не хочешь сам ничего делать, а тебе нужно всё готовенькое?
0
Xdron
13 / 13 / 0
Регистрация: 21.02.2010
Сообщений: 45
01.06.2010, 23:23 #10
мне очень нужна вот эта программа Program.rar !!!!только без ключа!!! я уже чача три колыпаюсь и не могу убрать ключ!!!!

Добавлено через 33 секунды
не могли бы вы помоч??зарание большое спасибо!!!
0
Erravielle
337 / 48 / 1
Регистрация: 27.04.2009
Сообщений: 36
02.06.2010, 09:33  [ТС] #11
Чувак, я б с радостью помог, но времени нет - сессия у меня... если не срочно то в июле помогу.... а щас никак....
0
EVIL SnaKe
02.06.2010, 22:54 #12
Вопрос к автору проги (ну или кто разбираеться другой) какие конкртено функции отвечают за замену битов картинки ? Где что нужно поменять чтоб например записывалось не в последний бит, а в первый (ну вот надо мне так ) Я сам покопался, но пока не нашёл...
Erravielle
337 / 48 / 1
Регистрация: 27.04.2009
Сообщений: 36
03.06.2010, 16:19  [ТС] #13
Цитата Сообщение от EVIL SnaKe Посмотреть сообщение
Вопрос к автору проги (ну или кто разбираеться другой) какие конкртено функции отвечают за замену битов картинки ? Где что нужно поменять чтоб например записывалось не в последний бит, а в первый (ну вот надо мне так ) Я сам покопался, но пока не нашёл...
BYTE ReadBitToByte (int Bit, BYTE B) отвечает за это... видишь переменную A ??? это маска... вот с ней надо поколдовать чтобы заменить другой бит, ну еще и бит фонуцикй GetBitValue надо получать тот который интересует...
опять же говорю - времени пока вообще нет, так что экспериментируйте )))
1
cooller01
0 / 0 / 0
Регистрация: 04.10.2010
Сообщений: 115
04.10.2010, 11:17 #14
а как быть с GIFом???

Добавлено через 2 минуты
в инете об этом маловато....(
0
Erravielle
337 / 48 / 1
Регистрация: 27.04.2009
Сообщений: 36
04.10.2010, 16:50  [ТС] #15
что касается GIFа - не знаю...
а вот с PNG легко можно... принцип во всяком случае тот же...
Основное правило - использовать формат без потери качества. В форматах с потерей используются алгоритмы сжатия, и такой фокус с заменой последнего бита не пройдет. Во всяком случае эти изменения достаточно легко обнаружить всвязи со спецификой формата
0
04.10.2010, 16:50
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
04.10.2010, 16:50
Привет! Вот еще темы с ответами:

Где скачать Руководство разработчика C++B6 - C++ Builder
Подскажите пожалуйста ссылочку, где можно БЕСПЛАТНО скачать &quot;Borland C++ Builder 6. Руководство разработчика&quot;, а то я кучу ссылок облазил и...

Краткое руководство по работе с классом TCanvas для начинающих - C++ Builder
Вступление Часто на форуме возникают вопросы по поводу рисования той или иной фигуры на канве, а также просят привести список всех...

Стеганография в BMP - C++
Проект выполняющий метод lsb. В коде ошибки. Не могу понять как исправить. Прошу помочь, может кто разбирается в таких вещах. ...

Стеганография LSB BMP - Delphi
Такой вопрос: мне нужно из едита побитно запихнуть в байты цвета файла-контейнера биты текста. Есть проблема, заголовок считываю, а вот как...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru