我怎样才能让 BCrypt 将我的密钥解释为十六进制?
How can I get BCrypt to interpret my key as hex?
我正在尝试与接受 GET 和 POST 请求的 API 交互,这些请求包括从消息派生的签名和我的私钥,使用 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/——输入上面的key作为input type=Base-64,上面的message string作为input type=TEXT,output type=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();
};
您需要使用CONST BYTE key[] = { 0x6C, ... };
方法来指定您的密钥。键和输入数据是二进制数据,在大多数编程语言中表示为字节数组。十六进制和 base 64 是 表示 或 编码 二进制值的两种方式,以便它们可以用作可打印文本。
但是,如果您使用字节数组,那么 sizeof
将 return 实际字节数。数组不是空终止的,因此没有理由删除最后的空字节。所以 sizeof(key) - 1
将删除键的最后一个字节作为输入参数,而不是删除 non-existent 空字节。
消息字符串是空终止的,所以它应该能正常工作。但是,您可能想要明确提及消息需要 US-ASCII 或明确编码字符串(例如 UTF-8)。
我正在尝试与接受 GET 和 POST 请求的 API 交互,这些请求包括从消息派生的签名和我的私钥,使用 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/——输入上面的key作为input type=Base-64,上面的message string作为input type=TEXT,output type=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();
};
您需要使用CONST BYTE key[] = { 0x6C, ... };
方法来指定您的密钥。键和输入数据是二进制数据,在大多数编程语言中表示为字节数组。十六进制和 base 64 是 表示 或 编码 二进制值的两种方式,以便它们可以用作可打印文本。
但是,如果您使用字节数组,那么 sizeof
将 return 实际字节数。数组不是空终止的,因此没有理由删除最后的空字节。所以 sizeof(key) - 1
将删除键的最后一个字节作为输入参数,而不是删除 non-existent 空字节。
消息字符串是空终止的,所以它应该能正常工作。但是,您可能想要明确提及消息需要 US-ASCII 或明确编码字符串(例如 UTF-8)。