CryptCreateHash

基本概念

CryptCreateHash属于Windows CryptoAPI(Advapi32.dll),作用是初始化一个哈希计算上下文(哈希对象),后续可通过CryptHashData向该对象添加数据,最终通过 CryptGetHashParam获取哈希结果。

基本语法

1
2
3
4
5
6
7
BOOL CryptCreateHash(
[in] HCRYPTPROV hProv,// 加密服务提供程序(CSP)的句柄
[in] ALG_ID Algid,// 哈希算法标识符
[in] HCRYPTKEY hKey, // 密钥句柄(哈希计算时设为NULL)
[in] DWORD dwFlags,// 标志位(通常设为0)
[out] HCRYPTHASH *phHash //创建的哈希对象句柄
);
数据类型

ALG_ID

1
typedef unsigned int ALG_ID;

ALG_ID本质是无符号整数,专门用来标识Windows CryptoAPI中的加密 / 哈希算法.

1
2
3
4
5
6
7
ALG_ID              常量	    对应的整数值	    算法类型	用途
CALG_MD5 0x00008003 哈希算法 MD5 哈希计算
CALG_SHA1 0x00008004 哈希算法 SHA1 哈希计算
CALG_SHA_256 0x0000800C 哈希算法 SHA256 哈希计算
CALG_SHA_512 0x0000800D 哈希算法 SHA512 哈希计算
CALG_AES_256 0x00006610 对称加密算法 AES-256 加密 / 解密
CALG_HMAC 0x00008009 密钥哈希算法 HMAC 验证(需配合密钥)

HCRYPTKEY:

1
typedef ULONG_PTR HCRYPTKEY;

Windows CryptoAPI中对加密密钥句柄的类型定义,核心作用是把ULONG_PTR类型重命名为HCRYPTKEY,用来标识一个加密 / 解密密钥的上下文对象。

HCRYPTHASH:

1
typedef ULONG_PTR HCRYPTHASH;

Windows CryptoAPI中对哈希对象句柄的类型定义,核心作用是将ULONG_PTR类型重命名为HCRYPTHASH,用来标识一个哈希计算的上下文对象。

CryptHashData

基本概念

CryptHashData的作用是将一段数据(字符串、文件内容、二进制流等)写入到HCRYPTHASH哈希对象中,可多次调用该函数向同一个哈希对象追加数据,最终计算所有数据的整体哈希值。

基本语法

1
2
3
4
5
6
BOOL CryptHashData(
[in] HCRYPTHASH hHash, // 已创建的哈希对象句柄(由CryptCreateHash生成)
[in] const BYTE *pbData, // 要计算哈希的数据源(二进制字节数组)
[in] DWORD dwDataLen,// 数据源的字节长度
[in] DWORD dwFlags // 标志位(通常设为0)
);

返回值
成功:返回TRUE(非 0)
失败:返回FALSE(0),可通过GetLastError()获取具体错误码(如NTE_INVALID_HANDLE表示哈希句柄无效)。

CryptGetHashParam

基本概念

CryptGetHashParam的核心作用是 “读取哈希对象的参数”,最常用的场景是获取最终计算出的哈希值(二进制形式),也可查询哈希算法的相关信息(如哈希值长度、算法 ID 等)。

基本语法

1
2
3
4
5
6
7
BOOL CryptGetHashParam(
[in] HCRYPTHASH hHash, // 已填充数据的哈希对象句柄
[in] DWORD dwParam,// 要获取的参数类型(核心是HP_HASHVAL)
[out] BYTE *pbData,// 接收参数值的缓冲区
[in, out] DWORD *pdwDataLen,// 输入:缓冲区长度;输出:实际返回的数据长度
[in] DWORD dwFlags // 标志位,固定设为0
);

返回值
成功:返回TRUE(非 0)
失败:返回FALSE(0),可通过GetLastError()获取错误码(如ERROR_MORE_DATA表示缓冲区长度不足)。

简单示例

计算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
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <string.h>

// 链接Advapi32库(编译时需指定,或通过#pragma)
#pragma comment(lib, "Advapi32.lib")

int main() {
// 1. 定义核心变量
HCRYPTPROV hProv = NULL; // CSP句柄
HCRYPTHASH hHash = NULL; // 哈希对象句柄
const char* input = "Hello World"; // 待计算哈希的字符串
BYTE hashResult[32] = {0}; // SHA256哈希固定32字节
DWORD hashLen = sizeof(hashResult);
DWORD i;

// 2. 获取CSP句柄(哈希计算的基础)
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
printf("CSP获取失败,错误码: %lu\n", GetLastError());
return 1;
}

// ===== 核心三步:创建哈希对象 → 填充数据 → 获取哈希值 =====
// 3. CryptCreateHash:创建SHA256哈希对象
if (!CryptCreateHash(hProv, CALG_SHA_256, NULL, 0, &hHash)) {
printf("创建哈希对象失败,错误码: %lu\n", GetLastError());
CryptReleaseContext(hProv, 0);
return 1;
}

// 4. CryptHashData:向哈希对象填充字符串数据
if (!CryptHashData(hHash, (const BYTE*)input, strlen(input), 0)) {
printf("填充哈希数据失败,错误码: %lu\n", GetLastError());
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return 1;
}

// 5. CryptGetHashParam:获取最终的SHA256哈希值
if (!CryptGetHashParam(hHash, HP_HASHVAL, hashResult, &hashLen, 0)) {
printf("获取哈希值失败,错误码: %lu\n", GetLastError());
CryptDestroyHash(hHash);
CryptReleaseContext(hProv, 0);
return 1;
}

// 6. 输出结果(二进制转十六进制)
printf("输入字符串: %s\n", input);
printf("SHA256哈希值: ");
for (i = 0; i < hashLen; i++) {
// %02x 确保单个字节输出两位十六进制,不足补0
printf("%02x", hashResult[i]);
}
printf("\n");

// 7. 释放资源(必须,避免句柄泄漏)
CryptDestroyHash(hHash); // 释放哈希对象句柄
CryptReleaseContext(hProv, 0); // 释放CSP句柄

return 0;
}

资源释放:创建的hHash必须通过CryptDestroyHash释放,hProv需通过CryptReleaseContext释放,否则会导致资源泄漏。