Приложение, реализующее метод замены наименее значащих битов для файлов с расширением bmp

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    78 Кб
  • Опубликовано:
    2013-02-13
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Приложение, реализующее метод замены наименее значащих битов для файлов с расширением bmp

1. Введение

Стеганография - наука, изучающая способы и методы сокрытия информации. Цель стеганографии - тайная передача информации с целью сокрытия существования сообщения, в отличие от криптографии, которая скрывает содержимое секретного сообщения, но не скрывает существование секретной коммуникации. Как правило, сообщение будет выглядеть как что-либо иное, например, как изображение, статья, список покупок, письмо или судоку. Стеганографию обычно используют совместно с методами криптографии, таким образом, дополняя её.

Хотя термин « стеганография» появился только в конце 15- того столетия, использовать стеганографию начали несколько тысячелетий тому назад. В древние времена, сообщения скрывали на задней стороне восковых табличек для письма, писали на желудках кроликов или наносили в виде татуировки на скальпе рабов. Невидимые чернила использовались в течение многих столетий - детьми и студентами для забавы и тайными агентами и террористами при серьёзном шпионаже. Микрофотоснимки и микрофильмы, основные элементы кинофильмов о войне и шпионах, появлялись после изобретения фотографии.

За последние десять-двадцать лет, благодаря массовому распространению мультимедийных технологий и средств телекоммуникации, развитие стеганографии вышло на принципиально новый этап, который специалисты называют компьютерной стеганографией. Среди основных областей использований компьютерной стеганографии - скрытие сообщений, путем встраивания их в цифровые данные, имеющие, как правило, аналоговую природу.

2. Термины и определения стеганографии

Использование единой терминологии для компьютерной стеганографии было предложено в 1996 году, на конференции Information Hiding: FirstInformationWorkshop. Стенографическая система или стегосистема - совокупность средств и методов, которые используются для формирования скрытого канала передачи информации. Основной целью сокрытия сообщения является не ограничение или регламентирование доступа к файлу-контейнеру, а гарантирование в значительной степени целостности и возможности восстановления встроенного сообщения.

При построении стегосистемы должны учитываться следующие положения[3, 5]:

стегосистема должна иметь приемлемую вычислительную сложность реализации;

должна обеспечиваться необходимая пропускная способность;

методы скрытия должны обеспечивать аутентичность и целостность секретной информации для авторизованного лица;

потенциальный нарушитель имеет полное представление о стегосистеме и детали ее реализации; единственное, что ему неизвестно - это ключ, с помощью которого только его обладатель может установить факт наличия и содержание скрытого сообщения;

если факт существования скрытого сообщения становится известным нарушителю, это не должно позволить последнему извлечь его до тех пор, пока ключ сохраняется втайне;

нарушитель должен быть лишен любых технических и других преимуществ в распознании или раскрытии содержания секретных сообщений;

В общем случае стегосистема может быть рассмотрена как система связи, изображенная на рис.1.

Рис.1: Структурная схема стегосистемы, как системы связи

Основными стенографическими понятиями являются сообщение и контейнер.

Сообщение mM - это секретная информация, наличие которой необходимо скрыть. M = {m1, m2, …mn} - множество всех сообщений.

Контейнер cCназывается несекретная информация, которую можно использовать для скрытия сообщения, С = {c1,c2,…cq} - множество все контейнеров, причем q>>n. В качестве сообщения и контейнера могут выступать как обычный текст, так и файлы мультимедийного формата.

Пустой контейнер (контейнер-оригинал) - это контейнер с, который не содержит скрытой информации.

Заполненный контейнер (контейнер-результат) - контейнер с, содержащий скрытую информацию m(cm). Одно из требований, которое при этом ставится: контейнер-результат не должен быть визуально отличим от контейнера-оригинала.

Выделяют два основных типа контейнера: потоковый и фиксированный.

