Как я в одиночку пишу мессенджер AegisTalk: техническая боль, Double Ratchet
Всем привет.
Недавно я пытался рассказать о своем проекте — защищенном мессенджере, который я назвал AegisTalk. Пишу его один, по ночам, на чистом энтузиазме. Но мой прошлый пост снесли с пометкой «реклама бренда». Обидно, ведь я не корпорация и не отдел маркетинга, а обычный разработчик, который хочет обсудить код и архитектуру.
Попробую еще раз, но теперь без ссылок и призывов — только хардкорная «техничка», с которой я столкнулся при реализации ядра.
Главный вызов: Протокол Double Ratchet на Go (Golang)
Для тех, кто не в танке: это сердце безопасности современных мессенджеров (Signal, WhatsApp). Суть в том, что ключи шифрования «прокручиваются» для каждого сообщения. Если злоумышленник перехватит один ключ, он всё равно не сможет расшифровать ни старую переписку, ни будущую.
Я выбрал Go для серверной части AegisTalk. И вот тут начались танцы с бубном, о которых молчат в туториалах.
1. Проблема состояний (Ratchet States) Double Ratchet — это не просто функция, это состояние. Нужно хранить цепочки ключей (Root Key, Chain Keys), индексы, публичные ключи собеседника... В одиночном проекте это превращается в ад с базой данных.
Мой костыль: Использую Protobuf для сериализации состояний ключей в PostgreSQL. Но как только меняется структура — всё летит к чертям. Коллеги, как вы решаете вопрос миграции криптографических структур данных?
2. Пропущенные сообщения (Out-of-order) Сеть — штука нестабильная. Сообщение №5 может прийти раньше сообщения №4. Протокол должен уметь «отложить» ключ для №4 в хранилище (Message Key Store).
Боль: Сколько таких ключей хранить? Если хранить долго — дыра в безопасности. Если мало — юзер не прочитает сообщение. Я поставил лимит в 100 ключей и TTL на 7 дней. Это адекватно или я перестраховываюсь?
3. Криптография в Go Стандартная библиотека crypto мощная, но низкоуровневая. Для реализации «диффи-хеллмана» на кривых X25519 приходится писать много оберток.
Go
// Схематичный пример поворота ключа func (s *Session) RotateRatchet(remotePubKey [32]byte) error { sharedSecret, err := curve25519.X25519(s.ourPrivKey, remotePubKey) if err != nil { return err } // Дальше идет KDF (Key Derivation Function) s.rootKey, s.chainKey = kdf(s.rootKey, sharedSecret) return nil }
Кто работал с ecdh в последних версиях Go? Есть ли смысл переходить на сторонние либы ради удобства, или лучше оставаться на «стандарте» ради безопасности?
Итог: Писать мессенджер в одиночку — это либо путь к просветлению, либо к нервному тику. Я выбрал название AegisTalk, потому что хочу сделать упор на реальную защиту данных.
Надеюсь, этот пост не сочтут рекламой, так как проект всё ещё в стадии «глубокой беты» и закрытого кода. Просто хочу поговорить с умными людьми и услышать критику по реализации протокола.
Если кому-то интересно следить за ходом разработки или хочется узнать подробности о проекте — вся информация и ссылки есть у меня в профиле Пикабу. Сюда не кидаю, чтобы снова не забанили.
Буду рад любым советам по Go и криптографии в комментариях!
