Стеганография и пробел нулевой длины
Болею, не спится мне. Вспомнил старую свою идею.
В Юникоде есть такой символ замечательный — пробел нулевой длины (код 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))
Если на вход ему подать текст без пробелов нулевой длины, он добавит в него скрытый текст, иначе попытается его оттуда извлечь.
В принципе, этот подход можно применять в вебе для маркировки своих текстов — браузеры, кроме вымирающих, нормально относятся к этому символу и отображают его адекватно.
Конечно, важна длина текста — таким способом не скрыть текст, длина которого много больше исходной, но способ можно и улучшить в этом смысле. Например, в качестве прерывающего символа выбрать что-то другое, что не выводится на экран как символ. Например, управляющий символ смены направления текста или что-то в этом роде.
Ничего себе! Не знал о таком символе. Интересно. Спасибо. :)
Скорейшего выздоровления!
Стеганография, а не стенография.
Кстати, если бы был какой-нибудь еще символ с тем же самым смыслом, то количество лишних байтов можно было бы сильно сократить, а то 120 × (2-3) байтов на один символ — это как-то чересчур.
Комментарий для Евгений Геращенко:
В два ночи с температурой я ещё и не такое напишу.
Комментарий для Евгений Геращенко:
Да, я вчера поленился уже об этом писать.
А поисковые системы индексировать такую страницу как будут? С их точки зрения в примере будет три слова Б, О, ЛК ?
Комментарий для lapinmax@yandex.ru:
Это надо спросить у поисковых машин. Например, эксперимент провести.
Можно использовать азбуку Морзе, тогда кол-во дополнительных символов в тексте резко уменьшится. Например, видимые символы — это тире, а невидимые пробелы — точки.
Комментарий для unno.me:
Да, но мне сильно лениво было в два ночи это программировать :) Я вообще о кодах Хаффмана подумал сначала.
а urlencode() как этот символ воспримет?
Комментарий для vtd:
Закодирует, как ещё. Или в чём вопрос?
Не «много больше», а просто «больше», нет? Ну или «больше или равно», если запретить нулевые пробелы в конце строки.
Зато и длина текста, который можно будет закодировать, уменьшится.
Комментарий для fulc.ru:
Да, была два ночи и я болею, к чёрту такие подробности :)
return ’’.join(chr(31+len(list(x[1]))) for x in groupby(input, lambda x: x == u«\u200b») if x[0])
Вот все-же этот Питонский стиль кодированя, от конца к началу, он для меня совершенно не натурален. Наверно все-же мозги слишком заражены Явой и PHP.
Комментарий для Agonych:
Это не питоновский стиль кодирования, а функциональщина. Можно записать иначе, более похоже на Яву и ПХП.