当前位置:   article > 正文

Cryptography API: Next Generation(CNG)使用梳理——Hash及随机数算法应用_hash随机数法

hash随机数法

一、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步前执行就可以

需要使用到的函数:

  1. //打开支持所需算法的算法提供程序
  2. NTSTATUS BCryptOpenAlgorithmProvider(
  3. [out] BCRYPT_ALG_HANDLE *phAlgorithm,
  4. [in] LPCWSTR pszAlgId,
  5. [in] LPCWSTR pszImplementation,
  6. [in] ULONG dwFlags
  7. );
  8. //获取Hash对象的大小
  9. NTSTATUS BCryptGetProperty(
  10. [in] BCRYPT_HANDLE hObject,
  11. [in] LPCWSTR pszProperty,
  12. [out] PUCHAR pbOutput,
  13. [in] ULONG cbOutput,
  14. [out] ULONG *pcbResult,
  15. [in] ULONG dwFlags
  16. );
  17. //创建Hash对象
  18. NTSTATUS BCryptCreateHash(
  19. [in, out] BCRYPT_ALG_HANDLE hAlgorithm,
  20. [out] BCRYPT_HASH_HANDLE *phHash,
  21. [out] PUCHAR pbHashObject,
  22. [in, optional] ULONG cbHashObject,
  23. [in, optional] PUCHAR pbSecret,
  24. [in] ULONG cbSecret,
  25. [in] ULONG dwFlags
  26. );
  27. //对数据进行哈希处理,可多次调用
  28. NTSTATUS BCryptHashData(
  29. [in, out] BCRYPT_HASH_HANDLE hHash,
  30. [in] PUCHAR pbInput,
  31. [in] ULONG cbInput,
  32. [in] ULONG dwFlags
  33. );
  34. //获取数据哈希值
  35. NTSTATUS BCryptFinishHash(
  36. [in, out] BCRYPT_HASH_HANDLE hHash,
  37. [out] PUCHAR pbOutput,
  38. [in] ULONG cbOutput,
  39. [in] ULONG dwFlags
  40. );
  41. //关闭Hash对象
  42. NTSTATUS BCryptDestroyHash(
  43. [in, out] BCRYPT_HASH_HANDLE hHash
  44. );
  45. //关闭算法提供程序
  46. NTSTATUS BCryptCloseAlgorithmProvider(
  47. [in, out] BCRYPT_ALG_HANDLE hAlgorithm,
  48. [in] ULONG dwFlags
  49. );

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

  1. #include <windows.h>
  2. #include <bcrypt.h>
  3. static const BYTE rgbMsg[] =
  4. {
  5. 0x61, 0x62, 0x63
  6. };
  7. int main()
  8. {
  9. BCRYPT_ALG_HANDLE hAlg = NULL;
  10. BCRYPT_HASH_HANDLE hHash = NULL;
  11. DWORD cbData = 0,
  12. cbHash = 0,
  13. cbHashObject = 0;
  14. PBYTE pbHashObject = NULL;
  15. PBYTE pbHash = NULL;
  16. //打开支持所需算法的算法提供程序,获取算法句柄
  17. BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, NULL, 0);
  18. //获取Hash对象的大小,Win7后可以不自行管理Hash对象,此步骤可以不做
  19. BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0);
  20. //为Hash对象分配空间,Win7后可以不自行管理Hash对象,此步骤可以不做
  21. pbHashObject = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHashObject);
  22. //获取Hash值所需空间大小
  23. BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0);
  24. //分配Hash值所需空间
  25. pbHash = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHash);
  26. //创建Hash对象
  27. BCryptCreateHash(hAlg, &hHash, pbHashObject, cbHashObject, NULL, 0, 0);
  28. //Win7后可以不需要pbHashObject和cbHashObject,如下
  29. //BCryptCreateHash(hAlg, &hHash, NULL, 0, NULL, 0, 0);
  30. //对数据进行哈希处理
  31. BCryptHashData(hHash, (PBYTE)rgbMsg, sizeof(rgbMsg), 0);
  32. //获取哈希值
  33. BCryptFinishHash(hHash, pbHash, cbHash, 0);
  34. //关闭Hash对象
  35. BCryptDestroyHash(hHash);
  36. //关闭算法提供程序
  37. BCryptCloseAlgorithmProvider(hAlg,0);
  38. //清理
  39. HeapFree(GetProcessHeap(), 0, pbHashObject);
  40. HeapFree(GetProcessHeap(), 0, pbHash);
  41. return 0;
  42. }
 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的认证密钥的缓冲区的指针,及其大小

  1. //获取哈希值
  2. 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.

