Skip to main content

Прячем секретное сообщение в аудио файле

Этот пост будет лишним доказательством того, что файлы типа 96kHz/24bps не несут в себе никакой дополнительной информации по сравнению с обычными (44.1kHz/16bps).

Мы возьмём файл с частотой дискретизации 96kHz и на фоне шума запишем в него секретное сообщение (которое, правда, сможет прослушать любой с соответствующей программой, так что никакого "реального" шифрования тут не происходит).

Работать это будет по принципу амплитудной модуляции, AM. Судя по википедии, видов амплитудной модуляции три — "обычная", double-sideband suppressed-carrier и single-sideband suppressed-carrier. О том, что это такое, подробно ниже.

Предположим, у нас есть входной сигнал — синусоида с частотой колебания $\omega_{s}$. Мы хотим замодулировать её с частотой $\omega_{c} > \omega_{s}$. Делаем это так:
$f(t) = (1 + \sin \omega_{s}t) \sin \omega_{c}t$

Вот график нашего замодулированного сигнала:
Синусоида $\sin t$, смодулированная с несущим сигналом $\sin 10 t$.

Перемножим синусы в смодулированном сигнале:
$f(t) = \sin (\omega_{c} t) + 1/2 (\cos (\omega_{c} - \omega_{s})t - \cos (\omega_{c} + \omega_{s})t)$

Видим, что тут есть колебания на трех частотах — одно на несущей и два на несущей плюс-минус частота сигнала. Это "классическая" амплитудная модуляция, такой сигнал легко демодулировать обратно с помощью так называемого детектора огибающей (envelope detector). Смысл работы этого детектора — нахождение огибающей сигнала, т.е. зеленой линии на картинке снизу. Эта огибающая — и есть наш сигнал плюс некое постоянное значение.


 Этот детектор можно построить на обычном диоде и конденсаторе. В каком-то номере журнала "Радио" даже была статья, как сделать радио из куска проволоки, диода, конденсатора и высокоомного наушника. Такому радио не нужно дополнительное питание, он использует как раз мощность волны-носителя.

Более сложная схема для реализации в железе, но простая для нас — DSB-SC (double-sideband suppressed-carrier). В ней колебания на частоте волны-носителя приглушены или убраны из смодулированного сигнала, т.е. модулируется он так:
$f(t) = \sin \omega_{s}t \sin \omega_{c}t = 1/2 (\cos (\omega_{c} - \omega_{s})t - \cos (\omega_{c} + \omega_{s})t)$

Для демодуляции этого сигнала воссоздаются колебания с несущей частотой и умножаются на смодулированный сигнал:
$f(t) = 1/2 (\cos (\omega_{c} - \omega_{s})t - \cos (\omega_{c} + \omega_{s})t) \sin \omega_{c} t = -1/2 \sin \omega_{s} t + 1/4 (\sin (2\omega_{c} - \omega_{s})t - \sin (2\omega_{c} + \omega_{s})t)$

Мы видим, что таким образом у нас есть наш исходный сигнал (с множителем $-1/2$) и сигналы с высокими частотами (около $2\omega_{c}$), которые мы можем просто отфильтровать.

Теперь к изначальной теме встраивания сообщения в аудио файл. Допустим, что самый высокий тон человеческой речи не превышает 5 кГц, и смодулируем сообщение с частотой 30 кГц по схеме DSB-SC. Тогда замодулированный сигнал будет лежать в диапазоне частот 25-35 кГц. Нижний предел находится выше предела восприятия человека, а верхний предел меньше половинного значения частота дискретизации (48 кГц). Таким образом, файл с частотой дискретизации 96 кГц может хранить одновременно и аудио, и некий секретный голосовой сигнал.

Вот реализация идеи на SuperCollider:
// Подготовка записи
s.recChannels = 2
s.recHeaderFormat = "WAV"
s.recSampleFormat = "int16"

// Модуляция. Записываем 10 секунд секретного сообщения на фоне обычного шума
(
{
 var noise = LPF.ar (WhiteNoise.ar (0.8)),
     // Модулируем сигнал с микрофона с частотой 30 кГц
     signal = SinOsc.ar (30000, mul: 0.2) * SoundIn.ar ([0,1]);
 noise + signal; // Складываем полезный сигнал и шум
}.play;
s.record ("~/test2/hiddenmessage.wav".standardizePath);
SystemClock.sched (10.0, {s.stopRecording; s.freeAll; nil}) // Запишем 10 секунд сообщения
)

