Cryptography API: Next Generation(CNG)使用梳理——非对称加密算法应用(一)数字验证及非对称密钥的导出与导入

本文介绍了CryptographyAPI:NextGeneration(CNG)中非对称加密的关键步骤,包括数字验证、密钥对创建、签名过程以及公钥的导入导出。通过NCrypto和BCrypto函数,展示了如何使用非对称密钥进行签名和验证,特别讨论了PKCS1填充在RSA签名中的应用。
摘要由CSDN通过智能技术生成

非对称加密算是CNG的重头戏,主要包括,数字验证、信息加密、共享密钥协议等,其中引入了NCtypto系列的函数用于非对称密钥的持久化保存与读取,这篇先以数字验证为例梳理一下,非对称密钥的使用,及导入导出。下一篇同样以数字验证为案例讲一下,非对称密钥导入导出时的持久化保存问题(即BCrypto生成的密钥导出后通过NCrypto保存),之后会再出一篇谈谈与OpenSSL3之间的密钥格式转换及相互签名及验证

一、一般流程

(一)对需要签名的数据进行哈希算法,具体参照,这里不做详述《Cryptography API: Next Generation(CNG)使用梳理——Hash及随机数算法应用》

(二)签名流程(NCtypto签名,BCtypto验证签名)

1、获取算法提供者句柄(NCtypto)

2、创建非对称密钥对

3、完成(NCtypto系列可以在本地固定目录保存密钥对)密钥对

4、对已经Hash的数据进行签名

5、导出公钥(NCtypto)

6、获取算法提供程序(BCtypto)

7、导入公钥(BCtypto)

8、验证签名

需要使用到的函数:

//打开支持所需算法的算法提供程序(NCrypt)
SECURITY_STATUS NCryptOpenStorageProvider(
  [out]          NCRYPT_PROV_HANDLE *phProvider,
  [in, optional] LPCWSTR            pszProviderName,
  [in]           DWORD              dwFlags
);

//创建一个新的密钥对,并将其存储在指定的密钥存储提供程序中
SECURITY_STATUS NCryptCreatePersistedKey(
  [in]           NCRYPT_PROV_HANDLE hProvider,
  [out]          NCRYPT_KEY_HANDLE  *phKey,
  [in]           LPCWSTR            pszAlgId,
  [in, optional] LPCWSTR            pszKeyName,
  [in]           DWORD              dwLegacyKeySpec,
  [in]           DWORD              dwFlags
);

//设置密钥对属性,但在调用 NCryptFinalizeKey 函数之前,不能使用该键
//比如:设置私钥可以导出
SECURITY_STATUS NCryptSetProperty(
  [in] NCRYPT_HANDLE hObject,
  [in] LPCWSTR       pszProperty,
  [in] PBYTE         pbInput,
  [in] DWORD         cbInput,
  [in] DWORD         dwFlags
);

//完成密钥存储。 在调用此函数之前,不能使用该密钥对
SECURITY_STATUS NCryptFinalizeKey(
  [in] NCRYPT_KEY_HANDLE hKey,
  [in] DWORD             dwFlags
);

//创建哈希值的签名
SECURITY_STATUS NCryptSignHash(
  [in]           NCRYPT_KEY_HANDLE hKey,
  [in, optional] VOID              *pPaddingInfo,
  [in]           PBYTE             pbHashValue,
  [in]           DWORD             cbHashValue,
  [out]          PBYTE             pbSignature,
  [in]           DWORD             cbSignature,
  [out]          DWORD             *pcbResult,
  [in]           DWORD             dwFlags
);

//密钥导出到内存BLOB
SECURITY_STATUS NCryptExportKey(
  [in]            NCRYPT_KEY_HANDLE hKey,
  [in, optional]  NCRYPT_KEY_HANDLE hExportKey,
  [in]            LPCWSTR           pszBlobType,
  [in, optional]  NCryptBufferDesc  *pParameterList,
  [out, optional] PBYTE             pbOutput,
  [in]            DWORD             cbOutput,
  [out]           DWORD             *pcbResult,
  [in]            DWORD             dwFlags
);

