Question

I Currently perform a large amount of encryption/decryption of text in c# using AES.

With a pure software system it can take quite a processor hit for a decent amount of time for the lots of datasets required to be decrypted. I know Intel have came out with their AES-NI instruction set and AMD has come out with similar.

I'm using .NET 4.0, I know that the windows CNG framework makes use of these instruction sets, but it does not appear that AesManaged in the .NET world does the same.

There is a fantastic project "CLR Security" which makes a gateway from .NET 3.5 to the windows CNG, however it hasn't been maintained in a year and I'd rather not (if possible) jump on a dying project.

There is a CNGProvider class in .NET 4 but there doesn't appear to be adequate documentation to cobble together a working decryption from it for AES.

Does anyone have experience with the topic they could point me in the right direction on how to get AES-NI implemented in a pure .NET environment, using pre-made classes, without having to do a p/invoke directly from c#? (It'd be fine if there was a wrapper class doing it, as long as it was maintained).

Was it helpful?

Solution

What about AesCryptoServiceProvider? It says that uses CAPI, and so hopefully CNG if available. – Rup

This comment has helped tremendously, after doing some digging it looks like AesCryptoServiceProvider will use AES-NI if available. I cannot find any 'official' documentation from Microsoft on this however. When running simple timing benchmarks the difference is ~15x faster so either the API itself is massively optimized (which for a 15x increase is pretty nice optimization) or it uses the AES-NI instruction set.

Unfortunately I don't have a non AES-NI box to test on, but if I ever get one I'll update this thread with results.

So I'm pretty confident this is the API to use for AES-NI but cannot guarantee without further testing.

OTHER TIPS

How to use a CNG (or AES-NI enabled instruction set) in .NET?

I'm going to focus on the AES-NI instruction set question. I found it to be interesting since I wondered it myself (for use in C and C++).

Microsoft added AES-NI support to Visual Studio 2008 SP1 (_MSC_FULL_VER >= 150030729). The earliest you can observe AES-NI in Microsoft products is circa 2008 since earlier compilers did not support it. That means Server 2008 has it, and possibly Windows Vista via a Service Pack, and above.

According to Does MS Crypto API supports AES and AES-NI processor instructions?, both rsaenh.dll and bcryptprimitives.dll have it. The statements made by IvanP tested on Windows 7 and Windows 10.

However, testing on Windows 8.1 reveals...

# Using a Developer Command prompt so dumpbin is on-path:
> dumpbin /disasm c:\Windows\System32\rsaenh.dll > rsaenh.dll.txt
> dumpbin /disasm c:\Windows\System32\bcryptprimitives.dll > bcryptprimitives.dll.txt

Then:

# Using a GitBash terminal for grep
$ grep -i aes rsaenh.dll.txt
$

And:

