如何在 c++ 中生成十六进制二进制数据的 sha256 哈希?

How to generate sha256 hashes of hexadecimal binary data in c++?

本文关键字:数据 二进制 sha256 哈希 十六进制 c++      更新时间:2023-10-16

我需要C++中的一个函数来生成与此命令在 Linux 中生成的类似结果。

echo -n "616161616161616" | xxd -r -p | sha256sum -b | awk '{print $1}'

此命令的作用是:给定一个六转储,将其转换为二进制文件格式,并显示二进制文件的 sha256 哈希。xxd -r 将六转储转换为二进制文件

谁能帮我?

首先,您应该知道您的命令行版本缺少半字节。 也就是说,如果你通过 xxd -r -p 发送'616161616161616',然后通过 xxd 发送回去,你会看到这个:

echo -n "616161616161616" | xxd -r -p | xxd
00000000: 6161 6161 6161 61                        aaaaaaa

请注意,缺少最后一个半6。xxd 实用程序使用成对数字的十六进制。一旦没有更多的,它就会停止并发出最终输出。您可能期望前导半字节视为单个八位字节的行为,因此如下所示:

echo -n "0616161616161616" | xxd -r -p | xxd
00000000: 0616 1616 1616 1616                      ........

无论哪种情况,无论您想如何处理,您都应该意识到这个问题。

关于您的实际问题,OpenSSL库具有一组相当丰富的功能,可让您几乎微不足道地完成大部分问题。从输入字符串计算摘要相当简单:

#include <iostream>
#include <vector>
#include <string>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>
int main()
{
std::string strHex = "616161616161616"; // get this from wherever
// prepend zero-nibble for odd character counts.
if (strHex.length() % 2)
strHex.insert(strHex.begin(), '0');
// convert to blob. returns dynamic memory allocated with
//  OPENSSL_malloc. Use OPENSSL_free to destroy it.
long len = 0;
unsigned char *bin = OPENSSL_hexstr2buf(strHex.c_str(), &len);
// digest the blob
const EVP_MD *md_algo = EVP_sha256();
unsigned int md_len = EVP_MD_size(md_algo);
std::vector<unsigned char> md( md_len );
EVP_Digest(bin, len, md.data(), &md_len, md_algo, nullptr);
// free the input data.
OPENSSL_free(bin);
// print the buffer to stdout in hex.
char *hexOut = OPENSSL_buf2hexstr(md.data(), md_len);
std::cout << hexOut << 'n';
OPENSSL_free(hexOut);
return 0;
}

请注意,上面的代码采用在奇数输入长度的情况下预置零半字节的方法。如果这不是您想要的行为(即,如果您想要与问题文本完全相同的忽略尾随奇数蚕食行为(,另一种方法是修剪最后一个蚕食(我严重怀疑您想要的是它删除相关位并且是摘要冲突的配方,但您的调用(。

#include <iostream>
#include <vector>
#include <string>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>
int main()
{
std::string strHex = "616161616161616"; // get this from wherever
// prepend zero-nibble for odd character counts.
if (strHex.length() % 2)
strHex.pop_back();
// convert to blob. returns dynamic memory allocated with
//  OPENSSL_malloc. Use OPENSSL_free to destroy it.
long len = 0;
unsigned char *bin = OPENSSL_hexstr2buf(strHex.c_str(), &len);
// digest the blob
const EVP_MD *md_algo = EVP_sha256();
unsigned int md_len = EVP_MD_size(md_algo);
std::vector<unsigned char> md( md_len );
EVP_Digest(bin, len, md.data(), &md_len, md_algo, nullptr);
// free the input data.
OPENSSL_free(bin);
// print the buffer to stdout in hex.
char *hexOut = OPENSSL_buf2hexstr(md.data(), md_len);
std::cout << hexOut << 'n';
OPENSSL_free(hexOut);
return 0;
}

在上述两种情况下,生成的输出都预配置为冒号分隔的八位字节。 即后一个示例输出如下所示:

E4:62:40:71:4B:5D:B3:A2:3E:EE:60:47:9A:62:3E:FB:A4:D6:33:D2:7F:E4:F0:3C:90:4B:9E:21:9A:7F:BE:60

这是由于OPENSSL_buf2hexstr的功能相当有限。如果这不是您想要的(可能不是(,您可以随时使用简单的查找表自己手动打印它,将每个八位字节处理为两个半字节:

#include <iostream>
#include <vector>
#include <string>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>
int main()
{
std::string strHex = "616161616161616";
// prepend zero-nibble for odd character counts.
if (strHex.length() % 2)
strHex.pop_back();
// convert to blob. returns dynamic memory allocated with
//  OPENSSL_malloc. Use OPENSSL_free to destroy it.
long len = 0;
unsigned char *bin = OPENSSL_hexstr2buf(strHex.c_str(), &len);
// digest the blob
const EVP_MD *md_algo = EVP_sha256();
unsigned int md_len = EVP_MD_size(md_algo);
std::vector<unsigned char> md( md_len );
EVP_Digest(bin, len, md.data(), &md_len, md_algo, nullptr);
// free the input data.
OPENSSL_free(bin);
// dump as continuous hex string
static const char alpha[] = "0123456789abcdef";
for (auto c : md)
{
std::cout << alpha[ (c >> 4) & 0xF];
std::cout << alpha[ c & 0xF];
}
std::cout.put('n');
return 0;
}

输出

e46240714b5db3a23eee60479a623efba4d633d27fe4f03c904b9e219a7fbe60

无论如何,比我预期的要长,但希望这是你要找的。

实际算法取决于你想要做什么 - 你可以将十六进制转换为字符串。我在下面的示例中做到了这一点。

您首先要做的是将字符串转换为二进制,这可以通过以下方式完成:

std::string toBin(std::string str){
int s = str.length();
std::string bin = ""
for (int i = 0; i <= n; i++){
int v = int(s[i]);
while (val > 0){
(val % 2)? bin.push_back('1') : bin.push_back('0');
val /= 2;
}
}
std::reverse(bin.begin(), bin.end());
}

但是,代码的下一部分太长了,很遗憾我无法将其包含在此答案中。但是我会将您链接到一个包含(希望(您需要的所有代码的网站。http://www.zedwood.com/article/cpp-sha256-function

愿你安好。