English TL;DR: A proof-of-concept covert channel where two machines (or two LLMs) exchange a message with zero payload bytes crossing the network. The sender encodes text into Morse-like pulses of CPU load; the receiver only observes a side effect — CPU counters via SSH, or simply the round-trip time of a no-op SSH command — and decodes the text. Classic timing/energy side-channel, strictly for research on your own authorized devices. Details below (in Russian).
Идея: Антон, авг–сен 2026. Реализация: DSH (макет, Python, только stdlib).
Передатчик кодирует текст в морзе-подобные импульсы нагрузки CPU (busy/idle). Приёмник не получает из data-plane ни байта полезной нагрузки — он наблюдает только побочный эффект (счётчики CPU / тайминг ответов SSH) и восстанавливает текст.
«Данные не передаются — передаётся информация»: в пакетах нет ни байта сообщения; сообщение существует только как паттерн энергии и времени на стороне передатчика.
- По Шеннону это всё равно канал связи: носитель — тайминг/энергия, а не байты. «Ноль данных» = ноль payload-байт, видимых файрволом/DPI. Информация физически едет на изменении вероятностей наблюдений приёмника.
- Канал медленный (доли бита/с — единицы бит/с) и детектируемый: варден, смотрящий на графики нагрузки или спектр таймингов, увидит аномалию.
- Никакой криптографии/аутентификации из коробки нет.
- Это классика академической безопасности (covert channels, air-gap research). Использовать только на своих или явно авторизованных устройствах.
Единица времени u задаётся обеим сторонам. Длительности в долях u:
| Символ | Уровень | Длительность |
|---|---|---|
| точка | busy | 1u |
| тире | busy | 3u |
| пауза в букве | idle | 1u |
| пауза между буквами | idle | 3u |
| пауза между словами | idle | 7u |
| START (начало) | busy | 6u |
| EOT (конец) | busy | 8u |
Самосинхронизация по длинам импульсов: общие часы не нужны, только одинаковое u.
Классификация с допусками: короткий <1.9u < длинный <4.6u < EOT-зона (≥7.5u);
приёмник ищет START и парсит до EOT. Адаптивный порог между p10/p90 наблюдений,
медианный фильтр по 3 точкам против выбросов дискретизации.
morse.py— общая таблица морзе (TX и RX)encoder.py— передатчик: текст → расписание нагрузки CPU (multiprocessing-«жигатели»)decoder.py— приёмник: наблюдение → бинаризация → импульсы → морзе → текстdemo.py— сквозное демо на одной машине (сам запускает TX и RX)
| Режим | Что меряет | Где работает |
|---|---|---|
cgroup |
busy-fraction своей cgroup (/sys/fs/cgroup/cpu.stat) |
локально; иммунно к соседям по shared-хосту |
stat |
busy-fraction /proc/stat |
локально на выделенной машине |
sshstat |
удалённый /proc/stat, читаемый по SSH |
две машины, выделенная машина-ТХ |
sshcgroup |
удалённый cpu.stat контейнера-«устройства» по SSH |
две машины, ТХ — контейнер |
ssh |
только RTT no-op команды true по SSH — payload 0 байт |
две машины; самый чистый, самый медленный |
cd morse-cpu
python3 demo.py "HI ANTON" # режим cgroup
python3 demo.py "SOS 2026" --unit 0.13 # цифры тоже работаютПроверено в контейнере (28 CPU): HI, HI ANTON, SOS 2026 — декодированы
без ошибок; ~0.5 симв/с при u=0.13.
Машина A (передатчик — грузим CPU):
python3 encoder.py --msg "HELLO WORLD" --unit 1.0Машина B (приёмник — только наблюдает):
# по таймингу SSH (payload = 0 байт):
python3 decoder.py --mode ssh --host user@A --duration 120 --unit 1.2
# по счётчикам CPU машины A (надёжнее):
python3 decoder.py --mode sshstat --host user@A --duration 60 --unit 0.8Проверено в макете «две машины = ssh localhost:2222»:
sshcgroup,u=0.5: «HI ANTON» ✅ за 47 c (on 0.92 / off 0.004)ssh(чистый RTT),u=1.2: «HI» ✅ за 44 c (RTT off 13 мс → on 32 мс)
--unit— базовый такт; уменьшать, пока декодирование не начнёт сыпаться (локально стабильно до ~0.13 c при опросе 20 Гц).--cores— сколько ядер жечь (все = максимальный контраст; пара ядер = скромнее).--repeat N— повтор кадра как простой FEC (декодер берёт первое полное чтение).- Если
statтонет в чужой нагрузке shared-хоста — перейти наcgroup/sshcgroup. - В RTT-режиме (
ssh) контраст зависит от того, что передатчик жжёт все ядра:--cores all.
- Варден: аномальная нагрузка/тайминги видны; маскировка «под шум» не делалась.
- Пропускная способность: единицы бит/с. Апгрейды:
- M-ary: 4 уровня нагрузки (25/50/75/100%) = 2 бита на символ;
- FEC: повтор + голосование, коды Хэмминга поверх битов;
- другие носители: обороты вентилятора, disk I/O, ping RTT, температура;
- ФАПЧ-синхронизация вместо фиксированного
u; - сжатие/словарь и обёртка для LLM: модель формирует/читает поток, «разговаривая» нагрузкой процессора.