LINUX.ORG.RU

Reticulum: Сложными словами о простом

 , reticulum,


1

2

Написанное ниже — мои заметки по протоколу Reticulum. Я решил, что они могут оказаться кому-то полезными и публикую их по этой причине. Особенности работы протокола рассматриваются только с позиции клиента ввиду моих крайне скудных знаний по этой теме.

Reticulum — радиопротокол для mesh-сети, по словам автора — попытка создать альтернативный протокол базового уровня для сетей передачи данных.

К сожалению основная документация под названием «Reticulum network stack», написанная Mark Qvist  — хороший пример того, как писать документацию не нужно. По большей частью этот текст — водяной раствор крупиц информации о протоколе. Более того, даже если вы продеретесь через философские рассуждения о приватности и инновационности Reticulum, полного понимания о протоколе у вас не будет. Автор совершенно бесстыдно предлагает понимать детали через чтение исходного кода эталонной реализации Reticulum. И к сожалению, для сбора большей части информации мне пришлось прибегнуть к LLM, который этот исходный код анализировал. К слову, все попробованные мною LLM по-настоящему не знают протокол и без очень большой помощи со стороны пользователя не способны писать программы с его использованием. В определенной мере помимо отсутствия полноценной документации это связано также с тем, что у протокола было несколько версий и детали его реализации менялись.

Дополнение: после написания этих строк один добрый человек написал полноценную спецификацию протокола и выложил её на гитхаб.

Идея Reticulum в корне проста — все ее участники по своему желанию могут быть как просто конечными клиентами, так и узлами-ретрансляторами. Все передающееся в сети можно поделить на 2 вида данных — незашифрованное распространение так называемых анонсов и broadcast пакетов с информацией всем участникам сети и зашифрованная передача данных кому-то конкретному.

Анонсы - пакеты данных в виде идентификатора сети с некими структурированными данными и цифровой подписью. В структуре этого пакета данных второй байт представляет собой счетчик перемещений (hops) между ретрансляторами.

Выглядит это следующим образом: допустим мессенджер на смартфоне шлет анонс на ретранслятор с 0 hops, ретранслятор пересылает сообщение другим подключенным к нему ретрансляторам и клиентам меняя счетчик на 1. При этом ретранслятор запоминает, от кого к нему пришел анонс. Остальные по цепочке передают анонс дальше меняя счетчик и запоминая откуда пришел анонс. Таким образом анонс достигает всех участников сети, кого-то даже несколько раз, но в этом случае такой пакет обычно игнорируется, если с момента получения предыдущего пакета прошло мало времени или величина hops больше.

Важно учитывать, что если Reticulum работает через TCP соединение, то это именно одно соединение без прерываний, через которое туда и обратно шлются пакеты Reticulum в виде непрерывного потока бинарных данных без особой последовательности и организации.

Уже на этом этапе можно понять, что фоновая активность сети у всех ее участников весьма высока даже при участии в сети только в качестве конечного клиента (за минуту приходят десятки, а то и сотни одних только анонсов). При этом следует отметить, что так как анонсы передаются в незашифрованном виде, то сеть reticulum не является цензуроустойчивой. Стоит порезать незашифрованную часть протокола - и маршрутизация развалится. Понимание устройства пакета у Reticulum осложняется весьма активным использованием криптографии.

Схема пакета в байтах:
Заголовок  Hops   Адрес   Контекст Данные
[1           ]     [1       ]  [16/32 ]  [1           ]   [До 465  ]

В самом первом байте пакета каждый бит является флагом:
1) - IFAC: Если равен 1, то после hops от 1 до 64 байта выделяются для кода доступа
2) - Тип заголовка: Если равен 0, то в поле адресов указан один адрес (16 байт), если 1 - два адреса (32 байта)
3) Контекст
4) Передача: 0 - broadcast, 1 - транспортная
5) Тип пункта назначения: 00 - одиночный, 01- группа, 10 - plain, 11- link
6) Типы пакетов: 00 - данные, 01 - анонс, 10 -  запрос на связь, 11 - proof

Во второй байте подсчитывается количество 
ретрансляций, те самые hops.

Затем следует опциональный сегмент IFAC
Как именно он реализован в Reticulum я не разбирался, на публичных серверах он не используется.
 
После следуют одно или два поля с адресами. Они представляют собой первые 128 бит SHA256, о том, как именно получается эти хэши напишу ниже. В пакете таких адресов может бы один или два. В зависимости от типа пакета, поля с адресами могут использоваться для разных целей, универсального принципа работы здесь нет.
 
 Контекст - еще одно однобайтовое поле, которое иногда несет в себе дополнительный параметр, если первого байта пакета не хватило. Сценариев использования контекста много, но в моем случае крайне примитивного понимания протокола это не важно.
 
 И наконец, блок данных. У данных также предусмотрена некая определенная структура, которая очень сильно зависит от типа пакета, универсальной схемы нет.