Потоковый контейнер представляет собой непрерывно изменяющуюся последовательность битов. Сообщение встраивается в него в реальном времени, поэтому в кодере заранее неизвестно, хватит ли размеров контейнера для передачи всего сообщения. В один контейнер большого размера может быть встроено несколько сообщений. Интервалы между встроенными битами определяются генератором ПСП с равномерным распределением интервалов между отсчетами.

В фиксированном контейнере размеры и характеристики заранее известны, что позволяет выполнять вложение данных оптимальным образом.

Контейнер может быть случайным, избранным или навязанным. Избранный контейнер зависит от встроенного сообщения. Навязанный контейнер появляется, когда лицо, которое предоставляет контейнер, подозревает о возможной переписке, и желает предотвратить ее. На практике чаще применяются случайные контейнеры.

Начальную обработку скрываемой информации выполняет прекодер. В качестве одной из важнейших предварительных обработок сообщения можно назвать вычисление его обобщенного преобразования Фурье[1]. Это позволяет встраивать данные в спектральной области, что значительно повышает устойчивость наполненного контейнера к искажениям.

Запись сообщения в контейнер-оригинал, осуществляется стеганокодером. Вложение происходит одним из методов стенографической записи, к примеру, методом наименьших значащих битов.

Также, в большинстве систем для упаковки и извлечения сообщений используется ключ. По аналогии с криптографией, по типу ключа стегосистемы можно подразделить на два типа:

с секретным ключом;

с открытым ключом.

В стегосистеме с секретным ключом используется один ключ, который должен быть определен либо до начала обмена секретными сообщениями, либо передан по защищенному каналу.

В стегосистеме с открытым ключом для встраивания и извлечения сообщения используются разные ключи, которые различаются таким образом, что с помощью вычислений невозможно вывести один ключ из другого. Поэтому один ключ (открытый) может передаваться свободно по незащищенному каналу связи. Кроме того, данная схема хорошо работает и при взаимном недоверии отправителя и получателя.

3. Метод замены наименее значащих битов для BMP файлов

Метод замены наименее значащих битов (НЗБ) наиболее распространен среди методов замены данных в пространственной области неподвижных изображений[1].

Младший значащий бит изображения несет в себе меньше всего информации, человеческим взглядом изменения в нем неощутимы, что позволяет незаметно заменять НЗБ контейнера битами секретного сообщения.

Метод замены НЗБ имеет низкую стойкость к любым искажениям контейнера, что частично исправляется помехоустойчивым кодированием встраиваемого сообщения.

Наиболее прост этот метод при работе с растровыми изображениями в форматах без компрессии, к которым относятся и BMP файлы.[3]

Рассмотрим структуру bmp файла представленную на рис. 2:

Рис. 2. Структура bmp файла

В данном методе нас интересуют только биты изображения. Каждый пиксел описывается 3 байтами: значение красного, зеленого и синего цветов. Метод НЗБ позволяется записывать информацию в младшие биты каждого из этих байтов. Так как заголовочная информация BMP занимает 54 байта в начале файла[6], то мы можем записать сообщение размером (количество_байт_в_файле - 54) бит.

Сам алгоритм метода подразумевает разбиения сообщения на биты, которые последовательно записываются в младшие биты изображения. Для того, чтобы усложнить определение наличия сообщения в контейнере для злоумышленника, сообщение кодируется с помощью одного из криптографических шифров, и лишь после этого записывается в стеганоконтейнер.[1]

Также, для скрытия наличия сообщения в файле, младшие биты незадействованных байтов заполняются шумом, генерируемым генератором псевдослучайных чисел[1].

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

стеганография файл программирование бит

4. Реализация метода замены НЗБ для BMP файлов на языке программирования Java

Программа представляет собой графическое приложение. Предусмотрены следующие функции:

открыть bmp файл;

загрузить текстовый файл с ключом, либо написать ключ в текстовом поле самому;

записать в текстовое поле сообщение;

загрузить сообщение из текстового файла;

записать сообщение в открытый графический файл, методом НЗБ, кодируя его XOR шифром по данному ключу;

прочитать сообщение из файла, декодировав егоXORшифром с помощью данного ключа;

сохранить прочитанное сообщение в файл;

