Этот блог является соавтором Элиада Цфадиа в рамках нашей работы в IBM Research - Хайфа.

Анклавы Intel® SGX обеспечивают аппаратное обеспечение конфиденциальности и гарантии целостности для выполнения вычислений. Это достигается главным образом за счет шифрования всей информации на выходе из ЦП, эффективно защищая данные в памяти от внешних наблюдателей.

Но каковы накладные расходы на выполнение вычислений внутри анклава? Можно было бы ожидать некоторых накладных расходов из-за дополнительной сложности шифрования и дешифрования. Кроме того, на производительность могут влиять дополнительные меры безопасности, такие как тесты целостности и ограничения использования памяти. В этом блоге мы пытаемся пролить свет на этот вопрос, представляя результаты тестов различных операций, выполняемых внутри и за пределами анклавов.

Накладные расходы на производительность могут возникать по двум основным причинам: во-первых, это накладные расходы на выполнение инструкций ЦП и доступ к зашифрованной памяти в анклаве. Второй - накладные расходы, связанные с входом в анклав и выходом из него. Анклавы вызываются только через специальный интерфейс, называемый ECALLs (определенный в файле «edl»). Известно, что сообщения ECALL влияют на производительность из-за переключений контекста ЦП, и это ясно видно в наших тестах ниже.

Наши тесты были протестированы в следующей конфигурации: Мы использовали ноутбук Lenovo с 8-ядерным процессором Intel® Core (TM) i7–6820HQ с частотой 2,70 ГГц, с 16 ГБ оперативной памяти DDR4 2133 МГц и работающей на ОС Ubuntu 16.04. Мы использовали библиотеки Intel® SGX Linux 2.0 и SGXSSL (взяты из репозитория Intel-sgx-ssl git 29 ноября 2017 г.).

Примечание. Все тесты, обсуждаемые в этом блоге, выполняются в однопоточном режиме.

Мы протестировали накладные расходы на использование анклавов для ряда вычислительных задач, уделяя особое внимание криптографическим функциям, которые, вероятно, будут выполняться в анклавах. В частности, мы протестировали операции хеширования и шифрования. Однако, поскольку это сложные вычисления, мы начинаем с более простого теста, который выполняет очень простое вычисление (с единственным требованием, чтобы он касался всего входного буфера).

Тестирование простой функции

Мы протестировали накладные расходы на поиск максимального 4-байтового целого числа в заданном массиве байтов (т. Е. Мы обрабатываем массив из N байтов как массив из N / 4 целых чисел) .

Мы реализовали четыре версии функции find_max:

1. Обычная функция, работающая в ненадежной области, как если бы ее запускали без анклавов.

2. Копирование и вычисление версии - массив копируется в зашифрованную память анклава, а затем по этому массиву определяется максимальное значение. Это реализуется с помощью ECALL, в котором входной массив объявляется с так называемой опцией «in» в файле edl.

3. Вычислить вариант с зашифрованной памятью - в этом варианте мы находим максимум в массиве, который находится в зашифрованной памяти анклава. Массив подготавливается перед ECALL (предыдущим ECALL). Это аналогично варианту 2, но не включает в измерения начальную операцию копирования буфера.

4. Вычислить в памяти открытого текста - в этом варианте ECALL находит максимум заданного внешнего входного массива, не перемещая его в память анклава (а именно, обращаясь только к памяти открытого текста). Это достигается объявлением массива с опцией «user_check» в файле edl.

Из 3 вариантов анклава вариант 4 должен быть самым быстрым, поскольку он не требует, чтобы массив дешифровался механизмом шифрования памяти (MEE) SGX. Варианты 2 и 3 действительно требуют дешифрования MEE для выполнения вычислений (в то время как вариант 2 также включает шифрование MEE, а также дешифрование).

Обратите внимание, что, оценивая производительность этих трех вариантов, мы получаем довольно хорошее представление об ожидаемых накладных расходах на переключение контекста ECALL, накладных расходах операций MEE и о накладных расходах при копировании данных с использованием «in» (или « out ») объявления в edl. Эти наблюдения должны относиться к другим вычислениям, а не только к функции «find_max».

