Личные крипто-инструменты: локальный CLI безопасности
Безопасность

Личные крипто-инструменты: мой локальный CLI безопасности

Сценарий восстановления собственной крипто-безопасности я держу в своих руках. Каждый инструмент, о котором пойдёт речь, работает локально и офлайн: слушает только петлю 127.0.0.1, ничего не отправляет в облако и сделан так, чтобы я мог восстановить свои секреты без доверия к панели вендора, расширению браузера или SaaS-сервису, который через год может быть взломан, закрыт или получить судебный запрос. Единственное намеренное исключение — продление TLS-сертификатов, но и оно идёт через DNS-токен, который я выпустил и ограничил сам.

Главный принцип — восстановление в своих руках, недоверие к хосту. Считаем сеть враждебной, а «удобные» инструменты — не на вашей стороне, и тогда границей безопасности становятся ваша файловая система и ваша дисциплина, а не чей-то сервер. Это подробный разбор восьми личных крипто-инструментов, которыми я реально пользуюсь: какую угрозу закрывает каждый и — что не менее важно — от чего каждый намеренно не защищает. Если у вас есть стек аппаратных кошельков и хочется, чтобы софт вокруг него был так же честен, как кремний, — вот как я об этом думаю.

Содержание
  1. Зачем вообще свой набор инструментов?
  2. PIN-инструменты: помощники памяти, а не шифры
  3. pin-shift — позиционный сдвиг цифр
  4. pin-24 — офлайн-восстановление PIN, выведенного устройством
  5. Seed-фразы, ключи и коды
  6. seed-generate / seed-validate — BIP39 по учебнику
  7. wg-peer — конфиг WireGuard, которому можно верить
  8. qr — текст в сканируемый квадрат (и ничего больше)
  9. Ledger Passwords: бэкап метаданных, но не секретов
  10. Сертификаты: доступность и целостность
  11. Менеджер SSL / Let’s Encrypt — чтобы локальный HTTPS жил
  12. smime-verify — проверить комплект S/MIME, прежде чем доверять
  13. Весь набор — по модели угроз
  14. Принципы, которыми я не поступаюсь
  15. Часто задаваемые вопросы
  16. pin-shift — это шифрование?
  17. Если украдут pin-24, смогут ли воссоздать мои пароли?
  18. Хранятся ли мои пароли Ledger в файлах бэкапа?
  19. Почему DNS-01 поверх Cloudflare, а не обычная HTTP-проверка?
  20. Зачем перезапускать всё приложение ради очистки секрета?
  21. Делает ли smime-verify мою почту безопасной?
  22. Нужна консультация?

Зачем вообще свой набор инструментов?

Личный CLI crypto-tools — терминал с командами BIP39, WireGuard и S/MIME рядом со щитом безопасности

Эти крипто-инструменты, которые сейчас выглядят аккуратным набором, начинались как папка разрозненных одноразовых скриптов — здесь помощник для PIN, там проверка seed-фразы, заметки, синтаксис которых я забывал к следующему месяцу. Это работало, но было неаудируемым и легко ломалось под давлением. Поэтому я свёл всю эту россыпь в единый интерфейс командной строки crypto-tools: одна точка входа, согласованные аргументы, предсказуемые коды возврата и одно место, где можно прочитать исходник. Старые скрипты по-прежнему лежат в репозитории, открыто помечены как «не часть поддерживаемого CLI» — стирать историю это тоже своего рода нечестность.

Поверх CLI — локальный Streamlit-«мультитул». Каждая визуальная страница — это тонкая обёртка, которая импортирует ту же логику, что вызывает командная строка, поэтому браузерный интерфейс и терминал не могут тихо разойтись в том, что делает инструмент. Стек — обычный Python (3.10+) поверх хорошо проверенных библиотек: cryptography для операций с ключами, mnemonic для BIP39, qrcode для QR — а не что-то самописное там, где есть выверенный примитив.

Два решения задают модель безопасности ещё до запуска любого инструмента. Первое — сетевая изоляция: лаунчер привязывает интерфейс только к 127.0.0.1, работает в headless-режиме и отключает телеметрию — ничего не доступно из локальной сети и ничего не звонит «домой». Второе — перезапуск с очисткой RAM: после того как по-настоящему чувствительное значение (например, seed-фраза) прошло через память, самый чистый способ его сбросить — завершить весь процесс и поднять новый с пустой кучей. Приложение именно так и делает: выходит со специальным кодом, а управляющий цикл лаунчера запускает его заново. Python не умеет надёжно обнулять неизменяемую строку, а UI-фреймворк хранит несколько копий каждого введённого значения в своих буферах; завершение процесса — единственное честное «забыть». Это не защищает от анализа живой памяти в момент использования секрета, ни от файла подкачки или дампа при сбое — и об этих границах я предпочитаю говорить прямо.