// Демодуляция
(
var buf = Buffer.read (s, "~/test2/hiddenmessage.wav".standardizePath);
{
 10 * BLowPass4.ar (SinOsc.ar (30000) *
 BHiPass4.ar (PlayBuf.ar (2, buf, doneAction: 2), 25000), 5000)
}.play
) 

Вот пример файла, закодированного таким образом:
Секретное сообщение

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

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

Comments

Popular posts from this blog

Гладкая сшивка кусочно-постоянной функции.

Накануне мне понадобилось найти гладкую функцию, определенную на $\textbf{R}[a,c]$, равную единице на одном отрезке числовой оси, скажем, $[a, b-\epsilon]$ и нулю на другом, скажем $[b+\epsilon, c]$. Для того, чтобы гладко склеить эти два кусочка, я решил найти монотонно убывающий многочлен $f(x)$, равный $f(0) = 1$ и $f(1) = 0$, а потом "вставить" его в отрезок $[b-\epsilon, b+\epsilon]$. Для гладкости сшивки должны выполняться условия $f'(0) = f'(1) = 0$. Я решил пойти далее и положить $f^{(n)}(0) = f^{(n)}(1) = 0$ для всех $n = 1,2,\cdots,N$. То есть первые N производных должны быть равны нулю в т. $x = 0$ и $x = 1$. Понятно, что это легко сделать при наперед известном N, но как найти общую формулу? Я некоторое время промучился над этой задачей, пока не решил её следующим способом. Пусть искомая функция $f(x) = 1 + x^{N+1}L_{1}(x)$, где $L_{1}(x)$ — некий многочлен. Тогда у нас выполняется условие $f(0) = 1$ и $f^{(n)}(0) = 0$ (так как первая производная будет...

На что влияет размер (глубина) семпла?

В этом посте я разберу ещё одну характеристику представления аудио на компьютере — размер или глубину семпла. В теореме Шеннона, с которой мы ознакомились в первом посте, сказано, что семплы нужно брать с определенной частотой, чтобы восстановить исходный сигнал. Однако, в ней ничего не сказано о том, сколько памяти компьютера нужно выделить на один семпл. По сути  ней семплы — это обычные вещественные числа. В компьютере же семплы чаще всего представляются целыми числами в диапазоне от $-2^{n-1}$ до $2^{n-1}-1$ (целые числа со знаком), где $n$ — количество бит на один семпл (bps, bits per sample). С количеством бит на семпл связана другая величина — динамический диапазон (или отношение сигнал-шум, что в данном случае то же самое). Он измеряется в децибелах определяется так: $DR = 20 \lg (2^{n}) \approx 6 n$ Динамический диапазон показывает логарифм отношения самого сильного сигнала к самому слабому. Теперь, что будет, если мы выберем $n$ маленьким? Если взять синусоидальную ...

Частичное решение задачи в Sanitarium

В предыдущем посте я рассмотрел задачу из игры Sanitarium, связанную с открытием зацепов, удерживающих камень. Я пришел к выводу, что задача частично сводится к нахождению многочленов $p(x)$, имеющих обратный по отношению к операции умножения, т.е. $p(x)q(x)=1$ на кольце $F_{2}[x]/(x^8+1)$. Был получен результат, что не каждый многочлен имеет обратный, так как генерирующий многочлен факторкольца разлагается на множители: $(x^8+1) = (x+1)^8$. Логично искать обратимые многочлены среди относительно простых по отношению к $x^8+1$, т.е. тех, которые не делятся на $x+1$. Проверим несколько многочленов: $1$ — крестовина из одного элемента, тривиальное решение. $x$ — аналогично. $x+1$ — делится на $x+1$. $x^2$ — опять крестовина из одного элемента. $x^2+1$ — делится на $x+1$. $x^2+x+1$ — не тривиальное решение и не делится на $x+1$ — наш клиент! Написав на своем любимом лиспике простую программку, я подобрал обратный многочлен $q(x) = x^7 + x^5 + x^4 + x^2 + x$. Как это работает? Н...