Cryptography API: Next Generation(CNG)使用梳理——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步前执行就可以

需要使用到的函数:

//打开支持所需算法的算法提供程序
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.

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

算法哈希值长度 (位)哈希值长度 (字节)
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参数

#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值