将十六进制转换为可打印的字符串/字符

Convert HEX to printable string/char

本文关键字:字符串 字符 打印 十六进制 转换      更新时间:2023-10-16

我正在使用CNG生成哈希。BCryptFinishHash 调用的结果是十六进制形式的输入的 MD5。例:

char *outHash = "x02x34x751..."

我想将其转换为可打印的字符串:02347501...

我该怎么做?

要以十六进制编码字节数组并将编码的数据写入std::string,请执行以下操作:

static inline char
hex_digit(unsigned int n)
{
    if (n < 10) return '0' + n;
    if (n < 16) return 'a' + (n - 10);
    abort();
}
std::string
encode_bytes(const unsigned char *bytes, size_t len)
{
    std::string rv;
    rv.reserve(len * 2);
    for (size_t i = 0; i < len; i++) {
        rv.push_back(hex_digit((bytes[i] & 0xF0) >> 4));
        rv.push_back(hex_digit((bytes[i] & 0x0F) >> 0));
    }
    return rv;
}

请注意,您必须知道字节数组的长度。 将其视为以 NUL 结尾的"C 字符串"是不安全的,因为二进制数据可以包含内部零字节。 若要了解 CNG 生成的哈希的长度,请调用 BCryptGetProperty 以获取BCRYPT_HASH_LENGTH属性。

我们可以在这里将CryptBinaryToStringCRYPT_STRING_HEXASCIICRYPT_STRING_HEXCRYPT_STRING_HEXRAWCRYPT_STRING_HEX | CRYPT_STRING_NOCRLF一起使用,或者CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF按照你想要的格式字符串进行设计

。 例如。
void print(PUCHAR pbHash, ULONG cbHash, DWORD dwFlags = CRYPT_STRING_HEXRAW | CRYPT_STRING_NOCRLF)
{
    ULONG cch = 0;
    if (CryptBinaryToStringW(pbHash, cbHash, dwFlags, 0, &cch))
    {
        if (PWSTR sz = (PWSTR)_malloca(cch * sizeof(WCHAR)))
        {
            if (CryptBinaryToStringW(pbHash, cbHash, dwFlags, sz, &cch))
            {
                DbgPrint("%Sn", sz);
            }
            _freea(sz);
        }
    }
}

如果您需要一个简单的一次性解决方案,这是一个有用的工具:https://codebeautify.org/hex-string-converter

但是,如果您希望在代码本身中执行此操作,我从较早的线程中找到了它(AKA,这不是我的工作,而是此处@KEINE LUST 的工作)

int main(void)
{
unsigned char readingreg[4];
readingreg[0] = 0x4a;
readingreg[1] = 0xaa;
readingreg[2] = 0xaa;
readingreg[3] = 0xa0;
char temp[4];
sprintf(temp, "%x", readingreg[0]);
printf("This is element 0: %sn", temp);
return 0;
}

你可以像这样打印它:

for(const char *wsk=outHash; *wsk; ++wsk){
    printf("%02hhx", *wsk);
}

基于编辑的 cstring 可以有 0x00 个数字。
C

const char outHash[] = "x02x34x75";
const int size = sizeof(outHash)/sizeof(char) - 1;
for(int i = 0; i < size; ++i){
    printf("%02hhx", outHash [i]);
}

C++

std::string outHash = "x02x34x75";
for(int i = 0; i < outHash.size(); ++i) {
    printf("%02hhx", outHash [i]);
}

遍历字符并打印数值(十六进制)。

#include <iostream>
#include <iomanip>
int main()
{
    char*  outHash = "x02x34x75x01x23xff";  // Get from your Hash function.
    int    sizeOfHash = 6;                        // Use appropriate size for BCryptFinishHash()

    // Set up the characteristics of the stream.
    // setw(2):       Each printed object will use a min width of 2
    // setfill('0'):  If the object is less than 2 char then fill the space with '0'
    // hex:           Print numbers in hex.
    std::cout << std::setw(2) << std::setfill('0') << std::hex;
    // Create a view of the object.
    // Makes it simpler to loop over.
    std::string_view view(outHash, sizeOfHash);
    // Loop over the string.
    for(unsigned char val: view) {
        // Convert to `unsigned char` to make sure you don't print
        // negative numbers. Then convert from there to `int` so that
        // the `std::hex will kick in and convert to hex value.
        std::cout << static_cast<int>(val);
    }   
    std::cout << "n";
}

我正在研究C++Windows Crypto API和CNG的包装器,我在项目中使用的包装器。我计划将其全部移至github,但现在它只是一个正在进行的工作,但您会发现它对于HEX/Base64编码/解码等加密基础知识很有用。

https://github.com/m4x1m1l14n/Crypto

您可以使用 Crypto::Hex::Encode() 方法来实现您想要的。

#include <CryptoHex.hpp>
#include <CryptoRandom.hpp>
using namespace m4x1m1l14n;
char arr[] = { 0xaa, 0xbb, 0xcc, 0xdd, 0x99, 0x00 };
encoded = Crypto::Hex::Encode(arr, sizeof(arr));
/* encoded = "aabbccdd9900" */

您也可以使用位于哈希命名空间中的 MD5 包装器,如下所示。(如果您没有使用大量数据)

#include <CryptoHex.hpp>
#include <CryptoHash.hpp>
using namespace m4x1m1l14n;
encoded = Crypto::Hex::Encode(Crypto::Hash::MD5("Whatever you want to hash"));