Для оценки производительности каждого варианта мы сравнили пропускную способность вызовов с использованием массивов разного размера. Результаты на рисунке 1 показывают пропускную способность (МБ, обрабатываемых в секунду) как функцию размера массива. Первое наблюдение заключается в том, что для небольших массивов при выполнении функции в анклаве возникают огромные накладные расходы, которые, вероятно, вызваны накладными расходами на переключение контекста при входе в анклав и выходе из него. Эти накладные расходы становятся незначительными для буферов большего размера, а разрыв между ненадежной и двумя более быстрыми доверенными версиями в основном закрывается массивами размером более 256 КБ.

Есть еще три интересных явления. Для массивов размером более 8 МБ мы видим снижение пропускной способности в ECALL, который работает с зашифрованной памятью анклава. Мы предполагаем, что это может быть связано с дополнительными промахами кэша L3 при чтении локального массива анклава (в нашей настройке размер кэша L3 составляет 8 МБ). Для массивов размером более 64 МБ производительность резко падает из-за ограничений кеша страниц анклава (EPC). Наконец, ECALL, использующий параметр «in», имеет значительное замедление для массивов размером более 64 КБ. Наше ограниченное исследование показывает, что это может быть вызвано замедлением при вызове функции memcpy внутри анклава с буферами размером более 64 КБ.

Тестирование SHA256

Мы переходим к исследованию накладных расходов, связанных с выполнением более тяжелых и более интересных задач внутри анклава, где мы сначала сосредотачиваемся на самой быстрой реализации ECALL, которая использует объявление «user_check» в файле edl как для входных, так и для выходных буферов. Начнем с изучения накладных расходов на вычисление SHA256. В ненадежной области мы протестировали реализацию SHA256 в openssl. В доверенной области (то есть внутри анклава) мы протестировали реализацию Intel-sgxssl алгоритма SHA256, которая, в свою очередь, вызывает openssl. Мы также протестировали функцию sgx_sha256_msg, предоставляемую Intel-sgxsdk API.

Результаты на рисунке 2 показывают, что, как и ожидалось, у нас все еще есть огромный разрыв в пропускной способности вычисления sha256 (msg) для сообщений небольшого размера. Однако по мере увеличения размера сообщений разрыв не закрывается полностью даже для сообщений очень большого размера. Пропускная способность для больших сообщений: openssl - 435 МБ / с, sgxsdk - 350 МБ / с (80% пропускной способности openssl) и sgxssl - 295 МБ / с (67% пропускной способности openssl). Мы подозреваем, что разница связана с разными реализациями функции, используемой при работе в анклаве (а не из-за естественного замедления фактических вычислений).

Кроме того, мы также провели аналогичный тест SHA256, в котором входное сообщение хранилось в локальной памяти анклава, а не в буферах ввода открытого текста из ненадежной памяти. В отличие от теста find_max, в котором мы наблюдали снижение пропускной способности для входных данных размером более 8 МБ, мы не заметили этого здесь, и результаты были похожи на буферы ввода с открытым текстом. Это можно объяснить тем, что общая пропускная способность в этом тесте намного ниже.

Тестирование шифрования AES

Наконец, мы протестировали накладные расходы на шифрование и дешифрование сообщений. В частности, мы сосредоточились на тестировании шифрования AES128-GCM. В доверенной зоне мы протестировали три библиотеки: sgxsdk, sgxssl и библиотеку шифрования, используемую в проекте с открытым исходным кодом Opaque, который можно найти здесь. В ненадежной области мы протестировали две библиотеки: openssl и Opaque (мы также пытались протестировать библиотеку sgxsdk в ненадежной области, но запустить ее не удалось). Как и в предыдущих тестах, для каждой протестированной библиотеки в доверенной области мы создали ECALL вида

aes128_gcm_encrypt (uint8_t * in_buf, uint32_t in_buf_len, uint8_t * out_buf, uint32_t out_buf_len)

Сначала мы сосредоточились на самой быстрой реализации ECALL, в которой как «in_buf», так и «out_buf» объявлены с опцией «user_check».

Результаты, показанные на рисунке 3, несколько удивительны и сложнее, чем можно было бы надеяться:

· Версия sgxsdk обеспечивает максимальную пропускную способность 2150 МБ / с (около 43% недоверенных пропускных способностей). Это связано с тем, что по умолчанию он запускает неоптимизированную версию библиотеки Intel IPP Crypto, которая не использует аппаратную оптимизацию Intel AES-NI. Нам сказали, что путем ручной компиляции и связывания SDK с оптимизированным двоичным кодом IPP Crypto для SGX можно добиться желаемого ускорения, но мы не пробовали этого.