Identity Reticulum достаточно активно использует криптографию как для формирования пакетов, так и для создания идентификатора. Перед началом использования сети необходимо произвести следующие действия: Сгенерировать закрытый ключ X25519 и на основе его открытый. Сгенерировать закрытый ключ Ed25519 и на основе его открытый. Затем 32 байтный открытый ключ X25519 объединяется с 32 байтами открытого ключа Ed25519 - получаем составной открытый ключ длиной в 64 байта. Одним из компонентов для получения уникального идентификатора в сети служит хэш sha256 из составного открытого ключа, точнее, первые 128 бит от этого хэша. Эти 128 бит будут примешиваться к другим хэшам, чтобы получать адреса. Но об этом позже.

Фреймирование пакетов производится в основном с помощью HDLC. Фреймирование через байт 7E. Этот байт стоит в начале и конце пакета, а если он встречается в самих передаваемых данных, то он заменяется на 2 байта: 7D 5E. А если в данных встречается 7D, то он заменяется на 7D 5D. Соответственно, для приема данных преобразовывать байты нужно в обратном порядке.

С чего начинается работа в сети? С отправки анонса чтобы 1) Узлы маршрутизации знали, какими путями слать нам пакеты 2) желающие отправить нам пакет знали наш публичный ключ шифрования.

Анонсы

Итак, мы решили послать анонс на публичный сервер. Перед отправкой нам потребуется идентификатор приложения, для которого будет отослан пакет. В Reticulum нет классической схемы «адрес устройства + порт». Вместо этого у каждого приложения на конкретном устройстве есть свой отдельный адрес в виде хэша.

Как это работает? Mark Qvist предлагает следующую схему. Нам потребуется имя приложения (допустим, mysuperapp). И некие «аспекты», которые расширяют его. Допустим, это v0005 и phone (пусть это будут версия приложения и указание на вид устройства, на котором оно запущено). Соединяем их через точку в «mysuperapp.v0005.phone», в единую строку. Берем первые 10 байт хэша sha256 от этой строки. И вот у нас получается так называемый хэш имени приложения. Эти самые 10 байт позволяют любому в сети, знающем о программе mysuperapp и его возможных «аспектах» понять, что пакет с таким идентификатором внутри предназначен для такой-то программы mysuperapp, а для незнающих это просто набор непонятных 10 байт. Теперь мы соединяем эти 10 байт с 16 байтами sha256 от публичных ключей, о которых писалось выше и берем от этих 26 байт еще один sha256, причем только первые 16 байт от него. Получаем адрес, по которому можно слать пакеты. Немного сложно. Однако, все указанное выше можно проделать даже и не владея никакими языками программирования с помощью разных криптографических утилит. Таким образом, у нашего устройства может быть столько же адресов, сколько на нем запущено приложений.

Анонс состоит из следующих частей:
1 Байт: 00010001 (возможны вариации по схеме выше)
2 байт: 00000000 (потому что мы посылаем анонс от себя и он прошел 0 ретрансляторов)
С 3 по 18 байт - адрес,который получили в предыдущем абзаце
19 байт - 00000000 (байт контекста)
Затем 64 байта нашего объединенного публичного ключа.
Потом 10 байт хэша от названия приложения
Затем блок из 10 байт, из которых первые 5 байт случайные, а другие 5 байт - текущего UnixTime с конца в формате BigEndian (служит временной меткой).
Затем n количество байт, для так называемого Ratchet - механизма динамической смены ключей шифрования при пересылке нескольких пакетов, в котором я разбираться буду в одну из последних очередей. Его использование активируется байтом контекста. При байте контекста 0 никаких данных у Ratchet нет, никаких байтов в пакете соответственно тоже.
Затем 64 байта подписи с помощью Ed25519 (о том, что конкретно подписывается, напишу немного ниже).
И, наконец, следует набор произвольных данных, можно написать сюда что угодно. Главное, чтобы размер пакета не превысил 500 байт.
Подписью подписывается: адрес+составной открытый ключ+хэш имени приложения+случайные 10 байт(которые были ранее в этом анонсе)+данные Ratchet (только при условии его использования)+произвольные данные в конце пакета.
Если вы где-то ошибетесь - пакет будет молча проигнорирован.
При успешном принятии пакета, ВОЗМОЖНО, следующий в цепочке пришлет пакет типа proof. А может быть и не пришлет - зависит от настроек. Этот ответный пакет редкость и не следует при создании приложений на него полагаться.
Следует добавить, что анонс распространяется по сети не в том виде, в котором мы отправляем его туда.
Получатель получит от ретранслятора пакет, преобразованный из одно- в двухадресный.
Первый адрес - ретранслятора, а второй - тот, что был указан в изначальном анонсе.

