I want to know if there is a way to test for the presence of AES-NI in the host system's CPU from C#.NET.
Let me say up front that this question is not asking about how to use AES-NI from .NET. It turns out simply using AESCryptoServiceProvider
will use AES-NI if it is available. This result is based on independent benchmarks I did comparing the performances of AESCryptoServiceProvider
against the benchmarks provided in TrueCrypt, which does indeed support AES-NI. The results were surprisingly similar on both machines with and without AES-NI.
The reason I want to be able to test for it is to be able to indicate to the user that their computer supports AES-NI. This would be relevant since it would reduce support incidents involving questions like "but my friend has a Core i5 also but his is a lot faster!" If the program's user interface could indicate to the user that their system does or does not support AES-NI, it would also be possible to indicate that "slower performance is normal since this system does not support AES-NI."
(We can thank Intel for all of the confusion with different processor steppings! :-) )
Is there a way to detect this information, perhaps through WMI?
Look in /proc/cpuinfo . If you have the aes flag then your CPU has AES support. , then you have AES.
From the System Utilities screen, select System Configuration > BIOS/Platform Configuration (RBSU) > Server Security > Processor AES-NI Support.
AES-NI is up 13.5 times faster than AES on this Intel processor. AES-NI on ARMv8 processor can encrypt around 355 MB/S. AES-NI is up to 10 times faster than AES on the ARM processor. Results also show that the performance on linux in most cases for AES and AES-NI is better than windows OS for the same CPU.
Check if AES-NI is Available on CPU Processors Before proceeding, first verify that current CPUs have the AES instruction set. For this you can inspect CPU flags as follows. If the output shows aes , that means AES-NI engine is available on current CPUs.
It's seems that there is the similar question on SO: Inline Assembly Code to Get CPU ID with the great answer.
But this answer requires some adjustments to suit your need.
First, as I understand, AES-NI can be presence at 64-bit processors only, right? Then you could ignore all 32-bit code in the answer above.
Second, you need ECX register or rather its 25th bit, so you must change code a bit:
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;
}
Finally, you need store ECX register in array:
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 */
};
As far as I can see, that's all changes.
The answer from Mark above is fantastic and got things working well for me, however I did notice that if the application is run in 32 bit mode that the ecx register wasn't pulled in the x86 code thus leading to no detection of AES-NI.
I added one line and changed another, basically applying the changes Mark made to the x64 code to the x86 code. This allows you to see the AES-NI bit from 32 bit mode as well. Not sure if it will help someone, but I thought I'd post it.
EDIT: While I was doing some testing, I noticed that the registers returned by the x64 code were incorrect. EDX was being returned at offset 0x4, 0x8, and 0xC, additionally the ECX and EDX registers were at different offsets with x86 code so you needed to check IntPtr.Size more often to keep things working in both environments. To simplify things I place the ECX register at 0x4 and EDX at 0x8 and that way the data is arranged correctly.
If someone requests I can post up the entire class that is a working example of what I've learned from this post and others.
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With