//打开支持所需算法的算法提供程序(BCrypt)
NTSTATUS BCryptOpenAlgorithmProvider(
  [out] BCRYPT_ALG_HANDLE *phAlgorithm,
  [in]  LPCWSTR           pszAlgId,
  [in]  LPCWSTR           pszImplementation,
  [in]  ULONG             dwFlags
);

//从 BLOB 中导入公钥或私钥
NTSTATUS BCryptImportKeyPair(
  [in]      BCRYPT_ALG_HANDLE hAlgorithm,
  [in, out] BCRYPT_KEY_HANDLE hImportKey,
  [in]      LPCWSTR           pszBlobType,
  [out]     BCRYPT_KEY_HANDLE *phKey,
  [in]      PUCHAR            pbInput,
  [in]      ULONG             cbInput,
  [in]      ULONG             dwFlags
);

//删除保存在本地的密钥对文件,同时释放句柄
//如果 NCryptDeleteKey 失败,应用程序可以使用 NCryptFreeObject 函数释放句柄。
SECURITY_STATUS NCryptDeleteKey(
  [in] NCRYPT_KEY_HANDLE hKey,
  [in] DWORD             dwFlags
);

//验证指定的签名是否与指定的哈希匹配
NTSTATUS BCryptVerifySignature(
  [in]           BCRYPT_KEY_HANDLE hKey,
  [in, optional] VOID              *pPaddingInfo,
  [in]           PUCHAR            pbHash,
  [in]           ULONG             cbHash,
  [in]           PUCHAR            pbSignature,
  [in]           ULONG             cbSignature,
  [in]           ULONG             dwFlags
);

实例:(代码根据官方演示案例修改而来,用于演示流程,因此去掉了返回校验过程)

#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#include <ncrypt.h>

#pragma comment(lib,"Bcrypt.lib")
#pragma comment(lib,"Ncrypt.lib")

#define NT_SUCCESS(Status)          (((NTSTATUS)(Status)) >= 0)

#define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)

static const  BYTE rgbMsg[] =
{
	0x04, 0x87, 0xec, 0x66, 0xa8, 0xbf, 0x17, 0xa6,
	0xe3, 0x62, 0x6f, 0x1a, 0x55, 0xe2, 0xaf, 0x5e,
	0xbc, 0x54, 0xa4, 0xdc, 0x68, 0x19, 0x3e, 0x94,
};

