Стеганография и пробел нулевой длины
Болею, не спится мне. Вспомнил старую свою идею.
В Юникоде есть такой символ замечательный — пробел нулевой длины (код 0x200B), на печать не выводится, понимается всеми современными браузерами и большинством редакторов. Интервала между буквами, как следует из названия, не даёт.
Идея простая, позволяет прятать в текст другой текст, так, чтобы первый не менялся, а второй всегда копировался вместе с первым. Основная мысль — пользуясь буквами исходного текста, как разделителем, ставим между ними столько пробелов нулевой длины, чтобы их число равнялось коду скрываемого символа.
Например. Дан текст: «Болк», в нём надо скрыть короткий текст: «yes». Я взял английские символы, чтобы не заморачиватсья с кодировкой.
Коды символов «yes» — 121, 101, 115. Значит текст приобретает следующий вид:
[121 символ пробела нулевой длины]Б[101 символ пробела нулевой длины]о[115 символов пробела нулевой длины]лк
Можно, кстати, вычитать из кода символа 31, если мы не планируем использовать символы перевода строки и табуляции в скрываемом тексте. Небольшой код на Пайтоне, приведённый ниже, иллюстрирует идею.
# Example by Evgeny Stepanischev
from itertools import groupby, izip_longest
import sys
import codecs
sys.stdin = codecs.getreader('utf-8')(sys.stdin)
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
toenc = 'Evgeny Stepanischev'
input = sys.stdin.read()
def decode(input):
return ''.join(chr(31+len(list(x[1])))
for x in groupby(input, lambda x: x == u"\u200b") if x[0])
def encode(input):
if len(input) < len(toenc):
raise ValueError()
return ''.join(x[0] + x[1]
for x in izip_longest((u"\u200b" * (ord(x)-31)
for x in toenc), input, fillvalue=''))
print(encode(input) if input.find(u"\u200b") == -1 else decode(input))Если на вход ему подать текст без пробелов нулевой длины, он добавит в него скрытый текст, иначе попытается его оттуда извлечь.
В принципе, этот подход можно применять в вебе для маркировки своих текстов — браузеры, кроме вымирающих, нормально относятся к этому символу и отображают его адекватно.
Конечно, важна длина текста — таким способом не скрыть текст, длина которого много больше исходной, но способ можно и улучшить в этом смысле. Например, в качестве прерывающего символа выбрать
Комментарии 14
Скорейшего выздоровления!
Кстати, если бы был
В два ночи с температурой я ещё и не такое напишу.
Да, я вчера поленился уже об этом писать.
Да, но мне сильно лениво было в два ночи это программировать :) Я вообще о кодах Хаффмана подумал сначала.
Не «много больше», а просто «больше», нет? Ну или «больше или равно», если запретить нулевые пробелы в конце строки.
Зато и длина текста, который можно будет закодировать, уменьшится.
Да, была два ночи и я болею, к чёрту такие подробности :)
Вот
Это не питоновский стиль кодирования, а функциональщина. Можно записать иначе, более похоже на Яву и ПХП.