закрыть bmp файл;шифрование -вид симметричного шифрования, при котором каждый бит сообщения преобразуется с использованием нового бита ключа по следующему правилу: 0+0=0, 0+1=1, 1+0=1, 1+1=0.

Рассмотрим особенности реализации программы:

Программа содержит 4 класса:

Entry - входная точка приложения, осуществляет загрузку графического интерфейса программы.

StegoForm - описание графического интерфейса, и реализация всех связанных с ним функций.

StegoMessenger - класс, в котором описаны методы проверки контейнера на наличие сообщения, а также записи и чтения сообщения в контейнер.

XOREncoder - класс описывающий методы кодирования и декодирования сообщения с помощью XOR шрифта и передаваемого ключа.

Рассмотрим методы класса StegoMessenger:- возвращает максимальный размер сообщения для данного файла, в байтах.- проверяет файл на то, записано ли в него сообщение, кодированное ключом key. Для этого читает последний бит у первых 32 байтов после заголовка файла, декодирует с данным ключом, с помощью метода decrypt класса XOREncoder, и сравнивает с проверочным числом. Возвращает true - если числа совпали, и false - если нет.- метод, записывающий сообщение в файл. На вход ему передается адрес файла изображения, сообщение и ключ. Далее метод высчитывает длину массива байт, которые будут использованы для записи сообщения. Следующим шагом будет кодирование проверочного числа, используемого для проверки контейнера на наличие сообщения, длины сообщения и самого сообщения с помощью метода encrypt класса XOREncoder. После чего все три кодированных последовательности байт разбиваются на биты и последовательно записываются в последний бит байтов изображения, методом writeToLSB. Последним будет заполнение младших бит неиспользованных байт шумом, с помощью вызова метода writeNoiseToLSB.

readFromImage - метод, читающий сообщение из файла. На вход получает адрес файла изображения и ключ. Первый шаг -проверка на существование в контейнере сообщения, записанного данным ключом, действия аналогичны методу isFullContainer. Следующий шаг - чтение и декодирование длины записанного сообщения. Длина l- 32 битное число и хранится соответственно в младших битах следующих после проверочных 32 байтах. Далее, метод читает само сообщение длиной lбайт, декодирует его и возвращает.

Исходный код программы содержится в разделе «Приложения».

Заключение

Таким образом, мы создали приложение, реализующее метод замены наименее значащих битов для файлов с расширением bmp. При его небольшой сложности, этот метод, тем не менее, способен сохранить в тайне факт передачи информации и позволяет передавать достаточно большие сообщения.

Сама стеганография сейчас занимает свою нишу в обеспечении безопасности: она не заменяет, а дополняет криптографию. Сокрытие сообщения методами стеганографии значительно снижает вероятность обнаружения самого факта передачи сообщения. А если это сообщение к тому же зашифровано, то оно имеет еще один, дополнительный, уровень защиты. Также очень перспективно использование стеганографии в тех странах, где существуют законы, ограничивающие применение криптографии, как еще одного способа ограничить доступ к файлам.

Список используемых источников

1.Конахович Г. Ф., Пузыренко А. Ю. Компьютерная стеганография. Теория и практика. - К.: МК-Пресс, 2006. - 288 с, ил.

2. Стеганография для судебного исследователя. Краткий Обзор Гари Кесслер (Gary C.Kessler)

. О. В. Генне, Опубликовано: журнал "Защита информации. Конфидент", №3, 2000

. Грибунин В.Г., Оков И. Н., Туринцев И.В. Цифровая стеганография. - М.: Солон-Пресс, 2002. - 272 с.

Приложения

Исходный код программы:

Классru.sgu.steganography.Entry:class Entry {static void main(String[] args) {frame = new JFrame("StegoForm");.setContentPane(new StegoForm().mainPanel);.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);.pack();.setVisible(true);

}

}

