下一代Windows加密API
对长期使用Visual C++的开发者来说,CryptoAPI是编程工具中一个非常熟悉的部分,其在Win32 SDK中第一次发布时就提供了哈希、加密、签名及认证管理等功能。在12年之后,CryptoAPI的替代者随着Windows Vista的发布而来了:Windows Cryptography API: Next Generation (CNG)——即下一代Windows加密API。
CNG相比CryptoAPI,有两个主要优势之处,其一:更好的API因式分解,允许同一函数使用多个加密算法;其二:包含了许多作为National Security Agency (NSA) Suite B一部分的更新的算法,而Suite B算法达到了满足最高级别机密信息传输的要求。在本文中,将会演示CNG中包含的椭圆曲线Diffie-Hellman密匙交换算法。
在深入了解CNG之前,先来回头看一下大环境。与CryptoAPI类似,CNG是与Windows操作系统一起提供的,且只限定于Windows Vista及以上操作系统。CNG针对C++开发者,但也提供了C语言DLL,以便可在C#及VB.NET中访问。CNG同时工作在用户及核心模式,并支持CryptoAPI中的所有算法,这样一来,就大大减轻了迁移难度。CNG是完全可分解的,它提供的任何功能都可以被第三方加密算法扩展或取代,微软CNG的实现主要封装在Bcrypt.dll中。
除了本文后面演示的功能之外,CNG还提供了以下功能:
随机数生成
数字签名
哈希
不对称加密
对称加密
大多数开发者可能都会知道对称加密与不对称加密之间的区别,对称加密也称为私匙加密,它用一个共享的密匙来保护数据,而不对称加密也称为公匙加密,它用一个公共的私有密匙对来保护数据。不对称加密有极高的计算开销,且许多高级的协议也使用了不对称方式先加密要交换的信息,再在一个会话期间使用对称加密,SSL握手协议就是现今一个典型的例子。
大家熟知的不对称加密算法,如RSA算法,其用两个质数的相乘作为公匙,这是因为非常难以算出原始的两个质数(其作为私匙)。随着数学理论及计算能力的发展,这种基于质数的不对称加密已需要非常大的密匙才能保证数据的机密性。椭圆曲线加密算法(ECC)则是另一种不对称加密算法,它基于椭圆线曲线上的坐标点,ECC算法的优势在于只需很短的密匙就可达到相同级别的加密强度。
目前,CNG的文档还不够完善,相关的SDK中也没有包含CNG示例代码,又因为CNG的接口被设计为要适应多种算法,所以要找出每种算法中调用各个函数的顺序几乎是项“不可能的任务”,本文以下部分只作一个简单的示例说明。
CNG首先要打开一个算法源(或称算法提供者),用于支持密匙交换,当打开算法源后,还要指定提供者及算法,以打开使用384位质数椭圆曲线Diffie-Hellman密匙交换算法的微软解决方案。
BCRYPT_ALG_HANDLE algHandle;
BCryptOpenAlgorithmProvider(&algHandle, BCRYPT_ECDH_P384_ALGORITHM, MS_PRIMITIVE_PROVIDER, 0);
某个算法提供者一旦打开,就需要生成一个密匙对或从原来存储的中读取一个。如果要生成密匙对,代码如下:
BCRYPT_KEY_HANDLE fullKey;
BCryptGenerateKeyPair(algHandle, &fullKey, 384, 0);
BCryptFinalizeKeyPair(fullKey, 0);
需要输出公匙,以便传递给信息交换的另一方:
PUCHAR publicKey;
ULONG publicKeySize = 0;
//取公匙的大小
BCryptExportKey(fullKey, NULL,
BCRYPT_ECCPUBLIC_BLOB, NULL, 0, &publicKeySize, 0);
//为公匙分配空间
publicKey = new UCHAR[publicKeySize];
//获取公匙
BCryptExportKey(fullKey, NULL, BCRYPT_ECCPUBLIC_BLOB, publicKey,
publicKeySize, &publicKeySize, 0);
//现在,可把publicKey通过非安全的传输途径传递给对方了。
双方现在交换了公匙,外部公匙被导入,且用于创建一个私密句柄:
//为外部公匙定义的变量
PUCHAR publicKeyFromOtherParty;
ULONG publicKeyFromOtherPartySize;
//导入另一方公匙
BCRYPT_KEY_HANDLE importedPublicKey;
BCryptImportKeyPair(algHandle, NULL,
BCRYPT_ECCPUBLIC_BLOB, &importedPublicKey,
publicKeyFromOtherParty, publicKeyFromOtherPartySize, 0);
//创建私密性
BCRYPT_SECRET_HANDLE secretHandle;
BCryptSecretAgreement(fullKey, importedPublicKey, &secretHandle, 0);
一旦私密句柄生成,可派生一对称密匙,它对交换了公钥的双方来说都是一样的:
PUCHAR derivedSymmetricKey;
ULONG derivedKeySize;
//取派生密匙的大小
BCryptDeriveKey(secretHandle, L"HASH", NULL, NULL, 0, &derivedKeySize, 0);
//为派生密匙分配空间
derivedSymmetricKey = new UCHAR[derivedKeySize];
//获取派生密钥
BCryptDeriveKey(secretHandle, L"HASH", NULL,
derivedSymmetricKey, derivedKeySize, &derivedKeySize, 0);
有了派生后的对称密钥,通信双方就能在不影响性能的情况下交换加密信息了。
CNG确实为加密开发带来了非常大的便利性,如果开发的系统专门面向Windows Vista或Windows Server 2008,那么用CNG就比用CryptoAPI意义大多了。