Комментарии 25
if padding != 0 {
    repeat := bytes.Repeat([]byte("\x00"), aes.BlockSize-(padding))
    content = append(content, repeat...)
}
...
encrypted = bytes.Trim(encrypted, string([]byte("\x00")))

Лучше так не делать, т.к. если в конце сообщения окажутся нулевые байты, то они будут откушены. Лучше воспользоваться padding'ом из PKCS#7

Хорошее замечание, учту!
Однако, шифруется json, и он всегда заканчивается на печатные байты "}" или "]", поэтому в текущей реализации проблем быть не должно.
А через пару лет кто то придумает как использовать другой баг добавляющий нули к json-у чтобы устроить MITM.
А ещё лучше использовать GCM режим шифрования (crypto/cipher.NewGCM) и не париться с padding-ом вообще: и код проще, и только шифрование используется, и распараллеливается. А самое главное: GCM автоматически даст аутентификацию сообщений. Шифрование без аутентификации… мягко говоря, недопустимо.

habr.com/ru/post/452200 — вот тут есть пример гораздо более безопасного решения, но на Python. Из сложностей: ASN.1 вместо простой сериализации как у вас (простота это тоже хорошо). И просто для справки: если хочется ГОСТ криптографию, то вот для Go есть GoGOST: gogost.cypherpunks.ru
Неплохая статья, очень даже неплохая.
По логам — мы используем github.com/uber-go/zap с небольшой оберткой, которая позволяет нам создавать нужные аппендеры на лету. Форматирование zap тоже поддерживает, но если хочется свой формат лог записей, то нужно написать немного кода. Универсализма как в log4j я пока не видел.
Изобретать очередной E2E протокол для общения конечно прикольно, но только давайте не будем называть его безопасным. В то время как уже давно есть и Double Ratchet и Noise Protocol это моветон.
Что касается конкретно вашей реализации:
1) ID пира должен быть хэшем от его статического публичного ключа, иначе MITM
2) Эфемерные ключи не подписаны. Тоже MITM
2) Вместо AES-CBC лучше использовать AES-GCM/AES-GCM-SIV, либо добавить HMAC. У вас нет никакой проверки корректности расшифрованного текста, можно напихать туда что угодно и собеседник ничего не заподозрит

Это только то, что сразу бросилось в глаза

Спасибо за препарацию моей самоделки и за Noise Protocol.
Я расчитывал как раз на подобный разбор.


1) Сейчас ID пира есть его публичный ключ. Первоначально не ставил задачу его скрывать, да и протокол был бы не такой лаконичный, а на будущее учту этот момент. Правда, не совсем понял как это уязвимо для MITM?


2) Эфемерные ключи передаются в подписанном конверте, поэтому можно считать что они подписаны


func (p Proto) SendName(peer *Peer) {
     /* ... */
    sign := ed25519.Sign(p.privKey, handShake)
    envelope := NewSignedEnvelope("HAND", p.PubKey[:], make([]byte, 32), sign, handShake)
}

Другое дело, что подпись проверяется, но реакция на некорректность реализована недостаточно.


3) Да, проверка корректности отсутствует. Была идея реализовать как в телеграмме AES+IGE. Была мысль, что контент сам себя провалидирует, если будет представлять собой gzip, в который я хотел упаковывать все сообщения для экономии трафика. А там уже проверки гзиповские будут. Но соглашусь, лучше использовать проверку корректности на основе режима шифрования.


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

Любая датаграмма (или пакет) могут быть сгенерированы в сеть третьей стороной. Поэтому недостаточно просто проверить корректность формата, каждое сообщение необходимо авторизовать, причем делать это нужно за константное время (иначе возможны тайминг-атаки) см. реализацию MAC (message authentication code) из TLS.

Технически статью осилить не способен, но за картинку плюс :)

Впечатляет! КТо-то пишет при обучении языку хэллоуворды, кто-то очережной твиттер, а мсье п2п мессенжер с е2е
причем с гуем на реакте, общением через один порт и вот этим всем
Полагаю, что возьми вы либп2п, навернка быстрее и лучше сбацаете (:
Хотелось прочувствовать go своими руками, поэтому libp2p сразу отложил
С libp2p еще разобраться нужно. И это не быстро, раньше там документации с гулькин нос было, сейчас, может, лучше стало.
Легкий грамматический троллинг :)
p2p мессерджер (кстати, есть ли русский синоним этому слову?).

Да. Мы в России его называем мессенджер :)


Если серьезно, то встречал разные, но "Система обмена мгновенными сообщениями" как-то сложно звучит, "болталка" — слишком несерьезно. Иногда встречал "чат", но это больше к виджету мессенджера, вставленному на сайт.

Спасибо
Опечатку исправил, правда на скрине она же =)
Чат — слово нерусское. Может «вещатель»?

Интересная статья.
Думаю, многим будет интересно "потыкать" проект. Но для тех, кто go не собирал поначалу может быть сложно. Можно собрать проект под разные системы (благо в go кросс-компиляция несложная) и положить статическим бинарен на GitHub. Или в крайнем случае — Docker образ. Так они смогут его скачать и запустить, а вы получить обширную обратную связь.

А можно в двух словах для не очень сообразительных, почему наименование половины функций начинается с маленькой буквы, а половина с большой?
Это еще одна особенность go.
Публичные (экспортируемые) методы пишутся с большой буквы, а приватные (неэкспортируемые) с маленькой. Такая себе инкапсуляция =)
golang.org/ref/spec#Exported_identifiers

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

Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.