Pull to refresh

Comments 67

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

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

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

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

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

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


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

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

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

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

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


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

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

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

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

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

Странно, в Википедии написано противоположное про квантовую стойкость кривых:

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

Как уже упомянул 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

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

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

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

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

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

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


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


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


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


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


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

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

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


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

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

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

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

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

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