PIN-инструменты: помощники памяти, а не шифры

Два инструмента работают с PIN-кодами, и самое важное про первый — это то, чем он не является. Называть трюк с цифрами «шифрованием» — верный способ начать доверять ему сверх меры, поэтому в словах я аккуратен.

pin-shift — позиционный сдвиг цифр

pin-shift берёт запомненный PIN и секретный вектор сдвига по позициям, а на выходе даёт PIN, который я набираю на самом деле. Математика в одну строку: для каждой позиции набранный[i] = (база[i] + вектор[i]) mod 10, без переноса между разрядами — поэтому я считаю это в уме у клавиатуры. Прибавить, чтобы закодировать; вычесть, чтобы раскодировать. База и вектор — строки цифр одинаковой длины, и принципиально вектор никогда не зацикливается на более длинный PIN, потому что повторное использование сократило бы пространство ключей. Ничего не сохраняется, ничего не уходит в сеть, показ на экране по умолчанию выключен.

Угроза, которую он закрывает, узкая и реальная: я перестаю носить записанный настоящий PIN и разрываю связь с базовым PIN, который может утечь (переиспользованным, давно подсмотренным, привязанным к дате рождения). Если злоумышленник знает базу, но не вектор, он по-прежнему сталкивается с полным пространством 10N вариантов — те же шансы, что у случайного PIN. А вот чего он точно не даёт — это криптографической секретности. Единственная утёкшая пара (база, набранный) восстанавливает весь вектор одним вычитанием. Алгоритм публичен; безопасность держится исключительно на секретности вектора, и осмысленна она только на целях с ограничением числа попыток и низкой-средней чувствительностью — дверной замок, карта, локальное приложение, — но никогда для банковского пароля, seed-фразы или ключа, которые перебираются на машинной скорости. Это мнемоника, и точка.

pin-24 — офлайн-восстановление PIN, выведенного устройством

Второй PIN-инструмент — тот, который я надеюсь никогда не использовать. pin-24 — это бит-в-бит офлайн-реализация открытого алгоритма деривации Ledger Passwords. Дайте ему 24-словную (или 12/15/18/21-словную) BIP39 seed-фразу и никнейм сервиса — и он воспроизведёт тот же самый пароль или PIN, который напечатало бы само устройство Ledger, на случай, когда устройство потеряно, стёрто или уничтожено, но seed у меня сохранён на металлической пластине.

Это детерминированная деривация, а не шифрование и не случайная генерация: одни и те же seed и никнейм всегда дают один и тот же результат. Внутри он точно повторяет пайплайн устройства — BIP39-фраза превращается в seed через PBKDF2-HMAC-SHA512 (2048 итераций, с опциональной парольной фразой), никнейм хешируется в hardened-путь деривации BIP32 на кривой secp256k1, полученный узел инициализирует детерминированный генератор (NIST SP 800-90A CTR_DRBG на AES-256), а из этого потока с отбраковкой (rejection sampling) и перемешиванием Фишера—Йейтса собирается пароль. Смысл точности в деталях прост: инструмент восстановления, который выдаёт почти верный пароль, хуже, чем никакой. Он проверен на канонических векторах BIP39/BIP32 и официальных функциональных векторах проекта на публичном тестовом seed — но я честно отмечаю: набор тестов проверяет математику, а не физическое устройство, так что последний шаг я подтверждаю руками сам.

Теперь неприятная часть, прямым текстом: главный риск инструмента — то, что он сам требует сделать: ввести BIP39 seed, корень всей вашей крипто-безопасности, в компьютер вообще. Это открывает её ОС, кейлоггерам, записи экрана, менеджерам буфера обмена и файлу подкачки. Поэтому pin-24 по замыслу только для восстановления: настоящее устройство всегда безопаснее, интерфейс начинается с баннера, который прямо это говорит, а после использования я очищаю поле и запускаю перезапуск со стиранием RAM. Пользуйтесь железом, пока железо работает.

Seed-фразы, ключи и коды

seed-generate / seed-validate — BIP39 по учебнику

