Можно так просто взять и скрыть информацию

в 8:22, , рубрики: php, безопасность, информационная безопасность, Программирование, Стеганография, метки: , , ,

Каждый из читателей наверняка много раз видел фильмы, где супергерой / суперзлодей передавал зашифрованную информацию. Мы привыкли к слову «шифр», «шифрование» и любая тайная передача информации сейчас ассоциируетсяименно с этими словами. Хотя на самом деле, это далеко не так. Безопасная передача информации далеко не ограничивается криптографией (шифрования), а есть еще много методов и средств для этого.
Можно так просто взять и скрыть информацию
В частности, автор этого материала хотел бы затронуть стеганографию. Стеганография — это сокрытие самого факта передачи информации.

Чем это принципиально отличается от криптографии.
В случае с криптографическими преобразованиями факт сокрытия информации очевиден. То есть, когда А передает информацию в Б, то В знает, что информация секретная, но не имеет (в лучшем случае) алгоритмов ее расшифровки, если она попадет ему в руки.

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

Чем стеганографический метод лучше криптографического.
Сокрытие факта передачи информации уменьшает риски того, что секретная или конфиденциальная информация попадет к злоумышленнику, а даже если и попадет, он может не увидеть в ней ничего ценного (почему — объясним ниже).

Это только в фильмах секретная информация героя обеспечена непробиваемым шифром. В реальной жизни, злоумышленник отправит к герою двух здоровенных Г. и Д., которые после очередного поломанного сустава все-таки узнают ключ для дешифровки.

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

Итак, как это работает?
Главный принцип стеганографии состоит в том, чтобы скрыть конфенденциальную информацию внутри открытой, как правило вседоступной информации. То есть один тип информации (текст, изображения, аудио итд) помещается внутрь другой информации (текст, изображения, аудио итд). Таким образом контейнер (информация, которая таит в себе стегосообщение) выглядит более чем безобидно.

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

Для начала напишем html страницу без лишнего дизайна (это не урок веб-дизайна все же). Следовательно файл index.php:

Адрес: <input type="url" name="url" id="url" value="">
Код: <input type="text" name="code" id="code" value="">
<input type="button" value="Скрыть" >
<input type="button" value="Извлечь" ><br>

<div id="img_new"></div>

Думаю тут особо объяснять не нужно, что в поле «Адрес» будет адрес изображения, а в поле «Код» — небольшая скрытая информация. Назначение кнопок тоже очевидно. В блоке img_new будет помещаться исходная информация, в том числе готовый контейнер с стегосообщением в нем.

При разработке будем использовать фреймворк Ajax, а точнее ровно одну его функцию. Поэтому подключим к index.php этот фреймворк и один наш js файл.

<script src="ajax.js"></script> 
<script src="stego.js"></script>

Стегоалгоритмы будут происходить в файлах stego.php и destego.php. Свяжем их с нашим index-ом с помощью двух функций нашего java script: stego (), de_stego ().

Итак, stego.js:

stego.js

	function stego (url, code) {
		$("#img_new").html(""); 
		 $.ajax({  
			        type: "POST",
               			url: "stego.php",  
			        data: 'url_img='+url+'&stego_code='+code+'',
                	        cache: false,  
                		success: function(html){ 
				$("#img_new").html(html);   
				}  
           		 });	
	}

	function de_stego (url) {
		$("#img_new").html(""); 
		 $.ajax({  
				type: "POST",
              			  url: "destego.php",  
				data: 'url_img='+url+'&stego_code='+code+'',
              			  cache: false,  
               			 success: function(html){ 
					$("#img_new").html(html);   
				}  
            	});	
	}

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

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

<input type="button" value="Скрыть" onclick="stego(document.getElementById('url').value,document.getElementById('code').value)">
<input type="button" value="Извлечь"  onclick="de_stego(document.getElementById('url').value)"><br>

Теперь перейдем к самому интересному, к стегопреобразованиям. Сначала рассмотрим файл stego.php.

Прежде добавим проверку наличия адреса изображения

if (!$_POST[url_img]) { echo "Введите все данные"; exit(); }

И проверку типа изображения. Будем считать, что пользователь будет использовать только самые распространенные форматы: jpg, gif, png. В противном случае, программа тоже будет пытаться загрузить изображение, но успех зависит от соответствующей сборки PHP.

$type_img = explode (".", $_POST[url_img]);

	switch(strtolower($type_img[count($type_img)-1])) {
		case "png": $img1 = imagecreatefrompng($_POST[url_img]); break;
		case "jpg": $img1 = imagecreatefromjpeg($_POST[url_img]); break;
		case "jpeg": $img1 = imagecreatefromjpeg($_POST[url_img]); break;
		case "gif": $img1 = imagecreatefromgif($_POST[url_img]); break;
		default: $img1 = imagecreatefromgd ($_POST[url_img]); break;
	}

