BCryptOpenAlgorithmProvider

基本概念

BCryptOpenAlgorithmProviderWindows系统中BCrypt (Cryptography Next Generation, CNG)接口的核心函数,作用是:
打开指定加密算法的 “算法提供程序” 句柄(类似于获取算法的操作入口);
后续可通过该句柄调用加密、解密、哈希、签名等具体加密操作;
支持指定算法实现的提供商(如微软默认的MS_PRIMITIVE_PROVIDER),也可留空使用系统默认提供商。

基本语法

1
2
3
4
5
6
NTSTATUS BCryptOpenAlgorithmProvider(
[out] BCRYPT_ALG_HANDLE *phAlgorithm, //打开的算法句柄
[in] LPCWSTR pszAlgId, //算法标识符(如哈希、加密算法的字符串)
[in] LPCWSTR pszImplementation,//算法提供商(通常为 NULL 使用默认)
[in] ULONG dwFlags //标志位(通常为 0)
);

返回值
成功:STATUS_SUCCESS(值为 0)
失败:返回NTSTATUS错误码(如STATUS_INVALID_PARAMETER表示参数错误)。

数据类型
BCRYPT_ALG_HANDLE:

1
2
typedef void *PVOID;
typedef PVOID BCRYPT_ALG_HANDLE;

将 “无类型指针” 命名为BCRYPT_ALG_HANDLE(BCrypt 算法句柄),作为CNG API中 “算法提供程序句柄” 的类型标识。

BCryptGetProperty

基本概念

BCryptGetPropertyBCrypt (CNG) 接口的核心辅助函数,作用是:
读取通过BCryptOpenAlgorithmProvider打开的算法句柄、密钥句柄或哈希句柄的属性;
比如获取算法支持的最大密钥长度、哈希输出长度、算法名称等关键信息;
支持 “先查询属性长度→再读取属性值” 的两步式读取,也可直接尝试读取(新手推荐两步式,避免缓冲区大小不足)。

基本语法

1
2
3
4
5
6
7
8
NTSTATUS BCryptGetProperty(
[in] BCRYPT_HANDLE hObject, //算法/密钥/哈希句柄(如BCryptOpenAlgorithmProvider返回的句柄)
[in] LPCWSTR pszProperty,//要查询的属性名称(宽字符串)
[out] PUCHAR pbOutput, //存储属性值的缓冲区
[in] ULONG cbOutput, //缓冲区大小(字节)
[out] ULONG *pcbResult, //实际读取到的属性值长度
[in] ULONG dwFlags //标志位(通常为 0)
);

返回值
成功:STATUS_SUCCESS(值为 0)
失败:常见错误码如STATUS_BUFFER_TOO_SMALL(缓冲区不足)STATUS_INVALID_PARAMETER(参数错误)

BCryptCreateHash

基本概念

BCryptCreateHashBCrypt (CNG) 接口中哈希计算的关键函数,主要作用:
基于BCryptOpenAlgorithmProvider打开的哈希算法句柄(如 SHA256),创建一个哈希对象句柄;
该哈希对象是后续写入数据(BCryptHashData)、获取最终哈希值(BCryptFinishHash)的核心载体;
支持传入密钥(如HMAC场景),普通哈希(如SHA256)可传NULL跳过密钥。

基本语法

1
2
3
4
5
6
7
8
9
NTSTATUS BCryptCreateHash(
[in, out] BCRYPT_ALG_HANDLE hAlgorithm,//已打开的哈希算法句柄(如SHA256)
[out] BCRYPT_HASH_HANDLE *phHash, // 创建的哈希对象句柄
[out, optional] PUCHAR pbHashObject,// 哈希对象缓冲区(可选,NULL则由系统分配)
[in] ULONG cbHashObject,// 缓冲区大小(pbHashObject为NULL时传0)
[in, optional] PUCHAR pbSecret, // 密钥(HMAC用,普通哈希传NULL)
[in] ULONG cbSecret, // 密钥长度(无密钥传0)
[in] ULONG dwFlags // 标志位(通常为0)
);

