[Из песочницы] Аппаратный ключ шифрования за 3$ — возможно ли это?

-qn7jnfoyjqizxzkhujdkdwcwhk.jpeg
Итоговый результат — ключ размером с флешку

Повсеместное шифрование и, как следствие, обилие ключей заставляет задуматься об их надежном хранении. Хранение ключей на внешних устройствах, откуда они не могут быть скопированы, уже давно считается хорошей практикой. Я расскажу о том, как за 3$ и 2 часа сделать такой девайс.

Кратко о принципах работы


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

  • Сохранить в файлике на рабочем столе — старый и проверенный годами способ записать что-то. Проблема в том, что помимо самого пользователя еще куча других программ имеет доступ к файлам на вашем рабочем столе. И если вы совершенно уверенны в том, что все они делают то, для чего они предназначены, не собирают о вас никакие данные и попросту не сливают их в сеть — эта статья не для вас.
  • Менеджеры паролей — по-сути такое же хранение в файлике, просто он теперь зашифрован и чтобы получить доступ нужно знать пароль. Уже неплохо, но раз менеджер паролей запускается на вашем компьютере, то незашифрованные ключи попадают в оперативную память, откуда могут быть украдены из-за какой-нибудь уязвимости ОС
  • Записать на бумажку — удивительно, но этот способ выглядит немного более безопасным. Ключи не хранятся на вашем компьютере, кишашем вирусами. Каждый раз, когда вам нужно использовать ключи вы просто вводите его с клавиатуры. Однако, если ваши ключи довольно длинные (как например ssh-ключи) это может стать проблемой. Да и кейлоггеры не дремлют


Как видно, основаная проблема состоит в том, что ключи либо непосредственно хранятся на вашем компьютере либо вводятся туда, посредством клавиатуры, флешки и т.п. Но, возразите вы, а как же тогда мой компьютер будет шифровать данные, если он не знает ключа? Правильный ответ — никак. Решение уже давно придумано. Главная идея в том, чтобы подключить к компьютеру специальное устройство, которое будет само шифровать данные. А компьютер будет только отправлять данные и получать результат. Так работают, например, многие смарт карты.

kwbrdm5ra5c6cbzc0thcwnk-cly.jpeg

Необходимые компоненты


Итак, приступим. Собирать наш девайс мы будем на недорогом и достаточно популярном микроконтроллере серии STM32. Конечно, можно самому изготовить печатную плату, но мы же хотим управиться за 2 часа? Так что возьмем уже готовое решение — программатор ST-Link v2. Выглядит этот девайс вот так.

zsykhgda844yz_1xyr1xxtccwjg.jpeg

Как ни странно, программатор для микроконтроллеров 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 проводка.

Итак, берем один из программаторов и стягиваем с него корпус. Выбранный программатор и будет нашим донором. Вот что мы найдем внутри

va-pzzkpf43ql4ecp0gnc2xp2xm.jpeg

Обратите внимание на 4 контакта на плате. К ним нам нужно будет припаяться. Я рекомендую использовать для этого провода, которые идут в комплекте с ST-Link. Зачищаем провода с одного конца и припаиваем их к контактам. Если нам повезло, то на плате будут обозначения этих контактов.

gx9v7vndydnn_2lh5rhmibp0pei.jpeg»

Теперь, второй конец проводов подключаем к оставшемуся целым программатору. Если вам повезло, то просто подключаем провода в соответствии с надписями:

GND к GND
3.3V к 3.3V
SWDIO к SWDIO
SWCLK к SWCLK

Если надписей на плате не оказалось, то прийдется тыкать наугад воспользоваться тестером. С его помощью можно легко найти GND (он соединен с GND на выводах программатора-донора), аналогично 3.3V. Остальные два провода прийдется подключать наугад. Благо, вариантов всего 2. В итоге, получается что-то похожее на это

yz9r8ekaabsxl15xkdmnxq6yyoy.jpeg

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

Загружаем прошивку


Мы в шаге от успеха, осталось только загрузить прошивку. Открываем терминал, переходим в папку с нашей прошивкой (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   


Теперь все готово.

Собираем все обратно


Теперь, когда все шаги позади, осталось позаботиться о внешнем виде нашего девайса. Отпаиваем провода. Оригинальная панель контактов нам тоже больше не нужна, так что можно смело выпаять её.

pwwqetghhzfjmsp95of6thl7700.jpeg

Разламываем крепление и выпаиваем контакты по одному.

qjbdzzru_bsnvafujtwduu8j2ks.jpeg

Теперь одеваем обратно корпус, и заклеиваем заднюю стенку подходящим куском пластика.

Как можно использовать


То, что мы собрали — эмулятор 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 используют такую же прошивку. В любом случае, использование такого устройства поднимет безопасность как минимум на уровень выше. Так что это отличный способ начать использовать аппаратные ключи.

Теперь поговорим немного о том, что будет еслы Вы потеряете этот ключ. Сам ключ защищен пин-кодом. После нескольких неудачных попыток ключ блокируется. Память самого устройства защищена от чтения, так что считать записанные в него ключи напрямую не получится.
Существуют некоторые виды атак на сам чип (например препарирование и подключение к нему микроэлектородов, что позволит измерять напряжение в любом месте чипа, в том числе и памяти), но они довольно затратные.

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

Ссылки на полезные материалы


В процессе использования устройства наверняка возникнет потребность в дополнительной информации. Я собрал список хороших источников.
Устройство которое мы собрали разрабатывается опенсорсным проектом GNUK (соб-сно так токен и называется), так что еще информации можно найти в гугле по запросу «GNUK».

© Habrahabr.ru