Отправка пакетов с информацией Существует 4 типа пакетов с информацией: Single — один пакет одному адресату Group — один пакет множеству адресатов Link — множество пакетов одному адресату с динамически меняющимися ключами шифрования. Инициализация такого соединения осуществляется в несколько этапов с использованием специальных пакетов. Broadcast — один незашифрованный пакет всем в сети. Однако, пакет не ретранслируется, то есть передать его кому-то вне прямого соединения нельзя.

Рассмотрим только отправку Single-пакетов, так как Link сильно мудреный, а все остальное применимо лишь в очень специфических случаях.

В первую очередь мы генерируем эфемерный ключ x25519. По протоколу Диффи-Хеллмана из нашего приватного x25519 ключа и публичного x25519 адресата получаем общий секретный ключ.  Применяем к этому общему ключу HMAC Key Derivation Function с SHA256. Параметр info должен быть пуст. Длина хэша - 64 байта.  Соль -- хэш-адрес получателя. Берем первые 32 байта для шифрования методом AES-256-CBC, для IV генерируем случайные 16 байт. Применяем к шифруемым данным PKCS7 паддинг и шифруем их.
Теперь подготавливаем hmac подпись.
Алгоритм sha256, в качестве ключа для подписи берем оставшиеся 32 байта хэша HKDF, подписываем IV+шифрованные данные. 
Теперь собираем пакет: 
1 байт -- заголовок типа Data  и Destination type Single
2 байт -- 00000000
Затем 16 байт хэш-адреса
Затем наш публичный эфемерный ключ x25519 (32 байта)
После следуют 16 байт IV.
Затем шифрованные данные
В конце -  HMAC подпись.
Все не более 500 байт.

Принимающая сторона получает пакет в том виде, в котором он был отправлен кроме измененного счетчика ретрансляций. Методом Диффи-Хелмана из нашего публичного эфемерного ключа и своего приватного x25519 получается общий секретный ключ.
Он используется с HKDF с указанными ранее параметрами. 
Затем используя 32 последних байта из полученных 64 проверяется подпись.
И, если все нормально, можно дешифровывать, используя первые 32 байта хэша HKDF, полученный IV и не забыть убрать PKCS7 паддинг.
А как понять, кто прислал пакет, спросите вы? Никак, они анонимные. Как ни странно, единственный, кто знает кто и кому шлет пакеты — первый ретранслятор в цепочке, который должен заслуживать доверия.

А как же узнать, что пакет дошел до цели? При желании получатель может прислать (а может и не прислать) пакет типа proof, который содержит в себе хэш принятого пакета и подпись. Ретрансляторы, теоретически, пересылают такой пакет обратно по цепочке до приславшего, ориентируясь на указанный хэш пакета. То есть какое-то непродолжительное время ретрансляторы хранят хэши всех пересланных пакетов типа data и откуда они пришли. Мои эксперементы с пересылкой этого пакета оканчивались неудачей, так что я ничего о нем рассказать не могу. Буду рад, если кто-нибудь укажет на ошибки или оставит свои мысли о протоколе в комментариях.

★★★★★

Проверено: hobbit ()
Последнее исправление: Leupold_cat (всего исправлений: 10)
Ответ на: комментарий от BruteForce

Меш-сеть, хорошо подходящая для передачи небольших объемов данных при использовании медленных каналов передачи. Плохо подходит для быстрой передачи данных и в больших количествах, т.к. пакеты идут с большими задержками и не всегда прямыми маршрутами. Показал себя лучше, чем internet protocol в области коммуникации с использованием радио-сигналов, особенно активно рекламируется его использование с применением LORA. Полностью самостоятельный протокол, не требующий для функционирования internet protocol - в теории можно передевать данные даже через телеграф.

Адрес в сети не привязан к конкретному устройству или локации, а определяется набором из 2 ключей для шифрования. Можно подключиться к сети из Москвы, затем из Вашингтона - и адрес не изменится. Можно передать ключи шифрования на другое устройство - и адрес тоже будет передан.

Leupold_cat ★★★★★
() автор топика
Последнее исправление: Leupold_cat (всего исправлений: 1)