返回值
成功:STATUS_SUCCESS(值为 0)
失败:常见错误码如STATUS_INVALID_HANDLE(无效算法句柄)STATUS_INVALID_PARAMETER(参数错误)

BCryptHashData

基本概念

BCryptHashDataWindows CNG接口中向已创建的哈希对象写入数据的函数,核心作用:
接收一段数据(如文件读取的缓冲区、字符串等),将其 “喂给” 通过BCryptCreateHash创建的哈希对象;
支持分段写入(多次调用),适合大文件 / 数据流的哈希计算(比如你之前代码中循环读取文件并调用该函数);
数据写入后,哈希对象会在内部累加计算哈希值,直到调用BCryptFinishHash完成最终计算。

基本语法

1
2
3
4
5
6
NTSTATUS BCryptHashData(
[in, out] BCRYPT_HASH_HANDLE hHash,//哈希对象句柄
[in] PUCHAR pbInput,//待哈希的数据缓冲区
[in] ULONG cbInput,//数据缓冲区的字节长度
[in] ULONG dwFlags//标志位(通常为0)
);

返回值
成功:STATUS_SUCCESS(值为 0)
失败:常见错误码:
STATUS_INVALID_HANDLE:hHash 是无效句柄(未创建 / 已释放);
STATUS_INVALID_PARAMETER:参数为空(如pbInput=NULL 但 cbInput>0);
STATUS_BUFFER_TOO_SMALL:极少出现,通常是参数错误导致。

BCryptFinishHash

基本概念

BCryptFinishHashWindows CNG接口中哈希计算的最终步骤函数,核心作用:
对已通过BCryptHashData写入所有数据的哈希对象,执行最后的哈希计算(如补位、最终摘要生成);
将计算完成的最终哈希值写入指定的缓冲区;
调用后,该哈希对象进入 “完成状态”,无法再通过BCryptHashData写入新数据(如需重新计算,需销毁并重建哈希对象)。

基本语法

1
2
3
4
5
6
NTSTATUS BCryptFinishHash(
[in, out] BCRYPT_HASH_HANDLE hHash, //哈希对象句柄
[out] PUCHAR pbOutput,//存储最终哈希值的缓冲区
[in] ULONG cbOutput,//缓冲区的字节长度
[in] ULONG dwFlags //标志位(通常为0)
);

返回值
成功:STATUS_SUCCESS(值为 0)
失败:常见错误码:
STATUS_INVALID_HANDLEhHash无效(未创建 / 已释放 / 已完成);
STATUS_INVALID_PARAMETER:缓冲区为空(pbOutput=NULL)或长度不匹配;
STATUS_BUFFER_TOO_SMALLcbOutput小于算法的哈希输出长度(如 SHA256 传 30 字节);
STATUS_HASH_STATE_INVALID:哈希对象已调用过BCryptFinishHash,无法重复调用。

简单示例

计算字符串的SHA256哈希值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include <Windows.h>
#include <bcrypt.h>
#include <stdio.h>
#include <string.h>

// 链接BCrypt库(必须)
#pragma comment(lib, "bcrypt.lib")

// 辅助函数:将字节数组转为十六进制字符串(方便查看哈希结果)
void BytesToHex(const BYTE* pbData, ULONG cbData, char* szHex) {
for (ULONG i = 0; i < cbData; i++) {
sprintf_s(szHex + 2*i, 3, "%02X", pbData[i]);
}
szHex[2*cbData] = '\0'; // 字符串结束符
}

