[О блоге]
[наверх]
[пред]
[2021-12-03 20:02:06+03:00]
[8a63bd890106f79fa53e52ba518c1a2873095eac]
Темы: [nncp]
NNCP развитие и использование людьми
https://jb55.com/log/2021-11-06-airgapped-bitcoin-node-nncp.html
https://blog.taoetc.org/how_to_publish_a_static_site_over_nncp/index.html
Чисто случайно (никакого поиска относящегося к NNCP не делал), ходя по
каким-то ссылкам, внезапно увидел что люди используют NNCP для таких
вещей как airgap BitCoin нода и в качестве транспорта для публикации в
блоги. Кто-то git фигачит поверх NNCP. Приятно что у всех без проблем
получается это собрать из tarball с использованием минималистичного
redo. И что авторы считают что NNCP легко пользоваться. Да и прям
буквально сейчас NNCP упомянут в рассылке обсуждения Gemini протокола и
тоже есть интересующиеся.
Когда я делал очередное изменение шифрованных пакетов
(9dbbfb48af71d290a67a389117411ded7ecc11a6), то подумал про себя что
забавно было бы наблюдать за прогрессом проекта и его изменений форматов
пакетов. Это же ведь и самый долгоживущий более-менее большой проект.
Например на какой-нибудь GoVPN я окончательно плюнул
(9ed0a1b3edd6548e2f9a8b8dadca4975c2bce969).
Простой пакет:
* v1: изначально состоял из:
TYPE || PATHLEN || PATH || PAYLOAD
* v2: дальше к нему добавился приоритет:
TYPE || NICE || PATHLEN || PATH || PAYLOAD
* v3: структура осталась прежней. Вместо zlib-сжатия стал использоваться
Zstandard. Сейчас вот смотрю и понимаю что можно было бы просто ввести
новый TYPE полезной нагрузки.
Типы простых пакетов:
* изначально были FILE, FREQ (file request), MAIL, TRNS (transitional)
* позже MAIL поменялся на EXEC, оставаясь обратно совместимым по
формату. NNCP стал не только почту посылать через вызов sendmail, но и
любую другу команду. Действительно, зачем надо было так себя
ограничивать? Но, видимо, потому что боялся того что было в UUCP, где
даже передача файлов превращалась в вызов "cp" команды, а хочется
эффективности и простоты
* позже узнал что люди применяются nncp-exec для посылки отнюдь не
маленьких простых файлов, а вообще всякой бинарщины. Как минимум, для
которой форсированное сжатие EXEC-пакетов будет даже вредным. Появился
EXEC-FAT тип пакетов, где просто навсего не применяется Zstandard
* ну и относительно недавно появились AREA пакеты, для multicast
рассылки FILE и EXEC(-FAT)
Sync protocol вообще не поменялся с момента создания. Пакеты имеют тип
и, зависимое от него, тело, всё фиксированного размера. Возможные типы:
HALT
PING
INFO || NICE || SIZE || HASH
FREQ || HASH || OFFSET
FILE || HASH || OFFSET || PAYLOAD
DONE || HASH
Пакеты для multicast discovery появились недавно и вообще состоят ровно
из одного (кроме магического числа) из идентификатора отправителя.
Формат еблобов (EBlob, Encrypted Blob) по сути оставался прежним, но
из-за изменения алгоритмов шифрования для зашифрованных пакетов, заодно
менял и шифрование в нём, поэтому три версии.
S || T || P || SALT || BLOB
Где S, T, P это параметры Balloon функции хэширования пароля, соль --
просто рандом, ну а BLOB это зашифрованный на выработанном ключе, кусок
данных. Команда nncp-cfgenc может использоваться для любых данных, не
только конфигов, но в NNCP штатно используется только для них.
Формат .nncp.meta пакетов, описывающих .nncp.chunk файлы, по сути тоже
не менялся, но версия один раз поменялась из-за глобальной замены хэш
функции. Всё очень тривиально:
FILESIZE || CHUNKSIZE || HASH0 || HASH1 || ...
AREA пакеты имеют своё выделенное магическое число, но формат самого
пакета идентичен зашифрованному пакету.
Наконец зашифрованные пакеты:
* v1: первая версия:
NICE || SENDER || EPUB || SIGN ||
SIZE || MAC ||
CIPHERTEXT || MAC || JUNK
SIGN = sign(NICE || RCPT || SENDER || EPUB
Использовала Twofish в режиме CTR, BLAKE2b-256-MAC для MAC.
SIZE зашифрован и для него есть отдельный MAC.
Четыре ключа (шифрование+MAC для SIZE и полезной нагрузки)
вырабатывались HKDF-Blake2b-256.
AES принципиально не хотелось. Почему сразу не выбрал Salsa20
какой-нибудь? Совершенно не могу вспомнить.
* v2: в заголовке появилось RCPT поле, явно указывающее получателя:
NICE || SENDER || RCPT || EPUB || SIGN || ...
Было ли недоработкой отсутствие RCPT прежде? Скорее да. Ничего
серьёзного бы не произошло, но неприятно видеть пакеты по какой-то
причине попавшие в spool, но мы их не можем дешифровать.
* v3: Twofish заменён ChaCha20.HKDF-BLAKE2b-256 заменён BLAKE2Xb.
Минус два криптографических примитива (ChaCha20 используется в SP
протоколе). Данные разбиваются на 128KiB блоки, шифруемые друг от
друга независимо, используя номер блока в качестве счётчика, nonce-а
для ChaCha20.
* v4: BLAKE2b-MAC-256 заменён на Poly1305 и теперь каждый 128KiB блок
аутентифицируется независимо от других. Это увеличивает суммарный
размер шифротекста, так как для каждых 128KiB добавляются 128-бит
Poly1305, но зато существенно упрощает код, и, самое главное то, блок
сначала дешифруется/аутентифицируется, а уж только потом его выход
подаётся например на вход внешней EXEC команды.
Считать ли недоработкой прежний формат? То что в EXEC подаются
неаутентифицированные данные -- ну это уже проблема вышестоящего
уровня, аналогичная "gpg -d < | cmd". А не использование Poly1305 всё
же уменьшало overhead. Мизерный, но всё равно в общем-то избыточный.
* v5: масштабная замена BLAKE2b-256 на BLAKE3 и MTH (Merkle Tree
Hashing). Содержимое самого пакета это повлияло только заменой
BLAKE2b KDF функции на BLAKE3. BLAKE2b XOF использовался для создания
padding-а -- теперь BLAKE3 XOF.
BLAKE3 на момент создания NNCP ещё не существовал. Когда появился и я
проникся скоростью его работы -- для меня это ещё не было поводом
замены BLAKE2b, реализации которого, вообще-то местами могут быть
сравнимы с BLAKE3. Да и вообще скорость настолько высокая, что не
проблема.
Но главное "изобретение" это MTH, который позволяет частями вычислять
хэш пакета. Главное для чего это делалось: не читать докачиваемый в
online режиме файл полностью от и до, а после скачивания только
прочитать его начало до момента начала докачивания. Ведь данные при
скачивании же всё равно через нас прошли -- хотелось бы сразу сделать
над ними вычисления и забыть. Ведь файлы могут быть на практике в
сотни гигабайт: обломались на скачивании первого килобайта, дальше
скачиваем оставшиеся сотни гигабайт и снова с нуля будем считывать их
с диска? С MTH это не нужно. Ну а раз это в любом случае делает формат
хэша над всем пакетом обратно несовместимым, то можно и низлежащий
алгоритм заменить (BLAKE2b на BLAKE3).
* v6: потоковый формат шифрования.
SIZE поле отсутствует, но каждый 128KiB блок может быть зашифрован
одним из двух ключей. В зависимости от ключа, определяется наличие в
начале блока метаинформации о полном размере пакета и pad-а. Теперь
временные файлы не нужны вообще, прежде использованные при получении
данных из stdin-а чтобы узнать их итоговый размер.
[оставить комментарий]