Introduction
The Cryptography API: Next Generation(CNG) is a new and agile framework in Windows Vista�, which implements an extensible provider model that allows you to load a provider by specifying the required cryptographic algorithm rather than having to hardcode a specific provider.
The advantage is that an algorithm provider can be replaced or upgraded and you will not have to change your code in any way to use the new provider. Also, if some algorithm is determined to be unsafe in the future, a more secure version of that algorithm can be installed with no effect to your code. To facilitate this, you load a CNG provider by identifying the cryptographic algorithm that you require, not the specific provider. Most of the CNG APIs require a provider or an object created by a provider.
In this article, I try to describe the new security feature Cryptography API: Next Generation(CNG) and compare it with an RSA and AES samples, both managed and unmanaged, using "Crypto API" (CAPI before Vista) and how it can be implemented using CNG in Windows Vista. Managed version of CNG is yet to come, if you feel like you want more, wait for the next release of Visual Studio "Orcas".
Background
About RSA
RSA is the established standard for public key encryption. The name RSA is derived from the names of the inventors of this algorithm, which are: Ron Rivest, Adi Shamir and Leonard Adleman. The principle and security of RSA is based on the fact that with today's knowledge, it is not possible to find the prime factors of a big number (n=pq, where p and q are prime numbers) in suitable time.
Short details
- Public Key: n=pq (p and q are big prime numbers)
- e relative prime to (p-1)(q-1)
- Private Key: d e-1 mod ((p-1)(q-1))
- Encryption: c = me mod n
- Decryption: m = cd mod n
About AES
Advanced Encryption Standard (AES), also known as Rijndael, is a symmetric 128-bit block cipher adopted as an encryption standard by the US government.
Short details
- AES operates on a 4�4 array of bytes.
- For encryption, each round of AES (except the last round) consists of four stages: AddRoundKey, Subbytes, Shift rows and Mix columns.
- At each stage, the bytes are manipulated and processed for the next level.
Crytography API: Next Generation(CNG)
CNG provides a set of APIs that are used for performing basic cryptographic operations, such as creating hashes, encrypting, and decrypting data.
Each algorithm class in CNG is represented by a primitive router. Applications making use of the primitive APIs will link to the router binary (Bcrypt.dll in user mode, or Ksecdd.sys in kernel mode), and make calls to the various CNG primitive functions. All of the algorithm primitives are managed by various router components. These routers keep track of each algorithm implementation that has been installed on the system. The router will route each function call to the appropriate primitive provider module.
The following illustration shows the design and function of the CNG cryptographic primitives.
CNG provides primitives for the following classes of algorithms:
- Random Number Generator: This class is used to represent pluggable random number generation (RNG).
- Hashing: This class represents algorithms used for hashing, such as SHA1 and SHA2.
- Symmetric encryption: This class represents algorithms used for symmetric encryption. Some examples are AES, 3DES, and RC4.
- Asymmetric encryption: This class represents asymmetric (public key) algorithms that support encryption, like RSA.
- Signature: This class represents signature algorithms such as DSA and ECDSA. This class can also be used with RSA.
- Secret Agreement: This class represents secret agreement algorithms such as Diffie-Hellman (DH) and elliptical curve Diffie-Hellman (ECDH).
Using the code
Using a RSA CryptoService Provider (CAPI)
In CAPI, all cryptographic algorithms are predefined in wincrypt.h which makes it very difficult to extend cryptographic functionality to suit your application's need. Adding a custom symmetric algorithm is not easy. Secondly the CAPI requires Microsoft to sign the implementation, so that it can be a part of a security namespace.
Encrypt
and Decrypt
in a traditional way, with RSACryptoServiceProvider
.
RSACryptoServiceProvider MyAsymmetricAlgorithm = new RSACryptoServiceProvider();
byte[] PlainTextBytes;
byte[] CipherTextBytes;
private void Encrypt()
{
PlainTextBytes = System.Text.Encoding.UTF8.GetBytes(TextBoxOriginal.Text);
CipherTextBytes = MyAsymmetricAlgorithm.Encrypt(PlainTextBytes, true);
TextBoxEncrypted.Text = TextBoxEncrypted.Text +
+ Convert.ToBase64String(CipherTextBytes);
ShowPublicPrivate();
}
private void Decrypt()
{
PlainTextBytes = MyAsymmetricAlgorithm.Decrypt(CipherTextBytes, true);
TextBoxOriginal.Text = System.Text.Encoding.UTF8.GetString
(PlainTextBytes);
}
private void ShowPublicPrivate()
{
RSAParameters MyParameters = new RSAParameters();
MyParameters = MyAsymmetricAlgorithm.ExportParameters(true);
TextBoxPrivateKey.Text = Convert.ToBase64String(MyParameters.D);
TextBoxPublicKey.Text = Convert.ToBase64String(MyParameters.Modulus);
}
Using the CryptoService Provider with CNG
In CNG, all cryptographic constants are "strings" rather than numeric constants. And since you can use any string constant you want to define your algorithm, when your application attempts to use the algorithm, CNG will load the crypto-provider that registered the name. You can also plug in custom cipher-suits for SSL and TLS. The core function that adds a new add-in is BCryptAddContextFunctionProvider
2.
The typical steps involved in using the CNG API for cryptographic primitive operations are:
- Open the Algorithm Provider
- Get or Set Algorithm Properties
- Create or Import a Key
- Perform Cryptographic Operations
- Close the Algorithm Provider
The code for "encrypting data", the string for RSA encryption is BCRYPT_RSA_ALGORITHM
. The following shows a pseudocode for the algorithm.
Encrypt pseudocode
BCryptOpenAlgorithmProvider(&hAlg...)
BCryptGetProperty(hAlg,BCRYPT_BLOCK_LENGTH,&dwBlockSize...)
BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,&cbKeyObjectLen...)
BCryptGenerateSymmetricKey(hAlg,&hKey...)
BCryptEncrypt(hKey,...)
BCryptDestroyKey(hKey)
BCryptCloseAlgorithmProvider(hAlg,0)
Portion of Encrypt code, key generation
I have added this example of CNG for AES, and not for RSA for simplicity and reference only.
BCRYPT_RSA_ALGORITHM
can also be implemented in a similar fashion. A complete sample program for AES-CBC encryption using CNG comes with the CNG3 SDK.
Here BCRYPT_AES_ALGORITHM
is the string variable which gives the handle to the actual algorithm. So later if this algorithm needs to be changed, all we will need to do is change the implementation of AES, keeping the existing code.
#include "stdafx.h"
using namespace std;
#pragma comment(lib, "bcrypt")
wchar_t *GetEncryptionAlg()
{
return BCRYPT_AES_ALGORITHM;
}
LPBYTE GetPwd()
{
static const BYTE key[] = {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,0};
return (LPBYTE)key;
}
LPBYTE GetIV()
{
static const BYTE iv[] = {1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8};
return (LPBYTE)iv;
}
int _tmain(int argc, _TCHAR* argv[])
{
BCRYPT_ALG_HANDLE hAlg = NULL;
if (BCryptOpenAlgorithmProvider(
&hAlg,
GetEncryptionAlg(),
NULL,
0) == STATUS_SUCCESS)
{
BCRYPT_KEY_HANDLE hKey = NULL;
DWORD cbKey = 0;
DWORD cbData = 0;
if (BCryptGetProperty(
hAlg,
BCRYPT_OBJECT_LENGTH,
reinterpret_cast(&cbKey),
sizeof cbKey,
&cbData,
0) == STATUS_SUCCESS)
{
LPBYTE pbKey = new (nothrow)BYTE[cbKey];
if (pbKey)
{
BCRYPT_KEY_HANDLE hKey = NULL;
LPCSTR szPwd = (LPCSTR)GetPwd();
if (BCryptGenerateSymmetricKey(
hAlg,
&hKey,
pbKey,
cbKey,
(PUCHAR)szPwd,
(ULONG)strlen(szPwd),
0) == STATUS_SUCCESS)
{
printf("!!!");
}
}
}
}
return 0;
}
Decrypting Data
Same as above, except for BCryptDecrypt
BCryptOpenAlgorithmProvider(&hAlg...)
BCryptGetProperty(hAlg,BCRYPT_BLOCK_LENGTH,&dwBlockSize...)
BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,&cbKeyObjectLen...)
BCryptGenerateSymmetricKey(hAlg,&hKey...)
BCryptDecrypt(hKey,...)
BCryptDestroyKey(hKey)
BCryptCloseAlgorithmProvider(hAlg,0)
Hashing Data
BCryptOpenAlgorithmProvider(&hAlg...)
BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,&cbHash...)
BCryptCreateHash(hAlg,&hHash,...)
BCryptHashData(hHash,...)
BCryptDestroyHash(hHash)
BCryptCloseAlgorithmProvider(hAlg,0)
With CNG, a cryptographer can create his own cryptographic provider, with all the needed interfaces and functionality for the provider and plug in the CNG framework. The core function which is required for this is BCryptAddContextFunctionProvider
.
Here is the basic structure which will be required to add a test algorithm
BCRYPT_MYTEST_ALGORITHM
, for details please refer to the steps to install and register "CNG add-ins" in the CNG SDK
3.
#define BCRYPT_MYTEST_ALGORITHM
status = BCryptAddContextFunctionProvider(
CRYPT_LOCAL,
NULL,
BCRYPT_CIPHER_INTERFACE,
BCRYPT_MYTEST_ALGORITHM,
L"MyTest Provider",
CRYPT_PRIORITY_TOP);
A CNG also allows you to query for all supported algorithms using the function BCryptResolveProviders
.
#include "stdafx.h"
#pragma comment(lib, "bcrypt")
#ifndef NT_SUCCESS
# define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif
int __cdecl main(int argc, __in_ecount(argc) LPWSTR *wargv)
{
argc;
wargv;
BOOLEAN bFipsEnabled = FALSE;
if (NT_SUCCESS(BCryptGetFipsAlgorithmMode(&bFipsEnabled)))
printf("FIPS is %Senabled.\n",bFipsEnabled ? L"" : L"not ");
PCRYPT_PROVIDER_REFS pProviders = NULL;
DWORD dwBufSize = 0;
const DWORD dwFlags = CRYPT_ALL_FUNCTIONS | CRYPT_ALL_PROVIDERS;
for (DWORD i = BCRYPT_CIPHER_INTERFACE; i <= BCRYPT_RNG_INTERFACE; i++)
{
NTSTATUS ret = BCryptResolveProviders(
NULL,
i,
NULL,
NULL,
CRYPT_UM,
dwFlags,
&dwBufSize,
&pProviders);
if (NT_SUCCESS(ret) && pProviders)
{
printf("dwInterface = %d\n", i);
for (DWORD k=0; k < pProviders->cProviders; k++)
{
PCRYPT_PROVIDER_REF pProv = pProviders->rgpProviders[k];
printf("\tFunction = %S\n", pProv->pszFunction);
printf("\tProvider = %S\n", pProv->pszProvider);
for ( DWORD j = 0; j < pProv->cProperties; j++)
printf("\tProperty %d = %S\n", j,
pProv->rgpProperties[j]->pszProperty);
printf("\n");
}
BCryptFreeBuffer(pProviders);
pProviders = NULL;
dwBufSize = 0;
}
}
return 0;
}
Managed library for CNG is coming with the next version of Visual Studio "Orcas" and is not available right now in Visual Studio 2005. You can download the unmanaged version of the CNG SDK3 to develop for Windows Vista.
CNG also has access to all the CAPI keys used by Microsoft Cryptographic Service providers.
List of CNG Cryptographic Primitive Functions
Here is a the list of functions defined by the Cryptographic Next Generation (CNG) API that are used for performing cryptographic operations.
BCryptCloseAlgorithmProvider
BCryptCreateHash
BCryptDecrypt
BCryptDeriveKey
BCryptDestroyHash
BCryptDestroyKey
BCryptDestroySecret
BCryptDuplicateHash
BCryptDuplicateKey
BCryptEncrypt
BCryptExportKey
BCryptFinalizeKeyPair
BCryptFinishHash
BCryptFreeBuffer
BCryptGenerateKeyPair
BCryptGenerateSymmetricKey
BCryptGenRandom
BCryptGetProperty
BCryptHashData
BCryptImportKey
BCryptImportKeyPair
BCryptOpenAlgorithmProvider
BCryptSecretAgreement
BCryptSetProperty
BCryptSignHash
BCryptVerifySignature
Look for details on each of these functions in MSDN.
New Crypto Algorithms in Orcas
The January CTP of Orcas, has the first set of managed wrappers around the new CNG APIs in Windows Vista5, which will use the "Cng suffix" on the implementation classes.
Hash Algorithms
Algorithm |
Class |
OS Required |
MD5 |
MD5Cng |
Windows Vista |
SHA-1 |
SHA1Cng |
Windows Vista |
SHA-256 |
SHA256CryptoServiceProvider
SHA256Cng |
Windows 2003 Windows Vista |
SHA-384 |
SHA384CryptoServiceProvider
SHA384Cng |
Windows 2003 Windows Vista |
SHA-512 |
SHA512CryptoServiceProvider
SHA512Cng |
Windows 2003 Windows Vista |
For applications targeting Vista which must use CNG, this set of algorithms also provides CNG wrappers for all of our hashing algorithms.
Asymmetric Algorithms
Algorithm |
Class |
OS Required |
Elliptic Curve DSA |
ECDSACng |
Windows Vista |
Elliptic Curve Diffie-Hellman |
ECDiffieHellmanCng |
Windows Vista |
Check Microsoft security5 blogs for the latest information on CNG.
Points of Interest
- Windows Vista supports the following four user modes cryptographic interfaces; CNG, Cryptographic API 1.0 (CAPI 1.0), Cryptographic API 2.0 (CAPI 2.0) and .NET Framework Cryptography
- CNG also includes kernel mode along with the user mode. In prior versions of Windows, technologies like CAPI were user mode only and kernel mode cryptography required totally different set of APIs. Now with the Next Generation Cryptography (CNG) there is a unified set of APIs for both
- CNG is highly flexible, enabling new algorithms to be added to Windows Vista for use in Secure Socket Layer/Transport Layer Security SSL/TLS and Internet Protocol Security IPSec
- CNG includes Elliptic Curve Cryptography, an emerging standard among cryptographic algorithms.
- Windows Vista includes a Base Smart Card Cryptographic Service Provider (Base CSP) in the platform. This will make smart cards more accessible, as vendors will no longer have to deal with writing complex CSPs. There will also be a smart card Key Storage Provider in the new CNG infrastructure.
- Only administrator can install a CNG Provider
References
- Encryption and Cryptography
- Writing Secure Code for Windows Vista
- Download CNG SDK for use in C++
- Orcas January CTP with Managed library for CNG
- CNG Reference, MSDN Security blog
- List Cryptographic algorithms available in your computer
History
- Apr 29, 2007: First Published
- May 02, 2007: CNG Enumerator & portion of AES encrypt
And thanks
For coming so far, I hope this article will help demystify some of the new security concepts in Windows Vista, and you will find it useful. Adios!