int main() {
// 1. 定义核心句柄和变量
BCRYPT_ALG_HANDLE hAlg = NULL; // 算法句柄
BCRYPT_HASH_HANDLE hHash = NULL; // 哈希对象句柄
NTSTATUS status; // API调用返回状态

// 待计算哈希的字符串(可替换成任意内容)
const char* inputStr = "Hello CNG API!";
ULONG inputLen = (ULONG)strlen(inputStr); // 数据字节长度

// 存储SHA256哈希结果(固定32字节)
BYTE sha256Result[32] = {0};
char sha256Hex[65] = {0}; // 32字节 * 2(十六进制) + 1(结束符)

// --------------------------
// 2. 打开SHA256算法提供程序(BCryptOpenAlgorithmProvider)
// --------------------------
status = BCryptOpenAlgorithmProvider(
&hAlg, // 输出:算法句柄
BCRYPT_SHA256_ALGORITHM,// 算法类型:SHA256
NULL, // 使用系统默认提供商
0 // 无特殊标志
);
if (status != STATUS_SUCCESS) {
printf("打开算法失败,错误码:0x%X\n", status);
goto Cleanup; // 失败则跳转到资源释放
}

// --------------------------
// 3. 创建哈希对象(BCryptCreateHash)
// --------------------------
status = BCryptCreateHash(
hAlg, // 已打开的SHA256算法句柄
&hHash, // 输出:哈希对象句柄
NULL, // 系统自动分配哈希对象缓冲区
0, // 缓冲区大小为0(系统分配时传0)
NULL, // 普通哈希无需密钥(HMAC才需要)
0, // 密钥长度为0
0 // 无特殊标志
);
if (status != STATUS_SUCCESS) {
printf("创建哈希对象失败,错误码:0x%X\n", status);
goto Cleanup;
}

// --------------------------
// 4. 写入数据到哈希对象(BCryptHashData)
// --------------------------
status = BCryptHashData(
hHash, // 哈希对象句柄
(PUCHAR)inputStr,// 待哈希的数据缓冲区
inputLen, // 数据字节长度
0 // 无特殊标志
);
if (status != STATUS_SUCCESS) {
printf("写入哈希数据失败,错误码:0x%X\n", status);
goto Cleanup;
}

// --------------------------
// 5. 完成哈希计算,获取结果(BCryptFinishHash)
// --------------------------
status = BCryptFinishHash(
hHash, // 哈希对象句柄
sha256Result, // 存储哈希结果的缓冲区
sizeof(sha256Result), // SHA256固定32字节
0 // 无特殊标志
);
if (status != STATUS_SUCCESS) {
printf("完成哈希计算失败,错误码:0x%X\n", status);
goto Cleanup;
}

// --------------------------
// 6. 输出结果
// --------------------------
BytesToHex(sha256Result, sizeof(sha256Result), sha256Hex);
printf("原始字符串:%s\n", inputStr);
printf("SHA256哈希值:%s\n", sha256Hex);

Cleanup:
// --------------------------
// 7. 释放所有资源(必须!)
// --------------------------
if (hHash != NULL) BCryptDestroyHash(hHash); // 释放哈希对象句柄
if (hAlg != NULL) BCryptCloseAlgorithmProvider(hAlg, 0); // 释放算法句柄

return 0;
}

通过BCryptOpenAlgorithmProvider创建的BCRYPT_ALG_HANDLE,必须通过BCryptCloseAlgorithmProvider释放;
通过BCryptCreateHash创建的BCRYPT_HASH_HANDLE,必须通过BCryptDestroyHash释放;

对比

1
2
3
4
5
6
7
功能	          CryptoAPI(MD5/SHA1)	    CNG API(SHA256)
初始化服务 CryptAcquireContext BCryptOpenAlgorithmProvider
创建哈希对象 CryptCreateHash BCryptCreateHash
写入数据计算哈希 CryptHashData BCryptHashData
获取最终哈希值 CryptGetHashParam BCryptFinishHash
释放哈希对象 CryptDestroyHash BCryptDestroyHash
释放核心句柄 CryptReleaseContext BCryptCloseAlgorithmProvider