【问题标题】:How can I check if OpenSSL is support/use the Intel AES-NI?如何检查 OpenSSL 是否支持/使用英特尔 AES-NI?
【发布时间】:2014-10-06 16:36:55
【问题描述】:

请告诉我,如何检查 OpenSSL 是否支持/使用 Intel AES-NI?

【问题讨论】:

    标签: openssl aes


    【解决方案1】:

    如何检查 OpenSSL 是否支持/使用 Intel AES-NI?

    它不是那么简单,虽然它应该是。 OpenSSL 曾经提供一个函数来获取为 ia32 处理器检测到的功能,但它不再可用。请参阅OPENSSL_ia32cap man page 中对OPENSSL_ia32cap_loc 的讨论。另请参阅 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导出。在这种情况下,您需要编写自己的检测代码。

    我什至不关心 OpenSSL,因为它只适用于库的静态链接。我在下面分享了我用于检测的代码。我相信我从英特尔的 Dave Johnston(他设计了 RDRAND 电路)那里抄袭了很大一部分。

    注意:下面的代码可能会错误地拒绝AMD processor with AES-NI。我没有要测试的处理器,所以我不能提供代码。

    注意:下面的代码在 Valgrind 下不会按预期执行。 AES-NI 或 RDRAND 指令没有仿真,因此 Valgrind 从CPUID 返回一个“篡改”值,因此它们似乎不可用。请参阅邮件列表中的Incorrect results from inline assembly when running under 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 测试机上,几乎翻了一番。

    【讨论】:

    • 不应该是 4 倍或 8 倍的速度而不是两倍吗?
    • 我在 16 个大小的块中获得了两倍的性能,但在 8192 个大小的块中获得了将近 14 倍的性能。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多