Эти двое — тонкие, намеренно простые обёртки над хорошо проверенной BIP39-библиотекой. seed-generate создаёт стандартную английскую мнемонику нужной длины — 12/15/18/21/24 слова, что соответствует 128/160/192/224/256 битам энтропии, — беря случайность из системного CSPRNG операционной системы, а не из чего-то «хитрого» своего. seed-validate убирает пробелы и говорит, является ли фраза настоящей BIP39-мнемоникой: верный словарь, верная длина, верная контрольная сумма.

По-настоящему полезен именно seed-validate. BIP39-мнемоника — это кодирование энтропии и контрольной суммы в слова (слова и есть секрет в человекочитаемом виде, а не шифртекст), и эта контрольная сумма — подарок: она ловит переставленное слово, пропущенное слово или неверное число слов до того, как я положусь на бэкап. Чего проверка не скажет — ничего о секретности: фраза может быть идеально валидной и при этом полностью скомпрометированной. «Валидно» означает «корректно сформировано», а не «безопасно, свежо, не использовалось». И сгенерированная фраза становится открытым секретным материалом в момент появления — этот код не применяет ни парольной фразы, ни собственного шифрования; защита в покое — отдельная, человеческая ответственность.

wg-peer — конфиг WireGuard, которому можно верить

wg-peer генерирует свежую пару ключей X25519 (Curve25519) и рендерит полный клиентский конфиг WireGuard — секции [Interface] и [Peer] с разумными значениями по умолчанию вроде PersistentKeepalive = 25. Главная идея проста и важна: долговременный приватный ключ генерируется локально и никогда не покидает машину; серверу предназначен только публичный ключ. Ни один ключ не набирается руками и не вставляется в чат — а именно там VPN-ключи обычно и утекают. Я сочетаю это с той же философией аппаратных ключей, что описал в материале про VPN на аппаратных ключах.

Он генерирует ключи и шаблонизирует конфиг — и всё; саму криптографию туннеля позже делает сам WireGuard. Отсюда честные оговорки: сгенерированный .conf содержит приватный ключ в открытом виде, поэтому утёкший конфиг и есть утёкший ключ (если так вышло — ротируйте профиль и отзывайте старый публичный ключ на сервере). Маршрут по умолчанию направляет весь трафик в туннель — обычно это то, что мне нужно, но знать стоит. И он не регистрирует пира за вас — добавленный публичный ключ на сервере я по-прежнему прописываю сам. Относитесь к .conf как к секрету: вне git, вне скриншотов, вне чатов.

qr — текст в сканируемый квадрат (и ничего больше)

qr кодирует произвольный текст в PNG-QR-код. Это самый скромный инструмент здесь и тот, который чаще всего понимают неверно. QR-код — это полностью обратимое оптическое кодирование ровно тех байтов, что вы ему дали: ни шифрования, ни хеширования, ни преобразования. Он существует ради удобства: перенести конфиг WireGuard, URI otpauth:// для TOTP или фрагмент конфигурации на телефон камерой, в том числе через «воздушный зазор» — без кабеля и без набора руками.

А значит, его свойство безопасности — ровно нулевая конфиденциальность. Любой, кто увидит или сфотографирует картинку, восстановит исходную полезную нагрузку дословно. Правило, которому я следую: QR-код ровно настолько чувствителен, насколько чувствителен текст внутри него. QR с публичным SSID Wi-Fi можно печатать на стене; QR с seed-фразой — это seed-фраза, и обращаюсь я с ним так же, как с самими словами.

Ledger Passwords: бэкап метаданных, но не секретов

Этот инструмент мне нравится объяснять больше всего, потому что звучит он тревожно, а на деле — успокаивающе, как только понимаешь модель. Приложение Ledger Passwords выводит каждый пароль на устройстве из вашего seed, никнейма записи и маски набора символов — сами пароли нигде не хранятся, ни на устройстве, ни в файле. Потерять можно список: какие записи существуют и как каждая настроена. Поэтому мой инструмент ledger-pw бэкапит именно это — метаданные, а не пароли.

Слот бэкапа — это небольшой JSON-файл с никнеймами записей и их масками наборов символов (8-битный селектор для верхнего/нижнего регистра, цифр, разделителей и спецсимволов). Формат — надмножество официального бэкапа passwords.ledger.com, поэтому файлы без потерь ходят туда-обратно с оригинальным open-source приложением. CLI умеет import, normalize (сортировка и дедупликация для чистых диффов), add/rm записей, diff двух бэкапов независимо от порядка и упаковку всего в точный бинарный формат устройства для повторной загрузки. Streamlit-страница общается с подключённым Ledger напрямую по USB, и каждое чтение или запись на устройстве требует физического нажатия кнопки на самом устройстве — хост может попросить, но подтверждает только мой палец.

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

