在 Crypto++ 中获取 Unicode 字符串的 SHA1
Get SHA1 of Unicode string in Crypto++
我自学C++,遇到一个问题,一个多星期都解决不了。我希望你能帮助我。
我需要获取 Unicode 字符串的 SHA1 摘要(如 Привет
),但我不知道该怎么做。
我试着这样做,但是 returns 一个错误的摘要!
对于wstring('Ы')
它 returns - A469A61DF29A7568A6CC63318EA8741FA1CF2A7
我需要 - 8dbe718ab1e0c4d75f7ab50fc9a53ec4f0528373
问候和抱歉我的英语:)。
CryptoPP 5.6.2
MVC++ 2013
#include <iostream>
#include "cryptopp562\cryptlib.h"
#include "cryptopp562\sha.h"
#include "cryptopp562\hex.h"
int main() {
std::wstring string(L"Ы");
int bs_size = (int)string.length() * sizeof(wchar_t);
byte* bytes_string = new byte[bs_size];
int n = 0; //real bytes count
for (int i = 0; i < string.length(); i++) {
wchar_t wcharacter = string[i];
int high_byte = wcharacter & 0xFF00;
high_byte = high_byte >> 8;
int low_byte = wcharacter & 0xFF;
if (high_byte != 0) {
bytes_string[n++] = (byte)high_byte;
}
bytes_string[n++] = (byte)low_byte;
}
CryptoPP::SHA1 sha1;
std::string hash;
CryptoPP::StringSource ss(bytes_string, n, true,
new CryptoPP::HashFilter(sha1,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(hash)
)
)
);
std::cout << hash << std::endl;
return 0;
}
这对我来说似乎很好用。
我没有尝试提取片段,而是简单地将宽字符缓冲区转换为 const byte*
并将其(以及调整后的大小)传递给哈希函数。
int main() {
std::wstring string(L"Привет");
CryptoPP::SHA1 sha1;
std::string hash;
CryptoPP::StringSource ss(
reinterpret_cast<const byte*>(string.c_str()), // cast to const byte*
string.size() * sizeof(std::wstring::value_type), // adjust for size
true,
new CryptoPP::HashFilter(sha1,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(hash)
)
)
);
std::cout << hash << std::endl;
return 0;
}
输出:
C6F8291E68E478DD5BD1BC2EC2A7B7FC0CEE1420
编辑: 添加。
结果将 encoding
依赖。例如我 运行 this on Linux
其中 wchar_t
是 4 个字节。在 Windows
我相信 wchar_t
可能只有 2 个字节。
为了保持一致性,最好使用 UTF8 以正常方式存储文本 std::string
。这也使得调用 API 更简单:
int main() {
std::string string("Привет"); // UTF-8 encoded
CryptoPP::SHA1 sha1;
std::string hash;
CryptoPP::StringSource ss(
string,
true,
new CryptoPP::HashFilter(sha1,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(hash)
)
)
);
std::cout << hash << std::endl;
return 0;
}
输出:
2805AE8E7E12F182135F92FB90843BB1080D3BE8
你说‘但是它 returns 错误的摘要’——你拿它和什么比较?
要点:SHA-1 等摘要不适用于字符序列,但适用于 字节 .
的序列
您在此代码片段中所做的是生成字符串 "Ы"
中 unicode 字符的临时 编码 。这种编码将(事实证明)匹配UTF-16编码如果字符串中的字符都在BMP中('基本多语言平面',在这种情况下是正确的) 和 if 以 wcharacter
结束的数字是表示 unicode 代码点的整数(这可能是正确的,但我认为不能保证)。
如果您与之比较的摘要使用 UTF-8 编码将输入字符串转换为字节序列(这很可能),那么它会产生与您的不同的字节序列,因此该序列的 SHA-1 摘要将与您在此处计算的摘要不同。
所以:
检查您的测试字符串使用的编码。
你最好使用一些库函数专门为你要处理的字符串生成UTF-16或UTF-8(视情况而定)编码,以确保字节序列您正在使用的就是您认为的那样。
中对 unicode 和编码进行了很好的介绍
I need to get a SHA1 digest of a Unicode string (like Привет), but I don't know how to do that.
这里的技巧是您需要知道如何对 Unicode 字符串进行编码。在Windows上,一个wchar_t
是2个八位字节;而在 Linux 上,wchar_t
是 4 个字节。 Character Set Considerations 上有一个 Crypto++ wiki 页面,但不是很好。
要最有效地进行互操作,请始终使用 UTF-8。这意味着您将 UTF-16 或 UTF-32 转换为 UTF-8。因为你在Windows,你会想打电话给WideCharToMultiByte function to convert it using CP_UTF8
. If you were on Linux, then you would use libiconv
。
Crypto++ 有一个名为 StringNarrow
的内置函数,它使用 C++。它在文件 misc.h
中。使用前一定要先调用setlocale
Stack Overflow 有几个关于使用 Windows 函数的问题。参见,例如,How do you properly use WideCharToMultiByte.
I need - 8dbe718ab1e0c4d75f7ab50fc9a53ec4f0528373
什么是散列值(SHA-1、SHA-256、...)?它是 HMAC(键控哈希)吗?信息是否已加盐(如存储中的密码)?它是如何编码的?我不得不问,因为我无法重现您想要的结果:
SHA-1: 2805AE8E7E12F182135F92FB90843BB1080D3BE8
SHA-224: 891CFB544EB6F3C212190705F7229D91DB6CECD4718EA65E0FA1B112
SHA-256: DD679C0B9FD408A04148AA7D30C9DF393F67B7227F65693FFFE0ED6D0F0ADE59
SHA-384: 0D83489095F455E4EF5186F2B071AB28E0D06132ABC9050B683DA28A463697AD
1195FF77F050F20AFBD3D5101DF18C0D
SHA-512: 0F9F88EE4FA40D2135F98B839F601F227B4710F00C8BC48FDE78FF3333BD17E4
1D80AF9FE6FD68515A5F5F91E83E87DE3C33F899661066B638DB505C9CC0153D
这是我使用的程序。请务必指定宽字符串的长度。如果您不这样做(并使用 -1
作为长度),则 WideCharToMultiByte
将在其计算中包括终止 ASCII-Z。由于我们使用的是 std::string
,因此我们不需要包含 ASCII-Z 终止符的函数。
int main(int argc, char* argv[])
{
wstring m1 = L"Привет"; string m2;
int req = WideCharToMultiByte(CP_UTF8, 0, m1.c_str(), (int)m1.length(), NULL, 0, NULL, NULL);
if(req < 0 || req == 0)
throw runtime_error("Failed to convert string");
m2.resize((size_t)req);
int cch = WideCharToMultiByte(CP_UTF8, 0, m1.c_str(), (int)m1.length(), &m2[0], (int)m2.length(), NULL, NULL);
if(cch < 0 || cch == 0)
throw runtime_error("Failed to convert string");
// Should not be required
m2.resize((size_t)cch);
string s1, s2, s3, s4, s5;
SHA1 sha1; SHA224 sha224; SHA256 sha256; SHA384 sha384; SHA512 sha512;
HashFilter f1(sha1, new HexEncoder(new StringSink(s1)));
HashFilter f2(sha224, new HexEncoder(new StringSink(s2)));
HashFilter f3(sha256, new HexEncoder(new StringSink(s3)));
HashFilter f4(sha384, new HexEncoder(new StringSink(s4)));
HashFilter f5(sha512, new HexEncoder(new StringSink(s5)));
ChannelSwitch cs;
cs.AddDefaultRoute(f1);
cs.AddDefaultRoute(f2);
cs.AddDefaultRoute(f3);
cs.AddDefaultRoute(f4);
cs.AddDefaultRoute(f5);
StringSource ss(m2, true /*pumpAll*/, new Redirector(cs));
cout << "SHA-1: " << s1 << endl;
cout << "SHA-224: " << s2 << endl;
cout << "SHA-256: " << s3 << endl;
cout << "SHA-384: " << s4 << endl;
cout << "SHA-512: " << s5 << endl;
return 0;
}
我自学C++,遇到一个问题,一个多星期都解决不了。我希望你能帮助我。
我需要获取 Unicode 字符串的 SHA1 摘要(如 Привет
),但我不知道该怎么做。
我试着这样做,但是 returns 一个错误的摘要!
对于wstring('Ы')
它 returns - A469A61DF29A7568A6CC63318EA8741FA1CF2A7
我需要 - 8dbe718ab1e0c4d75f7ab50fc9a53ec4f0528373
问候和抱歉我的英语:)。
CryptoPP 5.6.2 MVC++ 2013
#include <iostream>
#include "cryptopp562\cryptlib.h"
#include "cryptopp562\sha.h"
#include "cryptopp562\hex.h"
int main() {
std::wstring string(L"Ы");
int bs_size = (int)string.length() * sizeof(wchar_t);
byte* bytes_string = new byte[bs_size];
int n = 0; //real bytes count
for (int i = 0; i < string.length(); i++) {
wchar_t wcharacter = string[i];
int high_byte = wcharacter & 0xFF00;
high_byte = high_byte >> 8;
int low_byte = wcharacter & 0xFF;
if (high_byte != 0) {
bytes_string[n++] = (byte)high_byte;
}
bytes_string[n++] = (byte)low_byte;
}
CryptoPP::SHA1 sha1;
std::string hash;
CryptoPP::StringSource ss(bytes_string, n, true,
new CryptoPP::HashFilter(sha1,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(hash)
)
)
);
std::cout << hash << std::endl;
return 0;
}
这对我来说似乎很好用。
我没有尝试提取片段,而是简单地将宽字符缓冲区转换为 const byte*
并将其(以及调整后的大小)传递给哈希函数。
int main() {
std::wstring string(L"Привет");
CryptoPP::SHA1 sha1;
std::string hash;
CryptoPP::StringSource ss(
reinterpret_cast<const byte*>(string.c_str()), // cast to const byte*
string.size() * sizeof(std::wstring::value_type), // adjust for size
true,
new CryptoPP::HashFilter(sha1,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(hash)
)
)
);
std::cout << hash << std::endl;
return 0;
}
输出:
C6F8291E68E478DD5BD1BC2EC2A7B7FC0CEE1420
编辑: 添加。
结果将 encoding
依赖。例如我 运行 this on Linux
其中 wchar_t
是 4 个字节。在 Windows
我相信 wchar_t
可能只有 2 个字节。
为了保持一致性,最好使用 UTF8 以正常方式存储文本 std::string
。这也使得调用 API 更简单:
int main() {
std::string string("Привет"); // UTF-8 encoded
CryptoPP::SHA1 sha1;
std::string hash;
CryptoPP::StringSource ss(
string,
true,
new CryptoPP::HashFilter(sha1,
new CryptoPP::HexEncoder(
new CryptoPP::StringSink(hash)
)
)
);
std::cout << hash << std::endl;
return 0;
}
输出:
2805AE8E7E12F182135F92FB90843BB1080D3BE8
你说‘但是它 returns 错误的摘要’——你拿它和什么比较?
要点:SHA-1 等摘要不适用于字符序列,但适用于 字节 .
的序列您在此代码片段中所做的是生成字符串 "Ы"
中 unicode 字符的临时 编码 。这种编码将(事实证明)匹配UTF-16编码如果字符串中的字符都在BMP中('基本多语言平面',在这种情况下是正确的) 和 if 以 wcharacter
结束的数字是表示 unicode 代码点的整数(这可能是正确的,但我认为不能保证)。
如果您与之比较的摘要使用 UTF-8 编码将输入字符串转换为字节序列(这很可能),那么它会产生与您的不同的字节序列,因此该序列的 SHA-1 摘要将与您在此处计算的摘要不同。
所以:
检查您的测试字符串使用的编码。
你最好使用一些库函数专门为你要处理的字符串生成UTF-16或UTF-8(视情况而定)编码,以确保字节序列您正在使用的就是您认为的那样。
I need to get a SHA1 digest of a Unicode string (like Привет), but I don't know how to do that.
这里的技巧是您需要知道如何对 Unicode 字符串进行编码。在Windows上,一个wchar_t
是2个八位字节;而在 Linux 上,wchar_t
是 4 个字节。 Character Set Considerations 上有一个 Crypto++ wiki 页面,但不是很好。
要最有效地进行互操作,请始终使用 UTF-8。这意味着您将 UTF-16 或 UTF-32 转换为 UTF-8。因为你在Windows,你会想打电话给WideCharToMultiByte function to convert it using CP_UTF8
. If you were on Linux, then you would use libiconv
。
Crypto++ 有一个名为 StringNarrow
的内置函数,它使用 C++。它在文件 misc.h
中。使用前一定要先调用setlocale
Stack Overflow 有几个关于使用 Windows 函数的问题。参见,例如,How do you properly use WideCharToMultiByte.
I need - 8dbe718ab1e0c4d75f7ab50fc9a53ec4f0528373
什么是散列值(SHA-1、SHA-256、...)?它是 HMAC(键控哈希)吗?信息是否已加盐(如存储中的密码)?它是如何编码的?我不得不问,因为我无法重现您想要的结果:
SHA-1: 2805AE8E7E12F182135F92FB90843BB1080D3BE8
SHA-224: 891CFB544EB6F3C212190705F7229D91DB6CECD4718EA65E0FA1B112
SHA-256: DD679C0B9FD408A04148AA7D30C9DF393F67B7227F65693FFFE0ED6D0F0ADE59
SHA-384: 0D83489095F455E4EF5186F2B071AB28E0D06132ABC9050B683DA28A463697AD
1195FF77F050F20AFBD3D5101DF18C0D
SHA-512: 0F9F88EE4FA40D2135F98B839F601F227B4710F00C8BC48FDE78FF3333BD17E4
1D80AF9FE6FD68515A5F5F91E83E87DE3C33F899661066B638DB505C9CC0153D
这是我使用的程序。请务必指定宽字符串的长度。如果您不这样做(并使用 -1
作为长度),则 WideCharToMultiByte
将在其计算中包括终止 ASCII-Z。由于我们使用的是 std::string
,因此我们不需要包含 ASCII-Z 终止符的函数。
int main(int argc, char* argv[])
{
wstring m1 = L"Привет"; string m2;
int req = WideCharToMultiByte(CP_UTF8, 0, m1.c_str(), (int)m1.length(), NULL, 0, NULL, NULL);
if(req < 0 || req == 0)
throw runtime_error("Failed to convert string");
m2.resize((size_t)req);
int cch = WideCharToMultiByte(CP_UTF8, 0, m1.c_str(), (int)m1.length(), &m2[0], (int)m2.length(), NULL, NULL);
if(cch < 0 || cch == 0)
throw runtime_error("Failed to convert string");
// Should not be required
m2.resize((size_t)cch);
string s1, s2, s3, s4, s5;
SHA1 sha1; SHA224 sha224; SHA256 sha256; SHA384 sha384; SHA512 sha512;
HashFilter f1(sha1, new HexEncoder(new StringSink(s1)));
HashFilter f2(sha224, new HexEncoder(new StringSink(s2)));
HashFilter f3(sha256, new HexEncoder(new StringSink(s3)));
HashFilter f4(sha384, new HexEncoder(new StringSink(s4)));
HashFilter f5(sha512, new HexEncoder(new StringSink(s5)));
ChannelSwitch cs;
cs.AddDefaultRoute(f1);
cs.AddDefaultRoute(f2);
cs.AddDefaultRoute(f3);
cs.AddDefaultRoute(f4);
cs.AddDefaultRoute(f5);
StringSource ss(m2, true /*pumpAll*/, new Redirector(cs));
cout << "SHA-1: " << s1 << endl;
cout << "SHA-224: " << s2 << endl;
cout << "SHA-256: " << s3 << endl;
cout << "SHA-384: " << s4 << endl;
cout << "SHA-512: " << s5 << endl;
return 0;
}