- •Курсовий проект (робота)
- •Содержание
- •Общие сведения о стеганографии
- •1.1 Основные понятия и определения стеганографии
- •Сокрытие данных
- •1.3 Обзор методов стеганографии
- •1.3.1 Метод последнего бита
- •1.3.2 Метод дискретно косинусного преобразования
- •2 Проектирование
- •2.1 Выбор языка программирования
- •2.2 Выбор среды разработки
- •2.3 Выбор программного обеспечения промежуточного уровня
- •2.4 Выбор интерфейса
- •3 Разработка
- •3.1 Выбор системной архитектуры
- •3.2 Описание функций, реализуемых программой
- •3.3 Диаграмма классов
- •3.4 Разработка пользовательского интерфейса
- •3.5 Алгоритм работы программы
- •4 Верификация и тестирование
- •4.1 Верификация
- •4.2 Тестирование
- •1.Введение
- •1.1 Наименование программы
- •1.2 Краткая характеристика области применения
- •4 Требования к программе
- •4.1 Требования к функциональным характеристикам
- •4.1.1 Требования к составу выполняемых функций
- •4.1.2 Требования к организации входных и выходных данных
- •4.1.3 Требования к временным характеристикам
- •4.2 Требования к составу и параметрам технических средств
- •4.3 Требования к информационной и программной совместимости
- •4.3.1 Требования к исходным кодам и языкам программирования
- •4.3.2 Требования к программным средствам, используемым программой
- •4.3.3 Требования к информационным структурам и методам решения
- •5 Требования к программной документации
- •6 Стадии и этапы разработки
- •6.1 Стадии разработки
- •6.2 Этапы разработки
6 Стадии и этапы разработки
6.1 Стадии разработки
Разработка должна быть проведена в три стадии:
1. Разработка технического задания;
2. Рабочее проектирование;
3. Тестирование.
6.2 Этапы разработки
На стадии разработки технического задания должно быть выполнено согласование и утверждение темы технического задания.
На стадии рабочего проектирования должны быть выполнены перечисленные ниже этапы работ:
1. Разработка технического задания;
2. Рабочее проектирование;
3. Тестирование.
Приложение Б
Текст программы
Клас frmMain
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.IO;
using System.Text;
namespace PictureKey
{
/// <summary>
/// Zusammendfassende Beschreibung fьr Form1.
/// </summary>
public class frmMain : System.Windows.Forms.Form
{
private System.Windows.Forms.GroupBox grpPicture;
private System.Windows.Forms.Label fileName;
private System.Windows.Forms.TextBox txtImageFile;
private System.Windows.Forms.PictureBox picImage;
private System.Windows.Forms.Button btnImageFile;
private System.Windows.Forms.TextBox txtKeyFile;
private System.Windows.Forms.RadioButton rdoKeyText;
private System.Windows.Forms.GroupBox grpKey;
private System.Windows.Forms.TextBox txtKeyText;
private System.Windows.Forms.RadioButton rdoKeyFile;
private System.Windows.Forms.Button btnHide;
private System.Windows.Forms.Button btnExtract;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.Button btnSaveBitmap;
private System.Windows.Forms.GroupBox grpMessage;
private System.Windows.Forms.RadioButton rdoMessageText;
private System.Windows.Forms.TextBox txtMessageFile;
private System.Windows.Forms.TextBox txtMessageText;
private System.Windows.Forms.Button btnMessage;
private System.Windows.Forms.RadioButton rdoMessageFile;
private System.Windows.Forms.GroupBox extractBox;
private System.Windows.Forms.Label saveExtracted;
private System.Windows.Forms.Label extractedText;
private System.Windows.Forms.Button btnKeyFile;
private System.Windows.Forms.TextBox txtExtractedMsgFile;
private System.Windows.Forms.Button btnExtractedMsgFile;
private System.Windows.Forms.TextBox txtExtractedMsgText;
private System.Windows.Forms.CheckBox chkGrayscale;
private System.ComponentModel.Container components = null;
public frmMain()
{
InitializeComponent();
}
/// <summary>Cleanup</summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
static void Main()
{
Application.Run(new frmMain());
}
private void btnHide_Click(object sender, System.EventArgs e)
{
Bitmap bitmap = (Bitmap)picImage.Image;
//get a stream for the message to hide
Stream messageStream = GetMessageStream();
if(messageStream.Length == 0)
{
MessageBox.Show("Please enter a message or select a file.");
txtMessageText.Focus();
}
else
{
//get a stream fot the key
Stream keyStream = GetKeyStream();
if(keyStream.Length == 0)
{
MessageBox.Show("Please enter a password or select a key file.");
txtKeyText.Focus();
}
else
{
try
{
//hide the message
CryptUtility.HideMessageInBitmap(messageStream, bitmap, keyStream, chkGrayscale.Checked);
//display result
picImage.Image = bitmap;
btnSaveBitmap.Enabled = true;
}
catch(Exception ex)
{
MessageBox.Show("Exception:\r\n"+ex.Message);
}
}
keyStream.Close();
}
messageStream.Close();
bitmap = null;
}
private void btnExtract_Click(object sender, System.EventArgs e)
{
Bitmap bitmap = (Bitmap)picImage.Image;
//empty stream for the extracted message
Stream messageStream = new MemoryStream();
//get a stream for the key
Stream keyStream = GetKeyStream();
if(keyStream.Length == 0)
{
MessageBox.Show("Please enter a password or select a key file.");
txtKeyText.Focus();
}
else
{
try
{
//extract the hidden message from the bitmap
CryptUtility.ExtractMessageFromBitmap(bitmap, keyStream, ref messageStream);
//save the message, if a filename is available
if(txtExtractedMsgFile.Text.Length > 0)
{
messageStream.Seek(0, SeekOrigin.Begin);
FileStream fs = new FileStream(txtExtractedMsgFile.Text, FileMode.Create);
byte[] streamContent = new Byte[messageStream.Length];
messageStream.Read(streamContent, 0, streamContent.Length);
fs.Write(streamContent, 0, streamContent.Length);
}
//display the message - displays chaos, if it's no unicode text
messageStream.Seek(0, SeekOrigin.Begin);
StreamReader reader = new StreamReader(messageStream, UnicodeEncoding.Unicode);
String readerContent = reader.ReadToEnd();
if(readerContent.Length > txtExtractedMsgText.MaxLength){
readerContent = readerContent.Substring(0, txtExtractedMsgText.MaxLength);
}
txtExtractedMsgText.Text = readerContent;
}
catch(Exception ex)
{
MessageBox.Show("Exception:\r\n"+ex.Message);
}
}
//close the streams
messageStream.Close();
keyStream.Close();
bitmap = null;
}
/// <summary>Creates a stream to read the message from a string or a file</summary>
/// <returns>FileStream for a message file, or MemoryStream</returns>
private Stream GetMessageStream()
{
Stream messageStream;
if(rdoMessageText.Checked)
{
byte[] messageBytes = UnicodeEncoding.Unicode.GetBytes(txtMessageText.Text);
messageStream = new MemoryStream(messageBytes);
}
else
{
messageStream = new FileStream(txtMessageFile.Text, FileMode.Open, FileAccess.Read);
}
return messageStream;
}
/// <summary>Creates a stream to read the key from a string or a file</summary>
/// <returns>FileStream for a key file, or MemoryStream for a password</returns>
private Stream GetKeyStream()
{
Stream keyStream;
if(rdoKeyText.Checked)
{
byte[] keyBytes = UnicodeEncoding.Unicode.GetBytes(txtKeyText.Text);
keyStream = new MemoryStream(keyBytes);
}
else
{
keyStream = new FileStream(txtKeyFile.Text, FileMode.Open, FileAccess.Read);
}
return keyStream;
}
/// <summary>Opens a bitmap</summary>
/// <param name="fileName">Path and name of the bitmap file</param>
private void SetImage(String fileName)
{
picImage.Image = new Bitmap(fileName);
btnHide.Enabled = btnExtract.Enabled = true;
btnSaveBitmap.Enabled = false;
int index = fileName.LastIndexOf("\\")+1;
if(index > 0){ fileName = fileName.Substring(index); }
grpPicture.Text = "Carrier Bitmap ("+fileName+")";
}
/// <summary>Displays the OpenFile dialog</summary>
/// <returns>The selected file name, or null</returns>
private String GetFileName(String filter)
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Multiselect = false;
if(filter.Length > 0){ dlg.Filter = filter; }
if( dlg.ShowDialog(this) != DialogResult.Cancel)
{
return dlg.FileName;
}
else
{
return null;
}
}
private void rdoMessage_Click(object sender, System.EventArgs e)
{
txtMessageFile.Enabled = rdoMessageFile.Checked;
txtMessageText.Enabled = rdoMessageText.Checked;
}
private void rdoKey_Click(object sender, System.EventArgs e)
{
txtKeyFile.Enabled = rdoKeyFile.Checked;
txtKeyText.Enabled = rdoKeyText.Checked;
}
private void btnImageFile_Click(object sender, System.EventArgs e)
{
String fileName = GetFileName("Bitmaps (*.bmp)|*.bmp|Tagged Image File Format(*.tif)|*.tif|PNG-24(*.png)|*.png");
if(fileName != null)
{
txtImageFile.Text = fileName;
SetImage(fileName);
}
}
private void btnSaveBitmap_Click(object sender, System.EventArgs e)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "Bitmaps (*.bmp)|*.bmp|Tagged Image File Format(*.tif)|*.tif|PNG-24(*.png)|*.png";
if( dlg.ShowDialog() == DialogResult.OK )
{
System.Drawing.Imaging.ImageFormat format = System.Drawing.Imaging.ImageFormat.Bmp;
if(dlg.FilterIndex == 2)
{
format = System.Drawing.Imaging.ImageFormat.Tiff;
}
else if(dlg.FilterIndex == 3)
{
format = System.Drawing.Imaging.ImageFormat.Png;
}
//copy the bitmap
Image img = new Bitmap(picImage.Image);
//close bitmap file
this.SuspendLayout();
picImage.Image.Dispose();
picImage.Image = null;
btnSaveBitmap.Enabled = btnHide.Enabled = btnExtract.Enabled = false;
txtImageFile.Text = String.Empty;
this.ResumeLayout();
//save new bitmap
img.Save(dlg.FileName, format);
}
}
private void txtMessageFile_Enter(object sender, System.EventArgs e)
{
rdoKeyFile.Checked = true;
}
private void txtMessageText_Enter(object sender, System.EventArgs e)
{
rdoKeyText.Checked = true;
}
private void txtImageFile_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
{
if(e.KeyCode == Keys.Enter)
{
SetImage(txtImageFile.Text);
}
}
private void btnMessage_Click(object sender, System.EventArgs e)
{
String fileName = GetFileName("Text Files | *.txt");
if(fileName != null)
{
txtMessageFile.Text = fileName;
rdoMessageFile.Checked = true;
}
}
private void btnExtractedMsgFile_Click(object sender, System.EventArgs e)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "Text Files | *.txt";
if( dlg.ShowDialog() == DialogResult.OK )
{
txtExtractedMsgFile.Text = dlg.FileName;
}
}
private void btnKeyFile_Click(object sender, System.EventArgs e)
{
String fileName = GetFileName("Text Files | *.txt");
if(fileName != null)
{
txtKeyFile.Text = fileName;
rdoKeyFile.Checked = true;
}
}
}
}
Класс CryptUtility
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Text;
using System.IO;
namespace PictureKey
{
public class CryptUtility
{
/// <summary>Hides a message in a bitmap</summary>
/// <param name="messageStream">The message to hide</param>
/// <param name="bitmap">The carrier bitmap</param>
/// <param name="keyStream">The key to use</param>
public static void HideMessageInBitmap(Stream messageStream, Bitmap bitmap, Stream keyStream, bool useGrayscale)
{
HideOrExtract(ref messageStream, bitmap, keyStream, false, useGrayscale);
messageStream = null;
}
/// <summary>Extracts an hidden message from a bitmap</summary>
/// <param name="bitmap">The carrier bitmap</param>
/// <param name="keyStream">The key used for hiding the message</param>
/// <param name="messageStream">Empty stream to receive the message</param>
public static void ExtractMessageFromBitmap(Bitmap bitmap, Stream keyStream, ref Stream messageStream)
{
HideOrExtract(ref messageStream, bitmap, keyStream, true, false);
}
/// <summary>Stepts through the pixels of a bitmap using a key pattern and hides or extracts a message</summary>
/// <param name="messageStream">If exctract is false, the message to hide - otherwise an empty stream to receive the extracted message</param>
/// <param name="bitmap">The carrier bitmap</param>
/// <param name="keyStream">The key specifying the unchanged pixels between two hidden bytes</param>
/// <param name="extract">Extract a hidden message (true), or hide a message in a clean carrier bitmap (false)</param>
private static void HideOrExtract(ref Stream messageStream, Bitmap bitmap, Stream keyStream, bool extract, bool useGrayscale)
{
//Current count of pixels between two hidden message-bytes
//Changes with every hidden byte according to the key
int currentStepWidth = 0;
//Current byte in the key stream - normal direction
byte currentKeyByte;
//Current byte in the key stream - reverse direction
byte currentReverseKeyByte;
//current position in the key stream
long keyPosition;
//maximum X and Y position
int bitmapWidth = bitmap.Width-1;
int bitmapHeight = bitmap.Height-1;
//Color component to hide the next byte in (0-R, 1-G, 2-B)
//Rotates with every hidden byte
int currentColorComponent = 0;
//Stores the color of a pixel
Color pixelColor;
//Length of the message
Int32 messageLength;
if(extract)
{
//Read the length of the hidden message from the first pixel
pixelColor = bitmap.GetPixel(0,0);
messageLength = (pixelColor.R << 2) + (pixelColor.G << 1) + pixelColor.B;
messageStream = new MemoryStream(messageLength);
}
else
{
messageLength = (Int32)messageStream.Length;
if(messageStream.Length >= 16777215)
{ //The message is too long
String exceptionMessage = "Themessage is too long, only 16777215 bytes are allowed.";
throw new Exception(exceptionMessage);
}
//Check size of the carrier image
//Pixels available
long countPixels = (bitmapWidth*bitmapHeight) -1;
//Pixels required - start with one pixel for length of message
long countRequiredPixels = 1;
//add up the gaps between used pixels (sum up all the bytes of the key)
while((keyStream.Position < keyStream.Length)&&(keyStream.Position < messageLength))
{
countRequiredPixels += keyStream.ReadByte();
}
//If the key is shorter than the message, it will be repeated again and again
//Multiply with count of key periods
countRequiredPixels *= (long)System.Math.Ceiling( ((float)messageStream.Length / (float)keyStream.Length) );
if(countRequiredPixels > countPixels)
{ //The bitmap is too small
String exceptionMessage = "The image is too small for this message and key. "+countRequiredPixels+" pixels are required.";
throw new Exception(exceptionMessage);
}
//Write length of the bitmap into the first pixel
int colorValue = messageLength;
int red = colorValue >> 2;
colorValue -= red << 2;
int green = colorValue >> 1;
int blue = colorValue - (green << 1);
pixelColor = Color.FromArgb(red, green, blue);
bitmap.SetPixel(0,0, pixelColor);
}
//Reset the streams
keyStream.Seek(0, SeekOrigin.Begin);
messageStream.Seek(0, SeekOrigin.Begin);
//Current position in the carrier bitmap
//Start with 1, because (0,0) contains the message's length
Point pixelPosition = new Point(1,0);
//Loop over the message and hide each byte
for(int messageIndex = 0; messageIndex < messageLength; messageIndex++)
{
//repeat the key, if it is shorter than the message
if(keyStream.Position == keyStream.Length)
{
keyStream.Seek(0, SeekOrigin.Begin);//set it to 0
}
//Get the next pixel-count from the key, use "1" if it's 0
currentKeyByte = (byte)keyStream.ReadByte();
currentStepWidth = (currentKeyByte==0) ? (byte)1 : currentKeyByte;
//jump to reverse-read position and read from the end of the stream
keyPosition = keyStream.Position;
keyStream.Seek(-keyPosition, SeekOrigin.End);
currentReverseKeyByte = (byte)keyStream.ReadByte();
//jump back to normal read position
keyStream.Seek(keyPosition, SeekOrigin.Begin);
//Perform line breaks, if current step is wider than the image
while(currentStepWidth > bitmapWidth)
{
currentStepWidth -= bitmapWidth;
pixelPosition.Y++;
}
//Move X-position
if((bitmapWidth - pixelPosition.X) < currentStepWidth)
{
pixelPosition.X = currentStepWidth - (bitmapWidth - pixelPosition.X);
pixelPosition.Y++;
}
else
{
pixelPosition.X += currentStepWidth;
}
//Get color of the "clean" pixel
pixelColor = bitmap.GetPixel(pixelPosition.X, pixelPosition.Y);
if(extract)
{
//Extract the hidden message-byte from the color
byte foundByte = (byte)(currentReverseKeyByte ^ GetColorComponent(pixelColor, currentColorComponent));
messageStream.WriteByte(foundByte);
//Rotate color components
currentColorComponent = (currentColorComponent==2) ? 0 : (currentColorComponent+1);
}
else
{
//To add a bit of confusion, xor the byte with a byte read from the keyStream
int currentByte = messageStream.ReadByte() ^ currentReverseKeyByte;
if(useGrayscale)
{
pixelColor = Color.FromArgb(currentByte, currentByte, currentByte);
}
else
{
//Change one component of the color to the message-byte
SetColorComponent(ref pixelColor, currentColorComponent, currentByte);
//Rotate color components
currentColorComponent = (currentColorComponent==2) ? 0 : (currentColorComponent+1);
}
bitmap.SetPixel(pixelPosition.X, pixelPosition.Y, pixelColor);
}
}
//the stream will be closed by the calling method
bitmap = null;
keyStream = null;
}
/// <summary>Return one component of a color</summary>
/// <param name="pixelColor">The Color</param>
/// <param name="colorComponent">The component to return (0-R, 1-G, 2-B)</param>
/// <returns>The requested component</returns>
private static byte GetColorComponent(Color pixelColor, int colorComponent)
{
byte returnValue = 0;
switch(colorComponent)
{
case 0:
returnValue = pixelColor.R;
break;
case 1:
returnValue = pixelColor.G;
break;
case 2:
returnValue = pixelColor.B;
break;
}
return returnValue;
}
/// <summary>Changees one component of a color</summary>
/// <param name="pixelColor">The Color</param>
/// <param name="colorComponent">The component to change (0-R, 1-G, 2-B)</param>
/// <param name="newValue">New value of the component</param>
private static void SetColorComponent(ref Color pixelColor, int colorComponent, int newValue)
{
switch(colorComponent)
{
case 0:
pixelColor = Color.FromArgb(newValue, pixelColor.G, pixelColor.B);
break;
case 1:
pixelColor = Color.FromArgb(pixelColor.R, newValue, pixelColor.B);
break;
case 2:
pixelColor = Color.FromArgb(pixelColor.R, pixelColor.G, newValue);
break;
}
}
private static String UnTrimColorString(String color, int desiredLength)
{
int difference = desiredLength - color.Length;
if(difference > 0)
{
color = new String('0', difference) + color;
}
return color;
}
}
}
Приложение В
Руководство пользователя
Назначение программы
Приложение "Stegano" предназначено для кодирования некоторого текста в картинку. Данная работа является отличным примером программных методов защиты информации, подобным образом можно организовать сокрытие любой информации в картинке и её дальнейшей расшифровки.
Программа является однократно запускаемой и активизируется для выполнения оператором ПК с правами обычного пользователя. Программа разработана таким образом, чтобы, после перекомпиляции она имела возможность работать на любом компьютере с операционной системой Windows.
Программа предназначена для эксплуатации на ПК, установленном дома или в офисе.
Эксплуатация программы
После запуска программы на экране монитора появляется окно программы. В левом верхнем углу расположена кнопка для вызова окна выбора файла (картинки) и область для отображения выбранной картинки. Ниже, под ним, расположена область для ввода или загрузки строки-ключа. Область пользовательского окна расположена в правой части окна состоит из двух вкладок. Первая вкладка используется для ввода сообщения (или загрузки из текстового файла), которое нужно зашифровать в картинку. Если данные внесены верно, то окно программы будет выглядеть как на рисунке В.1.
Рисунок В.1 – Окно программы
Для того что бы скрыть тест необходимо нажать на кнопку «Hide Message» в правом нижнем углу окна программы. После этого появится возможность сохранить результат работы программы (кнопка «Save Result» станет доступной).
Для обратного действия, то есть получения зашифрованной ранее информации из картинки, необходимо перейти на вкладку «Extract» в правой части приложения. Далее необходимо ввести пароль и нажат кнопку «Extract hidden message», спрятанный текст появится в текстовом окне (рисунок В.2).
Рисунок В.2 –Извлечение сообщения
Извлеченный текст можно сохранить, указав путь к текстовому файлу и повторно нажать на кнопку «Extract hidden message».
Если пользователь попытается спрятать или извлечь сообщение, не введя пароль, то программа выдает сообщение, изображенное на рисунке В.3.
Рисунок В.3 – Сообщение об ошибке
Приложение Г Презентация
