Загрузка данных


Ты — senior backend/mobile security engineer и криптографический архитектор.

Мне нужно реализовать в моём приложении защищённый обмен личными сообщениями между пользователями по принципу Signal.

Главное требование:

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

Не пиши самодельную криптографию. Не используй AES или RSA как единственный механизм для построения мессенджера. Используй проверенную реализацию Signal Protocol, например libsignal или официально совместимую библиотеку для выбранного языка и платформы. Если библиотека недоступна или несовместима с проектом, сначала объясни ограничения и предложи безопасную альтернативу.

Сначала проанализируй текущий проект:

1. Определи используемый язык, фреймворк, платформу и архитектуру.
2. Найди существующие модели пользователей, API, базы данных, WebSocket/Pusher/FCM-механизмы и систему авторизации.
3. Проверь, где сейчас хранятся сообщения.
4. Не изменяй существующую архитектуру без объяснения.
5. Перед изменением файлов составь краткий план и список файлов, которые будут изменены.

Реализуй архитектуру следующим образом.

### 1. Ключи пользователя

На устройстве пользователя должны создаваться:

- identity key pair;
- signed pre-key;
- набор one-time pre-keys;
- при поддержке библиотеки — post-quantum pre-key, например Kyber-related key material;
- локальное состояние Signal-сессий для каждого собеседника и устройства.

Приватные ключи никогда не должны отправляться на сервер.

Приватные ключи должны храниться только в защищённом локальном хранилище платформы:

- Android Keystore;
- iOS Keychain/Secure Enclave, если применимо;
- Windows Credential Manager/DPAPI, если это desktop-приложение;
- безопасное хранилище, соответствующее текущей платформе.

Не сохраняй приватные ключи в обычном localStorage, открытом SQLite, plaintext-файлах, логах или обычных настройках приложения.

### 2. Серверные ключи

Сервер может хранить только публичные данные:

- user/device identifier;
- identity public key;
- signed pre-key public key;
- подпись signed pre-key;
- one-time pre-key public keys;
- публичные ключи устройств;
- минимальные технические данные, необходимые для доставки.

Создай API для:

- публикации key bundle;
- получения key bundle собеседника;
- добавления one-time pre-keys;
- обновления signed pre-key;
- регистрации и удаления устройства;
- запроса списка устройств пользователя.

Сервер не должен получать plaintext-сообщение или приватные ключи.

### 3. Установка сессии

При первом сообщении:

1. Клиент отправителя получает публичный key bundle получателя.
2. Клиент создаёт Signal Protocol session.
3. Клиент шифрует сообщение локально.
4. На сервер отправляется только ciphertext и необходимые технические поля.
5. Получатель расшифровывает ciphertext локально.
6. Состояние сессии сохраняется локально на обоих клиентах.

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

### 4. Формат сообщения

Разделяй:

- plaintext — только в оперативной памяти устройства до шифрования и после расшифровки;
- encrypted payload/ciphertext — единственное содержимое, которое передаётся через сервер;
- metadata — технические данные, необходимые для маршрутизации.

Пример серверного объекта:

{
  "message_id": "random-uuid",
  "recipient_device_id": "device-id",
  "encrypted_payload": "base64-or-binary-ciphertext",
  "message_type": "signal_prekey_or_signal_message",
  "created_at": "server-timestamp",
  "expires_at": "expiration-timestamp"
}

Не отправляй на сервер:

- текст сообщения;
- расшифрованные вложения;
- приватные ключи;
- ключи сессии;
- локальную историю переписки;
- пароль пользователя;
- ключ шифрования базы данных в открытом виде.

Если Signal Protocol требует дополнительные служебные поля, используй только поля, предусмотренные выбранной библиотекой.

### 5. Очередь offline-сообщений

Сервер может временно хранить encrypted payload для получателя, который offline.

Требования:

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

Добавь статусы:

- queued;
- delivered;
- read;
- expired;
- failed.

Не делай сервер источником истории переписки. История должна храниться локально на устройствах и быть зашифрована.

### 6. Локальная база данных

Создай локальное хранилище переписки:

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

Добавь защиту от случайного вывода plaintext через:

- console.log;
- debug logging;
- HTTP logging middleware;
- exception messages;
- analytics;
- telemetry;
- crash reporting.

### 7. Проверка identity key

Реализуй механизм проверки личности собеседника:

