典型 CNG 编程概述

CNG API 实现可扩展提供程序模型,该模型允许通过指定所需的加密算法而不是特定提供程序来加载提供程序。 优点是可以替换或升级算法提供程序,无需以任何方式更改代码即可使用新提供程序。 此外,如果将来确定某些算法不安全,则可以安装该算法的更安全版本,而不会影响代码。 大多数 CNG API 都需要提供程序或由提供程序创建的对象。

将 CNG API 用于加密基元作所涉及的典型步骤如下所示:

  1. 打开算法提供程序
  2. 获取或设置算法属性
  3. 创建或导入密钥
  4. 执行密码操作
  5. 关闭算法提供程序

有关详细信息,请参阅 编程示例

打开算法提供程序

BCryptOpenAlgorithmProvider 函数为你提供算法提供程序句柄,该句柄用于后续的 CNG API,例如 BCryptCreateHashBCryptGenerateKeyPair

获取或设置算法属性

可以使用算法提供程序句柄获取该算法的实现详细信息,例如密钥大小或当前操作模式。 可以使用 BCryptGetProperty 函数获取特定属性。

还可以修改算法的属性。 例如,如果要将 ECB 块密码链与 AES 一起使用,请将 AES 算法的 BCRYPT_CHAINING_MODE 属性设置为 BCRYPT_CHAIN_MODE_ECB;该属性分配给使用此算法句柄创建的所有 AES 密钥,而无需配置每个 AES 密钥。 使用 BCryptSetProperty 函数修改这些属性。

警告

不要将 ECB 模式用于生产数据。 ECB 会独立地加密每个块,这意味着相同的明文块会产生相同的密文,从而泄露数据中的模式。 将 CBC 模式与随机初始化向量(IV)配合使用,或者最好使用 GCM()等经过身份验证的加密模式,BCRYPT_CHAIN_MODE_GCM该模式提供机密性和完整性。

创建或导入密钥

根据所使用的算法类型,可能需要创建或加载密钥。 例如,BCryptEncrypt 函数接收一个键句柄作为第一个参数。 如果希望该函数使用对称加密算法(如 AES)加密数据,则必须首先获取密钥。 获取密钥的方式取决于所使用的算法类型和密钥的源。

可以使用 BCryptGenerateSymmetricKeyBCryptGenerateKeyPair 函数创建临时密钥。 还可以使用 BCryptImportKeyBCryptImportKeyPair 函数从内存 BLOB 导入临时密钥。

对于持久化密钥,可以使用密钥存储函数加载密钥存储提供程序,然后创建或加载密钥。 你还可以使用这些函数,通过为任何容器名称传递 NULL 来创建或加载临时密钥。 有关密钥存储函数的详细信息,请参阅 CNG 密钥存储函数

执行密码操作

现在可以分别使用 BCryptEncryptBCryptDecrypt 函数执行加密或解密数据等加密作。

关闭算法提供程序

不再需要提供程序时,必须将句柄传递给 BCryptCloseAlgorithmProvider 函数才能关闭提供程序。 这会导致提供程序释放为该算法提供程序实例分配的任何资源。 提供程序句柄关闭后,无法重复使用。

加载提供程序可能是一个相对耗时的过程。 因此,应缓存那些在应用程序整个生命周期内会被多次引用的提供程序句柄。

编程示例

以下示例介绍如何使用 CNG 执行特定加密作: