Не так давно в моём учебном заведении прошёл пилотный Хакатон для студентов. Тематика заданий была связана с информационной безопасностью, в том числе шифрованием данных.
Одним из колоритнейших заданий стал TASK-10: стеганография.
Дадим определение.
Стеганография — это способ передачи или хранения информации с учётом сохранения в тайне самого факта такой передачи (хранения).
Иными словами, если криптография скрывает саму информацию, то стеганография скрывает факт ее передачи.
К сожалению, мы с командой не успели сделать это задание вовремя, и я решил выполнить его уже после мероприятия.
Самым очевидным решением на тот момент казалось:
- Перевести шифруемый текст в наборы битов.
- Сделать тоже самое с изображением.
- Поместить текст в случайное место изображения и сохранить как картинку.
Вот небольшой код преобразования текста в наборы битов и обратно.
def text_to_binary(event):
return [int(format(ord(elem),'b')) for elem in event]
def binary_to_text(event):
return [chr(int(str(elem),2)) for elem in event]
Однако, рассказав о своих мыслях более опытным коллегам я был послан учить матчасть.
Начать нужно с того, что байты файла с картинкой напрямую редактировать не выйдет, если это не bmp.
{% — случайный кодер %}
Прочитав немного о цветовых моделях, я решил отказаться от разложения картинки до 1 и 0 в пользу модификаций самих пикселей в RGB палитре. Для данных манипуляций мной была выбрана библиотека Pillow, вот тут неплохая статья о ней.
Итак, у нас есть изображение. В изображении есть пиксели. Пиксели образованы из основных цветов — красного, зелёного и синего.
Каждый из цветов закодирован числом от 0 до 255.
А ещё у нас есть ASCII символы, которые закодированы также.
Давайте попробуем зашифровать в эту картинку немного текста.
Картинка:
Немного текста:
C makes it easy to shoot yourself in the foot; C++ makes it harder, but when you do, it blows away your whole leg
Подключим необходимые библиотеки.
from PIL import Image, ImageDraw
from random import randint
Затем объявим функцию и поместим в ней все объекты, которые нам пригодятся.
def stega_encrypt():
keys = []
img = Image.open(input("path to image: "))
draw = ImageDraw.Draw(img)
width = img.size[0]
height = img.size[1]
pix = img.load()
f = open('keys.txt','w')
Дальше — интереснее. Самая главная задача — придумать способ, по средством которого станет возможным шифровать сообщения. Мною был предложен такой способ:
- Берем символ, переводим его в число ASCII
- Создаём кортеж со случайными значениями координат
- Собираем зелёный и синий оттенки из пикселя по координатам
- Заменяем красный оттенок на номер символа по ASCII
for elem in ([ord(elem) for elem in input("text here: ")]):
key = (randint(1,width-10),randint(1,height-10))
g, b = pix[key][1:3]
draw.point(key, (elem,g , b))
f.write(str(key)+'n')
Cохраняем ключи и изображение.
print('keys were written to the keys.txt file')
img.save("newimage.png", "PNG")
f.close()
Пробуем выполнить скрипт.
В результате мы получили тоже самое изображение, но в формате png и с несколькими изменёнными пикселями.
Теперь осталось всё это как-то расшифровать.
Пишем скрипт для расшифровки!
Подключаем всё, что нужно.
from PIL import Image
from re import findall
Объявляем функцию для расшифровки, а также несколько объектов.
def stega_decrypt():
a = []
keys = []
img = Image.open(input("path to image: "))
pix = img.load()
f = open(input('path to keys: '),'r')
y = str([line.strip() for line in f])
Основной алгоритм расшифровки:
for i in range(len(findall(r'((d+),',y))):
keys.append((int(findall(r'((d+),',y)[i]),int(findall(r',s(d+))',y)[i])))
for key in keys:
a.append(pix[tuple(key)][0])
return ''.join([chr(elem) for elem in a])
Указанные регулярные выражения нужны для считывания кортежей из текстового файла.
Последнее действие — вывод на экран зашифрованного сообщения.
print("you message: ", stega_decrypt())
А теперь попробуем получить наше сообщение.
Что и требовалось доказать, всё работает!
Главный недостаток: видимость битых пикселей изображения в случае шифрования большого количества символов. Однако, этот недостаток отлично исправляется высоким разрешением.
Ссылки:
Автор: Николай Дмитриевич