如何让BCrypt将我的密钥解释为十六进制?

时间:2018-03-16 23:36:04

标签: visual-c++ cryptography bcrypt hmac sha512

我正在尝试与一个API进行交互,该API接受GET和POST请求,其中包括从消息和我的私钥派生的签名,使用HMAC SHA512进行哈希处理。文档给出了一个例子:

键(在base-64中):

bEDtDJnW0y/Ll4YZitxb+D5sTNnEpQKH67EJRCmQCqN9cvGiB8+IHzB7HjsOs3mSlxLmu4aiPDRpe9anuWzylw==

消息:

/account/balance1515058794242

应生成以下(base-64)签名:

NjqZ8Mgdkj6hrtY/xdKBy1S0kLjU2tA7G+pR2TdOBF45b7+evfpzGH/C/PiNHEDvuiRChRBlRo3AGJ7Gcvlwqw==

文档还说明在使用hmac之前需要从base-64解码密钥,但不清楚它应该采用什么格式。

我一直在玩在线hmac生成器,可以复制示例签名,没有任何问题。例如,在https://www.liavaag.org/English/SHA-Generator/HMAC/ - 输入上面的键作为输入类型= Base-64,上面的消息字符串作为输入类型= TEXT,输出类型= base-64,输出签名与上面相同。当我将密钥作为HEX类型提供并使用十六进制等效项时,它也可以正常工作:

6C40ED0C99D6D32FCB9786198ADC5BF83E6C4CD9C4A50287EBB1094429900AA37D72F1A207CF881F307B1E3B0EB379929712E6BB86A23C34697BD6A7B96CF297

但我无法使用BCrypt使用自己的程序复制示例签名。似乎BCrypt hmac以与在线生成器相同的方式将我的密钥解释为“TEXT”类型的输入。也就是说,当我将密钥作为十六进制字符串给出时:

CONST BYTE key[] = { "6C40ED0C99D6D32FCB9786198ADC5BF83E6C4CD9C4A50287EBB1094429900AA37D72F1A207CF881F307B1E3B0EB379929712E6BB86A23C34697BD6A7B96CF297" };

我得到了一个输出签名(十六进制):

16ab16ed3874fab51dbda66155edf269883d128de6067d77762dcee4129f1612b36fc556df10beb358c81262d034efe4c50d68d89ac43606df4318a8af56b

在在线生成器上,当我使用该十六进制字符串(6C40 ...)作为TEXT类型键并输出为HEX时,我得到相同的输出。

有什么方法可以强迫BCrypt将我的密钥解释为十六进制?我甚至尝试将密钥声明为十六进制文字,即:

CONST BYTE key[] = { 0x6C, 0x40, 0xed, 0x0c, 0x99, 0xd6, 0xd3, 0x2f, 
                         0xCB, 0x97, 0x86, 0x19, 0x8a, 0xdc, 0x5b, 0xf8,
                         0x3E, 0x6c, 0x4c, 0xd9, 0xc4, 0xa5, 0x02, 0x87,
                         0xeb, 0xb1, 0x09, 0x44, 0x29, 0x90, 0x0a, 0xa3,
                         0x7d, 0x72, 0xf1, 0xa2, 0x07, 0xcf, 0x88, 0x1f,
                         0x30, 0x7b, 0x1e, 0x3b, 0x0e, 0xb3, 0x79, 0x92,
                         0x97, 0x12, 0xe6, 0xbb, 0x86, 0xa2, 0x3c, 0x34,
                         0x69, 0x7b, 0xd6, 0xa7, 0xb9, 0x6c, 0xf2, 0x97 };

但这给出了另一个不同的签名。至少十六进制字符串键有点像复制在线转换器。很抱歉为什么我使用十六进制而不是base-64,这是我最终需要使用的 - 这只是目前一个额外的复杂步骤,所以现在我只是想获得十六进制等效工作,然后我可以专注于将其编码为base-64。我试图获得的base-64签名的十六进制等价物是:

363a99f0c81d923ea1aed63fc5d281cb54b490b8d4dad03b1bea51d9374e045e396fbf9ebdfa73187fc2fcf88d1c40efba2442851065468dc0189ec672f970ab

我正在使用的完整代码如下:

#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib") 
#define NT_SUCCESS(Status)          (((NTSTATUS)(Status)) >= 0)

#define STATUS_UNSUCCESSFUL         ((NTSTATUS)0xC0000001L)

#include <fstream>

int hexToInt(char ch)
{
    return 0;
}


