Хотите зашифровать вообще любое TCP соединение? Теперь у вас есть NoiseSocket



    Привет, %username%!

    Не всё в этом мире крутится вокруг браузеров и бывают ситуации, когда TLS избыточен или вообще неприменим. Далеко не всегда есть необходимость в сертификатах, очень часто хватает обычных публичных ключей, взять тот же SSH.

    А еще есть IoT, где впихивать TLS целиком это вообще задача не для слабонервных. И бэкенд, который, я почти уверен, у всех после балансера общается друг с другом по обычному HTTP. И P2P и еще и еще и еще…

    Не так давно в сети появилась спецификация Noise Protocol Framework. Это по сути конструктор протоколов безопасной передачи данных, который простым языком описывает стадию хэндшейка и то, что происходит после неё. Автор — Trevor Perrin, ведущий разработчик мессенджера Signal, а сам Noise используется в WhatsApp. Так что, был отличный повод рассмотреть этот протокольный фреймворк поближе.

    Он так понравился нам своей простотой и лаконичностью, что мы решили на его основе запилить аж целый новый протокол сетевого уровня, который не уступает TLS в безопасности, а в чём-то даже превосходит. Мы презентовали его на DEF CON 25, где он был очень тепло принят. Пора поговорить о нём и у нас.

    Сначала немного о непосредственно ядре NoiseSocket, а именно

    Noise Protocol Framework


    По сути, любой из описанных Noise Framework протоколов представляет собой последовательность из передаваемых публичных ключей и производимых над ними операций Diffie-Hellman.

    Главная идея Noise Protocol Framework в том, что абсолютно все действия во время хэндшейка влияют на состояние протокола, а следовательно и на итоговые сессионные ключи. Все DH, все дополнительные данные, которые передаются или учитываются во время рукопожатия, подмешиваются к общему состоянию с помощью хеширования и формируют в итоге общие симметричные ключи.

    Всё это происходит внутри нехитрой системы состояний, которая состоит из трёх частей.



    Есть, кстати видео, на английском, где David Wong довольно доступно рассказывает, как там чего работает.



    HandshakeState отвечает за процессинг токенов и сообщений.

    SymmetricState формирует симметричные ключи из результатов DH и обновляет их с каждым новым DH. Таким образом сразу же после самого первого DH данные, которые идут после него (статические ключи, полезная нагрузка), уже шифруются каким-то симметричным ключом.
    Еще SymmetricStatе хэширует в себя дополнительные данные, такие как сами ключи, опциональный пролог, имена протоколов и т.д. Всё это позволяет протоколу быть целостным и защищенным от вмешательства извне на всех этапах передачи данных.

    CipherState это просто инициализированный каким то ключом симметричный AEAD шифр + nonce (счетчик), который инкрементится с каждым вызовом функции шифрования.

    Протоколы в Noise описаны специальным языком, который состоит из паттернов, сообщений и токенов



    Рассмотрим для примера один из протоколов, Noise_XX, который позволяет установить защищенное соединение, обменявшись в процессе статическими ключами сервера и клиента:

    Noise_XX(s, rs):
    -> e
    <- e, ee, s, es
    -> s, se


    Noise_XX — это паттерн. Он описывает последовательность сообщений и их содержимое.

    (s, rs) обозначает, что клиент и сервер инициализируются своими статическими (s) ключевыми парами. Это те, что генерируются единожды. r означает remote.

    Как мы видим тут есть три строчки со стрелками. Одна строка — одно сообщение. Стрелка означает кто кому шлёт. Если направо, то клиент серверу, иначе наоборот.

    Каждая строка состоит из токенов. Это одно или двухбуквенные выражения, разделенные запятыми. Однобуквенные токены бывают лишь e и s и означают эфемерный и статический публичные ключи соответственно. Эфемерный генерируется один раз на соединение, статический многоразовый.
    Вообще в Noise все протоколы начинаются с передачи эфемерного ключа. Таким образом достигается Perfect Forward Secrecy. Примерно то же самое придумали в TLS 1.3 когда отменили все не-эфемерные ciphersuites.

    Двухбуквенные токены означают Diffie-Hellman между одним из ключей клиента и сервера. Они бывают, как несложно догадаться, четырех видов:
    ee, es, se, ss. В зависимости от того, между какими ключами делается DH, он выполняет различные функции. ee, к примеру, нужен чтобы рендомизировать итоговый ключ для транспортной сессии, а DH с участием статических ключей отвечают за взаимную аутентификацию.

    Как видно, в паттерне XX статический ключ клиента передаётся серверу, ровно, как и наоборот. Поэтому тут и используется три сообщения. Есть паттерны, которые предполагают наличие у клиента статического ключа сервера (например, когда он первый раз сделал XX) и сокращение количества сообщений до двух. К тому же, появляется возможность передавать зашифрованные данные сразу в первом сообщении, что зовётся 0-RTT и сокращает время ответа от сервера.



    К каждому handshake сообщению можно дописывать полезную нагрузку. Это могут быть настройки протокола верхнего уровня, те же сертификаты, просто цифровые подписи, в общем, всё что угодно в пределах 64к байт. Все Noise пакеты ограничены этим размером. Так упрощается парсинг, длина всегда помещается в 2 байта, проще работать с памятью.



    В результате хэндшейка у нас на руках остаётся по сути лишь два симметричных ключа, которые являются результатом всех DH, произошедших ранее. Один для отправки сообщений, второй для их приёма. Всё, после этого мы можем отправлять шифрованные пакеты, инкрементируя nonce каждый раз после отправки.

    Помимо паттерна Noise Protocol характеризуется алгоритмами, которые использует в каждом конкретном случае. В спецификации указаны алгоритмы для DH, AEAD и хеш. Большe Noise ничего не нужно.

    DH: Curve25519, Curve448,
    AEAD: AES-GCM, ChachaPoly1305,
    Hash: Blake2, SHA2

    Все примитивы очень быстрые, никаких RSA и прочего тормозного старья. Хотя, конечно, если хочется, можно сделать самому, никто не запрещает.

    NoiseSocket


    Увидели мы всю эту красоту и поняли, что это идеальный кандидат на роль транспортного протокола следующего поколения. Ведь тут сразу из коробки есть все нужные security фичи, производительность, возможность прикручивать свои механизмы аутентификации. А прогнозируемый размер кода должен позволить создавать нормальные защищенные соединения из любых, даже самых мелких девайсов. И начали думать.

    Первый PoC я написал на Go где-то в районе нового 2017 года. Почти ничего не добавлял к оригинальному Noise, только длину пакетов. Показал это ребятам, написал в Noise Mailing List и к концу июня мы наконец пришли к общему знаменателю, который можно было реализовывать на большем количестве платформ.

    Итак, что же мы в итоге добавили к Noise? После долгих разговоров и десятков вариантов остались по сути только три вещи:

    1. Negotiation data
    2. Padding
    3. Processing rules

    Negotiation data



    Это просто набор байт, в который вы можете положить всё что угодно. Он нужен для того, чтобы согласовать алгоритмы и паттерны между клиентом и сервером. В нашей версии он выглядит следующим образом:



    Всего 6 байт, но этого достаточно чтобы сервер понял как обрабатывать любые Noise сообщения, которые к нему попадают.

    Padding


    Очень рад, что он попал в итоговую спеку, иначе всем бы пришлось придумывать его самим. Это выравнивание пакетов, которое позволяет скрыть их истинный размер и предотвратить угадывание содержимого даже без расшифровки. Реализуется как дополнительные 2 байта вначале зашифрованных данных, которые указывают на настоящий размер пакета. Всё, что после — мусор, который нужно выкинуть.



    Processing rules


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

    Why?


    В Virgil есть свой PKI и нам очень не хватало возможности устанавливать защищенные соединения сразу с использованием публичных ключей, а не с помощью сертификатов и потом сверху всё еще раз валидировать. А теперь мы сделали NGINX модуль и можем весь бекенд обслуживать через NoiseSocket, добавив к нему цифровые подписи статических ключей.

    Вы наверное думаете что нужно всё менять для того, чтобы перейти на NoiseSocket? А вот нет.
    Если вы пишете на Go и у вас уже есть HTTP сервисы, то нужно лишь подменить метод DialTLS для клиентов и Listen для серверов, всё остальное будет думать, что работает по TLS. Это всё благодаря Go библиотеке, которую мы тоже реализовали.



    Конечно, предстоит еще много работы по коду и спецификации, но, черт возьми, у нас есть альтернатива TLS!

    Теперь не нужно выдумывать что-то своё когда вы хотите построить защищенный линк между двумя узлами, имея на руках лишь публичные ключи. Tor, i2p, bitcoin, где нода часто идентифицируется именно публичным ключом, могут использовать NoiseSocket сразу безо всяких добавок.

    SSH, VPN, всевозможные туннели могут добавить цифровые подписи статических ключей и получить полноценный защищенный линк с минимальным оверхедом без необходимости тащить к себе openssl, можно обойтись Libsodium или вообще Nacl.

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

    Заключение


    У меня были большие надежды на TLS 1.3, так как там и handshake roundtrips уменьшены с 8-9 до трех, как в Noise, и добавили 25519. Но

    Во-первых, решили не добавлять возможность работать без сертификатов, просто по ключам, хотя такое предложение было.
    Во-вторых, сертификаты ed25519 непонятно когда появятся, а в Noise я могу использовать подписи 25519 уже сегодня.

    К тому же, не так давно один из паттернов Noise, IK (который 0-RTT) получил формальное доказательство корректности от авторов WireGuard VPN, что лишь усилило нашу уверенность в правильности выбора.

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

    Ссылки


    Спецификация Noise Socket
    Github
    Спецификация Noise Protocol Framework
    Virgil Security, Inc.
    Мы превращаем программистов в криптографов.
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 67

      –5
      прикрутили Diffie-Hellman алгоритм к tcp — впрочем нового ноль, раньше это называлось pgp и вместо tcp была электронная почта.
        –2

        Я смотрю, в последние годы стало можно совать Curve25519 во всё подряд не разбираясь.

          +1
          Поясните, если не затруднит, в чём именно мы не разобрались?
            –4

            Моё личное мнение таково, что Curve25519 это абсолютно дилетантская крипта, придуманная исключительно скорости ради. И вся статья о Curve25519 тому яркое подтверждение.

              +8
              Не знаю о какой из сотен статей о curve25519 вы говорите, но на сегодня это по сути стандарт, который включен в том числе в TLS ciphersuites. Предлагаю пройти в CFRG Mailing list и предупредить всех о том, что они включили в стандарт дилетантскую крипту.
                –2

                Я говорю о самой первой статье: Curve25519: new Diffie-Hellman speed records (https://cr.yp.to/ecdh/curve25519-20060209.pdf)
                И не знаю, о каких сотнях статей вы говорите, я их вижу здесь только шесть:
                https://cr.yp.to/ecdh.html#papers


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

                  +2
                  Это не «какая-то еще одна кривая», а вполне себе обычная кривая монтгомери, у которой порядок — простое число 2255 — 19. Одного этого факта достаточно, чтобы утверждать о её безопасности. Есть конечно слабые кривые, но их довольно просто вычислить. Вот еще доп информация на этот счет
                    0
                    Одобряю то, что вы делаете, и тоже давно слежу за проектами Noise и Wireguard. Но все же не могу не заметить, что в криптографии с заявлениями типа «Одного этого факта достаточно, чтобы утверждать о её безопасности» нужно быть крайне осторожным.
                      0
                      Справедливо. Но тут так же работает презумция невиновности. По ссылке есть критерии слабых кривых, 25519 под них очевидно не подходит. Если есть какие то другие критерии, то они ударят не только по ней, но скорее и по всем остальным
                        +1
                        Простите, вклинюсь, просто зацепился взглядом за это:
                        Но тут так же работает презумция невиновности
                        Но это не так. Наоборот, в криптографии работает презумция виновности, в которой «все опасно, что не доказательно безопасно теоретически или хоть практически»
                          0
                          Кроме одноразового блокнота ни один из алгоритмов не имеет 100% доказательства стойкости, по сути мы все верим криптографам на слово. Я это имел в виду
                            0
                            Имеют, не обязательно же иметь абсолютную стойкость. Достаточно гарантированной, с доказательством «что, да как и почему»
          0
          ОК, это интересно, но вы говорите про IoT — а есть реализация на С/С++ для эмбеда?
            +2
            Библиотека в процессе разработки, я поэтому и привел приблизительные цифры, собранные по разным имплементациям примитивов. А под какую архитектуру интересно?
              0
              AVR/ESP8266/ARM
                +2
                Да, это то над чем мы работаем. Как только появятся результаты мы опубликуем или тут или на гитхабе
              0
              В IoT проблема скорее не в секурной передаче, а в удостоверении, что передатчик именно тот, кто имеет на это право (контроллер или датчик). Шифрование передачи здесь не поможет.
                +1
                Если датчик передаёт что-то полезное для потенциального взломщика, то лучше данные зашифровать. Тот же датчик присутствия, например
                  0
                  Смотря что передавать. Да и тот же указанный в статье AES-GCM — режим шифрования с аутентификацией. Два в одном.
                    0

                    На сколько я понимаю, применять дополнительное шифрование для IoT не нужно. Оно только будет увеличивать энергопотребление и снижать время работы до замены элемента питания. В табличках вот здесь есть строка шифрование.

                      0
                      Есть-то оно есть, но во-первых там, условно, «AES», я ничего не нашел про нормальную ассиметричную криптографию. Во-вторых на беспроводным IoT мир не заканчивается, есть еще PLC и там тоже нужна защита
                  +2
                  Огромное спасибо что привлекаете внимание к Noise framework-у! Среди всех протоколов которые стремятся к стандартизации, на мой взгляд, Noise наиболее продуман и прост. Подписан на их рассылку почти с самого зарождения и очень нравится их подходы: серьёзны, консервативны, вдумчивы. Самое главное: его стараются делать максимально простым и разумно гибким, без 100500 опций и возможностей. Если бы кто-то спрашивал какой ему протокол выбрать для задачи где надо обеспечить защиту трафика и аутентификацию собеседников, то в 99.99% случаев одного из Noise pattern-ов им будет достаточно.
                    +1
                    мы очень хотим когда-нибудь сделать Noise стандартом и NoiseSocket — первый шаг
                    0
                    xkcd://927
                    • UFO just landed and posted this here
                        0
                        RSA хоть и тормозной, но есть гипотеза что он более стойкий чем ECDSA и 25519 за счёт того что у него разрядность сильно выше, как минимум квантовые компы под него обойдутся сильно дороже.

                        Кривые на квантовых компьютерах ещё быстро ломать не умеют, в отличие от того же RSA.


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

                          0
                          Есть тут обшее правило, которое я закладываю в архитектуру.

                          Если государтво продвигает стандарт с длиной ключа ХХХ, то скорее всего, он знает как его ломать, поэтому рекомендую ключ ХХХ + NNN.

                          Поскольку можно допустить что алгоритм имеет backdoor независимо от длины ключа, то дополнительно нужно криптовать данные алгоритмом конкуририющей страны.

                          Например АЕS 512 + ГОСТ Р 34.10-2001 512 вполне покрывают большинство потребностей.

                            +1
                            Но AES 512 не существует!
                            0
                            Странно, в Википедии написано противоположное про квантовую стойкость кривых:

                            https://en.wikipedia.org/wiki/Elliptic_curve_cryptography#Quantum_computing_attacks
                          0

                          Хм… вот это бы на С/С++ и в WebAssembly для браузеров скомпилировать, как раз работаю над одной штуковиной, где всё это будет нужно, очень не хотелось бы изобретать велосипеды.

                            0

                            В целом, Noise приятный протокол. Но, увы, есть некоторые ограничения. Например:


                            All Noise messages are less than or equal to 65535 bytes in length.

                            Я понимаю доводы авторов. Но, тем не менее, для некоторых условий это ограничение слишком жестко. До неприемлемости.

                              0
                              А это на самом деле легко делается, можно о размере пакета договориться во время хэндшейка. В спеку не вошло, но никто не мешает сделать самому. Мы тоже скоро выложим «наш» вариант NoiseSocket, возможно там появится в том числе и ограничение на размер пакета
                                0
                                это на самом деле легко делается, можно о размере пакета договориться во время хэндшейка

                                Не совсем понял, что Вы имеете в виду под "это". Изменить спеку? Изменить какую-то стороннюю (или свою) опенсорсную реализацию протокола? Или что-то уже предусмотрено на уровне хэндшейка о чем Вы вскользь упомянули и что я, по-видимому, упустил?

                                  0
                                  Спецификация протокола позволяет писать друг другу любые данные во время хэндшейка внутри полезной нагрузки. Можно добавить туда максимальный размер пакета и учитывать его во время транспортной фазы.
                                    0

                                    То, что в хэндшейк можно добавить прикладную информацию — это хорошо.
                                    Но как это повлияет на жестко заданную в спеке длину мессаджей Noise? Как его парсер узнает, что мы хотим иметь длину более 65К?
                                    Я понимаю, что можно внутрь Noise инкапсулировать свой прикладной протокол и резать его на любые мессаджи по-своему. Но хотелось бы как раз обойтись, т.е. сделать так, чтобы мессадж своего протокола целиком помещался внутрь мессаджа Noise.

                                      0
                                      Вон оно что, я сразу не понял вопроса. Потому что IoTшники наборот хотят, чтобы пакет был не больше 2х кб, например.

                                      Вообще да, разбивать придется в любом случае, т.к. подразумевается что мы там и гигабайты можем слать. Это не так уж и сложно, вполне соответствует семантике ReadXXX/WriteXXX. Вот как я например сделал в go
                                      А читать из этого коннекшена и писать в него можно буферами любого размера.
                                        0
                                        Это не так уж и сложно

                                        Разумеется :) Мы сейчас TLS используем. На скоростях существенно выше 10Gbps. И тут каждое копирование память-память (что есть и в Вашем примере) стоит дорого. Хотелось бы избегать этого. Я рассматривал Noise как-то, как альтернативу TLS, но вот то ограничение и не понравилось.
                                        Понятно, что в "80%" случаев 65К будет достаточно, но вот нам тесты дают несколько другое оптимальное значение размера мессаджа в нашем приложении — 2М. Было бы неплохо, если б в протокол добавили бы, например, в тот же хэндшейк, scale поля длины мессаджа. Меня б такой "костыль" устроил бы более чем ;-)

                                          0
                                          в TLS же вообще 16кб, если мне не изменяет память. Но я вас понял, подумаем )
                                          Заходите в Noise Mailing List, там можно это дальше обсудить
                                            0
                                            Ну и раз уж на то пошло, то транспортный пакет — это всего лишь AEAD шифротекст с длиной спереди. Да, в либах этого нет, но по сути можно делать эти шифротексты хоть по гигабайту размером и спереди писать не 2, а 3 или 4 байта длины. Как вы можете видеть, NoiseSocket больше концепция, а не законченный протокол.
                                              0
                                              NoiseSocket больше концепция, а не законченный протокол.

                                              Ну, для нас больше был актуален Noise в чистом виде, т.к. у нас всё сильно C++&boost::asio зависимо. Т.е. внутри приложения нечто своё, похожее на NoiceSocket, работающее к тому же через несколько параллельных TCP-коннектов...

                                              0
                                              в TLS же вообще 16кб

                                              Угу, там есть много ещё другой боли.


                                              Заходите в Noise Mailing List, там можно это дальше обсудить

                                              Спасибо. Как только опять вернемся к вопросу замены-ускорения TLS у нас...

                                              0
                                              И тут каждое копирование память-память (что есть и в Вашем примере) стоит дорого.

                                              Я, конечно, не представляю архитектуру вашего приложения, но раз вы не любите копировать массивы (и в случае с TLS этого избегаете), то что мешает послать 32 раза по 64K, передавая каждый раз функции передачи новый указатель на нужное смещение в исходном 2М массиве?
                                                0

                                                Так оно и происходит. Но 32 вызова дороже одного.

                                  0
                                  А зачем в NoiseSocket настолько легко-определимый пролог? С таким прологом вам разработчики DPI только спасибо скажут.
                                    0
                                    не легче, чем в TLS. Можно если есть желание его обфусцировать, конечно. Спека это не регламентирует
                                      0
                                      Да я про то в общем-то и говорю, что спека Noise достаточно устойчива к DPI и даже дает рекомендации как обфусцировать публичные ключи которые всегда посылаются в открытом виде.
                                      А вот в спеке NoiseSocket четко в прологе предлагается слать некороткую специфическую ASCII строку.
                                        0
                                        Ну не Ascii, просто данные в открытом виде. Но ведь нужно как то согласовать используемые алгоритмы пока еще не было никакого обмена ключами. Можно этого и не делать, если вы заранее знаете что к вам придёт. А иначе как?
                                          0
                                          Ээээ… Мы об одном и том-же говорим? В спецификации NoiseSocket, в секции 4, прямо говорится что пролог должен начинаться с: The UTF-8 string «NoiseSocketInit1»
                                            0
                                            пролог! Это не negotiation_data, это, условно, строка, которую мы скармливаем фреймворку, чтобы состояние на обоих концах было одинаковое. Её передавать не нужно, её нужно сконкатенировать
                                              0
                                              Ясно. Спасибо за разъяснение.
                                                0
                                                обращайтесь )
                                    –1
                                    > Это выравнивание пакетов, которое позволяет скрыть их истинный размер и предотвратить угадывание содержимого даже без расшифровки.

                                    Не совсем понятно, а что мешает тому, кто перехватывает сообщения, использовать соответствующее поле в пакете и анализировать уже данные с отброшенным «мусором»?
                                      +2
                                      это поле находится внутри зашифрованных данных, без расшифровки никак. Там даже слайд про это есть )
                                      0
                                      Поправьте меня, если я неправ, но у предлагаемого решения ровно одно преимущество перед своим протоколом, завернутым в TLS: более быстрое установление соединения.
                                        0
                                        Не только. Преимуществ много, и в статье упомянуты:
                                        — не нужен сертификат
                                        — сильно проще реализация (жрет гораздо меньше памяти)
                                        — более гибкая настройка хендшейка в зависимости от ваших требований

                                        По поводу реализации, где-то лет около 15 назад затаскивали OpenSSL на один из первых сотовых телефонов. Так вот, в телефоне было что-то около 1Мб RAM, сейчас уже точно не вспомню. Одна SSL сессия «кушала» где-то порядка 150-200 Кб. Понятно что это было абсолютно неприемлемо и проект умер не родившись.
                                        Для Noise как уже говорилось достаточно несколько Кб.
                                        0

                                        Как уже упомянул Sklott несколькими комментариями выше, этот протокол очень легко обнаружить по хендшейку и отфильтровать посредством DPI. Несколько лет назад у меня возникла идея, как можно с этим бороться и сделать создание правила для DPI-фильтра невозможным на практике.


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


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


                                        Для кодирования следует разбить открытые данные на чанки по N бит, затем для каждого чанка нужно брутфорсом подобрать такой случайный блок данных фиксированного размера H, который при декодировании превратится в ожидаемый чанк открытых данных в N бит размером. Пример такой процедуры декодирования — циклически посчитать SHA256 от блока случайных данных 1000 раз, и затем вернуть младшие N бит хэша.




                                        Приведу пример декодирования готовой строки. Допустим, у нас есть следующие бинарные данные:


                                        4b 82 93 6a b5 0f 39 9b 33 18 2a 7d b4 96 c2 f8 | K..j..9.3.*}....
                                        cb 57 49 b7 67 6d f6 c2 9a e2 73 64 54 1f 92 7d | .WI.gm....sdT..}
                                        65 44 12 7e de 07 c2 85 41 15 9e 32 28 3b c5 3a | eD.~....A..2(;.:
                                        0f 16 3a d9                                     | ..:.

                                        Мы заранее знаем, что открытый текст делился на блоки по 8 бит каждый, и что мы использовали блоки "шифротекста" по 32 бита.


                                        Первый блок — 4b 82 93 6a.
                                        SHA256 от него = 486b84b02736885238a0d8ba871a78262362f1dfe7422f1d50b257ed6c99bcc3.
                                        Младшие 8 байт этого хэша в little endian = 0x48, т.е. "H" в ASCII.


                                        Следующий блок — b5 0f 39 9b.
                                        SHA256 от него = 6546ec1ccea61e68c70671b6a04d9a074c0bf024f92d72d9103e78c3641801eb.
                                        Младшие 8 байт этого хэша в little endian = 0x65, т.е. "e" в ASCII.


                                        Продолжая декодирование таким же образом, получим строку "Hello, world!".




                                        И для демонстрации, я сделал наивную PoC-реализацию описанного выше подхода на Python: https://gist.github.com/toriningen/7c56c262bff38fda40b5cb6a014b87a2

                                          0

                                          Хотя, возможно, мое замечание нерелевантно… но мне тогда жалко удалять написанное.

                                            0
                                            Вполне релевантно. Просто я думал что там совсем все плохо, но оказалось что там «слегка все плохо» :)
                                            Т.е. все равно есть немного данных поддающихся некоторому анализу и скрыть их все же хотелось бы.

                                            Но с другой стороны, не совсем понятно зачем для такого скрытия делать именно «трудозатратный» алгоритм. Мне кажется достаточно сделать так чтобы количество ложнопозитивных срабатываний было достаточно большим. А иначе теряется смысл использования в некоторых приложениях (IoT и т.п.)
                                              0
                                              Дополню. Хотя ваш алгоритм и «трудозатратный», но с другой стороны он не увеличивает количество ложнопозитивных срабатываний, а наоборот уменьшает их.

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

                                              Мне кажется чтобы увеличить количество ложноположительных срабатываний нужно наоборот использовать «нестойкие» алгоритмы которые с большей вероятностью будут выдавать нечто «осмысленное».
                                                0
                                                т.к. вероятность что что-то осмысленное получится после 1000 раундов SHA256 очень мала, а умножив это на количество блоков мы получим вообще исчезающе малую величину.

                                                Вы не совсем правы. В предложенной мной схеме речь не идет о поиске такого прообраза, после хэширования которого мы получим "осмысленный пакет" (т.е. некую фиксированную битовую последовательность) — вероятность угадать такой прообраз, учитывая, что выхлоп сильной хэш-функции можно полагать случайным, составляет 2**(-N), где N — длина искомого "смысла". 100-битный осмысленный пакет можно искать неимоверно долго, и абсолютно впустую — добывать биткоины при таком количестве свободного времени и ресурсов явно выгоднее :)


                                                Предложенную схему не стоит рассматривать как средство сокрытия информации — очевидно же, что если ваш пакет начинается с "Lorem ipsum" (88 бит), то каждый 309485009821345068724781056-й в среднем пакет должен будет "расшировываться" в "Lorem ipsum", и если наблюдаемая частота таких сообщений значительно превышает ожидаемый среднестатистический, то это "бжжж" тут явно неспроста.


                                                Суть же предложенной мной схемы как раз заключается в том, чтобы сделать слежку невозможной именно в глобальных масштабах, основываясь на, скажем, эдаком proof-of-work. Если невозможно заранее, глядя только на мусорные блоки, отличить их от настоящего мусора, то атакующей стороне в любом случае потребуется потратить энное количество ватт (времени, денег) на вычисление хэш-функции от этого мусорного блока.


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


                                                Утрируя, мы можем передавать 1 бит данных в 128 битах мусора. Уже даже с такой избыточностью невозможно составить таблицу соответствия мусорных данных истинным данным, значит, DPI-фильтру придется "играть честно", и чем сложнее будет для вычисления хэш-функция (pbkdf2? scrypt? bcrypt?), тем меньшее количество сообщений выйдет декодировать, потратив 1 кВт, и тем быстрее правительству^W атакующей стороне это надоест.


                                                Ну а процент "ложноположительных срабатываний" у этой схемы и так статистически неотличим от шума, куда уж лучше?

                                                  0
                                                  В принципе вы наверно правы. В том смысле что если мы получаем из 4-х байт «шума» 1 байт «выхода», то теоретически неважно каким алгоритмом мы это делаем. Просто интуитивно кажется, что чем «навороченней» алгоритм, тем менее вероятно случайное совпадение ;)
                                                  0

                                                  Насчет IoT — насколько вероятна угроза цензуры общения между IoT-устройствами? Если не слишком вероятна, то, возможно, подобные меры просто не стоит в них использовать?


                                                  Например, "десктопное" устройство может сначала пытаться работать с прологом, как с настоящим пакетом, и в случае некорректных входящих данных, пытаться декодировать его, как пакет с мусорными блоками. IoT-устройства могут даже не пытаться декодировать мусор и просто считать это некорректной передачей.

                                                    0
                                                    Ну тут IoT по большому счету просто в качестве примера «слабой» железяки. Да и вообще кто его знает как оно в жизни сложится.
                                              0
                                              Scratch, почитал повнимательней спеки, и вот какой у меня народился вопрос:
                                              а почему negotiation_data передается перед noise_message, да еще и в открытом виде, вместо того чтобы передаваться например как message_payload, да еще желательно только после начала шифрования.

                                              Или, как вариант, почему сначала не установить безопасный канал, например по Noise_NN, а в нем уже договориться о дальнейшем протоколе и не провести re-handshake по новому протоколу?
                                                0
                                                Мы можем не смочь прочитать первый payload, потому что там могут быть
                                                1) разные кривые, хэши и алгоритмы
                                                2) Noise_IK, у которого payload сразу зашифрован

                                                мы должны знать паттерн и алгоритмы заранее, иначе ничего не прочитается. NN конечно можно было бы сделать, но это лишний раундтрип и нагрузка на CPU.
                                                0

                                                Только собрался писать статью о том как шифровать соединение с применением DH на nodejs. А тут оказывается и велосипед изобретать не придется. Можете посоветовать проверенный пакет под nodejs?

                                                  0
                                                  Насколько мне известно, на JS Noise еще никто не сделал. Можете стать первым ) Спека самого нойза приятно читается и реализовывать её одно удовольствие. Пока поддерживается только C, Java, Go, Haskell и Rust.

                                                Only users with full accounts can post comments. Log in, please.