Классru.sgu.steganography.StegoForm:class StegoForm {static final String CURRENT_DIR_PATH = "D:/";static final String TEXT_SIZE_LABEL_TEXT = "Available text size = %d";;;;;;;;;;;;;;;;;;;;;byte[] data;String key = "";long maxTextByteLength = 0;long writeAreaByteSize = 0;void createUIComponents() {= new JPanel();= new JPanel();= new JButton();= new JLabel();= new JFileChooser(new File(CURRENT_DIR_PATH));.setFileFilter(new FileNameExtensionFilter("Bmp files", "bmp"));= new JButton();= new JLabel();= new JButton();= new JPanel();= new JTextArea();= new JScrollPane(writeTextArea);= new JButton();= new JButton();= new JTextPane();= new JScrollPane(readTextPane);= new JButton();= new JTextField(1);= new JButton();= new JFileChooser(new File(CURRENT_DIR_PATH));.setFileFilter(new FileNameExtensionFilter("Txt files", "txt"));= new JFileChooser(new File(CURRENT_DIR_PATH));

}() {.setDocument(new PlainDocument() {

@Overridevoid removeUpdate(DefaultDocumentEventchng) {= writeTextArea.getText().getBytes().length;

}

@Overridevoid insertString(int offset, String str, AttributeSetattr) throws BadLocationException {(str == null);.setText(String.format(TEXT_SIZE_LABEL_TEXT, maxTextByteLength - writeAreaByteSize));((writeAreaByteSize) <= maxTextByteLength) {(char c : str.toCharArray()) {+= String.valueOf(c).getBytes().length;.insertString(offset, str, attr);

++offset;

}

}

}

});.setDocument(new PlainDocument() {

@Overridevoid removeUpdate(DefaultDocumentEventchng) {.removeUpdate(chng); //To change body of overridden methods use File | Settings | File Templates.= keyTextField.getText();

}

@Overridevoid insertString(int offs, String str, AttributeSet a) throws BadLocationException {(str == null);= str.substring(0, Math.min(100 - getLength(), str.length()));.insertString(offs, str, a);= keyTextField.getText();

}

});.addActionListener(new ActionListener() {

@Overridevoid actionPerformed(ActionEvent e) {status = imageFileChooser.showOpenDialog(null);(status == JFileChooser.APPROVE_OPTION) {imageFile = imageFileChooser.getSelectedFile();(imageFile != null) {(imageFile);= StegoMessenger.getMaximumMessageByteLength(imageFile);.setText(String.format(TEXT_SIZE_LABEL_TEXT, maxTextByteLength));

}

}

}

});.addActionListener(new ActionListener() {

@Overridevoid actionPerformed(ActionEvent e) {{.writeToImage(imageFileChooser.getSelectedFile(),writeTextArea.getText(), key);(imageFileChooser.getSelectedFile());(true, readTextPane, readMessageButton, saveReadedDataButton);

} catch (IOException e1) {.out.println("message was not write");

}

}

});.addActionListener(new ActionListener() {

@Overridevoid actionPerformed(ActionEvent e) {(checkToRead(imageFileChooser.getSelectedFile())) {.setText(" ");{= StegoMessenger.readFromImage(imageFileChooser.getSelectedFile(), key);.setText(new String(data));(true, readTextPane, saveReadedDataButton);

} catch (IOException e1) {(false, readTextPane, saveReadedDataButton);.setText("File does not contain message");

}

}else {(false, readTextPane, saveReadedDataButton);.setText("File does not contain message");

}

}

});.addActionListener(new ActionListener() {

@Overridevoid actionPerformed(ActionEvent e) {.setIcon(null);(false, closeBmpButton, readTextPane, readMessageButton, writeMessageButton, writeTextArea, saveReadedDataButton);

}

});.addActionListener(new ActionListener() {

@Overridevoid actionPerformed(ActionEvent e) {status = keyFileChooser.showOpenDialog(null);(status == JFileChooser.APPROVE_OPTION) {keyFile = keyFileChooser.getSelectedFile();(keyFile != null) {= new String(readDataFrom(keyFile));.setText(key);

}

}

}

});.addActionListener(new ActionListener() {

@Overridevoid actionPerformed(ActionEvent e) {status = keyFileChooser.showOpenDialog(null);(status == JFileChooser.APPROVE_OPTION) {msgFile = keyFileChooser.getSelectedFile();(msgFile != null) {= readDataFrom(msgFile);(msgFile.getName().endsWith("txt")){.setText(new String(data));

}{.writeToImage(imageFileChooser.getSelectedFile(),new String(data), key);(imageFileChooser.getSelectedFile());(true, readTextPane, readMessageButton, saveReadedDataButton);

} catch (IOException e1) {.out.println("message was not write");

}

}

}

}

});.addActionListener(new ActionListener() {

@Overridevoid actionPerformed(ActionEvent e) {status = keyFileChooser.showSaveDialog(null);(status == JFileChooser.APPROVE_OPTION) {msgFile = keyFileChooser.getSelectedFile();(msgFile != null) {{= new BufferedWriter(new FileWriter(msgFile));(byte b : data) {.write(b);

}.close();

} catch (IOException e1) {.out.println("File not save");

}

}

}

}

});

}byte[] readDataFrom(File keyFile) {{bb = ByteBuffer.allocate((int) keyFile.length());= new BufferedReader(new FileReader(keyFile));(br.ready()) {.put((byte) br.read());

}.close();.array();

} catch (IOException e) {new byte[0];

}

}void reloadImage(File imageFile) {image;= null;{= ImageIO.read(imageFile);.yield();

} catch (IOException e1) {.out.println("Load image error");

}(imageLabel, image);(true, closeBmpButton, writeTextArea, writeMessageButton, readMessageButton, readTextPane);

} catch (IOException e) {false;

}

}void setRightIconTo(JLabelimageLabel, BufferedImage image) {= getMinimumBound(image.getWidth(), image.getHeight(), imagePanel.getWidth(), imagePanel.getHeight());= (int) (image.getWidth() * minBoundCoefficient) - 7;= (int) (image.getHeight() * minBoundCoefficient) - 7;imageIcon = image.getScaledInstance(imageWidth, imageHeight, Image.SCALE_DEFAULT);icon = new ImageIcon(imageIcon);.setIcon(icon);

}double getMinimumBound(intinWidth, intinHeight, intoutWidth, intoutHeight) {.min((double) outWidth / inWidth, (double) outHeight / inHeight);

}void setEnabledTo(boolean enabled, JComponent... params) {(params.length == 0) {;

}(JComponentparam : params) {.setEnabled(enabled);

}

}

}