Сертификаты: доступность и целостность

Менеджер SSL / Let’s Encrypt — чтобы локальный HTTPS жил

Даже инструменты, которые слушают только 127.0.0.1, заслуживают настоящего, доверенного браузером HTTPS — предупреждения о самоподписанных сертификатах приучают кликать сквозь опасность. Менеджер сертификатов ведёт инвентарь моих локальных сертификатов, разбирает каждый и сообщает, сколько именно дней осталось, и продлевает агрессивно, задолго до истечения. Выпуск идёт через ACME DNS-01 поверх Cloudflare: контроль над доменом доказывается записью временной DNS-записи через API-токен, который я ограничил правом Zone:DNS:Edit и ничем больше. DNS-01 — это и есть трюк, благодаря которому публично-доверенные сертификаты работают для сервиса только на петле: DNS-запись может указывать реальное имя хоста на 127.0.0.1, так что браузер доверяет «замочку», а сервис ни на секунду не покидает мою машину.

Угроза здесь не в секретности — её уже обеспечивает TLS, — а в доступности: сертификат тихо истекает и ломает инструмент в самый неподходящий момент. Менеджер продлевает с большим запасом (действует на сертификаты, у которых осталось меньше 60 дней, поверх собственного порога ACME-клиента) и показывает цветную таблицу статусов, чтобы ничего не истекло внезапно. Откровенная часть: это единственный инструмент во всём наборе, который делает исходящий сетевой вызов, и используемый им токен Cloudflare — настоящий секрет: утёкший токен означает, что кто-то может менять DNS для зоны. Поэтому токен и приватные ключи лежат в git-игнорируемом каталоге secrets/, с правами chmod 600, и вне любых скриншотов.

smime-verify — проверить комплект S/MIME, прежде чем доверять

smime-verify — это read-only диагностика, а не подписывание и не шифрование почты. Прежде чем импортировать комплект учётных данных S/MIME в почтовый клиент, он проверяет, что детали действительно сходятся: контейнер PKCS#12 (.p12), опциональную цепочку сертификатов (P7B) и опциональный внешний публичный ключ. Проверки — ровно те, что больно бьют позже, если их пропустить: действительно ли приватный ключ соответствует листовому сертификату, присутствует ли лист в собственной цепочке, валидны ли подписи цепочки, находится ли сертификат в окне действия, и говорят ли атрибуты Key Usage, Extended Key Usage и политики S/MIME CA/Browser Forum то, что должны.

Деталь, которой я горжусь, — доказательство владения (proof-of-possession): вместо того чтобы лишь сравнивать публичные ключи как данные, он заставляет приватный ключ подписать случайный вызов и проверяет эту подпись публичным ключом сертификата — настоящее криптографическое доказательство, что они принадлежат друг другу. Границы — честно: онлайн-проверки отзыва нет (ни OCSP, ни CRL), доверия к выпустившему УЦ он не устанавливает и приватный ключ не защищает — пароль от комплекта я по-прежнему ввожу сам, лучше через приглашение или файл, чем флагом командной строки, который осел бы в истории шелла. Он говорит, что комплект внутренне согласован, — а это иное и более скромное утверждение, чем «безопасен».

Весь набор — по модели угроз

Ни один инструмент не закрывает всё — и в этом суть. Каждый отвечает на конкретный вопрос и открыто оставляет остальное другим слоям: железу, операционной системе и моей собственной дисциплине:

ИнструментЧто это на самом делеОт чего защищаетОт чего НЕ защищает
pin-shiftПозиционная мнемоникаУтёкший/записанный базовый PIN на целях с лимитом попытокАналитика — одна пара (база, набранный) выдаёт вектор
pin-24Офлайн-реплика деривации устройстваВосстановление пароля Ledger без устройстваВвод seed в хост (кейлоггеры, swap)
seed-validateПроверка контрольной суммы BIP39Опечатки в записанной seed-фразеСекретность — валидная фраза может быть скомпрометирована
wg-peerГенератор ключа X25519 и конфигаУтечку ключей при ручном копированииУтёкший .conf (приватный ключ в открытом виде)
qrОбратимое оптическое кодированиеНичего — чистое удобствоКонфиденциальность — кто сканирует, тот читает
ledger-pwБэкап/восстановление метаданныхПотерю списка записей на пересозданном устройствеСокрытие списка сервисов (метаданные не шифруются)
Менеджер SSLЖизненный цикл сертификатовТихое истечение / простой локального HTTPSУтёкший токен Cloudflare = контроль DNS зоны
smime-verifyДиагностика PKI-комплектаНесоответствие ключ/сертификат, битые цепочкиОтзыв (нет OCSP/CRL); доверие к УЦ

