Использование шифрования для защиты битового потока Xilinx 7-й серии

Когда возникла необходимость защитить устройство от нежелательного использования, оказалось, что на эту тему мало информации. В конце концов, процесс перехода по множеству ссылок, которые выдал поисковик, вывел на XAPP1239, UG470 и XAPP1084. Перед прочтением этой статьи лучше с ними ознакомится, так будет понятнее о чём идёт речь. Ниже будут пошагово описаны процессы создания зашифрованного bitstream и конфигурации ПЛИС на отладочной плате ARTY A7 и XC7K325T KINTEX-7 на кастомной плате для программирования этим зашифрованным bitstream.

Дисклеймер
Здесь будут описаны конкретный опыт за последние пару дней и несколько экспериментов с отладочными платами. Это не опыт и эксперименты профессионального разработчика под ПЛИС. Может быть, это прочитают специалисты, которые хорошо разбираются в этой теме и дадут конструктивную критику.

Введение

Сначала поэкспериментируем с ARTY A7 и воспользуемся её BBRAM. Даже, несмотря на то что батарейка там не предусмотрена, она подойдёт для того, чтобы набить руку. Далее будет описан процесс (с кое-какими скриншотами и комментариями) программирования eFUSE и программирования flash зашифрованным bitstream.

Работа будет вестись в Vivado 2021. Для тестов использованы несколько старых дизайнов с использованием MicroBlaze, который запрограммирован в Vitis 2021. Но от Vitis потребуется только сгенерированный .elf, с прикреплением которого могут возникнуть сложности, если Вы привыкли работать с tcl в части соединения .bit и .elf с помощью утилиты updatemem. Но обо всём по порядку.

Генерация шифрованного bitstream

Для этого необходимо открыть синтезированный дизайн (Open Synthesized Design)

Скрытый текст

Рис. 1. Open Synthesized Design

Рис. 1. Open Synthesized Design

В меню Tools → Edit Device Properties необходимо перейти на вкладку Encryption. На вкладке Encryption в поле Enable Bitstream Encryption необходимо указать «YES» (там всего два варианта), а в поле Select location of encryption key необходимо выбрать где будут храниться ключи (которые сгенерированы самой Vivado или самостоятельно). На данном этапе в качестве тренировки местом хранения указана BBRAM, но память эта энергозависимая! Необходимо использовать специальную батарейку для такого подхода!

На платах автора батарейка не предусмотрена. Эксперименты с BBRAM велись исключительно, для того чтобы потренироваться. Далее будет рассмотрен рабочий вариант с хранением ключей в eFUSE.

Скрытый текст

Рис. 2. Edit Device Properties

Рис. 2. Edit Device Properties

Рис. 3. Encryption

Рис. 3. Encryption

Key Settings

На вкладке Encryption есть поля:

Эти поля можно оставить пустыми и тогда Vivado сгенерирует ключи сама, а можно заполнить HMAC, key 0 и CBC (с input encryption file автор не экспериментировал). И тогда шифрование будет более надёжным. Как написано в XAPP1239, Вам необходимо решить, от кого Вы защищаетесь? От комнатного белого хакера или от государственного учреждения противника?

Замечание автора
К шифрованию это никак не относится, но повлияет на скорость загрузки bitstream из flash при включении питания. В меню Edit Device Properties есть вкладка Configuration, а на ней поле Configuration Rate (MHz). Лучше поменять стандартное значение на значение, которое поддерживает Ваша flash, например, на 33 MHz. А в configuration Modes включить Master SPI x4.

Автор этого не сделал сразу и место уже привычной ему на тот момент загрузки за 7 секунд шифрованный bitstream стал загружаться за 30. Это же никуда не годится!

Скрытый текст

Рис. 4. Confuguration Rate

Рис. 4. Confuguration Rate

Рис. 5. Configuration Modes

Рис. 5. Configuration Modes

После всех этих настроек нужно сохранить Constraints (а если этого не сделать, то Vivado сама предложит это сделать) и сгенерировать новый bitstream (Generate Bitstream). С такими настройками он будет уже зашифрованный. Теперь, если зайти в .xdc файл (так называемые constraints) там появятся новые строки set_property BITSTREAM.ENCRYPTION.ENCRYPT YES [current_design]. И если Вы сами указывали ключи, а не доверили это Vivado появятся ещё строки с этими ключами.

Скрытый текст

Рис. 6. Generate Bitstream

Рис. 6. Generate Bitstream

