Использует ли код скомпилированной библиотеки Crypto ++, использующий шифрование AES / GCM, инструкции Intel AES-NI?

Я реализую AES256 / GCM шифрование и аутентификация с использованием библиотеки Crypto ++. Мой код скомпилирован с использованием Visual Studio 2008 как проект C ++ / MFC. Это несколько более старый проект, который использует предыдущую версию библиотеки, Cryptopp562,

Мне любопытно, будет ли полученный скомпилированный код использовать Intel AES-NI инструкции? И если так, что произойдет, если аппаратное обеспечение (старый процессор) не поддерживает его?

РЕДАКТИРОВАТЬ: Вот пример кода, с которым я его тестирую:

int nIV_Length = 12;
int nAES_KeyLength = 32;
BYTE* iv = new BYTE[nIV_Length];
BYTE* key = new BYTE[nAES_KeyLength];

int nLnPlainText = 128;
BYTE* pDataPlainText = new BYTE[nLnPlainText];

CryptoPP::AutoSeededRandomPool rng;
rng.GenerateBlock(iv, nIV_Length);

CryptoPP::GCM<CryptoPP::AES>::Encryption enc;
enc.SetKeyWithIV(key, nAES_KeyLength, iv, nIV_Length);

BYTE* pDataOut_AES_GCM = new BYTE[nLnPlainText];
memset(pDataOut_AES_GCM, 0, nLnPlainText);

BYTE mac[16] = {0};
enc.EncryptAndAuthenticate(pDataOut_AES_GCM, mac, sizeof(mac), iv, nIV_Length, NULL, 0, pDataPlainText, nLnPlainText);

delete[] pDataPlainText;
delete[] pDataOut_AES_GCM;
delete[] key;
delete[] iv;

0

Решение

Если вы запускаете код, содержащий инструкции AES-NI на оборудовании x86, которое не поддерживает эти инструкции, вы должны получить недопустимые ошибки инструкций. Если код не делает что-то умное (например, смотрит на CPUID, чтобы решить, следует ли запускать оптимизированный код AES-NI, или что-то еще), это также можно использовать для определения, действительно ли используются инструкции AES-NI.

В противном случае вы всегда можете использовать отладчик и установить контрольные точки в инструкциях AES-NI, чтобы увидеть, использует ли ваш процесс эту часть кода.

В соответствии с Примечания к выпуску Crypto ++ Поддержка AES-NI была добавлена ​​в версии 5.6.1. Глядя на исходный код версии 5.6.5 Crypto ++, если поддержка AES-NI была включена во время компиляции, то она использует проверки во время выполнения ( HasAESNI() функция, вероятно, с использованием CPUID), чтобы решить, использовать ли эти встроенные функции. Увидеть rijndael.cpp (а также cpu.cpp для кода CPUID) в его исходном коде для деталей.

2

Другие решения

Мне любопытно, будет ли полученный скомпилированный код использовать инструкции Intel AES-NI?

В Crypto ++ 5.6.1 добавлена ​​поддержка AES-NI и Carryless Multiplies в GCM. Используется, когда выполняются два или три условия. Во-первых, вы используете версию библиотеки с поддержкой. С домашней страницы под Новости (или ПРОЧТИ МЕНЯ):

  • 09.08.2010 — Выпущена версия 5.6.1

    • добавлена ​​поддержка наборов команд AES-NI и CLMUL в AES и GMAC / GCM

Во-вторых, компилятор, ассемблер и компоновщик должны поддерживать инструкции. Для Crypto ++ это означает, что вы используете как минимум MSVC 2008 SP1, GCC 4.3 и Binutils 2.19. Для MSVC, если вы посмотрите на config.h, его охраняют следующим образом (__AES__ есть для GCC и друзей тоже)

#if ... (_MSC_FULL_VER >= 150030729) ...
#define CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE 1
#else
#define CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE 0
#endif

Вы можете искать _MSC_FULL_VER числа в Версия для Visual Studio. По иронии судьбы, я никогда не видел подобную страницу в MSDN, хотя пакеты обновления имеют значение. Вы должны перейти на китайский сайт. Например, проверенные итераторы появились в VS2005 SP1 (IIRC).

Для Linux и GCC-совместимых GNUmakefile проверяет версию компилятора и ассемблера. Если они слишком старые, то makefile добавляет CRYPTOPP_DISABLE_AESNI в командной строке, чтобы отключить поддержку, даже если __AES__ определено.

CRYPTOPP_DISABLE_AESNI появляется чаще, чем вы думаете. Например, если вы загружаете OpenBSD 6.0 (текущая версия), то
CRYPTOPP_DISABLE_AESNI будет присутствовать, потому что их ассемблер так стар. Они в основном застряли в версии своих инструментов до GPL-2 (очевидно, они не согласились с изменениями лицензии).

В-третьих, ЦП поддерживает инструкции AES и SSE4 (причина инструкций SSE4 поясняется ниже). Эти проверки выполняются во время выполнения, и вызывается интересующая функция. HasAES() от cpu.h (есть также HasSSE4()):

//! \brief Determines AES-NI availability
//! \returns true if AES-NI is determined to be available, false otherwise
//! \details HasAESNI() is a runtime check performed using CPUID
inline bool HasAESNI()
{
if (!g_x86DetectionDone)
DetectX86Features();
return g_hasAESNI;
}

Предостережение о Item (3) — это библиотека, которая должна быть скомпилирована с поддержкой Item (2). Если Item (2) не включает поддержку времени компиляции, то Item (3) не может предложить поддержку времени выполнения.

