Ответ 1
как я могу проверить, поддерживает ли OpenSSL/использует Intel AES-NI?
Это не так просто, хотя и должно быть. OpenSSL используется для предоставления функций для обнаружения возможностей для процессора ia32, но его больше нет. См. Обсуждение OPENSSL_ia32cap_loc
на странице OPENSSL_ia32cap
. Также см. Проверить использование AES-NI во время выполнения? в списке рассылки OpenSSL.
Если вы ссылаетесь на статическую библиотеку OpenSSL, вы можете использовать:
extern unsigned int OPENSSL_ia32cap_P[];
# define AESNI_CAPABLE (OPENSSL_ia32cap_P[1]&(1<<(57-32)))
if(AESNI_CAPABLE)
/* AES-NI is available */
Если вы ссылаетесь на общий объект OpenSSL, символ OPENSSL_ia32cap_P
не экспортируется. В этом случае вам нужно написать свой собственный код обнаружения.
Я даже не беспокоюсь о OpenSSL, поскольку он работает только со статической привязкой библиотеки. Я использовал код, который я использую для обнаружения ниже. Я считаю, что я разорвал значительную часть его от Dave Johnston от Intel (он разработал схему RDRAND).
Примечание: приведенный ниже код может неправильно отклонить процессор AMD с AES-NI. У меня нет процессора для тестирования, поэтому я не могу предложить код.
Примечание: приведенный ниже код не будет работать так, как ожидалось в Valgrind. Там нет эмуляции для инструкций AES-NI или RDRAND, поэтому Valgrind возвращает значение "doctored" из CPUID
, поэтому, похоже, они недоступны. См. Неверные результаты встроенной сборки при работе под Valgrind в списке рассылки.
Несмотря на то, что AES-NI доступен, это не значит, что вы собираетесь его использовать.
Если вы используете примитивы низкого уровня, такие как AES_*
, то вы не будете использовать AES-NI, потому что это программная реализация.
Если вы используете механизм высокого уровня EVP_*
, тогда вы будете использовать AES-NI, если он доступен. Библиотека автоматически переключится на AES-NI.
Если AES-NI доступен, но вы не хотите его использовать, выполните следующие действия перед запуском программы:
$ export OPENSSL_ia32cap="~0x200000200000000"
Вы можете протестировать разницу скорости со следующей командой OpenSSL. Переключите экспорт выше, чтобы увидеть различия:
$ openssl speed -elapsed -evp aes-128-ecb
struct CPUIDinfo {
unsigned int EAX;
unsigned int EBX;
unsigned int ECX;
unsigned int EDX;
};
int HasIntelCpu();
int HasAESNI();
int HasRDRAND();
void cpuid_info(CPUIDinfo *info, const unsigned int func,
const unsigned int subfunc);
int HasIntelCpu() {
CPUIDinfo info;
cpuid_info(&info, 0, 0);
if (memcmp((char *) (&info.EBX), "Genu", 4) == 0
&& memcmp((char *) (&info.EDX), "ineI", 4) == 0
&& memcmp((char *) (&info.ECX), "ntel", 4) == 0) {
return 1;
}
return 0;
}
int HasAESNI() {
if (!HasIntelCpu())
return 0;
CPUIDinfo info;
cpuid_info(&info, 1, 0);
static const unsigned int AESNI_FLAG = (1 << 25);
if ((info.ECX & AESNI_FLAG) == AESNI_FLAG)
return 1;
return 0;
}
int HasRDRAND() {
if (!HasIntelCpu())
return 0;
CPUIDinfo info;
cpuid_info(&info, 1, 0);
static const unsigned int RDRAND_FLAG = (1 << 30);
if ((info.ECX & RDRAND_FLAG) == RDRAND_FLAG)
return 1;
return 0;
}
void cpuid_info(CPUIDinfo *info, unsigned int func, unsigned int subfunc) {
__asm__ __volatile__ (
"cpuid"
: "=a"(info->EAX), "=b"(info->EBX), "=c"(info->ECX), "=d"(info->EDX)
: "a"(func), "c"(subfunc)
);
}