- safety number/подобный fingerprint;
- отображение fingerprint пользователю;
- возможность сканирования QR-кода;
- предупреждение при изменении identity key;
- явное подтверждение новой личности;
- защита от автоматического молчаливого принятия нового identity key.

Не отключай проверку identity key ради удобства.

### 8. Push-уведомления

Push-уведомление не должно содержать текст сообщения.

Разрешённый вариант:

- “Новое сообщение”;
- случайный идентификатор;
- минимальный технический payload.

После получения push клиент должен самостоятельно запросить ciphertext с сервера и расшифровать его локально.

### 9. Защита API

Добавь:

- TLS;
- проверку авторизации;
- rate limiting;
- защиту от replay атак;
- проверку timestamp/expiration;
- идемпотентность отправки;
- уникальные message_id;
- серверную валидацию размера ciphertext;
- защиту от подмены recipient_device_id;
- аудит операций без записи текста сообщений;
- безопасное удаление queued messages после ACK.

Не считай TLS заменой end-to-end encryption.

### 10. Криптографические требования

Используй:

- Signal Protocol;
- Double Ratchet для последовательного обмена;
- X3DH или актуальный механизм initial key agreement, поддерживаемый библиотекой;
- pre-key bundle;
- one-time pre-keys;
- forward secrecy;
- post-compromise security, если это поддерживается библиотекой;
- authenticated encryption, предоставленную Signal Protocol.

Не реализуй самостоятельно:

- генерацию криптографических примитивов;
- Double Ratchet;
- X3DH;
- подпись identity keys;
- управление цепочками ratchet keys;
- проверку MAC;
- случайную генерацию ключей;
- собственный формат криптографического протокола.

### 11. Групповые чаты

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

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

### 12. Резервные копии

Не делай резервную копию plaintext-переписки.

Если проект поддерживает backup:

- backup должен шифроваться end-to-end;
- ключ backup не должен храниться на сервере в открытом виде;
- пользователь должен получить recovery key;
- recovery key нельзя отправлять на сервер;
- добавь предупреждение о невозможности восстановления при потере recovery key;
- не логируй recovery key.

### 13. Тесты

Создай unit-, integration- и security-тесты:

1. Отправитель и получатель успешно создают сессию.
2. Сообщение шифруется на клиенте.
3. Сервер получает только ciphertext.
4. Попытка расшифровать сообщение сервером невозможна.
5. Получатель успешно расшифровывает сообщение.
6. Повторное использование one-time pre-key обрабатывается безопасно.
7. Подмена ciphertext обнаруживается.
8. Изменение identity key вызывает предупреждение.
9. Offline-сообщение удаляется после delivery ACK.
10. Просроченное сообщение удаляется.
11. Push payload не содержит plaintext.
12. В логах отсутствует текст сообщения.
13. Вложение нельзя прочитать без клиентского ключа.
14. Поддерживается несколько устройств.
15. Повторная отправка с тем же message_id не создаёт дубликат.

Добавь тест, который проверяет фактическое содержимое HTTP-запроса к серверу и гарантирует отсутствие plaintext.

### 14. Документация

Создай документацию:

- архитектура шифрования;
- схема обмена ключами;
- формат API;
- жизненный цикл сообщения;
- модель угроз;
- какие данные видит сервер;
- какие данные сервер не может увидеть;
- порядок восстановления после потери устройства;
- порядок смены identity key;
- ограничения реализации;
- инструкции локального запуска;
- инструкции миграции существующих сообщений.

Обязательно явно укажи:

“End-to-end encryption означает, что сервер не может прочитать содержимое сообщения, но сервер всё ещё может видеть некоторые технические метаданные, например время подключения, IP-адрес, факт доставки, размер ciphertext и идентификатор устройства, если дополнительно не реализованы механизмы защиты метаданных.”

### 15. Правила работы

- Не удаляй существующие функции без моего согласия.
- Не меняй публичные API без объяснения.
- Не добавляй фиктивную криптографию.
- Не называй систему “полностью анонимной”.
- Не утверждай, что метаданные полностью скрыты.
- Если выбранная библиотека не поддерживает необходимую функцию, сообщи об этом до реализации.
- Если есть несколько вариантов, сравни их и выбери самый безопасный для текущего стека.
- Все секреты и ключи должны иметь безопасный lifecycle.
- После реализации покажи diff и кратко объясни каждое изменение.
- Перед завершением выполни тесты и сообщи, какие прошли, а какие нет.

Начни с аудита репозитория и предложи план реализации. Пока я не подтвержу план, не выполняй масштабные изменения.