Здесь следует заметить, что часто хостеры не включают графическую библиотеку GD в PHP. Если программа у Вас не будет работать — обратитесь с этим вопросом к Вашему хостер-провайдеру.

Продолжим…

Выводим изображение пользователя на экран в формате png. Почему именно этот формат? Потому что выводить другое изображение мы будем тоже в png. Так лучше будет сравнивать потом между собой изображения.

imagepng ($img1, "img/img_code1".date(si).".png");
	echo "Входное изображение: <img src='img/img_code1".date(si).".png' 	width='400px'>";

Далее определяем размер изображения, задаем начальные координаты x, y, узнаем длину сообщения и заносим сообщения в рабочую переменную $code.

$size = getimagesize($_POST[url_img]);
	$w = $size[0];
	$h = $size[1];
	
	$x = $y = 0;
	$length = strlen($_POST[stego_code]);
	$code = $_POST[stego_code];

Далее начинается самое интересное. А именно цикл, в котором наше сообщение попадет в изображение. Сначала приведем код, а дальше будем разбирать:

	while ($length--) {
		$color_pixel = imagecolorat ($img1, $x, $y);
		$color_pixel_RGB = imagecolorsforindex ($img1, $color_pixel);
		$color_pixel_RGB[blue] = ord ($code[$length]); 
		$color_new_pixel =
 imagecolorclosest ($img1, $color_pixel_RGB[red], $color_pixel_RGB[green], $color_pixel_RGB[blue]);
		imagesetpixel ($img1, $x, $y, $color_new_pixel);
		$x+=50; 
		if ($x>$w) {$x=0; $y++;}
	}

Цикл будет повторяться пока не дойдем конца сообщения. К тому же будем начинать с последнего символа. Сначала мы узнаем цвет пикселя по координатам x, y ($ color_pixel = imagecolorat ($ img1, $ x, $ y) ;), заносим в массив $ color_pixel_RGB значение соотношения красного, зеленого и синего цветов в пикселях.

Прошу обратить внимания на строчку: $ color_pixel_RGB [blue] = ord ($ code [$ length]) — Именно здесь уровень синего цвета заменяются на номер символа сообщения в ASCII таблице. Это удобно, потому что они не должны преувеличивать число 255 как и значение переменной соответственно RGB. Автор наугад выбрал синий цвет. Можете попробовать с любым другим (зеленым или красным цветом), которые в данной программе остаются нетронутыми, за исключением одного случая, о котором будет дальше.

Далее в цикле происходит нанесение пикселя на новое изображение и увеличение координат. Если они превышают ширину изображения, то происходит увеличение значения координаты по высоте (y), а x приравнивается к нулю.
Вот таким не хитрым способом мы скрыли наше сообщение в изображении.

Но как программа при изъятии стегосообщения узнает, что наступил конец сообщения? Для этого в последнем пикселе сообщение меняем уровень красного цвета на 1.

	$color_new_pixel = imagecolorclosest ($img1, 1, $color_pixel_RGB[green], 	$color_pixel_RGB[blue]);
	imagesetpixel ($img1, $x, $y, $color_new_pixel);

И выводим новое изображение на экран:

	imagepng ($img1, "img/img_code2".date(si).".png");
	echo "Исходное изображение: <img src='img/img_code2".date(si).".png'  width='400px'>";

Таким образом файл stego.php готов и выглядит так:

stego.php

<?php
	if (!$_POST[url_img]) { echo "Введіть всі дані"; exit(); }
	
	$type_img = explode (".", $_POST[url_img]);

	switch(strtolower($type_img[count($type_img)-1])) {
		case "png": $img1 = imagecreatefrompng($_POST[url_img]); break;
		case "jpg": $img1 = imagecreatefromjpeg($_POST[url_img]); break;
		case "jpeg": $img1 = imagecreatefromjpeg($_POST[url_img]); break;
		case "gif": $img1 = imagecreatefromgif($_POST[url_img]); break;
		default: $img1 = imagecreatefromgd ($_POST[url_img]); break;
	}
	
	
	imagepng ($img1, "img/img_code1".date(si).".png");
	echo "Входное изображение: <img src='img/img_code1".date(si).".png' 	width='400px'>";
	$size = getimagesize($_POST[url_img]);
	$w = $size[0];
	$h = $size[1];
	
	$x = $y = 0;
	$length = strlen($_POST[stego_code]);
	$code = $_POST[stego_code];
	while ($length--) {
		$color_pixel = imagecolorat ($img1, $x, $y);
		$color_pixel_RGB = imagecolorsforindex ($img1, $color_pixel);
		$color_pixel_RGB[blue] = ord ($code[$length]); 
		$color_new_pixel =
 imagecolorclosest ($img1, $color_pixel_RGB[red],$color_pixel_RGB[green], $color_pixel_RGB[blue]);
		imagesetpixel ($img1, $x, $y, $color_new_pixel);
		$x+=50; 
		if ($x>$w) {$x=0; $y++;}
	}
	
	$color_new_pixel = imagecolorclosest ($img1, 1, $color_pixel_RGB[green],  $color_pixel_RGB[blue]);
	imagesetpixel ($img1, $x, $y, $color_new_pixel);
		
	imagepng ($img1, "img/img_code2".date(si).".png");
	echo "Исходное изображение: <img src='img/img_code2".date(si).".png'  	width='400px'>";