Принципы, которыми я не поступаюсь

Локальность — это свойство безопасности, а не предпочтение. Каждая секретная операция, которая может пройти офлайн, проходит офлайн. Единственный инструмент, выходящий в сеть (продление сертификатов), огорожен узко ограниченным токеном, и я отношусь к нему как к исключению, подтверждающему правило, а не как к двери, которую можно подпереть открытой.

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

Относитесь к конфигам и кодам как к секретам, которые они несут. Файл .conf WireGuard, QR с seed, бэкап метаданных паролей — каждый ровно настолько чувствителен, насколько чувствительно его содержимое, и каждый держится вне публичного git, чатов и скриншотов. Бэкапы, раскрывающие, какими аккаунтами я владею, живут в приватных репозиториях, никогда в публичных.

«Только для восстановления» значит только для восстановления. Инструменты, способные восстановить секрет из seed, существуют на случай отказа железа, а не для ежедневного удобства. Пока устройство работает, оно всегда безопаснее, и набор устроен так, чтобы стирать собственную память, как только чувствительное значение сделало своё дело. Точно так же, как я держу ключи на железе для повседневной подписи, офлайн-реплики лежат в ящике, пока не понадобятся по-настоящему.

Часто задаваемые вопросы

pin-shift — это шифрование?

Нет, и различие важно. Это позиционная мнемоника — каждая цифра сдвигается на секретную величину по позиции, по модулю 10. Пространство ключей — всего 10N, а одна известная пара (база, набранный) восстанавливает весь вектор сдвига одним вычитанием. Он прячет базовый PIN от случайного подглядывания на целях с лимитом попыток; криптографической секретности он не даёт и никогда не должен охранять пароль, seed или ключ.

Если украдут pin-24, смогут ли воссоздать мои пароли?

Сам по себе инструмент им бесполезен. Деривация требует вашей BIP39 seed-фразы — он лишь воспроизводит офлайн то, что вычислил бы Ledger. Настоящая опасность не в коде, а в том, чтобы вообще вводить seed в компьютер. Поэтому он только для восстановления, работает офлайн и стирает RAM перезапуском процесса, когда вы закончили.

Хранятся ли мои пароли Ledger в файлах бэкапа?

Нет. Файлы слотов хранят только метаданные — никнеймы записей и маски наборов символов. Пароли выводятся на устройстве из seed и никогда его не покидают. Файлы безопасно держать в приватном git, но они всё же раскрывают, какими сервисами вы пользуетесь, поэтому их нельзя публиковать, и они не зашифрованы.

Почему DNS-01 поверх Cloudflare, а не обычная HTTP-проверка?

DNS-01 доказывает контроль над доменом, создавая временную DNS-запись через API Cloudflare, поэтому он работает для сервисов только на петле без публичного веб-сервера — имя хоста может разрешаться в 127.0.0.1 и при этом проходить проверку. Токен ограничен правом редактировать DNS одной зоны, чтобы сузить радиус поражения, и это единственный исходящий вызов всего набора.

Зачем перезапускать всё приложение ради очистки секрета?

Потому что Python не умеет надёжно обнулить неизменяемую строку, а UI-фреймворк хранит несколько копий каждого введённого значения. После ввода seed единственная надёжная очистка — завершить процесс и поднять новый с пустой кучей. Это не защищает от анализа живой памяти в момент использования секрета или от swap и дампов при сбое — это намеренная, ограниченная мера.

Делает ли smime-verify мою почту безопасной?

Нет — это диагностический верификатор, а не подписывание и не шифрование почты. Он подтверждает, что комплект PKCS#12 внутренне согласован (ключ соответствует сертификату через доказательство владения, лист есть в цепочке, подписи валидны, окно действия и атрибуты политик в порядке) до импорта. Онлайн-проверки отзыва он не делает и доверия к выпустившему УЦ не устанавливает.

Нужна консультация?

Если вы строите инструменты безопасности для себя или команды и хотите второй взгляд на модель угроз — запишитесь на бесплатную 15-минутную консультацию.

Оцените статью