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

Повсеместное шифрование и, как следствие, обилие ключей заставляет задуматься об их надежном хранении. Хранение ключей на внешних устройствах, откуда они не могут быть скопированы, уже давно считается хорошей практикой. Я расскажу о том, как за 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 проекта.
Запускаем configure скрипт

$ ./configure --vidpid=234b:0000

Запускаем утилиту make и наблюдаем как компилируется наша прошивка.

$ make

После компиляции появится папка build, а в ней файл gnuk.elf — он-то нам и нужен.

Загрузка прошивки на устройство


Теперь, когда у нас есть готовый файл с прошивкой нам нужно только загрузить её на устройство. Для этого, нам придется немного поработать паяльником. Не беспокойтесь, особых навыков тут не потребуется, всего-то припаять 4 проводка.

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



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

"

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

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

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



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

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


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

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