Замечание автора
Если Вы работаете с MicroBlaze, то можете столкнуться с некоторыми особенностями. Всё зависит от того, как Вы соединяете .bit и .elf файлы. Когда автор начинал экспериментировать с Vivado и Vitis, то воспользовался прекрасной
статьёй с ресурса fpga-systems.ru. Как хорошо, что есть люди, которые описывают, казалось бы, простые вещи. Но они простые когда их делаешь уже сотый раз, а когда надо сгенерировать бинарный файл для загрузки ПЛИС с flash и ещё ни разу этого не делал это не кажется чем-то простым. На fpga-systems.ru описаны два способа соединения .bit и .elf и автору больше приглянулся способ с утилитой updatemem, но вот незадача — она не работает с зашифрованным bitstream. Если погуглить, то можно найти вот такой комментарий от специалиста AMD. Тогда необходимо обратиться ко второму способу соединения .bit и .elf через графический интерфейс.

Немного скриншотов для Vivado 2021 не повредят:

  1. В Design Sources правой кнопкой мыши по .bd и кликаем по Associate ELF Files;

  2. В открывшемся диалоговом окне указать путь до Вашего .elf;

Скрытый текст

Рис 7. Associate ELF Files

Рис 7. Associate ELF Files

Рис. 8. Select ELF Files

Рис. 8. Select ELF Files

  1. Теперь в иерархии проекта появился необходимый .elf и вымахиваться tcl скриптами не получится.

Скрытый текст

Рис. 9. Файл прошивки для MicroBlaze прикреплён к проекту Vivado

Рис. 9. Файл прошивки для MicroBlaze прикреплён к проекту Vivado

Программирование отладочной платы

Если открыть Hardware Manager и попытаться запрограммировать ПЛИС зашифрованным bitstream без подготовки к этому ПЛИС, то процесс завершится с ошибкой.

Рис. 10. Ошибка при попытке запрограммировать не подготовленную ПЛИС зашифрованным bitstream

Рис. 10. Ошибка при попытке запрограммировать не подготовленную ПЛИС зашифрованным bitstream

Поэтому в Hardware Manager нажимаем правой кнопкой мыши по ПЛИС и заходим в Program BBR Key

Рис. 11. Program BBR Key

Рис. 11. Program BBR Key

При успешной генерации зашифрованного bitstream был сформирован файл .nky и в открывшемся диалоговом окне необходимо указать к нему путь в поле AES key file (.nky). Обычно этот файл находится в каталоге impl_1. При подгрузке этого файла будет выведен AES Key 0, его необходимо сверить с тем, что Вы указали при настройке генерации bitstream. В случае экспериментов с BBRAM и неподключенной батарейкой ничего страшного не произойдёт, но при использовании eFUSE обратной дороги не будет, к ключам следует учиться относиться очень внимательно! Когда всё будет верно, необходимо нажать «Ok». При этом в Tcl Console будет выведена информация об успешном программировании ключей.

Скрытый текст

Рис. 12. Program BBR Key. На скриншоте поле пустое, но когда путь до .nky файла указан, здесь появятся байты.

Рис. 12. Program BBR Key. На скриншоте поле пустое, но когда путь до .nky файла указан, здесь появятся байты.

Рис. 13. Ключ успешно запрограммирован

Рис. 13. Ключ успешно запрограммирован

Теперь можно загрузить зашифрованный bitstream на настроенную ПЛИС и работать как обычно.

Промежуточные итоги первого эксперимента

Зашифровать bitstream и запрограммировать им ПЛИС оказалось не так уж и сложно. Теперь если сохранить бинарник в загрузочную flash (из которой прошивка загружается при подаче питания), его по-прежнему можно считать с помощью Readback Configuration Memory Device в Hardware Manager.

Рис. 14. Как стырить незашифрованную прошивку шаг №1

Рис. 14. Как стырить незашифрованную прошивку шаг №1

Запрограммировать другую точно такую отладочную плату Arty A7 этим бинарником уже не получится. Если, конечно, предварительно не подготовить ПЛИС для работы с зашифрованным bitstream с помощью специальных ключей шифрования. Но пока эти ключи никому неизвестны, кроме Вас, как-то использовать этот зашифрованный бинарный файл будет достаточно проблематично.

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

eFUSE для хранения ключей шифрования

Для тренировки BBRAM без батарейки хороша тем, что любые изменения восстановятся после сброса питания. При работе с eFUSE надо быть внимательным, потому что эта память прожигается только один раз. Все достоинства и недостатки, а также критерии выбора того где лучше всего хранить ключи для Вашего проекта исчерпывающе хорошо изложены в XAPP1239.

Bitstream для eFUSE