int main()
{
	NCRYPT_PROV_HANDLE      hProv           = NULL;
	NCRYPT_KEY_HANDLE       hKey            = NULL;
	BCRYPT_KEY_HANDLE       hTmpKey         = NULL;
	BCRYPT_ALG_HANDLE       hHashAlg        = NULL,
						    hSignAlg        = NULL;
	BCRYPT_HASH_HANDLE      hHash           = NULL;
	NTSTATUS                status          = STATUS_UNSUCCESSFUL;
	DWORD                   cbData          = 0,
						    cbHash          = 0,
						    cbBlob          = 0,
						    cbSignature     = 0,
						    cbHashObject    = 0;
	PBYTE                   pbHashObject    = NULL;
	PBYTE                   pbHash          = NULL,
						    pbBlob          = NULL,
						    pbSignature     = NULL;

	//获取数据的哈希值,具体参照《Cryptography API: Next Generation(CNG)使用梳理——Hash及随机数算法应用》
	BCryptOpenAlgorithmProvider(&hHashAlg, BCRYPT_SHA1_ALGORITHM, NULL, 0);
	BCryptGetProperty(hHashAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0);
	pbHashObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHashObject);
	BCryptGetProperty(hHashAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0);
	pbHash = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHash);
	BCryptCreateHash(hHashAlg, &hHash, pbHashObject, cbHashObject, NULL, 0, 0);
	BCryptHashData(hHash, (PBYTE)rgbMsg, sizeof(rgbMsg), 0);
	BCryptFinishHash(hHash, pbHash, cbHash, 0);
	//完成获取数据的哈希值

	//加载并初始化 CNG 密钥存储提供程序
	NCryptOpenStorageProvider(&hProv, MS_KEY_STORAGE_PROVIDER, 0);

	//创建一个新密钥对
	NCryptCreatePersistedKey(hProv, &hKey, NCRYPT_ECDSA_P256_ALGORITHM, L"my ecc key", 0, 0);

	//完成密钥对(并存储)
	NCryptFinalizeKey(hKey, 0);

	//创建哈希值的签名
	NCryptSignHash(hKey, NULL, pbHash, cbHash, NULL, 0, &cbSignature, 0);

	//分配存储签名所需空间
	pbSignature = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbSignature);

	//对哈希值签名
	NCryptSignHash(hKey, NULL, pbHash, cbHash, pbSignature, cbSignature, &cbSignature, 0);

	//导出公钥,获取导出公钥所需空间大小
	NCryptExportKey(hKey, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, NULL, 0, &cbBlob, 0);

	//分配公钥所需要空间
	pbBlob = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbBlob);

	//导出公钥
	NCryptExportKey(hKey, NULL, BCRYPT_ECCPUBLIC_BLOB, NULL, pbBlob, cbBlob, &cbBlob, 0);

	//加载并初始化BCrypt提供程序
	BCryptOpenAlgorithmProvider(&hSignAlg, BCRYPT_ECDSA_P256_ALGORITHM, NULL, 0);

	//导入公钥
	BCryptImportKeyPair(hSignAlg, NULL, BCRYPT_ECCPUBLIC_BLOB, &hTmpKey, pbBlob, cbBlob, 0);

	//验证指定的签名是否与指定的哈希匹配
	if(!NT_SUCCESS(status = BCryptVerifySignature(hTmpKey,
											NULL,
											pbHash,
											cbHash,
											pbSignature,
											cbSignature,
											0)))
	{
		wprintf(L"**** Error 0x%x returned by BCryptVerifySignature\n", status);
	}
	else {
		wprintf(L"Success!\n");
	}

	if(hHashAlg) {
		BCryptCloseAlgorithmProvider(hHashAlg,0);
	}

	if(hSignAlg) {
		BCryptCloseAlgorithmProvider(hSignAlg,0);
	}

	if (hHash) {
		BCryptDestroyHash(hHash);
	}

	if(pbHashObject) {
		HeapFree(GetProcessHeap(), 0, pbHashObject);
	}

	if(pbHash) {
		HeapFree(GetProcessHeap(), 0, pbHash);
	}

	if(pbSignature) {
		HeapFree(GetProcessHeap(), 0, pbSignature);
	}

	if(pbBlob) {
		HeapFree(GetProcessHeap(), 0, pbBlob);
	}

	if (hTmpKey) {
		BCryptDestroyKey(hTmpKey);
	}

	if (hKey) {
		NCryptDeleteKey(hKey, 0);
	}

	if (hProv) {
		NCryptFreeObject(hProv);
	}

	return 0;
}

这小单元最后以RSA签名为例,说一下加密填充的情况

NCryptSignHash和BCryptSignHash中pPaddingInfo参数用于设置填充信息的结构的指针。 此参数指向的实际结构类型取决于 dwFlags 参数的值。 此参数仅用于非对称密钥,否则必须为 NULL

dwFlags 参数的值

BCRYPT_PAD_PKCS1使用 PKCS1 填充方案。 pPaddingInfo 参数是指向BCRYPT_PKCS1_PADDING_INFO结构的指针。

BCRYPT_PAD_PSS使用概率签名方案 (PSS) 填充方案。 pPaddingInfo 参数是指向BCRYPT_PSS_PADDING_INFO结构的指针。

BCRYPT_PAD_PKCS1和BCRYPT_PAD_PSS都是为RSA准备的,而其它,如ECDH_P256,不能使用填充
BCRYPT_PAD_PKCS1为PKCS#1 v1.5标准,BCRYPT_PAD_PSS为PKCS#1 v2.1标准,前者有安全隐患,后者更好

