Microsoft Windows Vista中的下一代加密API
CNG是Windows Vista中最新的加密体系,其支持新的API、一体式用户及内核模式、灵活的加密方法及新的密码套件。
简介
CNG是Windows Vista中一种新的、灵活的框架结构,其实现了可扩展的提供者模式,可允许你通过指定所需的加密算法来加载某个提供者,而不用针对某个特殊的提供者进行硬编码。
其好处在于算法提供者可被替换或升级,而无需修改相关程序代码就可使用新的提供者;同时,如果确定某些算法在将来会变得不安全,也可以安装更安全的版本,且对原程序代码无任何影响。这样一来,就可通过识别所需的加密算法,而不是特定的提供者来加载一个CNG提供者。大多数CNG API都需要一个提供者或由提供者创建的一个对象。
在本文中,将会讲解CNG新的安全特性,并与RSA及AES进行比较,并在托管及非托管模式下使用“Crypto API”(Vista之前的加密API),及它们如何在Windows Vista下通过CNG来实现。
背景知识
关于RSA
RSA是公匙加密中已确定的标准,RSA本身的名称派生自算法发明的名字,他们是:Ron Rivest、Adi Shamir、Leonard Adleman。RSA的原理及安全性基于现今的认识——即不可能在适当的时间内找到一个大数的质数因子(如n=qp,在这p及q为质数)。细则如下:
公匙:n=qp(p及q为大质数)
E相关质数(p-1)(q-1)
私匙:d e-1 mod ((p-1)(q-1))
加密:c = me mod n
解密:m = cd mod n
关于AES
Advanced Encryption Standard (AES),也称为Rijndael,是一种128位块的对称加密,已被采用为美国政府的一种加密标准。细则如下:
AES操作一个4×4的字节数组。
加密时,每轮AES(除了最后一轮)由四阶段组成:AddRoundKey、Subbytes、Shift rows、Mix columns。
在每一阶段,字节为下一级进行了相关操纵及处理。
下一代加密API:CNG
CNG提供一个API集,用于执行基本的加密操作,如创建哈希、加密及解密数据。CNG中的每个算法类都有一个原语路由,使用这些原语API的程序则会链接到路由库(用户模式中是Bcrypt.dll,核心模式中是Dsecdd.sys),并调用不同的CNG原语函数。所有这些算法原语都由各个不同的路由组件管理,这些路由跟踪安装在系统中每个算法的实现,并把对各个函数的调用,路由到适当的原语提供者模块中。
下图演示了CNG加密原语的设计与函数模式。
CNG为下列算法提供了原语:
随机数生成:表示可插入的随机数生成(RNG)。
哈希:表示用于哈希的算法,如SHA1及SHA2。
对称加密:表示对称加密的算法,如AES、3DES、RC4。
非对称加密:表示非对称加密算法,如RSA。
签名:表示如DSA及ECDSA之类的签名算法,也可与RSA一同使用。
秘密协定:表示私密协定算法,如Diffie-Hellman及椭圆曲线Diffie-Hellman。
使用RSA CryptoService Provider(CAPI)
就CAPI而言,所有的加密算法都预定义在wincrypt.h中,这样就非常难以扩展加密功能以适应各自程序的需要,比如说添加一个自定义的对称加密算法就不是一件简单的事;其次,CAPI需要微软来签名其实现,所以它可作为安全命名空间的一部分。
以下是传统方式的加密及解密,使用了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);
//剩余代码已省略
}
与CNG一同使用CryptoService Provider
在CNG中,所有加密常量均为“字符串”而不是数值,因为可使用任何字符串常量来定义算法,所以当程序试图使用算法时,CNG会加载注册了此名字的加密算法提供者。我们也可为SSL及TLS插入自定义的加密算法,添加一个新插件的核心函数是:BCryptAddContextFunctionProvider。
使用CNG API用于加密原语操作的一般步骤如下:
1、 打开算法提供者(Provider)。
2、 Get或Set算法属性。
3、 创建或导入一个密钥。
4、 执行加密操作。
5、 关闭算法提供者。
用作RSA加密的字符串是:BCRYPT_RSA_ALGORITHM,以下是此算法的伪代码:
BCryptOpenAlgorithmProvider(&hAlg...)
BCryptGetProperty(hAlg,BCRYPT_BLOCK_LENGTH,&dwBlockSize...)
//分配缓冲区,取整到下一块大小
BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,&cbKeyObjectLen...)
//为密钥对象分配缓冲区
BCryptGenerateSymmetricKey(hAlg,&hKey...)
BCryptEncrypt(hKey,...)
//数据现在已被加密
BCryptDestroyKey(hKey)
BCryptCloseAlgorithmProvider(hAlg,0)
//释放缓冲区
BCRYPT_AES_ALGORITHM是字符串变量,其把句柄交给了真正的算法,所以在此之后,如果算法需要修改,我们只需修改AES的实现部分即可,以下代码还包括了密钥的生成。
#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;
}
解密数据与上面类似,除了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)
//释放缓冲区
以下代码是对数据进行哈希处理。
BCryptOpenAlgorithmProvider(&hAlg...)
BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,&cbHash...)
//为哈希分配缓冲区
BCryptCreateHash(hAlg,&hHash,...)
BCryptHashData(hHash,...)
//使用哈希数据
//其他程序代码
BCryptDestroyHash(hHash)
BCryptCloseAlgorithmProvider(hAlg,0)
//释放缓冲区
一个加密程序可通过CNG,创建其自己的加密提供者,在CNG框架中,已自带了所有相关所需的接口及功能插件,此核心函数为:BCryptAddContextFunctionProvider。
以下是添加一个BCRYPT_MYTEST_ALGORITHM测试算法所需的基本结构,详细步骤请查阅CNG SDK3中的Install and register “CNG add-ins”。
#define BCRYPT_MYTEST_ALGORITHM
status = BCryptAddContextFunctionProvider(
CRYPT_LOCAL,
NULL, //default
BCRYPT_CIPHER_INTERFACE,
BCRYPT_MYTEST_ALGORITHM,
L"MyTest Provider",
CRYPT_PRIORITY_TOP);
也可使用CNG中的函数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);
// print property names
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;
}
CNG的托管库已随Visual Studio 2008提供,如果使用Visual Studio 2005,可使用CNG SDK3的非托管版本在Windows Vista上进行开发。同时,CNG也可访问Microsoft Cryptographic Service providers中所使用的所有CAPI密钥。
CNG加密原语函数列表
以下是CNG API中定义的用于加密的函数列表:
• 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
Visual Studio 2008中新的加密算法
在Visual Studio 2008中,已自带了Windows Vista中新的CNG API托管包装函数,其在实现类中以Cng后缀表明。
哈希算法
算法 |
类 |
所支持的操作系统 |
Elliptic Curve DSA |
ECDSACng |
Windows Vista |
Elliptic Curve Diffie-Hellman |
ECDiffieHellmanCng |
Windows Vista |