Итоговый результат — ключ размером с флешку
Повсеместное шифрование и, как следствие, обилие ключей заставляет задуматься об их надежном хранении. Хранение ключей на внешних устройствах, откуда они не могут быть скопированы, уже давно считается хорошей практикой. Я расскажу о том, как за 3$ и 2 часа сделать такой девайс.
Кратко о принципах работы
Криптография дает нам возможность скрывать то, что мы хотим отправить, убедиться в том, что мы общаемся именно с тем, с кем мы думаем и много других интересных вещей. Обычно для того, чтобы все это хорошо работало от нас просят только одно — держать в секрете наши ключи шифрования. Звучит просто, не правда ли? Что ж, давайте посмотрим как же можно припрятать наши ключи:
- Сохранить в файлике на рабочем столе — старый и проверенный годами способ записать что-то. Проблема в том, что помимо самого пользователя еще куча других программ имеет доступ к файлам на вашем рабочем столе. И если вы совершенно уверенны в том, что все они делают то, для чего они предназначены, не собирают о вас никакие данные и попросту не сливают их в сеть — эта статья не для вас.
- Менеджеры паролей — по-сути такое же хранение в файлике, просто он теперь зашифрован и чтобы получить доступ нужно знать пароль. Уже неплохо, но раз менеджер паролей запускается на вашем компьютере, то незашифрованные ключи попадают в оперативную память, откуда могут быть украдены из-за какой-нибудь уязвимости ОС
- Записать на бумажку — удивительно, но этот способ выглядит немного более безопасным. Ключи не хранятся на вашем компьютере, кишашем вирусами. Каждый раз, когда вам нужно использовать ключи вы просто вводите его с клавиатуры. Однако, если ваши ключи довольно длинные(как например ssh-ключи) это может стать проблемой. Да и кейлоггеры не дремлют
Как видно, основаная проблема состоит в том, что ключи либо непосредственно хранятся на вашем компьютере либо вводятся туда, посредством клавиатуры, флешки и т.п. Но, возразите вы, а как же тогда мой компьютер будет шифровать данные, если он не знает ключа? Правильный ответ — никак. Решение уже давно придумано. Главная идея в том, чтобы подключить к компьютеру специальное устройство, которое будет само шифровать данные. А компьютер будет только отправлять данные и получать результат. Так работают, например, многие смарт карты.
Необходимые компоненты
Итак, приступим. Собирать наш девайс мы будем на недорогом и достаточно популярном микроконтроллере серии STM32. Конечно, можно самому изготовить печатную плату но мы же хотим управиться за 2 часа? Так что возьмем уже готовое решение — программатор ST-Link v2. Выглядит этот девайс вот так.
Как ни странно, программатор для микроконтроллеров STM32 собран на микроконтроллере STM32. Этот девайс внешне очень напоминает флешку, что нам как нельзя на руку. К тому, же его корпус изготовлен из алюминия, так что можно не переживать что он повредиться. Стоит это чудо на алиэкспресс 1.5-3 доллара. Нам потребуется две такие штуки. Одну мы переделаем под ключ, а вторую будем использовать чтобы залить прошивку на первую. Если у Вас уже есть программатор STM32 можно обойтись и одной штукой.
Итого, нам потребуется:
- Программатор ST-Link v2 — 2 штуки
- Паяльник
- Немного проводов — как правило подходящие провода уже идут в комплекте с ST-Link
- Linux, для того, чтобы скомпилировать и залить прошивку
Компилируем прошивку
Итак, начнем с софтварной части — сборке прошивки для нашего ключа. Исходные коды прошивки можно найти в этом репозитории. Я бы посоветовал скачать последнюю стабильную версию(её можно найти во вкладке tags). Можно склонировать репозиторий либо скачать в виде zip архива. Разминаем пальцы, запускаем терминал и переходим в папку с проектом. Переходим в папку src
$ cd src
Для того чтобы скомпилировать и загрузить прошивку нам нужно установить несколько пакетов:
- arm-none-eabi-gcc
- arm-none-eabi-newlib
- openocd
Я использую пакетный менеджер pacman, в моей случае это виглядит вот так
$ sudo pacman -S arm-none-eabi-gcc
$ sudo pacman -S arm-none-eabi-newlib
$ sudo pacman -S openocd
Если Вы сидите на Ubuntu — используйте apt.
Напомню, что мы находимся в папке src проекта. Запускаем утилиту make и наблюдаем как компилируется наша прошивка.
$ make
После компиляции появится папка build, а в ней файл gnuk.elf — он то нам и нужен.
Загрузка прошивки на устройство
Теперь, когда у нас есть готовый файл с прошивкой нам нужно только загрузить её на устройство. Для этого, нам прийдется немного поработать паяльником. Не беспокойтесь, особых навыков тут не потребуется, всего-то припаять 4 проводка.
Итак, берем один из программаторов и стягиваем с него корпус. Выбранный программатор и будет нашим донором. Вот что мы найдем внутри
Обратите внимание на 4 контакта на плате. К ним нам нужно будет припаяться. Я рекомендую использовать для этого провода, которые идут в комплекте с ST-Link. Зачищаем провода с одного конца и припаиваем их к контактам. Если нам повезло, то на плате будут обозначения этих контактов.
"
Теперь, второй конец проводов подключаем к оставшемуся целым программатору. Если вам повезло, то просто подключаем провода в соответствии с надписями:
GND к GND
3.3V к 3.3V
SWDIO к SWDIO
SWCLK к SWCLK
Если надписей на плате не оказалось, то прийдется
На этом фото синий девайс — программматор, который мы используем только как программатор. Пусть вас не смущает то, что на фото в начале статьи у итогового девайса синий цвет корпуса. Это не он. Будущий девайс находиться справа.
Загружаем прошивку
Мы в шаге от успеха, осталось только загрузить прошивку. Открываем терминал, переходим в папку с нашей прошивкой(gnuk.elf).
Запускаем команду:
$ openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c 'program build/gnuk.elf verify reset exit'
Итак, теперь мы залили прошивку на наш девайс. Остался один шаг — запретить чтение памяти микроконтроллера. ВНИМАНИЕ! Это очень важный этап, который не позволит человеку, который украл ваш ключ, вытащить из него секретную информацию.
Для этого запускаем команду:
openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c init -c "reset halt" -c "stm32f1x lock 0" -c reset -c exit
Теперь все готово.
Собираем все обратно
Теперь, когда все шаги позади, осталось позаботиться о внешнем виде нашего девайса. Отпаиваем провода. Оригинальная панель контактов нам тоже больше не нужна, так что можно смело выпаять её.
Разламываем крепление и выпаиваем контакты по одному.
Теперь одеваем обратно корпус, и заклеиваем заднюю стенку подходящим куском пластика.
Как можно использовать
То, что мы собрали — эмулятор OpenPGP смарт карты. Такая карта может хранить в себе GPG, SSH ключи. Область применения довольно большая, например:
- Подписывание git коммитов — вопрос безопасности уже поднимался тут
- Хранение SSH ключей
- Шифрование и подписывание электронной почты по стандарту S/MIME — не проверял, но пишут что работает
- Вход в ОС без пароля — хороший гайд уже есть на хабре
Как видим, можно сделать много чего интересного и полезного
Пример использования для ssh
И под конец, давайте посмотрим как можно использовать этот ключ для хранения ssh-ключей и подключения к удаленному серверу.
Есть два пути — сгенерировать новый ключ или импортировать уже имеющийся ключ на токен.
Посмотрим оба варианта. Вставляем токен в USB. В dmesg можно посмотреть информацию о подключенном устройстве.
$ dmesg
[11073.599862] usb 1-3: USB disconnect, device number 11
[11311.647551] usb 1-3: new full-speed USB device number 12 using xhci_hcd
[11311.796881] usb 1-3: New USB device found, idVendor=234b, idProduct=0000, bcdDevice= 2.00
[11311.796884] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[11311.796885] usb 1-3: Product: Gnuk Token
[11311.796887] usb 1-3: Manufacturer: Free Software Initiative of Japan
Генерация нового ssh ключа
Важно понимать, что ключ генерируется на самом устройстве, а не на вашем компьютере. Так что, такой ключ вообще никогда не покидает пределы устройства.
Заходим в gpg:
$ gpg --card-edit
Открывается интерактивный режим gpg, включаем режим администратора коммандой admin:
gpg/card> admin
Далее запускаем команду генерации нового ключа:
gpg/card> generate
Далее идет стандартная процедура генерации ключа gpg. Во время которой вам будет предложено сохранить бекап ключа на диск. Разработчики рекомендуют делать бэкапы, но решать вам.
Единственно — аппаратно поддерживается генерация RSA ключей до 2048 бит. Если нужно 4096 — ключ прийдется генерировать на компьютере, а потом уже импортировать на само устройство.
Далее вам потребуются пин-коды. По умолчанию в прошивке зашиты следующие пин-коды:
CARD PIN — 123456
ADMIN PIN — 12345678
В будущем их обязательно нужно поменять.
Ключ может генерироваться немного дольше, чем если бы он генерировался непосредственно на компьютере, поэтому запасаемся терпением.
Импорт уже имеющегося ключа
Теперь посмотрим что делать, если у вас уже есть ssh-ключ, который вы хотели бы использовать.
Для этого импортируем ключ в gpg:
$ pem2openpgp temporary_id < id_rsa | gpg --import
Теперь нам нужно узнать id ключа. Для этого выводим список всех доступных в gpg:
$ gpg -K
И находим импортированный ключ:
sec> rsa2048 2020-02-05 [C]
DFEFF02E226560B7F5A5F2CAB19534F88F8FE4EC
Card serial no. = FFFE 87144751
uid [ unknown] temporary_id
В моем случае id ключа — DFEFF02E226560B7F5A5F2CAB19534F88F8FE4EC
Заходим в интерактивный режим редактирования ключа gpg:
$ gpg --edit-key DFEFF02E226560B7F5A5F2CAB19534F88F8FE4EC
И даем команду на копирование ключа на смарт карту:
gpg> keytocard
Все, ключ записан.
Экспорт публичного ключа в ssh формате
Достаем нужный публичный ключ с токена для того, чтобы положить его на сервер:
$ pkcs15-tool --list-keys
В моем случае вывод выглядит так:
Using reader with a card: Free Software Initiative of Japan Gnuk (FSIJ-1.2.15-87144751) 00 00
Private RSA Key [Signature key]
Object Flags : [0x03], private, modifiable
Usage : [0x20C], sign, signRecover, nonRepudiation
Access Flags : [0x1D], sensitive, alwaysSensitive, neverExtract, local
ModLength : 2048
Key ref : 0 (0x00)
Native : yes
Auth ID : 01
ID : 01
MD:guid : f3de5f55-d100-4973-d572-40d67e20f033
Тут нас интересует ID-шник ключа, в моем случае 01. Теперь экспортируем публичный ключ:
$ pkcs15-tool --read-public-key 01
Копируем публичный ключ в файлик pub.key:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyzHQIWEApliWYaf0T8jb
Vh2nc5+LklKXeuJFTN3BW2VqdrTw1rpKXiANWpi+qbtZhZ2nP3CJX6qoGobXyCOd
/iAiygFlyW4BwTQpnAm81IE9lPzfasOK7SBuKJ+ZbB4WpuYJRozgtt/gpWzmnWnW
84/CU9Lqbhz95v/C/DImSf6LiwVdmiEj4CUNInl5pY4trguDsSfkw1u8gGqSPEsD
ZXtlVRx8iBGi0JR02g9KTL4dDGocUtcTK8W0eY+BDbQSXfTGCy93v8sEyhdQjHs8
oDiwkvFQ86gYqwL5DJ7U/rFSO3A5X6zmkFFV8nJZjxB2qfE5aommtXxow4iPml3x
YwIDAQAB
-----END PUBLIC KEY-----
И конвертируем его в ssh-rsa формат:
$ ssh-keygen -f pub.key -i -mPKCS8
Получается публичный ключ в нужном формате:
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLMdAhYQCmWJZhp/RPyNtWHadzn4uSUpd64kVM3cFbZWp2tPDWukpeIA1amL6pu1mFnac/cIlfqqgahtfII53+ICLKAWXJbgHBNCmcCbzUgT2U/N9qw4rtIG4on5lsHham5glGjOC23+ClbOadadbzj8JT0upuHP3m/8L8MiZJ/ouLBV2aISPgJQ0ieXmlji2uC4OxJ+TDW7yAapI8SwNle2VVHHyIEaLQlHTaD0pMvh0MahxS1xMrxbR5j4ENtBJd9MYLL3e/ywTKF1CMezygOLCS8VDzqBirAvkMntT+sVI7cDlfrOaQUVXyclmPEHap8Tlqiaa1fGjDiI+aXfFj
Дальше идет стандартная процедура настройки ssh для входа по заданному ключу — нужно добавить ключ в файлик ~/.ssh/authorized_keys на удаленной сервере.
Конфигурирование ssh
Теперь, для того, чтобы зайти на сервер с использованием нашего токена нужно вызвать ssh с ключем -I и передать путь в драйверу токена. Наш токен совместим с одним из стандартных драйверов, так что будем использовать его
$ ssh -I /usr/lib/opensc-pkcs11.so martin@remotehost
Однако, удобнее будет воспользоваться config файлом (~/.ssh/config)
Добавляем в него следующие строки
Host digitalOceanServer
HostName 178.62.38.97
User root
PKCS11Provider /usr/lib/opensc-pkcs11.so
Теперь вызов ssh стал еще проще:
$ ssh digitalOceanServer
Как поменять стандартные пин-коды
Не менее важным шагом будет установка собственных пин-кодов. Для начала нужно понять, что тут используется два разных пин-кода:
- PIN-code — этот код используется при рутинных операциях со смарт картой — зашифровать что-то, подписать и т.д.
- Admin Pin-code — этот код нужен для того, чтобы изменять/удалять ключи и делать всякие подобные «админские» вещи
- Reset code — код, который позволит разблокировать токен, после трех неправильных попыток ввода PIN-кода. Его использование не обязательно, так что решать вам
У вас есть только 3 попытки для каждого из кодов. После чего токен блокируется.
Теперь приступим. Для этого опять заходим в интерактивный режим GPG:
$ gpg --card-edit
И вводим комманду passwd:
gpg/card> passwd
Откроется окно, где можно будет сменить пин-код от токена.
Теперь нужно поменять пин-код администратора. Для этого переходим в режим администратора:
gpg/card> admin
Вводим команду passwd снова:
gpg/card> passwd
Однако теперь она работает в расширенном режиме и нам предложат несколько вариантов:
1 - change PIN
2 - unblock PIN
3 - change Admin PIN
4 - set the Reset Code
Q - quit
Your selection?
Выбираем change Admin PIN и по стандартной схеме устанавливаем пароль администратора. Напомню, default Admin PIN — 12345678.
О безопасности устройства
Разумеется, за 3$ нельзя достичь секьюрности уровня ключей за 200+ долларов. Однако, собранный девайс можно рассматривать как ключ начального уровня. Насколько мне известно, заводские ключи Nitrokey Start используют такую же прошивку. В любом случае, использование такого устройства поднимет безопасность как минимум на уровень выше. Так что это отличный способ начать использовать аппаратные ключи.
Теперь поговорим немного о том, что будет еслы Вы потеряете этот ключ. Сам ключ защищен пин-кодом. После нескольких неудачных попыток ключ блокируется. Память самого устройства защищена от чтения, так что считать записанные в него ключи напрямую не получится.
Существуют некоторые виды атак на сам чип(например препарирование и подключение к нему микроэлектородов, что позволит измерять напряжение в любом месте чипа, в том числе и памяти), но они довольно затратные.
Так что, повторюсь еще раз, это отличный вариант начального уровня, и даже с ним безопасность выйдет на принципиально новый уровень.
Ссылки на полезные материалы
В процессе использования устройства наверняка возникнет потребность в дополнительной информации. Я собрал список хороших источников.
- Страница на сайте Debian
- Документация по токену
- Мануал по токену Nitrokey Start — в нем используется та же прошивка, так что советы подойдут и нам
Устройство которое мы собрали разрабатывается опенсорсным проектом GNUK (соб-сно так токен и называется), так что еще информации можно найти в гугле по запросу «GNUK».