当然,这个散列值的大小对于不同算法其值实际上是固定的

算法哈希值长度 (位)哈希值长度 (字节)
MD212816
MD412816
MD512816
SHA-116020
SHA-25625632
SHA-38438448
SHA-51251264

(二)HMAC(Hash-based Message Authentication Code):

具体流程和普通Hash一样,区别在于获取算法句柄时添加BCRYPT_ALG_HANDLE_HMAC_FLAG标志,在BCryptCreateHash中输入pbSecret和cbSecret参数

  1. #include <windows.h>
  2. #include <bcrypt.h>
  3. static const BYTE rgbMsg[] =
  4. {
  5. 0x61, 0x62, 0x63
  6. };
  7. static const BYTE rgbSecret[] =
  8. {
  9. 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  10. 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
  11. };
  12. int main()
  13. {
  14. BCRYPT_ALG_HANDLE hAlg = NULL;
  15. BCRYPT_HASH_HANDLE hHash = NULL;
  16. DWORD cbData = 0,
  17. cbHash = 0;
  18. PBYTE pbHash = NULL;
  19. //打开支持所需算法的算法提供程序,获取算法句柄
  20. BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, NULL, BCRYPT_ALG_HANDLE_HMAC_FLAG);
  21. //获取Hash值所需空间大小
  22. BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0);
  23. //分配Hash值所需空间
  24. pbHash = (PBYTE)HeapAlloc (GetProcessHeap (), 0, cbHash);
  25. //创建Hash对象,Win7后可以不需要pbHashObject和cbHashObject
  26. BCryptCreateHash(hAlg, &hHash, NULL, 0, rgbSecret, sizeof(rgbSecret), 0);
  27. //对数据进行哈希处理
  28. BCryptHashData(hHash, (PBYTE)rgbMsg, sizeof(rgbMsg), 0);
  29. //获取哈希值
  30. BCryptFinishHash(hHash, pbHash, cbHash, 0);
  31. //关闭Hash对象
  32. BCryptDestroyHash(hHash);
  33. //关闭算法提供程序
  34. BCryptCloseAlgorithmProvider(hAlg,0);
  35. //清理
  36. HeapFree(GetProcessHeap(), 0, pbHashObject);
  37. HeapFree(GetProcessHeap(), 0, pbHash);
  38. return 0;
  39. }

复制Hash对象:

  1. //复制现有的Hash或消息身份验证(MAC)对象。复制对象包含复制时原始对象中包含的所有状态和数据。
  2. NTSTATUS BCryptDuplicateHash(
  3. [in] BCRYPT_HASH_HANDLE hHash,
  4. [out] BCRYPT_HASH_HANDLE *phNewHash,
  5. [out] PUCHAR pbHashObject,
  6. [in] ULONG cbHashObject,
  7. [in] ULONG dwFlags
  8. );

如果需要的哈希值是由多个部分组成的,且,其拥有公共部分时,就可以使用此函数,先将公共部分或者通用数据添加(BCryptHashData)到Hash对象中,而后对Hash对象进行的复制,复制的Hash对象包含与原始相同的状态信息和哈希数据,但它是完全独立的Hash对象。其后可以再使用复制对象添加需要计算哈希值的后续数据(BCryptHashData)直至获取最后的哈希值(BCryptFinishHash)

二、随机数

随机数就比较简单了,可以使用BCryptOpenAlgorithmProvider获取算法句柄,也可以使用BCRYPT_USE_SYSTEM_PREFERRED_RNG标志,使用系统选用的随机数算法

  1. #include <windows.h>
  2. #include <bcrypt.h>
  3. int main()
  4. {
  5. BCRYPT_ALG_HANDLE hAlg = NULL;
  6. BYTE buffer[128];
  7. //打开支持所需算法的算法提供程序,获取算法句柄
  8. BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_RNG_ALGORITHM, NULL, 0);
  9. //创建随机数
  10. BCryptGenRandom(hAlg, buffer, sizeof(buffer), 0);
  11. //关闭算法提供程序
  12. BCryptCloseAlgorithmProvider(hAlg,0);
  13. return 0;
  14. }

或者用BCRYPT_USE_SYSTEM_PREFERRED_RNG标志,此标志仅适用于与Windows Vista SP2及以后版本

  1. #include <windows.h>
  2. #include <bcrypt.h>
  3. int main()
  4. {
  5. BCRYPT_ALG_HANDLE hAlg = NULL;
  6. BYTE buffer[128];
  7. //创建随机数
  8. BCryptGenRandom(NULL, buffer, sizeof(buffer), BCRYPT_USE_SYSTEM_PREFERRED_RNG);
  9. return 0;
  10. }

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号