КлассStegoMessenger:class StegoMessenger {static final int BYTE_SIZE = 8;static final int MSG_LENGTH_PREFIX = 4 * 8;static final int BMP_HEADER_LENGTH = 54;static final int MSG_CHECK_PREFIX = 4 * 8;static final long[] CHECK_MESSAGE_NUMBER = {314159265l};static final int GLOBAL_PREFIX = BMP_HEADER_LENGTH + MSG_CHECK_PREFIX + MSG_LENGTH_PREFIX;static final Random rand = new Random();static long getMaximumMessageByteLength(File file) {(file.length() - GLOBAL_PREFIX) / 8;

}static void writeToImage(File image, String message, String key){= null;= BitSet.valueOf(key.getBytes());= BitSet.valueOf(message.getBytes());= (int) messageBitSet.length();check;length;= BitSet.valueOf(CHECK_MESSAGE_NUMBER);= BitSet.valueOf(new long[]{(long) messageBitLength});[] checkPixels;[] lengthPixels;[] messagePixels;tail;{= new RandomAccessFile(image, "rw");.seek(BMP_HEADER_LENGTH);= (raf.length() - messageBitLength - GLOBAL_PREFIX);(tail < 0) {new IOException("Stego container is too small for this message. Available to writing " +

+((raf.length() - GLOBAL_PREFIX) / 8)

+ "bytes, but expected message length = "

+ message.length());

}= XOREncoder.encrypt(check, keyBitSet);= XOREncoder.encrypt(length, keyBitSet);= XOREncoder.encrypt(messageBitSet, keyBitSet);= new byte[MSG_CHECK_PREFIX];= new byte[MSG_LENGTH_PREFIX];= new byte[messageBitLength];.read(checkPixels);.read(lengthPixels);.read(messagePixels);(checkPixels, check);(lengthPixels, length);(messagePixels, messageBitSet);.seek(BMP_HEADER_LENGTH); /**/.write(checkPixels);.write(lengthPixels);.write(messagePixels);(raf);

} catch (IOException e) {new IOException(

"Error when process is run in file " + image, e);

} catch (Exception e) {.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.

} finally {(raf != null) {.close();

}

}

}static byte[] readFromImage(File image, String key) throws IOException {= null;= BitSet.valueOf(key.getBytes());;check;length;[] checkPixels;[] lengthPixels;[] messagePixels;{= new RandomAccessFile(image, "rw");.seek(BMP_HEADER_LENGTH);= new byte[MSG_CHECK_PREFIX];.read(checkPixels);= readFromLSB(checkPixels);= XOREncoder.decrypt(check, keyBitSet);.clear(MSG_CHECK_PREFIX, check.size());(CHECK_MESSAGE_NUMBER[0] != check.toLongArray()[0]) {new IOException("Message is not stegocontainer");

}= new byte[MSG_LENGTH_PREFIX];.read(lengthPixels);= readFromLSB(lengthPixels);= XOREncoder.decrypt(length, keyBitSet);.clear(MSG_LENGTH_PREFIX, length.size());= (int) length.toLongArray()[0];= new byte[messageBitSize];.read(messagePixels);= readFromLSB(messagePixels);= XOREncoder.decrypt(messageBitSet, keyBitSet);.clear(messageBitSize, messageBitSet.length());.toByteArray();

} catch (IOException e) {new IOException("Error when process is run in file "

+ image + " \n" + e, e);

} catch (Exception e) {new IOException("Error when process is run in file "

+ image + " \n" + e, e);

} finally {(raf != null) {.close();

}

}

}static booleanisFullContainer(File image, String key) throws IOException {= null;= BitSet.valueOf(key.getBytes());[] checkPixels;check;{= new RandomAccessFile(image, "r");.seek(BMP_HEADER_LENGTH);= new byte[MSG_CHECK_PREFIX];.read(checkPixels);= readFromLSB(checkPixels);= XOREncoder.decrypt(check, keyBitSet);.clear(MSG_CHECK_PREFIX, check.size());(CHECK_MESSAGE_NUMBER[0] == check.toLongArray()[0]) {true;

}false;

} catch (IOException e) {new IOException("Error in read image", e);

} finally {(raf != null) {.close();

}

}

}static void writeNoiseToLSB(RandomAccessFileraf) throws IOException {tail = (int) (raf.length() - raf.getFilePointer());[] b = new byte[3];(inti = 0; i< tail; i += 3) {.read(b);(int j = 0; j <b.length; j++) {[j] &= 254;[j] |= rand.nextBoolean() ? 1 : 0;

}.seek(raf.getFilePointer() - 3);.write(b);

}

}static void writeToLSB(byte[] p, BitSet message) {(inti = 0; i<p.length; i++) {[i] &= 254;[i] |= message.get(i) ? 1 : 0;

}

}static BitSetreadFromLSB(byte[] p) {= new BitSet(p.length);(inti = 0; i<p.length; i++) {.set(i, (p[i] & 1) == 1);

};

}

}

КлассXOREncoder:class XOREncoder {static BitSet encrypt(BitSet message, BitSet key) {crypt(message, key);

}static BitSet crypt(BitSet message, BitSetkeyBits) {= new BitSet(message.length());= 0;bit;(keyBits.size() == 0){message;

}(inti = 0; i<message.size(); i++) {= message.get(i) ^ keyBits.get(keyBitIndex);.set(i, bit);++;%= keyBits.size();

};

}static BitSet decrypt(BitSet cipher, BitSet key) {message = crypt(cipher, key);message;

}

}

Похожие работы на - Приложение, реализующее метод замены наименее значащих битов для файлов с расширением bmp

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!