Comments 67
Я смотрю, в последние годы стало можно совать Curve25519 во всё подряд не разбираясь.
Моё личное мнение таково, что Curve25519 это абсолютно дилетантская крипта, придуманная исключительно скорости ради. И вся статья о Curve25519 тому яркое подтверждение.
Я говорю о самой первой статье: Curve25519: new Diffie-Hellman speed records (https://cr.yp.to/ecdh/curve25519-20060209.pdf)
И не знаю, о каких сотнях статей вы говорите, я их вижу здесь только шесть:
https://cr.yp.to/ecdh.html#papers
Аргумент в стиле "тысячи мух не могут ошибаться" не принимается. Покажите хоть одну нормальную статью про исследование безопасности этой кривой.
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.
Я понимаю доводы авторов. Но, тем не менее, для некоторых условий это ограничение слишком жестко. До неприемлемости.
это на самом деле легко делается, можно о размере пакета договориться во время хэндшейка
Не совсем понял, что Вы имеете в виду под "это". Изменить спеку? Изменить какую-то стороннюю (или свою) опенсорсную реализацию протокола? Или что-то уже предусмотрено на уровне хэндшейка о чем Вы вскользь упомянули и что я, по-видимому, упустил?
То, что в хэндшейк можно добавить прикладную информацию — это хорошо.
Но как это повлияет на жестко заданную в спеке длину мессаджей Noise? Как его парсер узнает, что мы хотим иметь длину более 65К?
Я понимаю, что можно внутрь Noise инкапсулировать свой прикладной протокол и резать его на любые мессаджи по-своему. Но хотелось бы как раз обойтись, т.е. сделать так, чтобы мессадж своего протокола целиком помещался внутрь мессаджа Noise.
Вообще да, разбивать придется в любом случае, т.к. подразумевается что мы там и гигабайты можем слать. Это не так уж и сложно, вполне соответствует семантике ReadXXX/WriteXXX. Вот как я например сделал в go
А читать из этого коннекшена и писать в него можно буферами любого размера.
Это не так уж и сложно
Разумеется :) Мы сейчас TLS используем. На скоростях существенно выше 10Gbps. И тут каждое копирование память-память (что есть и в Вашем примере) стоит дорого. Хотелось бы избегать этого. Я рассматривал Noise как-то, как альтернативу TLS, но вот то ограничение и не понравилось.
Понятно, что в "80%" случаев 65К будет достаточно, но вот нам тесты дают несколько другое оптимальное значение размера мессаджа в нашем приложении — 2М. Было бы неплохо, если б в протокол добавили бы, например, в тот же хэндшейк, scale поля длины мессаджа. Меня б такой "костыль" устроил бы более чем ;-)
Заходите в Noise Mailing List, там можно это дальше обсудить
в TLS же вообще 16кб
Угу, там есть много ещё другой боли.
Заходите в Noise Mailing List, там можно это дальше обсудить
Спасибо. Как только опять вернемся к вопросу замены-ускорения TLS у нас...
И тут каждое копирование память-память (что есть и в Вашем примере) стоит дорого.
Я, конечно, не представляю архитектуру вашего приложения, но раз вы не любите копировать массивы (и в случае с TLS этого избегаете), то что мешает послать 32 раза по 64K, передавая каждый раз функции передачи новый указатель на нужное смещение в исходном 2М массиве?
А вот в спеке NoiseSocket четко в прологе предлагается слать некороткую специфическую ASCII строку.
— не нужен сертификат
— сильно проще реализация (жрет гораздо меньше памяти)
— более гибкая настройка хендшейка в зависимости от ваших требований
По поводу реализации, где-то лет около 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 атакующей стороне это надоест.
Ну а процент "ложноположительных срабатываний" у этой схемы и так статистически неотличим от шума, куда уж лучше?
Насчет IoT — насколько вероятна угроза цензуры общения между IoT-устройствами? Если не слишком вероятна, то, возможно, подобные меры просто не стоит в них использовать?
Например, "десктопное" устройство может сначала пытаться работать с прологом, как с настоящим пакетом, и в случае некорректных входящих данных, пытаться декодировать его, как пакет с мусорными блоками. IoT-устройства могут даже не пытаться декодировать мусор и просто считать это некорректной передачей.
а почему negotiation_data передается перед noise_message, да еще и в открытом виде, вместо того чтобы передаваться например как message_payload, да еще желательно только после начала шифрования.
Или, как вариант, почему сначала не установить безопасный канал, например по Noise_NN, а в нем уже договориться о дальнейшем протоколе и не провести re-handshake по новому протоколу?
1) разные кривые, хэши и алгоритмы
2) Noise_IK, у которого payload сразу зашифрован
мы должны знать паттерн и алгоритмы заранее, иначе ничего не прочитается. NN конечно можно было бы сделать, но это лишний раундтрип и нагрузка на CPU.
Только собрался писать статью о том как шифровать соединение с применением DH на nodejs. А тут оказывается и велосипед изобретать не придется. Можете посоветовать проверенный пакет под nodejs?
Хотите зашифровать вообще любое TCP соединение? Теперь у вас есть NoiseSocket