Dites-moi s'il vous plaît, comment puis-je vérifier si OpenSSL prend en charge/utilise Intel AES-NI?
comment puis-je vérifier si OpenSSL prend en charge/utilise Intel AES-NI?
Ce n'est pas aussi simple que ça, mais ça devrait l'être. OpenSSL fournissait une fonction pour obtenir les capacités détectées pour un processeur ia32, mais ce n'est plus disponible. Voir la discussion de OPENSSL_ia32cap_loc
dans le OPENSSL_ia32cap
page de manuel . Voir aussi Vérifier l'utilisation d'AES-NI lors de l'exécution? sur la liste de diffusion OpenSSL.
Si vous vous connectez à la bibliothèque statique OpenSSL, vous pouvez utiliser:
extern unsigned int OPENSSL_ia32cap_P[];
# define AESNI_CAPABLE (OPENSSL_ia32cap_P[1]&(1<<(57-32)))
if(AESNI_CAPABLE)
/* AES-NI is available */
Si vous vous connectez à l'objet partagé OpenSSL, alors le symbole OPENSSL_ia32cap_P
est pas exporté. Dans ce cas, vous devez écrire votre propre code de détection.
Je ne m'embête même pas avec OpenSSL car il ne fonctionne qu'avec la liaison statique de la bibliothèque. J'ai partagé le code que j'utilise pour la détection ci-dessous. Je crois que j'en ai arraché une partie importante à Dave Johnston d'Intel (il a conçu le circuit RDRAND).
Remarque: le code ci-dessous pourrait rejeter incorrectement un processeur AMD avec AES-NI . Je n'ai pas de processeur pour tester, donc je ne peux pas proposer le code.
Remarque: le code ci-dessous ne fonctionnera pas comme prévu sous Valgrind. Il n'y a pas d'émulation pour les instructions AES-NI ou RDRAND, donc Valgrind retourne une valeur "falsifiée" de CPUID
donc il semble qu'elles ne soient pas disponibles. Voir Résultats incorrects de l'assemblage en ligne lors de l'exécution sous Valgrind sur la liste de diffusion.
Même si AES-NI est disponible, cela signifie pas que vous allez l'utiliser.
Si vous utilisez les primitives de bas niveau comme AES_*
, alors vous allez pas utiliser AES-NI car c'est une implémentation logicielle.
Si vous utilisez le niveau élevé EVP_*
gear, vous utiliserez alors AES-NI s'il est disponible. La bibliothèque passera automatiquement à AES-NI.
Si AES-NI est disponible mais vous ne voulez pas l'utiliser, alors procédez comme suit avant de lancer votre programme:
$ export OPENSSL_ia32cap="~0x200000200000000"
Vous pouvez tester la différence de vitesse avec la commande OpenSSL suivante. Basculez l'exportation ci-dessus pour voir les différences:
$ 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)
);
}
Quelques doublons rapides construits à partir des informations fournies par jww :
openssl speed -elapsed -evp aes-128-cbc ... OPENSSL_ia32cap = "~ 0x200000200000000" openssl speed -elapsed -evp aes-128-cbc ...
La sortie de la première ligne doit être nettement plus rapide que la seconde. Dans mon cas sur une machine de test i5, presque le double.