RSA签名时,内部已经默认使用BCRYPT_PAD_PKCS1填充了填充算法需要与签名的哈希算法相匹配,如果哈希为SHA256时,则BCRYPT_PAD_PKCS1填充SHA256哈希函数

以BCRYPT_PAD_PKCS1为例,只需将BCRYPT_PKCS1_PADDING_INFO中的pszAlgId设置为一个哈希算法

typedef struct _BCRYPT_PKCS1_PADDING_INFO {
  LPCWSTR pszAlgId;
} BCRYPT_PKCS1_PADDING_INFO;

代码如下:

#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#include <ncrypt.h>

#pragma comment(lib,"Bcrypt.lib")
#pragma comment(lib,"Ncrypt.lib")

#define NT_SUCCESS(Status)          (((NTSTATUS)(Status)) >= 0)

#define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)

static const  BYTE rgbMsg[] =
{
	0x04, 0x87, 0xec, 0x66, 0xa8, 0xbf, 0x17, 0xa6,
	0xe3, 0x62, 0x6f, 0x1a, 0x55, 0xe2, 0xaf, 0x5e,
	0xbc, 0x54, 0xa4, 0xdc, 0x68, 0x19, 0x3e, 0x94,
};

int main()
{
	NCRYPT_PROV_HANDLE      hProv           = NULL;
	NCRYPT_KEY_HANDLE       hKey            = NULL;
	BCRYPT_KEY_HANDLE       hTmpKey         = NULL;
	BCRYPT_ALG_HANDLE       hHashAlg        = NULL,
						    hSignAlg        = NULL;
	BCRYPT_HASH_HANDLE      hHash           = NULL;
	NTSTATUS                status          = STATUS_UNSUCCESSFUL;
	DWORD                   cbData          = 0,
						    cbHash          = 0,
						    cbBlob          = 0,
						    cbSignature     = 0,
						    cbHashObject    = 0,
						    cbKeyLength     = 2048;
	PBYTE                   pbHashObject    = NULL;
	PBYTE                   pbHash          = NULL,
						    pbBlob          = NULL,
						    pbSignature     = NULL;

	//获取数据的哈希值,具体参照《Cryptography API: Next Generation(CNG)使用梳理——Hash及随机数算法应用》
	BCryptOpenAlgorithmProvider(&hHashAlg, BCRYPT_SHA256_ALGORITHM, NULL, 0);
	BCryptGetProperty(hHashAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0);
	pbHashObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHashObject);
	BCryptGetProperty(hHashAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0);
	pbHash = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHash);
	BCryptCreateHash(hHashAlg, &hHash, pbHashObject, cbHashObject, NULL, 0, 0);
	BCryptHashData(hHash, (PBYTE)rgbMsg, sizeof(rgbMsg), 0);
	BCryptFinishHash(hHash, pbHash, cbHash, 0);
	//完成获取数据的哈希值

	//加载并初始化 CNG 密钥存储提供程序
	NCryptOpenStorageProvider(&hProv, MS_KEY_STORAGE_PROVIDER, 0);

	//创建一个新密钥对
	NCryptCreatePersistedKey(hProv, &hKey, NCRYPT_RSA_ALGORITHM, L"my rsa key", 0, 0);

	//设置密钥长度
	NCryptSetProperty(hKey, NCRYPT_LENGTH_PROPERTY, (PBYTE)&cbKeyLength, sizeof(DWORD), 0);

	//完成密钥对(并存储)
	NCryptFinalizeKey(hKey, 0);

	//设置填充,需要和上面对数据获取哈希值的算法相同,不然无法通过
	BCRYPT_PKCS1_PADDING_INFO bPaddingInfo = {BCRYPT_SHA256_ALGORITHM};

	//获取哈希值签名所需空间大小
	NCryptSignHash(hKey, &bPaddingInfo, pbHash, cbHash, NULL, 0, &cbSignature, BCRYPT_PAD_PKCS1);

	//分配存储签名所需空间
	pbSignature = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbSignature);

	//对哈希值签名
	NCryptSignHash(hKey, &bPaddingInfo, pbHash, cbHash, pbSignature, cbSignature, &cbSignature, BCRYPT_PAD_PKCS1);

	//导出公钥,获取导出公钥所需空间大小
	NCryptExportKey(hKey, NULL, BCRYPT_RSAPUBLIC_BLOB, NULL, NULL, 0, &cbBlob, 0);

	//分配公钥所需要空间
	pbBlob = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbBlob);

	//导出公钥
	NCryptExportKey(hKey, NULL, BCRYPT_RSAPUBLIC_BLOB, NULL, pbBlob, cbBlob, &cbBlob, 0);

	//加载并初始化BCrypt提供程序
	BCryptOpenAlgorithmProvider(&hSignAlg, BCRYPT_RSA_ALGORITHM, NULL, 0);

	//导入公钥
	BCryptImportKeyPair(hSignAlg, NULL, BCRYPT_RSAPUBLIC_BLOB, &hTmpKey, pbBlob, cbBlob, 0);

	//验证指定的签名是否与指定的哈希匹配
	if(!NT_SUCCESS(status = BCryptVerifySignature(hTmpKey,
											&bPaddingInfo,
											pbHash,
											cbHash,
											pbSignature,
											cbSignature,
											BCRYPT_PAD_PKCS1)))
	{
		wprintf(L"**** Error 0x%x returned by BCryptVerifySignature\n", status);
	}
	else {
		wprintf(L"Success!\n");
	}

	if(hHashAlg) {
		BCryptCloseAlgorithmProvider(hHashAlg,0);
	}

	if(hSignAlg) {
		BCryptCloseAlgorithmProvider(hSignAlg,0);
	}

	if (hHash) {
		BCryptDestroyHash(hHash);
	}

	if(pbHashObject) {
		HeapFree(GetProcessHeap(), 0, pbHashObject);
	}

	if(pbHash) {
		HeapFree(GetProcessHeap(), 0, pbHash);
	}

	if(pbSignature) {
		HeapFree(GetProcessHeap(), 0, pbSignature);
	}

	if(pbBlob) {
		HeapFree(GetProcessHeap(), 0, pbBlob);
	}

	if (hTmpKey) {
		BCryptDestroyKey(hTmpKey);
	}

	if (hKey) {
		NCryptDeleteKey(hKey, 0);
	}

	if (hProv) {
		NCryptFreeObject(hProv);
	}

	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
