AES-NI is a new security feature available on the latest Intel® Atom™ Z3000 processors (codename Bay Trail). AES-NI provides a set of hardware instructions onboard the processor that implement some of the intensive sub-steps of the AES algorithm. This yields additional performance when performing AES cryptographic operations. This blog discusses a method of adding encryption and decryption that utilizes AES-NI in a Windows 8 C# app.
To learn more about AES-NI, please see the link below.
http://www.intel.com/content/www/us/en/architecture-and-technology/advanced-encryption-standard--aes-/data-protection-aes-general-technology.html
An easy way to take advantage of AES-NI under the hood in a Windows 8 app is to use the Microsoft Cryptography API: Next Generation (CNG) library. The CNG library was developed in C++ and is available to use in other languages by importing the Bcrypt.dll file.
To learn more about the CNG library and API’s, please see the link below.
http://msdn.microsoft.com/en-us/library/aa376210(v=vs.85).aspx
To use the Bcrypt.dll in your C# application, import the functions using the System.Runtime.Interop Services. The following code below are example DllImport statements.
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint BCryptOpenAlgorithmProvider(
[In] [Out] ref IntPtr phAlgorithm,
[In] String pszAlgId,
[In] String pszImplementation,
[In] int dwFlags
);
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint BCryptGetProperty(
[In] IntPtr hObject,
[In] String pszProperty,
[Out] byte[] pbOutput,
[In] int cbOutput,
[In] [Out] ref int pcbResult,
[In] int dwFlags);
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint BCryptGenerateSymmetricKey(
[In] IntPtr hAlgorithm,
[In] [Out] ref IntPtr phKey,
[Out] byte[] pbKeyObject,
[In] int cbKeyObject,
[In] byte[] pbSecret,
[In] int cbSecret,
[In] int dwFlags
);
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint BCryptEncrypt(
[In][Out] IntPtr hKey,
[In] byte[] pbInput,
[In] int cbInput,
[In] IntPtr pPaddingInfo,
[In] byte[] pbIV,
[In] int cbIV,
[Out] byte[] pbOutput,
[In] int cbOutput,
[In] [Out] ref int pcbResult,
[In] int dwFlags
);
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint BCryptDecrypt(
[In][Out] IntPtr hKey,
[In] byte[] pbInput,
[In] int cbInput,
[In] IntPtr pPaddingInfo,
[In] byte[] pbIV,
[In] int cbIV,
[Out] byte[] pbOutput,
[In] int cbOutput,
[In] [Out] ref int pcbResult,
[In] int dwFlags
);
[DllImport("Bcrypt.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern uint BCryptCloseAlgorithmProvider(
[In] IntPtr phAlgorithm,
[In] int dwFlags
);
The following six steps below show an example on how to use the CNG library functions to perform AES encryption & decryption. The CNG library function calls are shown in bold.
1. Open the Algorithm Provider
//Initialize Status
uint status = 0;
//Initialize AlgHandle
IntPtr pAlgHandle = IntPtr.Zero;
//Open Algorithm Provider
status = BCryptOpenAlgorithmProvider(
ref pAlgHandle,
"AES",
"Microsoft Primitive Provider",
0);
2. Get Algorithm Properties
//Allocate DWORD for ObjectLength
byte[] pbObjectLength = new byte[4];
//Initialize ObjectLength Byte Count
int pcbObjectLength = 0;
//Get Algorithm Properties(BCRYPT_OBJECT_LENGTH)
status = BCryptGetProperty(
pAlgHandle,
"ObjectLength",
pbObjectLength,
pbObjectLength.Length,
ref pcbObjectLength,
0);
3. Generate the Key Object
//Initialize KeyHandle
IntPtr pKeyHandle = IntPtr.Zero;
//Initialize Key Object Size with ObjectLength
int keyObjectSize = pbObjectLength[3]<<24 | pbObjectLength[2]<<16 | pbObjectLength[1]<<8 | pbObjectLength[0];
//Initialize AES Key
byte[] pbKey = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
//Allocate KeyObject With Key Object Size
byte[] pbKeyObject = new byte[keyObjectSize];
//Generate Symmetric Key Object
status = BCryptGenerateSymmetricKey(
pAlgHandle,
ref pKeyHandle,
pbKeyObject,
keyObjectSize,
pbKey,
pbKey.Length,
0);
4. Encrypt the Plain Text Data
//Initialize Data To Encrypt
byte[] pbData = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
//Initialize Initialization Vector
byte[] pbIV = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
//Initialize PaddingInfo
IntPtr pPaddingInfo = IntPtr.Zero;
//Initialize Cipher Text Byte Count
int pcbCipherText = 0;
//Get Cipher Text Byte Count
status = BCryptEncrypt(
pKeyHandle,
pbData,
pbData.Length,
pPaddingInfo,
pbIV,
pbIV.Length,
null,
0,
ref pcbCipherText,
0);
//Allocate Cipher Text Buffer
byte[] pbCipherText = new byte[pcbCipherText];
//Encrypt The Data
status = BCryptEncrypt(
pKeyHandle,
pbData,
pbData.Length,
pPaddingInfo,
pbIV,
pbIV.Length,
pbCipherText,
pcbCipherText,
ref pcbCipherText,
0);
5. Decrypt the Cipher Text
//Initialize Initialization Vector
byte[] pbIV2 = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F };
//Initialize Plain Text Byte Count
int pcbPlainText = 0;
//Get Plain Text Byte Count
status = BCryptDecrypt(
pKeyHandle,
pbCipherText,
pcbCipherText,
pPaddingInfo,
pbIV2,
pbIV2.Length,
null,
0,
ref pcbPlainText,
0);
//Allocate Plain Text Buffer
byte[] pbPlainText = new byte[pcbPlainText];
//Decrypt The Data
status = BCryptDecrypt(
pKeyHandle,
pbCipherText,
pcbCipherText,
pPaddingInfo,
pbIV2,
pbIV2.Length,
pbPlainText,
pbPlainText.Length,
ref pcbPlainText,
0);
6. Close the Algorithm Provider
status = BCryptCloseAlgorithmProvider(pAlgHandle, 0);
***This sample source code is released under the Microsoft Limited Public License (MS-LPL)