void __cdecl wmain(
    int                      argc,
    __in_ecount(argc) LPWSTR *wargv)
{
    std::wofstream fout;
    fout.open("signature.txt");


    BCRYPT_ALG_HANDLE       hAlg = NULL;
    BCRYPT_HASH_HANDLE      hHash = NULL;
    NTSTATUS                status = STATUS_UNSUCCESSFUL;
    DWORD                   cbData = 0,
        cbHash = 0,
        cbHashObject = 0;
    PBYTE                   pbHashObject = NULL;
    PBYTE                   pbHash = NULL;


    CONST BYTE message[] = { "/account/balance1515058794242" };
    CONST BYTE key[] = { "6C40ED0C99D6D32FCB9786198ADC5BF83E6C4CD9C4A50287EBB1094429900AA37D72F1A207CF881F307B1E3B0EB379929712E6BB86A23C34697BD6A7B96CF297" };




    //open an algorithm handle
    if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(
        &hAlg,
        BCRYPT_SHA512_ALGORITHM,
        NULL,
        BCRYPT_ALG_HANDLE_HMAC_FLAG)))
    {
        fout << "**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n" << status;
        goto Cleanup;
    }

    //calculate the size of the buffer to hold the hash object
    if (!NT_SUCCESS(status = BCryptGetProperty(
        hAlg,
        BCRYPT_OBJECT_LENGTH,
        (PBYTE)&cbHashObject,
        sizeof(DWORD),
        &cbData,
        0)))
    {
        fout << "**** Error 0x%x returned by BCryptGetProperty\n" << status;
        goto Cleanup;
    }

    //allocate the hash object on the heap
    pbHashObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHashObject);
    if (NULL == pbHashObject)
    {
        fout << "**** memory allocation failed\n";
        goto Cleanup;
    }

    //calculate the length of the hash
    if (!NT_SUCCESS(status = BCryptGetProperty(
        hAlg,
        BCRYPT_HASH_LENGTH,
        (PBYTE)&cbHash,
        sizeof(DWORD),
        &cbData,
        0)))
    {
        fout << "**** Error 0x%x returned by BCryptGetProperty\n" << status;
        goto Cleanup;
    }

    //allocate the hash buffer on the heap
    pbHash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbHash);
    if (NULL == pbHash)
    {
        fout << "**** memory allocation failed\n";
        goto Cleanup;
    }

    //create a hash
    if (!NT_SUCCESS(status = BCryptCreateHash(
        hAlg,
        &hHash,
        pbHashObject,
        cbHashObject,
        (PBYTE)key,
        sizeof(key) - 1,
        0)))
    {
        fout << "**** Error 0x%x returned by BCryptCreateHash\n" << status;
        goto Cleanup;
    }

    //hash some data
    if (!NT_SUCCESS(status = BCryptHashData(
        hHash,
        (PBYTE)message,
        sizeof(message) - 1,
        0)))
    {
        fout << "**** Error 0x%x returned by BCryptHashData\n" << status;
        goto Cleanup;
    }

    //close the hash
    if (!NT_SUCCESS(status = BCryptFinishHash(
        hHash,
        pbHash,
        cbHash,
        0)))
    {
        fout << "**** Error 0x%x returned by BCryptFinishHash\n" << status;
        goto Cleanup;
    }


    fout << "\nThe hash is:  \n";
    for (DWORD i = 0; i < cbHash; i++)
    {
        fout <<  std::hex << pbHash[i];
    }



Cleanup:

    if (hAlg)
    {
        BCryptCloseAlgorithmProvider(hAlg, 0);
    }

    if (hHash)
    {
        BCryptDestroyHash(hHash);
    }

    if (pbHashObject)
    {
        HeapFree(GetProcessHeap(), 0, pbHashObject);
    }

    if (pbHash)
    {
        HeapFree(GetProcessHeap(), 0, pbHash);
    }


    fout.close();
};

1 个答案:

答案 0 :(得分:0)

您需要使用指定密钥的CONST BYTE key[] = { 0x6C, ... };方法。键和输入数据是二进制数据,在大多数编程语言中表示为字节数组。十六进制和基数64是表示编码二进制值的两种方式,因此它们可以用作可打印文本。

但是,如果使用字节数组,则sizeof将返回实际字节数。数组不会终止,因此没有理由删除最后的空字节。因此sizeof(key) - 1将删除键的最后一个字节作为输入参数,而不是删除不存在的空字节。

消息字符串 以null结尾,因此它应该可以正常工作。但是,您可能明确要提及消息需要是US-ASCII或显式编码字符串(例如,UTF-8)。