Как я могу проверить, поддерживает ли OpenSSL/использует Intel AES-NI?

Скажите, пожалуйста, как я могу проверить, поддерживает ли OpenSSL/использует Intel AES-NI?

Ответы

Ответ 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)
    );
}

Ответ 2

Несколько быстрых лайнеров, построенных на основе информации, предоставленной jww:

openssl speed -elapsed -evp aes-128-cbc
...
OPENSSL_ia32cap="~0x200000200000000" openssl speed -elapsed -evp aes-128-cbc
...

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