对称加密算法和非对称加密算法是两种常用的加密算法,它们各自的算法有以下几种: 对称加密算法: 1. DES(Data Encryption Standard):数据加密标准,是一种较为古老的对称加密算法。 2. 3DES(Triple DES):三重DES加密算法,是一种对DES算法的加强版,提高了安全性。 3. AES(Advanced Encryption Standard):高级加密标准,是一种目前应用最为广泛的对称加密算法,具有高安全性和高效率的特点。 4. Blowfish:一种高效的对称加密算法,被广泛应用于信息安全领域。 非对称加密算法: 1. RSA:一种非对称加密算法,广泛应用数字签名、身份验证等方面。 2. DSA(Digital Signature Algorithm):数字签名算法,是一种非对称加密算法,被广泛应用数字签名领域。 3. ECC(Elliptic Curve Cryptography):椭圆曲线加密算法,是一种比RSA更加高效的非对称加密算法。 对称加密算法的优势在于加密解密速度快,加密效率高。但由于它采用的是同一个密钥进行加密和解密,因此密钥安全性较差,容易被破解。 非对称加密算法的优势在于密钥安全性较高,可以采用公钥加密、私钥解密的方式来保障数据安全。但由于加密解密过程较为复杂,加密效率比对称加密算法低。 综上所述,对称加密算法和非对称加密算法各有优劣,可以根据具体的应用场景来选择合适的加密算法。在实际应用中,通常会将对称加密算法和非对称加密算法结合起来使用,以充分发挥它们各自的优势。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值