Генерация bitstream настраивается абсолютно точно так же, как и для BBRAM, только для хранения ключей необходимо указать в поле Select location of encryption key «EFUSE»

Рис. 15. Выбираем eFUSE для хранения ключей шифрования

Рис. 15. Выбираем eFUSE для хранения ключей шифрования

Сохраняем. В .xdc теперь set_property BITSTREAM.ENCRYPTION.ENCRYPTKEYSELECT EFUSE. И генерируем bitstream (Generate Bitstream). Опять же запрограммировать этим ПЛИС без подготовки не получится.

Program eFUSE Registers

Как и раньше, в Hardware Manager правой кнопкой мыши нажать по ПЛИС, но теперь необходимо выбрать Program eFUSE Registers.

Рис. 16. Подготовка ПЛИС к работе с зашифрованным bitstream и ключами в eFUSE

Рис. 16. Подготовка ПЛИС к работе с зашифрованным bitstream и ключами в eFUSE

В открывшемся wizard необходимо активировать checkbox Enable AES key programming и указать путь до .nky файла, который обычно в каталоге impl_1. Проверьте ещё раз ключ на соответствие тому, что Вы указали при настройке генерации bitstream, память eFUSE прожигается один раз! При желании можно запрограммировать user bits (стрелки 2, 3 и 4). Туда можно поместить номер версии ПО или версию схемотехники, или дату (как автор), или вообще ничего.

Рис. 17. Wizard для программирования eFUSE

Рис. 17. Wizard для программирования eFUSE

На следующей странице устанавливаются биты FUSE_CNTL. Необходимо выставить эти биты, в зависимости от кого Вы решили защититься.

Заметка от автора
Автор решил пока не защищаться от мнимых врагов и оставил checkbox Enable control register programming не активным. Или нет …

Скрытый текст

Рис. 18. Но это действительно можно оставить в таком виде, и всё будет зашифровано, и будет работать

Рис. 18. Но это действительно можно оставить в таком виде, и всё будет зашифровано, и будет работать

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

Рис. 19. Export information Program eFUSE Registers

Рис. 19. Export information Program eFUSE Registers

На следующей странице wizard выведет информацию о ключе шифрования (проверьте его еще раз на всякий случай), информацию, которая будет запрограммирована в USER registers (там просто какая-то полезная информация или нули по умолчанию) и путь до экспортированного файла с настройками.

С Вашего позволения здесь не будет скрина, чтобы не скомпрометировать ключ шифрования автора, но кроме кнопки Finish там и нажать-то него.

Потом Vivado предупредит о невозможности перепрограммирования eFUSE.

Рис. 20. Финальное предупреждение от Vivado перед прожиганием eFUSE

Рис. 20. Финальное предупреждение от Vivado перед прожиганием eFUSE

Мы были внимательны и во всём уверены, поэтому нажмём Ok и получим в консоль сообщения об успешном прожигании eFUSE. Теперь можно смело генерировать файл для загрузочной flash, программировать им загрузочную flash и быть уверенным, что устройство теперь по-простому не клонируешь.

Заметка от автора
Для генерации файла для загрузочной flash автор пользуется GUI Vivado.

  1. Выбирать формат (всегда bin);

  2. указать для какой flash;

  3. место и имя для выходного файла;

  4. Interface (должен совпадать с тем, что указано в Configuration Modes);

  5. Активировать checkbox;

  6. Указать путь к необходимому bitstream;

  7. Сгенерировать файл.

Скрытый текст

Рис. 21. GUI для генерации файла для загрузочной flash

Рис. 21. GUI для генерации файла для загрузочной flash

Загрузка в flash происходит в стандартном режиме.

Итоги

После нескольких экспериментов получилось сгенерировать зашифрованный bitstream и запрограммировать им ПЛИС даже после сброса питания.

Заметка от автора
У автора в распоряжении было четыре одинаковых кастомных платы с Kintex-7 на борту. Запрограммировав таким образом (ключи в eFUSE) одну из плат и считав данные из загрузочной flash с помощью Readback Configuration Memory Device у автора не получилось запрограммировать зашифрованным файлом другие ПЛИС без программирования ключей шифрования в ПЛИС.

А как Вы защищаете свои прошивки?

P. S.

В 2020 году в журнале ХАКЕР вышла статья об уязвимости в чипах FPGA Xilinx. Тогда я не придал особого значения, но теперь прочитал оригинальную статью, и у меня возникла масса вопросов. Может быть, Вы про это слышали или специалист в этой области, тогда, пожалуйста, напишите насколько реально взломать описанную выше защиту?

Спасибо.

С. Н.

© Habrahabr.ru