Como posso verificar se o OpenSSL é compatível / use o Intel AES-NI?

Diga-me por favor, como posso verificar se o OpenSSL é suporte / use o Intel AES-NI?

Como posso verificar se o OpenSSL é suporte / use o Intel AES-NI?

Não é tão simples, embora deva ser. OpenSSL usado para fornecer uma function para obter os resources detectados para um processador ia32, mas não está mais disponível. Veja a discussão de OPENSSL_ia32cap_loc na página do manual OPENSSL_ia32cap . Veja também o uso do AES-NI no tempo de execução? na lista de discussão do OpenSSL.

Se você estiver vinculando à biblioteca estática do OpenSSL, poderá usar:

 extern unsigned int OPENSSL_ia32cap_P[]; # define AESNI_CAPABLE (OPENSSL_ia32cap_P[1]&(1<<(57-32))) if(AESNI_CAPABLE) /* AES-NI is available */ 

Se você estiver vinculando ao object compartilhado OpenSSL, o símbolo OPENSSL_ia32cap_P não será exportado. Neste caso, você precisa escrever seu próprio código de detecção.

Eu nem me incomodo com o OpenSSL, pois ele só funciona com a vinculação estática da biblioteca. Eu compartilhei o código que uso para detecção abaixo. Acredito que rasguei uma parte significativa de Dave Johnston da Intel (ele projetou o circuito RDRAND).

Nota : o código abaixo poderia rejeitar incorretamente um processador AMD com AES-NI . Eu não tenho um processador para testar, então não posso oferecer o código.

Nota : o código abaixo não funcionará como esperado em Valgrind. Não há emulação para as instruções AES-NI ou RDRAND, então Valgrind retorna um valor "medicado" da CPUID portanto, parece que eles não estão disponíveis. Veja Resultados incorretos da assembly inline quando executando sob Valgrind na lista de discussão.


Mesmo que o AES-NI esteja disponível, isso não significa que você irá usá-lo.

Se você usar os primitivos de baixo nível como AES_* , você não usará o AES-NI porque é uma implementação de software.

Se você usar a engrenagem EVP_* alto nível, você usará AES-NI se estiver disponível. A biblioteca mudará para AES-NI automaticamente.


Se o AES-NI estiver disponível, mas você não quiser usá-lo, execute o seguinte antes de iniciar seu programa:

 $ export OPENSSL_ia32cap="~0x200000200000000" 

Você pode testar a diferença de velocidade com o seguinte comando OpenSSL. Alterne a exportação acima para ver as diferenças:

 $ 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) ); } 

Um par de forros rápidos construídos a partir das informações fornecidas pelo jww :

 velocidade de openssl -selapsed -evp aes-128-cbc
 ...
 OPENSSL_ia32cap = "~ 0x200000200000000" velocidade do openssl -elapsed -evp aes-128-cbc
 ...

A saída da primeira linha deve ser significativamente mais rápida que a segunda. No meu caso, em uma máquina de teste i5, quase o dobro.