我想知道是否有办法在C#.NET的主机系统CPU中测试AES-NI的 presence 。
让我先说这个问题不询问如何从.NET中使用 AES-NI。事实证明,简单地使用AESCryptoServiceProvider
将使用AES-NI(如果可用)。这个结果基于独立的基准测试,我将AESCryptoServiceProvider
的性能与TrueCrypt中提供的基准进行了比较,后者确实支持AES-NI。在使用和不使用AES-NI的两台机器上,结果令人惊讶地相似。
我希望能够测试它的原因是能够向用户表明他们的计算机支持AES-NI。这是相关的,因为它会减少涉及问题的支持事件,但我的朋友也有Core i5,但他的速度要快得多!"如果程序的用户界面可以向用户指示他们的系统支持或不支持AES-NI,则还可以指示"性能较低是正常的,因为该系统不支持AES- NI"
(我们可以感谢英特尔对不同处理器步进的所有困惑!:-))
有没有办法通过WMI检测这些信息?
答案 0 :(得分:2)
似乎在SO上有类似的问题:Inline Assembly Code to Get CPU ID并给出了很好的答案。
但这个答案需要进行一些调整以满足您的需要。
首先,据我所知,AES-NI只能出现在64位处理器上,对吧?然后你可以忽略上面答案中的所有32位代码。
其次,您需要ECX寄存器或更确切地说是第25位,因此您必须稍微更改代码:
private static bool IsAESNIPresent()
{
byte[] sn = new byte[16]; // !!! Here were 8 bytes
if (!ExecuteCode(ref sn))
return false;
var ecx = BitConverter.ToUInt32(sn, 8);
return (ecx & (1 << 25)) != 0;
}
最后,您需要在阵列中存储ECX寄存器:
byte[] code_x64 = new byte[] {
0x53, /* push rbx */
0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00, /* mov rax, 0x1 */
0x0f, 0xa2, /* cpuid */
0x41, 0x89, 0x00, /* mov [r8], eax */
0x41, 0x89, 0x50, 0x04, /* mov [r8+0x4], ebx !!! changed */
0x41, 0x89, 0x50, 0x08, /* mov [r8+0x8], ecx !!! added */
0x41, 0x89, 0x50, 0x0C, /* mov [r8+0xC], edx !!! added*/
0x5b, /* pop rbx */
0xc3, /* ret */
};
据我所见,这一切都有所改变。
答案 1 :(得分:1)
Mark上面的回答很棒,让我的工作得很好,但是我注意到如果应用程序在32位模式下运行,那么ecx寄存器没有被x86代码拉入,从而导致没有检测到AES-NI。
我添加了一行并更改了另一行,基本上将对x64代码所做的更改应用于x86代码。这允许您从32位模式查看AES-NI位。不确定它是否会对某人有所帮助,但我想我会发布它。
编辑:当我做一些测试时,我注意到x64代码返回的寄存器不正确。 EDX在偏移量0x4,0x8和0xC处返回,另外ECX和EDX寄存器与x86代码处于不同的偏移量,因此您需要更频繁地检查IntPtr.Size以保持两种环境中的工作。为简化起见,我将ECX寄存器置于0x4,将EDX置于0x8,这样就可以正确排列数据。
如果有人要求我可以发布整个课程,这是我从这篇文章和其他人那里学到的一个实例。
public static bool ExecuteCode(ref byte[] result) {
byte[] code_x86 = new byte[] {
0x55, /* push ebp */
0x89, 0xE5, /* mov ebp, esp */
0x57, /* push edi */
0x8b, 0x7D, 0x10, /* mov edi, [ebp+0x10] */
0x6A, 0x01, /* push 0x1 */
0x58, /* pop eax */
0x53, /* push ebx */
0x0F, 0xA2, /* cpuid */
0x89, 0x07, /* mov [edi], eax */
0x89, 0x4F, 0x04, /* mov [edi+0x4], ecx Changed */
0x89, 0x57, 0x08, /* mov [edi+0x8], edx Changed */
0x5B, /* pop ebx */
0x5F, /* pop edi */
0x89, 0xEC, /* mov esp, ebp */
0x5D, /* pop ebp */
0xC2, 0x10, 0x00, /* ret 0x10 */
};
byte[] code_x64 = new byte[] {
0x53, /* push rbx */
0x48, 0xC7, 0xC0, 0x01, 0x00, 0x00, 0x00, /* mov rax, 0x1 */
0x0f, 0xA2, /* cpuid */
0x41, 0x89, 0x00, /* mov [r8], eax */
0x41, 0x89, 0x48, 0x04, /* mov [r8+0x4], ecx Changed */
0x41, 0x89, 0x50, 0x08, /* mov [r8+0x8], edx Changed*/
0x5B, /* pop rbx */
0xC3, /* ret */
};
int num;
byte[] code = (IntPtr.Size == 4) ? code_x86 : code_x64;
IntPtr ptr = new IntPtr(code.Length);
if (!VirtualProtect(code, ptr, PAGE_EXECUTE_READWRITE, out num))
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
ptr = new IntPtr(result.Length);
return (ExecuteNativeCode(code, IntPtr.Zero, 0, result, ptr) != IntPtr.Zero);