?>

Теперь перейдем ко второй функции, так как, какой смысл в сокрытии информации, если сами потом вытащить не сможем?

И так файл destego.php.

Половина кода аналогично коду stego.php:

destego половина

	if (!$_POST[url_img]) { echo "Введите все данные"; exit(); }
	
	$type_img = explode (".", $_POST[url_img]);

	switch(strtolower($type_img[count($type_img)-1])) {
		case "png": $img1 = imagecreatefrompng($_POST[url_img]); break;
		case "jpg": $img1 = imagecreatefromjpeg($_POST[url_img]); break;
		case "jpeg": $img1 = imagecreatefromjpeg($_POST[url_img]); break;
		case "gif": $img1 = imagecreatefromgif($_POST[url_img]); break;
		default: $img1 = imagecreatefromgd ($_POST[url_img]); break;
	}
	
	echo "Входное изображение: <img src='".$_POST[url_img]."' 	width='400px'>    ";
	echo "Код: ";
	$size = getimagesize($_POST[url_img]);
	$w = $size[0];
	$h = $size[1];
	
	$x = $y = 0;

Здесь уже знакомые нам проверки ввода информации, загрузки изображения и вывод его на экран

Далее идет цикл, который вытягивает нашу информацию с картинки:

	while ($color_pixel_RGB[red]!=1)  {
		$color_pixel = imagecolorat ($img1, $x, $y);
		$color_pixel_RGB = imagecolorsforindex ($img1, $color_pixel);
		$text = chr($color_pixel_RGB[blue]).$text;
		$x+=50;  if ($x>$w) {$x=0; $y++;}
	} ;

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

Выводим сообщение.

	$text[0] = "";
	echo $text;

$ Text [0] = "" — нужно так как первый символ остается пустым и может быть заполнен всяким «мусором».

И так, destego.php выглядит так:

destego.php

<?php
	if (!$_POST[url_img]) { echo "Введите все данные"; exit(); }
	
	$type_img = explode (".", $_POST[url_img]);

	switch(strtolower($type_img[count($type_img)-1])) {
		case "png": $img1 = imagecreatefrompng($_POST[url_img]); break;
		case "jpg": $img1 = imagecreatefromjpeg($_POST[url_img]); break;
		case "jpeg": $img1 = imagecreatefromjpeg($_POST[url_img]); break;
		case "gif": $img1 = imagecreatefromgif($_POST[url_img]); break;
		default: $img1 = imagecreatefromgd ($_POST[url_img]); break;
	}
	
	echo "Входное изображение: <img src='".$_POST[url_img]."' 	width='400px'>    ";
	echo "Код: ";
	$size = getimagesize($_POST[url_img]);
	$w = $size[0];
	$h = $size[1];
	
	$x = $y = 0;

	while ($color_pixel_RGB[red]!=1)  {
		$color_pixel = imagecolorat ($img1, $x, $y);
		$color_pixel_RGB = imagecolorsforindex ($img1, $color_pixel);
		$text = chr($color_pixel_RGB[blue]).$text;
		$x+=50;  if ($x>$w) {$x=0; $y++;}
	} ;

	$text[0] = "";
	echo $text;
?>

Так, наша программа есть и в интернете. Так она выглядит:
Можно так просто взять и скрыть информацию

Вводим адрес изображения.
Вводим сообщение автора материала: Осадчий Сергей
Нажимаем «Скрыть» и получаем исходное изображение:
Можно так просто взять и скрыть информацию

Входное изображение:

image

Исходное изображение:

image

Как видите, изображение идентичны.

Копируем адрес исходного изображения, вставляем в адрес изображения и нажимаем «Изъять». Получаем:
Можно так просто взять и скрыть информацию
Убедиться можете сами.

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

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

P.S. Не будьте слишком строги к автору. Это моя первая статья на хабре. Спасибо!

Автор: RDSergij

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js