$ grep -i aes bcryptprimitives.dll.txt
  000000018000234A: 66 0F 3A DF C0 00  aeskeygenassist xmm0,xmm0,0
  0000000180002363: 66 0F 38 DB C0     aesimc      xmm0,xmm0
  000000018000237E: 66 0F 38 DC 41 10  aesenc      xmm0,xmmword ptr [rcx+10h]
  0000000180002384: 66 0F 38 DC 41 20  aesenc      xmm0,xmmword ptr [rcx+20h]
  000000018000238A: 66 0F 38 DC 41 30  aesenc      xmm0,xmmword ptr [rcx+30h]
  0000000180002390: 66 0F 38 DC 41 40  aesenc      xmm0,xmmword ptr [rcx+40h]
  0000000180002396: 66 0F 38 DC 41 50  aesenc      xmm0,xmmword ptr [rcx+50h]
  000000018000239C: 66 0F 38 DC 41 60  aesenc      xmm0,xmmword ptr [rcx+60h]
  00000001800023A2: 66 0F 38 DC 41 70  aesenc      xmm0,xmmword ptr [rcx+70h]
  00000001800023AF: 66 0F 38 DC 01     aesenc      xmm0,xmmword ptr [rcx]
  00000001800023B4: 66 0F 38 DC 41 10  aesenc      xmm0,xmmword ptr [rcx+10h]
  00000001800023C3: 66 41 0F 38 DD 02  aesenclast  xmm0,xmmword ptr [r10]
  000000018001936E: 66 0F 38 DC 41 10  aesenc      xmm0,xmmword ptr [rcx+10h]
  0000000180019374: 66 0F 38 DC 41 20  aesenc      xmm0,xmmword ptr [rcx+20h]
  000000018001937A: 66 0F 38 DC 41 30  aesenc      xmm0,xmmword ptr [rcx+30h]
  0000000180019380: 66 0F 38 DC 41 40  aesenc      xmm0,xmmword ptr [rcx+40h]
  0000000180019386: 66 0F 38 DC 41 50  aesenc      xmm0,xmmword ptr [rcx+50h]
  000000018001938C: 66 0F 38 DC 41 60  aesenc      xmm0,xmmword ptr [rcx+60h]
  0000000180019392: 66 0F 38 DC 41 70  aesenc      xmm0,xmmword ptr [rcx+70h]
  000000018001939F: 66 0F 38 DC 01     aesenc      xmm0,xmmword ptr [rcx]
  00000001800193A4: 66 0F 38 DC 41 10  aesenc      xmm0,xmmword ptr [rcx+10h]
  00000001800193B3: 66 41 0F 38 DD 02  aesenclast  xmm0,xmmword ptr [r10]
  000000018001952E: 66 0F 38 DE C4     aesdec      xmm0,xmm4
  0000000180019533: 66 0F 38 DE CC     aesdec      xmm1,xmm4
  0000000180019538: 66 0F 38 DE D4     aesdec      xmm2,xmm4
  000000018001953D: 66 0F 38 DE DC     aesdec      xmm3,xmm4
  000000018001954B: 66 0F 38 DF C4     aesdeclast  xmm0,xmm4
  0000000180019550: 66 0F 38 DF CC     aesdeclast  xmm1,xmm4
  0000000180019555: 66 0F 38 DF D4     aesdeclast  xmm2,xmm4
  000000018001955A: 66 0F 38 DF DC     aesdeclast  xmm3,xmm4
  000000018002E8B5: 66 0F 38 DE 41 10  aesdec      xmm0,xmmword ptr [rcx+10h]
  000000018002E8BB: 66 0F 38 DE 41 20  aesdec      xmm0,xmmword ptr [rcx+20h]
  000000018002E8C1: 66 0F 38 DE 41 30  aesdec      xmm0,xmmword ptr [rcx+30h]
  000000018002E8C7: 66 0F 38 DE 41 40  aesdec      xmm0,xmmword ptr [rcx+40h]
  000000018002E8CD: 66 0F 38 DE 41 50  aesdec      xmm0,xmmword ptr [rcx+50h]
  000000018002E8D3: 66 0F 38 DE 41 60  aesdec      xmm0,xmmword ptr [rcx+60h]
  000000018002E8D9: 66 0F 38 DE 41 70  aesdec      xmm0,xmmword ptr [rcx+70h]
  000000018002E8E6: 66 0F 38 DE 01     aesdec      xmm0,xmmword ptr [rcx]
  000000018002E8EB: 66 0F 38 DE 41 10  aesdec      xmm0,xmmword ptr [rcx+10h]
  000000018002E8FA: 66 41 0F 38 DF 02  aesdeclast  xmm0,xmmword ptr [r10]
  000000018003F458: 66 0F 38 DC E8     aesenc      xmm5,xmm0
  000000018003F45D: 66 0F 38 DC D8     aesenc      xmm3,xmm0
  000000018003F462: 66 0F 38 DC E0     aesenc      xmm4,xmm0
  000000018003F467: 66 0F 38 DC F0     aesenc      xmm6,xmm0
  000000018003F475: 66 0F 38 DD EF     aesenclast  xmm5,xmm7
  000000018003F47A: 66 0F 38 DD DF     aesenclast  xmm3,xmm7
  000000018003F47F: 66 0F 38 DD E7     aesenclast  xmm4,xmm7
  000000018003F492: 66 0F 38 DD F7     aesenclast  xmm6,xmm7

So, on modern Windows, you need to use something that depends on bcryptprimitives.dll. I don't know what .Net primitives enlist bcryptprimitives.dll.


I also checked the following DLLs on Windows 8.1, and there were no AES-NI instructions present:

  • advapi32.dll
  • bcrypt.dll
  • crypt32.dll
  • cryptbase.dll
  • cryptcatsvc.dll
  • cryptdlg.dll
  • cryptdll.dll
  • cryptext.dll
  • cryptnet.dll
  • cryptowinrt.dll
  • cryptsp.dll
  • cryptsvc.dll

There's not much information about the subject on Microsoft's site. I got two hits from csp "aes-ni" site:microsoft.com, and 0 hits for csp "aesni" site:microsoft.com. Whatever is going on, Microsoft is keeping it secret.

I had worked in the earliest of chipsets that had these features. At that time Windows 7 didn't have the ability to work with AES. I resorted to the then available Ubuntu and used the Intel doc and with some inline assembly did a cpuid. That served my purpose of a training. Nevertheless one thing I learned is "Intel secure key" was made available almost at the same time as "AES-NI". So if I found RDRAND instruction in the chipset that means I "probably" had AES-NI. So this way the simplest I can do (but not quite documented) is

//PF_RDRAND_INSTRUCTION_AVAILABLE is not documented yet as part of MSDN API as of //this writing IsProcessorFeaturePresent(PF_RDRAND_INSTRUCTION_AVAILABLE);

We can also use the CPU intrinsics this way https://docs.microsoft.com/en-us/cpp/intrinsics/cpuid-cpuidex?view=vs-2019

Also see below document for more "proof". https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp1894.pdf

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top