Как Conchshell хранит пароли и проверяет ключи хостов

Что делает хранилище, чего оно делать отказывается и где проходит граница.

Хранилище

Данные запечатаны XChaCha20-Poly1305 одним случайным ключом данных. У каждого способа разблокировки — связка ключей системы, парольная фраза (её растягивает Argon2id), код восстановления — свой слот, оборачивающий этот же ключ. На Mac, iPhone, iPad и Android хранилище открывается связкой ключей системы (на Android — Keystore) и парольной фразы не требует. В Windows и Linux связку ключей системы приложение не использует, поэтому там хранилищу нужна парольная фраза не короче 12 символов — её спрашивают при каждом запуске — и к нему выдаётся код восстановления. Добавление или отзыв способа переписывает один слот; само хранилище не перешифровывается.

На iPhone и iPad хранилище использует те же XChaCha20-Poly1305 и Argon2id, а его ключ лежит в связке ключей iOS и не попадает в связку ключей iCloud.

Интерфейс умеет создать запись и удалить запись. Прочитать обратно — не умеет. Не потому что чтение запрещено, а потому что команды, которая бы на такой вопрос ответила, не существует.

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

парольная фраза → Argon2id → ключ слота → ключ данных → XChaCha20-Poly1305 → хранилище

Привязка к маршруту

Запись в хранилище привязана ко всему маршруту, по которому ею впервые воспользовались: хост, порт, пользователь, прокси и промежуточный узел. Измените любое из этого — и запись не предложится, подключение спросит вас. Подменённое окно не может увести сохранённый пароль на другой сервер, потому что хранилище не отдаст его ни для какого другого маршрута. Пароли, которые лежат незашифрованными вне хранилища, такой привязки не получают.

Ключи хостов

Первое подключение и смена ключа подтверждаются диалогом, который рисует операционная система, вне поверхности приложения. Приложение не может его перерисовать, не может нажать за вас и не может выдать подмену ключа за первое подключение. Это единственный запрос, который стоит читать внимательно, — поэтому это единственный запрос, который приложение не рисует само.

Сертификаты серверов RDP и FTPS тоже закрепляются. Сертификат, за который ручается сама система, — цепочка до доверенного корня, имя, которое вы ввели, действующий срок, — принимается без вопроса и закрепляется. Любой другой при первом подключении показывает отпечаток и сведения о себе, вы его подтверждаете, и после закрепления цепочка, имя и срок для него уже не важны. Сменившийся сертификат не используется, пока вы не подтвердите замену в том же системном окне, — кроме случая, когда и прежний закреплённый сертификат, и новый подтверждены системой. На Android системной проверки нет: там каждый сертификат подтверждаете вы. Сверьте отпечаток при первом подключении.

На iPhone и iPad ключ хоста проверяется при каждом подключении: в первый раз вы видите его отпечаток и решаете сами; если ключ сменится, соединение остановится до входа и покажет старый и новый отпечатки. Сертификат сервера RDP или FTPS, которому система не доверяет, показывается вам, и решаете вы.

Закрыть этот диалог, не нажав кнопку доверия, — Escape, крестиком, Alt+F4, кнопкой «Назад» на Android, — значит отказаться, на любой платформе. На телефоне вопрос, оставленный без ответа на 10 минут, тоже считается отказом. В версии 2.16.0 и раньше здесь был дефект: в Windows и Linux закрытие диалога считалось доверием к ключу, а на Android — кнопка «Назад»; в 2.17.0 это исправлено.

Обновлено 2026-11-02 · v2.17.1