Просьба модераторов удалить статью, так как пару дней назад назад добрый человек написал полноценную спецификацию протокола в github. В моих записях больше нет смысла.

Leupold_cat ★★★★★
() автор топика
Ответ на: комментарий от Leupold_cat

В моих записях больше нет смысла.

Есть.

dataman ★★★★★
()

Автор совершенно бесстыдно предлагает понимать детали через чтение исходного кода эталонной реализации Reticulum.

Ну к слову, довольно часто бывает, что это самое адекватное (если не единственно адекватное) описание чего-либо.

hobbit ★★★★★
()

Этот Reticulum плохо масштабируется на большое кол-во узлов. А так-то да, адекватный сетевой протокол должен изначально обеспечивать приватные соединения между узлами, адреса должны быть мобильными, т.е. не меняться при подключении к сети из разных точек, и всё это как-то должно быть масштабируемым, и не зависеть ни от каких централизованных регистров. А TCP/IP стэк - мусор изначально, только вся инфраструктура в нём настолько погрязла, что теперь заменить чем-то более адекватным дорого, поэтому все проблемы решаются костылями.

yvv1
()
Последнее исправление: yvv1 (всего исправлений: 3)
Ответ на: комментарий от yvv1

Согласен с вами относительно масштабируемости. Каждое устройство (на самом деле каждое приложение, так что ситация еще сложнее) периодически шлет во всю сеть пакеты о своем присутствии. Пока устройств несколько десятков - это терпимо. Когда это глобальный Reticulum, количество пакетов становится огромным. Я подключаюсь к сети пообщаться с другом в чате и почитать новости, а по итогу каждое приложение на каждом устройстве присылает мне по пакету, что оно в сети. И в итоге большая часть моего трафика - бесполезно для меня как конечного клиента.

Leupold_cat ★★★★★
() автор топика
Последнее исправление: Leupold_cat (всего исправлений: 1)

так и узлами-ретрансляторами

Посодют.

thunar ★★★★★
()

радиопротокол

Ретикулум и по IP-сетям спокойно работает, не только по радио.

alexei-i
()
Ответ на: комментарий от hobbit

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

VIT ★★
()
Ответ на: комментарий от VIT

Поэтому управлению компании следует очень хорошо подумать

Если уж совсем к слову, то управлениям компаниями совершенно фиолетово, что там документацией на код еще с прошлого тысячелетия, если код не на публику. Выше группы разработки это не поднимется - менеджер первого уровня никогда не поднимет этот вопрос на уровень выше.

r--r--r--
()
Ответ на: комментарий от r--r--r--

По разному бывает, особенно в тех компаниях, которые в последнее время стали на слуху. Там CEO не чурается пару строчек кода чиркануть прямо перед отправкой изделия на полигон для тестового запуска. Я не конкретно про Илона, а про характерный для таких, как он стиль управления с вниканием в детали. Да и Стив такой был, не зря он аппле два раза из дерьма вытаскивал. Так что по разному бывает.

VIT ★★
()
Ответ на: комментарий от VIT

Ты так прямо говоришь, как будто управлении компанией это такой рыцарь Света, который всегда всё документирует, а вредный разработчик только и думает, как бы бомбу под несчастного рыцаря заложить.

На самом деле управление может и вообще на документацию положить, и её положить под сукно, предложив жрать что дают. Бывает, разумеется, и наоборот. (Кстати, как там у Телеграма того же – протокол где-то отдельно документирован, или единственное его описание это исходники десктопного клиента? Я не в курсе, если что.)

В данном же случае имеем разработчика-энтузиаста, который создал открытый протокол. Компания есть, но это его собственная компания, которая зарабатывает деньги на разработке и продаже оборудования для радиосвязи (модули RNode, модемы MicroModem и OpenModem, пруф на Хабре). Другой энтузиаст по его наработкам сделал спецификацию и выложил на гитхаб.

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

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от Leupold_cat

Удалять я и ещё трое отметившихся смысла не видим, лишний пиар, да ещё и на русском языке не помешает. Ссылку на гитхаб в статью добавил.

hobbit ★★★★★
()
Ответ на: комментарий от hobbit

А такие вот комментарии про вредных разработчиков и бомбы замедленного действия демотивируют людей вобще что-либо выкладывать

Такие комментарии предназначены выразить совсем другую мысль. Странно, что вы этого так и не понимаете.

VIT ★★
()
Ответ на: комментарий от hobbit

Дополню: а бывает и так, что руководство прямо рекомендует разработчику не выделываться и не тратить силы на руководство программиста (с описанием как раз API и протоколов), был свидетелем.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 1)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.