Мессенджер доставляет контейнер
Secure Chat работает отдельно от Telegram, почты и других способов передачи. На устройстве отправителя текст или файл превращается в зашифрованный контейнер. Через выбранный канал передаётся этот контейнер, а получатель расшифровывает его локально своим закрытым ключом.
- Собеседники создают собственные профили и обмениваются публичными карточками ключей.
- Они независимо сверяют полные отпечатки ключей и подтверждают контакт в приложении.
- Отправитель выбирает свой профиль, получателя и алгоритм. Secure Chat шифрует содержимое и подписывает контейнер.
- Получатель открывает контейнер, вводит пароль кошелька при необходимости и получает проверенный результат.
Доступ к истории мессенджера сам по себе не даёт закрытый ключ Secure Chat. Дополнительный слой защиты полезен именно для содержимого, которое вы предварительно зашифровали. Он не скрывает факт общения, участников, время передачи или сетевые адреса и не защищает устройство, на котором уже действует вредоносная программа.
Две пары ключей в каждом профиле
| Назначение | Механизм |
|---|---|
| Передача ключа содержимого | RSA-3072 с OAEP-SHA256 |
| Подпись контейнера | ECDSA, кривая NIST P-256, хеш SHA-256 |
| Формат публичных ключей | Канонический DER SubjectPublicKeyInfo (SPKI) |
| Формат закрытых ключей | DER PKCS#8, внутри зашифрованного кошелька |
Публичная карточка
.scpub
содержит имя, оба публичных ключа, отпечаток и версию формата. Закрытых ключей в ней нет. Формат карточки — читаемый JSON; бинарные поля записываются в Base64.
Format: SecureChat.PublicKey
Version: 1
Name
EncryptionPublicKey
SigningPublicKey
Fingerprint
Как проверяется собеседник
Отпечаток объединяет оба публичных ключа в один SHA-256 хеш: 64 шестнадцатеричных символа. Перед отправкой его нужно полностью сверить при личной встрече или по другому доверенному каналу. Имя в импортированной карточке не является доказательством личности.
SHA256(
UTF8("SecureChat.Identity.v1\0")
|| int32BE(length(RSA_SPKI)) || RSA_SPKI
|| int32BE(length(ECDSA_SPKI)) || ECDSA_SPKI
)
Импортированный контакт всегда получает статус непроверенного. Приложение разрешает шифрование этому контакту после подтверждения сверки. Собственные профили можно выбирать в качестве получателя для проверки работы приложения.
Корректная цифровая подпись подтверждает соответствие контейнера ключу подписи. Связь этого ключа с конкретным человеком устанавливается сверенным отпечатком. Для неизвестного или несверенного ключа приложение отдельно показывает, что личность отправителя не подтверждена.
Отдельный случайный ключ для каждого контейнера
Каждое новое сообщение и каждый файл получают новый случайный 256-битный ключ через
RandomNumberGenerator.GetBytes
. Пользователь выбирает один из двух режимов аутентифицированного шифрования — AEAD:
| Алгоритм | Ключ | Nonce | Тег |
|---|---|---|---|
| AES-256-GCM | 32 байта | 12 байт | 16 байт |
| ChaCha20-Poly1305 | 32 байта | 12 байт | 16 байт |
ChaCha20-Poly1305 предлагается только при поддержке операционной системой. Выбранный алгоритм входит в аутентифицированный заголовок; автоматического переключения на более слабый вариант нет.
Случайный ключ содержимого шифруется публичным RSA-ключом получателя. Его отдельная копия шифруется публичным RSA-ключом отправителя, поэтому отправитель также может открыть своё исходящее сообщение. При отправке самому себе создаётся один такой слот.
AEAD проверяет целостность содержимого и связанных данных. Подпись ECDSA-P256/SHA-256 дополнительно связывает контейнер с ключом отправителя. Неуспешная проверка прерывает расшифровку.
Кошелёк под паролем
Профили с закрытыми ключами, контакты, защищённые настройки и история находятся в одном файле
Data/wallet.scvault
рядом с программой. Для шифрования кошелька используется AES-256-GCM.
| Параметр | Значение |
|---|---|
| Получение ключа из пароля | PBKDF2-HMAC-SHA-256, 600 000 итераций |
| Случайная соль | 32 байта |
| Производный ключ | 32 байта |
| Nonce при сохранении | Новые случайные 12 байт |
| Тег аутентификации | 16 байт |
| Длина пароля при создании | От 12 до 1024 символов |
| Максимальный открытый размер кошелька | 64 МиБ |
Пароль и отдельный проверочный хеш пароля не сохраняются. PBKDF2 замедляет перебор, но стойкость защиты по-прежнему зависит от самого пароля. Для длинной уникальной парольной фразы желательно использовать случайные слова или менеджер паролей.
Заголовок длиной 64 байта тоже аутентифицируется. После него записаны шифротекст и тег:
"SCVAULT1"[8]
|| version:int32LE
|| iterations:int32LE
|| salt[32]
|| nonce[12]
|| ciphertext_length:int32LE
|| ciphertext
|| tag[16]
Формат версии 1 принимает только заданные параметры KDF, ограниченный размер и точную длину файла. Запись выполняется через полностью подготовленную зашифрованную копию и замену файла. Параллельная запись и сохранение поверх обнаруженных внешних изменений отклоняются. Служебный
.lock
не содержит ключей.
Что записано в открытом заголовке
Контейнер сообщения или файла начинается с четырёх байт типа, длины JSON-заголовка и самого заголовка. Размер JSON ограничен 16 384 байтами.
magic[4] || header_length:int32LE || header_json[header_length]
| Поле | Содержимое |
|---|---|
Version
|
Версия формата: 1 |
Kind
|
text
или
file
|
Algorithm
|
0 — AES-256-GCM; 1 — ChaCha20-Poly1305 |
SenderEncryptionPublicKey
,
SenderSigningPublicKey
|
Публичные ключи отправителя |
RecipientFingerprint
|
Отпечаток основного получателя |
PlaintextLength
|
Длина исходного содержимого в байтах |
OriginalFileName
|
Имя файла; для текста — пустая строка |
ChunkSize
|
1 048 576 для файла, 0 для текста |
Nonce
|
12 случайных байт для текста либо случайный префикс из 4 байт для файла |
KeySlots
|
Один или два слота: отпечаток и RSA-обёртка ключа длиной 384 байта |
Эти метаданные не зашифрованы. Видимы алгоритм, размер, имя файла, публичные ключи и отпечатки. Постоянные ключи позволяют связывать контейнеры одного отправителя. Если имя файла чувствительно, переименуйте его перед шифрованием.
Открытый заголовок защищён от незаметной подмены: подпись и AEAD используют его исходные байты, а не повторно собранный JSON. В описании ниже
||
означает соединение байт. Целые числа записываются little-endian; исключения с big-endian явно отмечены.
Текст: контейнер SC1 и вложение .scmsg
Исходный текст ограничен 1 МиБ в строгой кодировке UTF-8. Бинарный контейнер имеет тип
SCT1
:
"SCT1"
|| header_length:int32LE || header_json
|| ciphertext_length:int32LE || ciphertext
|| tag[16] || signature[64]
В качестве дополнительных аутентифицируемых данных (AAD) используется весь префикс: тип, длина и JSON заголовка. Подпись ECDSA-P256 вычисляется над SHA-256 всех предшествующих байт. Формат подписи —
IeeeP1363FixedFieldConcatenation
:
r || s
, по 32 байта.
Для передачи бинарный контейнер преобразуется в Base64url без символов заполнения
=
:
SC1:<base64url(binary_container)>
securechat://message/<base64url(binary_container)>
Прежде чем раскрыть текст, программа проверяет структуру, точную длину и подпись, затем расшифровывает RSA-обёртку и проверяет AEAD. Недопустимые символы, переносы внутри конверта, дополнительные URI-параметры и повреждённые данные отклоняются.
Передача через Telegram
Кнопка «Файл для чата» копирует зашифрованный
.scmsg
в файловый буфер Windows. Вставьте его в чат через
Ctrl
+
V
и отправьте вложение. Получатель скачивает файл и открывает его в Secure Chat. Заблокированное приложение сначала запросит пароль.
Обычный конверт
SC1:…
также можно копировать и вставлять вручную. Windows-ссылка
securechat://…
ограничена 8000 символами и становится кликабельной не во всех клиентах. Telegram Desktop не превращает эту произвольную схему в обычную автоссылку; для него предназначено вложение
.scmsg
. Старые
.sct
открываются явно внутри приложения.
Файлы: блоки, подпись и два прохода проверки
Зашифрованный файл получает расширение
.scx
и тип
SCF1
. Предел исходного файла в формате — 1 ТиБ. Обработка потоковая: файл целиком не загружается в память, содержимое разделено на блоки по 1 МиБ.
"SCF1" || header_length:int32LE || header_json
|| (chunk_length:int32LE || ciphertext[chunk_length] || tag[16])*
|| 0:int32LE || terminal_tag[16]
|| signature[64]
Для каждого блока получается собственный 12-байтовый nonce. Он составлен из случайного четырёхбайтового префикса контейнера и восьмибайтового индекса блока:
nonce = Nonce[4] || uint64BE(chunk_index)
AAD = SHA256(full_prefix)[32]
|| uint64BE(chunk_index)
|| int32LE(chunk_length)
Индекс начинается с нуля. Завершающий пустой блок получает следующий индекс и собственный тег. Даже у пустого файла есть заголовок, завершающий блок, тег и подпись. Ключ содержимого генерируется заново для каждого нового файла.
В подпись входят все байты от
SCF1
до завершающего AEAD-тега включительно. Проверяются порядок и размер блоков, точная длина контейнера и конец файла. Перестановка, дублирование, удаление блоков, усечение или дописывание приводят к отказу.
Что происходит при расшифровке
- Проверяются ограниченный заголовок, длина файла и наличие подходящего закрытого ключа.
- Первый проход читает контейнер и проверяет полную подпись. Открытый временный файл ещё не создаётся.
- Второй проход проверяет AEAD каждого блока, пишет расшифрованные данные во временный файл и повторно проверяет итоговую подпись.
- После успешного завершения результат переименовывается в выбранный пользователем новый файл. Уже существующий файл не перезаписывается.
Строка состояния показывает общий процент: проверку подписи, расшифровку и сохранение. 100% означает успешное сохранение результата. Кнопка отмены доступна во время обработки; при штатной ошибке или отмене временный файл удаляется.
Исходный файл сохраняется. Расшифрованный результат не запускается автоматически. Сбой питания, принудительное завершение процесса или препятствующий удалению внешний дескриптор могут оставить временный открытый файл. Защита выходной папки и диска остаётся важной частью работы с секретами.
Локальное хранение, история и блокировка
| Файл или папка | Назначение |
|---|---|
Data/wallet.scvault
|
Зашифрованные профили, ключи, контакты, настройки и история |
Data/window-state.json
|
Размер, положение и состояние окна; без ключей и переписок |
Data/ui-preferences.json
|
Язык и выбор проверки обновлений; без данных кошелька |
Data/ClipboardAttachments
|
Временные копии зашифрованных сообщений для вставки в чат |
История содержит метаданные операций и зашифрованные текстовые конверты. Открытый текст и содержимое файлов в неё не записываются. Сохраняются последние 100 записей с общим размером конвертов около 8 МиБ; старые записи удаляются автоматически. Историю можно отключить или очистить.
Кошелёк блокируется по Ctrl + L , при сворачивании, блокировке или отключении сеанса Windows, переходе в сон и по бездействию. Интервал бездействия выбирается от 1 до 15 минут, по умолчанию — 5 минут. Текущая файловая операция отменяется перед освобождением ключей.
При блокировке очищаются поля и ссылки на записи, а принадлежащие приложению массивы закрытых ключей и производного ключа обнуляются. Полное удаление всех копий из памяти не гарантируется: управляемые строки, буфер обмена, дампы и файл подкачки могут сохранять остатки данных.
Два разных режима буфера обмена
«Копировать текст» помечает собственную запись приложения и очищает её через 30 секунд либо при блокировке, если запись всё ещё принадлежит Secure Chat. Более новая запись другой программы не стирается. Обычное копирование системной командой Ctrl + C этим таймером не управляется.
«Файл для чата» помещает в Windows FileDrop путь к готовому
.scmsg
, содержащему только шифротекст. Эта копия остаётся доступной после блокировки и закрытия кошелька, чтобы мессенджер успел её прочитать. Каждое копирование создаёт отдельное вложение.
Копии старше 24 часов очищаются при последующем запуске или копировании. Одновременно хранится до 128 временных вложений; при достижении лимита можно явно сохранить сообщение в выбранную папку. Запреты на историю и облачный буфер передаются как подсказки Windows; сторонние менеджеры буфера могут их игнорировать.
Резервные копии, перенос и обновление
Резервная копия — полный зашифрованный кошелёк. Для её открытия нужен пароль, который действовал в момент создания. После добавления новых ключей обновите резервную копию. Восстановление доступа без пароля и закрытых ключей не предусмотрено.
Смена пароля, удаление профиля или очистка истории изменяют текущий кошелёк. Старые резервные копии сохраняют прежний пароль, ключи и историю. Удаление записи также не гарантирует физическое стирание данных с SSD, из снимков и журналируемой файловой системы.
Для обновления до 0.1.6 закройте Secure Chat и замените
SecureChat.exe
в прежней папке.
Сохраните всю папку Data.
Форматы кошелька и контейнеров остаются версии 1, миграция не требуется. Для будущих выпусков с изменением формата порядок миграции будет описан отдельно.
При переносе в другую папку переносите EXE вместе с
Data
и нужными внешними переводами
Languages
. Затем включите обработку
.scmsg
,
.scx
и ссылок в настройках заново: регистрация Windows хранит абсолютный путь. Однофайловый EXE может извлекать нативные библиотеки .NET в системный кеш пользователя.
Какие сетевые обращения есть у приложения
Для шифрования и расшифровки сервер не нужен. У Secure Chat нет транспорта сообщений, учётной записи для обмена ключами или сервиса сброса пароля. Доставку контейнеров выполняет выбранный вами мессенджер, почта или другой канал.
По кнопке «Проверить обновления» приложение получает небольшой JSON с
https://itmsft.com/securechat/update/latest.json
. Проверку при запуске можно включить отдельно; по умолчанию она выключена. Передаются обычные сетевые сведения HTTPS-запроса и общий User-Agent с версией программы. Пароль, ключи, профили, история и содержимое файлов в запрос не включаются.
Клиент ограничивает размер ответа 64 КиБ и время чтения 10 секундами, проверяет версию и наличие пакета для своей архитектуры. Ошибка сервера, сети или формата показывает невозможность проверки и не объявляет установленную версию актуальной.
Кнопка скачивания открывает разрешённый HTTPS-адрес пакета на
itmsft.com
в обычном браузере. Приложение не выполняет автоматическую установку и не запускает скачанный файл. Формат поля SHA-256 проверяется, но байты скачанного браузером ZIP приложение не проверяет. В версии 0.1.6 цифровой подписи издателя у EXE нет.
Границы, которые важно учитывать
- Безопасность устройства. Вредоносная программа, кейлоггер, чтение памяти, подмена EXE или удалённый доступ могут раскрыть текст до шифрования и после расшифровки.
- Метаданные. Видимы открытый заголовок контейнера и сетевые сведения канала передачи. Это не средство анонимности.
- Статические ключи. Forward secrecy не реализована: украденный закрытый ключ позволяет читать ранее перехваченные контейнеры этому ключу.
- Восстановление секретности. Double Ratchet и post-compromise security отсутствуют. Это собственный формат, а не реализация протокола Signal.
- Повторы и откат. Валидный контейнер можно переслать повторно. Корректная старая копия кошелька не защищена от отката: целостность не доказывает актуальность.
- Пароль. Минимальная длина и задержка в интерфейсе не останавливают оффлайн-перебор украденного кошелька. Основные меры — сильный пароль и KDF.
- Удаление данных. Полное стирание из RAM, подкачки, облачного буфера и с накопителя не гарантируется.
- Криптографические свойства. Схема не является постквантовой. Подпись доступна для проверки третьим лицам, получившим контейнер; криптографическая отрицаемость не предоставляется.
- Статус проверки. Стандартные примитивы и автоматические тесты не заменяют независимый аудит протокола и реализации.
Secure Chat добавляет отдельный контроль над выбранным содержимым. Для использования с особо чувствительными данными необходимы оценка вашей модели угроз, защищённое устройство и независимая экспертная проверка реализации.