17

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).

user2864740
  • 60,010
  • 15
  • 145
  • 220
John Mitchell
  • 9,653
  • 9
  • 57
  • 91
  • 1
    What about [AesCryptoServiceProvider](http://msdn.microsoft.com/en-us/library/system.security.cryptography.aescryptoserviceprovider.aspx)? It says that uses CAPI, and so hopefully CNG if available. – Rup Nov 15 '11 at 18:02
  • I'm going to give it a spin, problem is without some nice docs then the only way to tell is benchmark so will test and report back when I can get some results. – John Mitchell Nov 16 '11 at 00:01
  • @Rup: Any documentation on CAPI leveraging CNG if available part? It was my understanding that CAPI and CNG are entirely separate APIs under the hood. We are investigating this so your input would help. – DeepSpace101 Jun 06 '13 at 06:44
  • @Sid No, I don't remember where I found that - sorry. – Rup Jun 06 '13 at 08:42

3 Answers3

16

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.

jww
  • 97,681
  • 90
  • 411
  • 885
John Mitchell
  • 9,653
  • 9
  • 57
  • 91
  • Wanted to check back - any confirmation that AesCryptoServiceProvider indeed used CNG on Windows Server 2008 R2/2012 and not CAPI itself? Thanks! – DeepSpace101 Jun 06 '13 at 06:46
  • Hi Sid, when I used it on a Non AES-NI box the performance dropped significantly, however I have still not seen any documentation from Microsoft to 100% confirm my beliefs. However at this point I'm going with the assumption (and I believe it to be a pretty safe one) that it utilizes the AES-NI instruction set. – John Mitchell Jun 06 '13 at 22:00
  • I believe AES-NI is indeed supported for Windows 7 and above using Cryptography Next Generation (CNG). – Anthony Gatlin Apr 13 '14 at 04:03
  • 1
    At least on my Win7 machine which supports AES-NI (64 bit, i7-3520M, ivy bridge) `AesCryptoServiceProvider` runs at about 23 cycles-per-byte. So it's quite unlikely that it uses AES-NI. A proper AES-NI based implementation should be at least 10 times faster than that. – CodesInChaos Oct 13 '14 at 11:09
1

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.

jww
  • 97,681
  • 90
  • 411
  • 885
  • The best chain I can find is that .NET loads rsaenh ([AesCryptoServiceProvider](https://github.com/microsoft/referencesource/blob/master/System.Core/System/Security/Cryptography/AesCryptoServiceProvider.cs#L42) loads "Microsoft Enhanced RSA and AES Cryptographic Provider" which is rsaenh.dll in my registry), which depends on bcrypt.dll, which depends on bcryptprimitives.dll. If I copy/paste the example program from the AesCryptoServiceProvider MSDN page and 'Enable native code debugging' then I do see bcryptprimitives.dll in the Modules window. Haven't tried setting breakpoints in it through. – Rup Aug 19 '19 at 16:29
  • Yes, I can hit aesenc instructions in VS from .NET. For the MSDN example, which uses CBC mode, you want SymCryptAesCbcEncrypt in bcryptprimitives which either calls SymCryptAesCbcEncryptXmm which uses AES-NI or SymCryptAesCbcEncryptAsm which doesn't – Rup Aug 19 '19 at 16:55
0

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://learn.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