web-dev-qa-db-ja.com

OpenSSLがIntel AES-NIをサポートしているかどうかを確認するにはどうすればよいですか?

OpenSSLがIntel AES-NIをサポート/使用しているかどうかを確認するにはどうすればよいですか?

20
niXman

openSSLがIntel AES-NIをサポート/使用しているかどうかを確認するにはどうすればよいですか?

それはそうあるべきですが、それはそれほど単純ではありません。 OpenSSLは、ia32プロセッサーに対して検出された機能を取得する機能を提供するために使用されていましたが、現在は利用できません。 OPENSSL_ia32cap_loc manページOPENSSL_ia32capの説明を参照してください。 OpenSSLメーリングリストの Verify AES-NI use at runtime? もご覧ください。

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 not にエクスポートされます。この場合、独自の検出コードを作成する必要があります。

OpenSSLはライブラリの静的リンクでのみ機能するため、気にする必要もありません。検出に使用するコードを以下に共有しました。私はその大部分をIntelのDave Johnstonからリッピングしたと思います(彼はRDRAND回路を設計しました)。

Note :以下のコードは AMDプロセッサを誤って拒否する可能性がありますAES-NI 。テストするプロセッサがないので、コードを提供できません。

Note :以下のコードはValgrindで期待どおりに動作しません。 AES-NIまたはRDRAND命令にはエミュレーションがないため、Valgrindは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)
    );
}
29
jww

jww によって提供される情報から構築されたいくつかの簡単なワンライナー:

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

最初の行の出力は、2番目の行よりも大幅に速くなるはずです。私の場合、i5テストマシンでは、ほぼ2倍になります。

15
NuSkooler