· Реализация sgxssl предположительно запускает тот же код, что и ненадежная версия openssl. Однако его производительность полностью падает и достигает пропускной способности только 110 МБ / с (около 2% от ненадежной пропускной способности). ОБНОВЛЕНИЕ. Эта проблема исследована и устранена корпорацией Intel. См. Обновление внизу этого блога.

· Единственным кодом, который работал достаточно хорошо как внутри, так и за пределами анклава, была библиотека шифрования Opaque. Здесь мы видим ожидаемые тенденции, которые мы наблюдали в более простых случаях: для коротких сообщений у нас есть огромный разрыв между надежной и ненадежной пропускной способностью, что вызвано накладными расходами на переключение контекста. Однако для сообщений большого размера доверенная версия Opaque почти закрывает разрыв с ненадежными библиотеками, достигая пропускной способности 4900 МБ / с.

Кроме того, мы также запустили вариант теста шифрования «локальный ввод», в котором входящие сообщения находились в зашифрованной памяти анклава, а не в буферах ввода открытого текста из ненадежной памяти. Результаты на рисунке 4 показывают, что «доверенная» непрозрачная библиотека, которая обеспечивает лучшую пропускную способность в доверенной области, страдает от снижения пропускной способности для сообщений размером более 8 МБ, что аналогично тому, которое мы видели в find_max тест.

Обратите внимание, что результаты дешифрования (а не шифрования) были очень похожи.

Выводы

С положительной стороны, мы видим, что при работе с большими входными данными код, работающий внутри анклавов, может достигать очень высокой пропускной способности, наравне с кодом, работающим вне анклавов. Для коротких входных данных существуют значительные накладные расходы на вызовы анклава. Однако такие эффекты могут быть смягчены, по большей части, с помощью методов, которые максимально избегают ECALL и OCALL. См., Например, статью Eleos: Exit-Less OS Services для анклавов SGX »М. Оренбаха, М. Минкин, П. Лифшиц, М. Зильберштейн на выставке Eurosys 2017 или статью Восстановление потерянных циклов с помощью HotCalls: быстрый интерфейс для безопасных анклавов SGX », О. Вайсе, В. Бертакко, Т. Остин на ISCA 2017.

С другой стороны, мы видим, что с анклавами SGX нет ничего простого. Во-первых, использование криптографических библиотек по умолчанию, предоставляемых Intel®, или любой библиотеки, перенесенной для SGX, не гарантирует оптимальной производительности. Во-вторых, даже если у нас есть код, который обеспечивает оптимальную пропускную способность при доступе к данным в виде открытого текста, он может не достичь этого при доступе к локальной памяти анклава. Фактически, при работе с памятью анклава, кажется, есть ограниченная зона наилучшего восприятия, когда ввод не должен быть ни слишком маленьким, ни слишком большим.

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

ОБНОВЛЕНИЕ (март 2018 г.)

Проблема sgxssl была исследована и решена Intel: «Основная причина была связана с потоком автоматического запуска OpenSSL и его интеграцией в стек SGX SW. OpenSSL не получил возможности ЦП для определения наилучшей реализации AES-GCM для данной платформы. Поэтому из-за отсутствия информации о платформе OpenSSL имеет запасной вариант для базовой реализации C (которая вообще не оптимизирована).
Решение: для достижения максимальной производительности разработчики анклава должны явно инициализировать криптографическую библиотеку OpenSSL. Процесс автоматического запуска будет исправлен в будущих выпусках ».

Проблема и способы ее решения были обновлены в документации sgxssl здесь.

Повторный запуск тестов с этим исправлением приводит к тому, что поведение sgxssl очень близко к поведению библиотеки Opaque, и демонстрирует такое же общее поведение. На рисунках 5 и 6 показаны эти новые тесты (только для доверенных и ненадежных баз кода OpenSSL).

  • Эта работа частично проводилась в рамках европейского проекта H2020 RestAssured и является частью исследования, проводимого в группе облачных хранилищ в IBM Research - Хайфа в отношении использования Intel SGX в облаке. Вы можете прочитать о нашем исследовании SPARK SQL и SGX здесь.