赞
踩
一、Hash算法
(一)散列算法,主要执行步骤:
1、获取算法提供程序
2、获取Hash对象的大小
3、为Hash对象分配空间
4、获取Hash值所需空间大小
5、分配Hash值所需空间
6、创建Hash对象
7、对数据执行哈希处理
8、获取Hash值
9、关闭Hash对象
10、关闭算法提供程序
11、清理(释放不需要的堆空间)
其中,2、3两不在Win7以后的系统中可以不执行,其Hash对象会由CNG自行管理,而4、5只需要在第8步前执行就可以
需要使用到的函数:
- //打开支持所需算法的算法提供程序
- NTSTATUS BCryptOpenAlgorithmProvider(
- [out] BCRYPT_ALG_HANDLE *phAlgorithm,
- [in] LPCWSTR pszAlgId,
- [in] LPCWSTR pszImplementation,
- [in] ULONG dwFlags
- );
- //获取Hash对象的大小
- NTSTATUS BCryptGetProperty(
- [in] BCRYPT_HANDLE hObject,
- [in] LPCWSTR pszProperty,
- [out] PUCHAR pbOutput,
- [in] ULONG cbOutput,
- [out] ULONG *pcbResult,
- [in] ULONG dwFlags
- );
- //创建Hash对象
- NTSTATUS BCryptCreateHash(
- [in, out] BCRYPT_ALG_HANDLE hAlgorithm,
- [out] BCRYPT_HASH_HANDLE *phHash,
- [out] PUCHAR pbHashObject,
- [in, optional] ULONG cbHashObject,
- [in, optional] PUCHAR pbSecret,
- [in] ULONG cbSecret,
- [in] ULONG dwFlags
- );
- //对数据进行哈希处理,可多次调用
- NTSTATUS BCryptHashData(
- [in, out] BCRYPT_HASH_HANDLE hHash,
- [in] PUCHAR pbInput,
- [in] ULONG cbInput,
- [in] ULONG dwFlags
- );
- //获取数据哈希值
- NTSTATUS BCryptFinishHash(
- [in, out] BCRYPT_HASH_HANDLE hHash,
- [out] PUCHAR pbOutput,
- [in] ULONG cbOutput,
- [in] ULONG dwFlags
- );
- //关闭Hash对象
- NTSTATUS BCryptDestroyHash(
- [in, out] BCRYPT_HASH_HANDLE hHash
- );
- //关闭算法提供程序
- NTSTATUS BCryptCloseAlgorithmProvider(
- [in, out] BCRYPT_ALG_HANDLE hAlgorithm,
- [in] ULONG dwFlags
- );
实例:(代码根据官方演示案例修改而来,用于演示流程,因此去掉了返回校验过程)
- #include <windows.h>
- #include <bcrypt.h>
-
- static const BYTE rgbMsg[] =
- {
- 0x61, 0x62, 0x63
- };
-
- int main()
- {
- BCRYPT_ALG_HANDLE hAlg = NULL;
- BCRYPT_HASH_HANDLE hHash = NULL;
- DWORD cbData = 0,
- cbHash = 0,
- cbHashObject = 0;
- PBYTE pbHashObject = NULL;
- PBYTE pbHash = NULL;
-
-
- //打开支持所需算法的算法提供程序,获取算法句柄
- BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, NULL, 0);
-
- //获取Hash对象的大小,Win7后可以不自行管理Hash对象,此步骤可以不做
- BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0);
-
- //为Hash对象分配空间,Win7后可以不自行管理Hash对象,此步骤可以不做
- pbHashObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHashObject);
-
- //获取Hash值所需空间大小
- BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0);
-
- //分配Hash值所需空间
- pbHash = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHash);
-
- //创建Hash对象
- BCryptCreateHash(hAlg, &hHash, pbHashObject, cbHashObject, NULL, 0, 0);
- //Win7后可以不需要pbHashObject和cbHashObject,如下
- //BCryptCreateHash(hAlg, &hHash, NULL, 0, NULL, 0, 0);
-
- //对数据进行哈希处理
- BCryptHashData(hHash, (PBYTE)rgbMsg, sizeof(rgbMsg), 0);
-
- //获取哈希值
- BCryptFinishHash(hHash, pbHash, cbHash, 0);
-
- //关闭Hash对象
- BCryptDestroyHash(hHash);
-
- //关闭算法提供程序
- BCryptCloseAlgorithmProvider(hAlg,0);
-
- //清理
- HeapFree(GetProcessHeap(), 0, pbHashObject);
-
- HeapFree(GetProcessHeap(), 0, pbHash);
-
- return 0;
- }
BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, NULL, 0);
BCryptOpenAlgorithmProvider函数中对于Hash比较有用的就是dwFlags参数,主要有两个值
BCRYPT_ALG_HANDLE_HMAC_FLAG和BCRYPT_HASH_REUSABLE_FLAG
其中BCRYPT_HASH_REUSABLE_FLAG也可以用于BCryptCreateHash函数,作用是在算法调用完BCryptFinishHash后,使用此标志的Hash对象可以再次重复使用,而不使用的则必须直接调用BCryptDestroyHash销毁对象。而此标志作用于BCryptOpenAlgorithmProvider和BCryptCreateHash函数的区别是,前者作用于全局,也就是基于BCryptOpenAlgorithmProvider所生成的hAlg而创建的Hash对象都会拥有BCRYPT_HASH_REUSABLE_FLAG,而BCryptCreateHash则只对当前对象有效。
BCRYPT_ALG_HANDLE_HMAC_FLAG则代表当前算法是基于哈希的消息身份验证代码,使用此标志的后,需要在BCryptCreateHash的pbSecret和cbSecret参数分别输入指向包含用于hash或MAC的认证密钥的缓冲区的指针,及其大小
- //获取哈希值
- BCryptFinishHash(hHash, pbHash, cbHash, 0);
注意:
此处有个容易忽略的关键点,BCryptFinishHash函数的cbOutput参数,也就是上方代码的cbHash,其值必须严格等于BCryptGetProperty获取BCRYPT_HASH_LENGTH的值,小了自然不行,大了也不行,依然会报参数错误STATUS_INVALID_PARAMETER,其介绍中也提到
This includes the case where cbOutput is not the same size as the hash.
当然,这个散列值的大小对于不同算法其值实际上是固定的
算法 | 哈希值长度 (位) | 哈希值长度 (字节) |
---|---|---|
MD2 | 128 | 16 |
MD4 | 128 | 16 |
MD5 | 128 | 16 |
SHA-1 | 160 | 20 |
SHA-256 | 256 | 32 |
SHA-384 | 384 | 48 |
SHA-512 | 512 | 64 |
(二)HMAC(Hash-based Message Authentication Code):
具体流程和普通Hash一样,区别在于获取算法句柄时添加BCRYPT_ALG_HANDLE_HMAC_FLAG标志,在BCryptCreateHash中输入pbSecret和cbSecret参数
- #include <windows.h>
- #include <bcrypt.h>
-
- static const BYTE rgbMsg[] =
- {
- 0x61, 0x62, 0x63
- };
-
- static const BYTE rgbSecret[] =
- {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
- };
-
- int main()
- {
- BCRYPT_ALG_HANDLE hAlg = NULL;
- BCRYPT_HASH_HANDLE hHash = NULL;
- DWORD cbData = 0,
- cbHash = 0;
- PBYTE pbHash = NULL;
-
-
- //打开支持所需算法的算法提供程序,获取算法句柄
- BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG);
-
- //获取Hash值所需空间大小
- BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0);
-
- //分配Hash值所需空间
- pbHash = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHash);
-
- //创建Hash对象,Win7后可以不需要pbHashObject和cbHashObject
- BCryptCreateHash(hAlg, &hHash, NULL, 0, rgbSecret, sizeof(rgbSecret), 0);
-
- //对数据进行哈希处理
- BCryptHashData(hHash, (PBYTE)rgbMsg, sizeof(rgbMsg), 0);
-
- //获取哈希值
- BCryptFinishHash(hHash, pbHash, cbHash, 0);
-
- //关闭Hash对象
- BCryptDestroyHash(hHash);
-
- //关闭算法提供程序
- BCryptCloseAlgorithmProvider(hAlg,0);
-
- //清理
- HeapFree(GetProcessHeap(), 0, pbHashObject);
-
- HeapFree(GetProcessHeap(), 0, pbHash);
-
- return 0;
- }
复制Hash对象:
- //复制现有的Hash或消息身份验证(MAC)对象。复制对象包含复制时原始对象中包含的所有状态和数据。
- NTSTATUS BCryptDuplicateHash(
- [in] BCRYPT_HASH_HANDLE hHash,
- [out] BCRYPT_HASH_HANDLE *phNewHash,
- [out] PUCHAR pbHashObject,
- [in] ULONG cbHashObject,
- [in] ULONG dwFlags
- );
如果需要的哈希值是由多个部分组成的,且,其拥有公共部分时,就可以使用此函数,先将公共部分或者通用数据添加(BCryptHashData)到Hash对象中,而后对Hash对象进行的复制,复制的Hash对象包含与原始相同的状态信息和哈希数据,但它是完全独立的Hash对象。其后可以再使用复制对象添加需要计算哈希值的后续数据(BCryptHashData)直至获取最后的哈希值(BCryptFinishHash)
二、随机数
随机数就比较简单了,可以使用BCryptOpenAlgorithmProvider获取算法句柄,也可以使用BCRYPT_USE_SYSTEM_PREFERRED_RNG标志,使用系统选用的随机数算法
- #include <windows.h>
- #include <bcrypt.h>
-
- int main()
- {
- BCRYPT_ALG_HANDLE hAlg = NULL;
- BYTE buffer[128];
-
- //打开支持所需算法的算法提供程序,获取算法句柄
- BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0);
-
- //创建随机数
- BCryptGenRandom(hAlg, buffer, sizeof(buffer), 0);
-
- //关闭算法提供程序
- BCryptCloseAlgorithmProvider(hAlg,0);
-
- return 0;
- }
或者用BCRYPT_USE_SYSTEM_PREFERRED_RNG标志,此标志仅适用于与Windows Vista SP2及以后版本
- #include <windows.h>
- #include <bcrypt.h>
-
- int main()
- {
- BCRYPT_ALG_HANDLE hAlg = NULL;
- BYTE buffer[128];
-
- //创建随机数
- BCryptGenRandom(NULL, buffer, sizeof(buffer), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。