章节目录
作者能力有限, 如果您在阅读过程中发现任何错误, 还请您务必联系本人,指出错误, 避免后来读者再学习错误的知识.谢谢!
简介##
CNG 全称 Cryptography API: Next Generation (CNG). 是 windows 平台下一代加密相关 API 的总称, 它是 Crypto API 的替代. 比较与 CryptoAPI, 它的功能更加强大.
本文将以实例的形式给出使用 CNG 操作 Key 的方法以及相关的 API.
请注意, 文章中我们使用 RSA key 作为示例, DSA 和 ECC key 也是同样适用的.
创建 Key##
CNG 当前版本支持了 RSA, DSA, ECC 算法, 这里我们来创建一个 key 长度 为 2048 bits 的 RSA key. 注意, 当你尝试创建 2048 的 DSA key 时, 请确保你的系统是否支持, 本人的 Win7 是不支持的, 而 Win10 是支持的(亲测).
这里我们依次使用了以下API:
NCryptOpenStorageProvider
该方法用于加载和初始化一个已经存在 CNG Key Storage Provider. 当前 Windows 系统中内置了两个 KSP:MS_KEY_STORAGE_PROVIDER,MS_SMART_CARD_KEY_STORAGE_PROVIDER. 我们例子中使用 MS_KEY_STORAGE_PROVIDER.
NCryptCreatePersistedKey
该方法用于常见一个特定算法的 Key, 并把它存在指定的 KSP 中. 注意, 这个方法创建的 key 会以文件形式存储在 Windows 系统中.
NCryptSetProperty
该方法用于设置 key 的属性. 例子中我们将使用它设置 key 的长度为 2048 bits.
NCryptFinalizeKey
该方法用于通知 Windows 我们创建 key 的操作已经完成, 调用该方法后, 我们创建的 Key 将可以被用于签名加密等操作, 否则不能.
NCryptFreeObject
该方法用于释放前面操作中我们所使用到系统 Handle.
int Create2048RSAKey() {
int errCode = 0;
NCRYPT_PROV_HANDLE prov = NULL;
NCRYPT_KEY_HANDLE key = NULL;
DWORD keyLength = 2048;
DWORD policy = NCRYPT_ALLOW_EXPORT_FLAG | NCRYPT_ALLOW_PLAINTEXT_EXPORT_FLAG;
if (errCode = NCryptOpenStorageProvider(&prov, MS_KEY_STORAGE_PROVIDER, 0)) goto done;
if (errCode = NCryptCreatePersistedKey(prov, &key, NCRYPT_RSA_ALGORITHM, L"TestRSAKey", 0, NCRYPT_OVERWRITE_KEY_FLAG)) goto done;
if (errCode = NCryptSetProperty(key, NCRYPT_LENGTH_PROPERTY, (PBYTE)(&keyLength), sizeof(keyLength), NCRYPT_PERSIST_FLAG)) goto done;
if (errCode = NCryptSetProperty(key, NCRYPT_EXPORT_POLICY_PROPERTY, (PBYTE)(&policy), sizeof(policy), NCRYPT_PERSIST_FLAG)) goto done;
if (errCode = NCryptFinalizeKey(key, 0)) goto done;
done:
if (prov) NCryptFreeObject(prov);
if (key) NCryptFreeObject(key);
return errCode;
}
当你在你的 Windows 电脑上执行了该方法之后, 你的系统中就会存有我们刚刚创建的 Key 了.
下一节, 我们将使用 CNG API 来查看我们创建的 Key 的信息.
查看系统中的 Key##
这里我们将会使用到的 CNG API 有:
NCryptEnumKeys
该方法用于遍历保存在当前 KSP 中的所有 Key.
这里我们解释一下它的几个参数:
NCryptKeyName **ppKeyName
该参数作为方法的返回值, 其中保存了当前 Key 的名称, key 算法等重要信息. name 尤为重要, 比如我们例子中会使用 name 来获取该 key 的 handle, 依次来使用该 key 做更多的操作.
PVOID *ppEnumState
该参数也作为方法的返回值. 但是它的值对于调用者来说是没有任何意义的. 它存储了遍历 key 的中间信息, 是我