Что касается Item (3) и поддержки во время выполнения, нам недавно пришлось его настроить. Кажется, что некоторые младшие процессоры Atom, такие как D2500, имеют SSE2, SSE3, SSSE3 и AES-NI, но не SSE4.1 или SSE4.2. По словам Intel ARK, это необязательная конфигурация процессора. Мы получили одно сообщение об ошибке о недопустимой инструкции SSE4 в пути кода AES-NI, поэтому нам пришлось добавить HasSSE4() проверять. Увидеть PR 172, Проверьте поддержку SSE4 перед использованием инструкции SSE4.1.


И если так, что произойдет, если аппаратное обеспечение (старый процессор) не поддерживает его?

Ничего такого. Используется стандартная реализация CXX, а не AES с аппаратным ускорением.

Возможно, вам будет интересно узнать, что у нас также есть другое аппаратное ускорение AES, включая ARMv8 Crypto и VIA Padlock. Мы также предоставляем другое аппаратное ускорение, такое как CRC32, Carryless-Multiplies и SHA. Все они функционируют одинаково — поддержка времени компиляции переводится в поддержку времени выполнения.


(Комментарий): Я просто установил точку останова для метода DetectX86Features в cpu.cpp … и он никогда не срабатывал …

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

Во-вторых, есть глобальный генератор случайных чисел, к которому GlobalRNG(), GlobalRNG() AES в режиме OFB. Когда инициализаторы запускаются для test.cpp блок перевода, GlobalRNG() создается, что вызывает DetectX86Features() бежать очень рано (до того, как контроль входит main).

Возможно, вам повезет с наблюдением деталей низкого уровня с WinDbg.


Стоит также упомянуть, что AES / GCM может быть ускорен путем чередования AES с GCM. Я считаю, что идея состоит в том, чтобы выполнить 4 раунда вычисления ключа AES и 1 CLMUL параллельно. Crypto ++ не пользуется этим, но OpenSSL использует эту возможность. Я не знаю, что делают Botan или mbedTLS.

1

Просто чтобы закончить мой вопрос, вот мои выводы.

Метод, который вилки выполнение на поддерживаемое оборудование AES-NI инструкции, в отличие от программного обеспечения, реализованного в библиотеке Crypto ++ для моего Пример кода выше, является Rijndael::Enc::AdvancedProcessBlocks находится в rijndael.cpp, Это начинается так:

size_t Rijndael::Enc::AdvancedProcessBlocks(const byte *inBlocks, const byte *xorBlocks, byte *outBlocks, size_t length, word32 flags) const
{
#if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
if (HasAESNI())
return AESNI_AdvancedProcessBlocks(AESNI_Enc_Block, AESNI_Enc_4_Blocks, (MAYBE_CONST __m128i *)(const void *)m_key.begin(), m_rounds, inBlocks, xorBlocks, outBlocks, length, flags);
#endif

CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE Переменная препроцессора будет определена, если вы собираете библиотеку Crypto ++ по крайней мере Visual Studio 2008 with SP1 (Обратите внимание, что SP1 важно.) Такая зависимость необходима, чтобы иметь возможность использовать AES-NI внутренние (такие как _mm_aesenc_si128 а также _mm_aesenclast_si128) для создания Intel AES-NI инструкции машинного кода.

Таким образом, добавив точку останова в начале

введите описание изображения здесь

позволит вам отладить его прямо из Visual Studio. Внешний отладчик не требуется.

Если вы затем вступите в AESNI_AdvancedProcessBlocks Метод фактического шифрования AES будет обработан в одном из AESNI_Enc_* методы. Вот как актуально aesenc а также aesenclast машинные инструкции могут выглядеть как x86 конфигурация в Release построить:

введите описание изображения здесь

Таким образом, чтобы ответить на мой оригинальный вопрос, чтобы образец кода в моем посте выше мог использовать Intel AES-NI инструкции, необходимые для создания примера кода и библиотеки Crypto ++, по крайней мере, Visual Studio 2008 with SP1, (Просто строю это с Visual Studio 2008или более ранняя версия, не буду сделать работу, даже если процессор, на котором работает код, поддерживает AES-NI инструкции.) После этого никакие другие шаги не кажутся необходимыми. Библиотека обнаружит присутствие AES-NI инструкции автоматически (HasAESNI() функция) и будет использовать их при наличии. В противном случае по умолчанию будет реализована программная реализация.

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

int nCntTest = 100000;
DWORD dwmsIniTicks = ::GetTickCount();

for(int i = 0; i < nCntTest; i++)
{
enc.EncryptAndAuthenticate(pDataOut_AES_GCM, mac, sizeof(mac), iv, nIV_Length, NULL, 0, pDataPlainText, nLnPlainText);
}

DWORD dwmsElapsed = ::GetTickCount() - dwmsIniTicks;

bool bHaveHwAES_Support = false;
#if CRYPTOPP_BOOL_AESNI_INTRINSICS_AVAILABLE
bHaveHwAES_Support = CryptoPP::HasAESNI();
#endif
_tprintf(L"\nTimed %d AES256-GCM encryptions %s hardware encryption of %d bytes: %u ms\n",
nCntTest, bHaveHwAES_Support ? L"with" : L"without",
nLnRealPlainText, dwmsElapsed);

Вот два результата:

введите описание изображения здесь

а также

введите описание изображения здесь

Это явно не всеобъемлющий тест. Я запустил его на своем рабочем столе с "Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz" ЦПУ.

Но хорошие новости в том, что AES-GCM шифрование кажется очень быстрым, даже без аппаратной поддержки AES.

0