使用Crypto++生成SHA256哈希,以字符串作为输入和输出?

25

我需要一个使用Crypto++从std::string生成SHA256哈希并输出为std::string的示例。我似乎无法想出这个方法。我尝试过的所有方法都给了我无效的输出。

在interjay的回答之后,这是新代码:

string SHA256(string data)
{
    byte const* pbData = (byte*) data.data();
    unsigned int nDataLen = data.size();
    byte abDigest[CryptoPP::SHA256::DIGESTSIZE];

    CryptoPP::SHA256().CalculateDigest(abDigest, pbData, nDataLen);

    return string((char*)abDigest);
}

对于SHA256("A");的输出结果为:

enter image description here

我该如何将其转换为可读格式?

感谢interjay的答案,我成功生成了最终哈希值。

3个回答

25

这将使用 CryptoPP::Base64Encoder 输出一个 base64 字符串:

#include "sha.h"
#include "filters.h"
#include "base64.h"

std::string SHA256HashString(std::string aString){
    std::string digest;
    CryptoPP::SHA256 hash;

    CryptoPP::StringSource foo(aString, true,
    new CryptoPP::HashFilter(hash,
      new CryptoPP::Base64Encoder (
         new CryptoPP::StringSink(digest))));

    return digest;
}

太棒了,我一直在寻找使用管道处理这个的方法! - Ethan
CryptoPP还使用SIMD x64指令来加速它。 - ahmd0
1
嗨,我在其他地方看到了类似的代码。我想知道为什么HashFilter、Base64Encoder和StringSink不需要显式删除?先谢谢了! - Hei
@Hei:是的,看起来像是一堆内存泄漏。或者,作者是Java的粉丝吗。 :) - MikeF
1
不,这不会泄漏内存。这是使用https://www.cryptopp.com/wiki/Pipelining的惯用CyptoPP代码。 - Rooke
非常好的答案,但通常更适合输出十六进制数字而不是 base64。 - Arthur Tacca

20

这行代码会得到错误的结果:

unsigned int nDataLen = sizeof(pbData);

它总会返回指针的大小。你实际需要的是 data.size()

此外,你不需要这部分:

if(!CryptoPP::SHA256().VerifyDigest(abDigest, pbData, nDataLen))
{
    return SHA256(data);
}

由于您只是根据相同的数据计算摘要,因此它应始终正确验证。如果没有,则会进入无限递归。

为了获得可读的输出,您可以将其转换为十六进制。以下是来自Crypto ++ Wiki的MD5示例,如果您用SHA256替换MD5,则应该适用于您:

CryptoPP::MD5 hash;
byte digest[ CryptoPP::MD5::DIGESTSIZE ];
std::string message = "abcdefghijklmnopqrstuvwxyz";

hash.CalculateDigest( digest, (byte*) message.c_str(), message.length() );

CryptoPP::HexEncoder encoder;
std::string output;
encoder.Attach( new CryptoPP::StringSink( output ) );
encoder.Put( digest, sizeof(digest) );
encoder.MessageEnd();

std::cout << output << std::endl;  

好的,我进行了那些更改,现在似乎每次输出都一样了,但是输出结果却全是一些随意奇怪的字符。我该如何将其改成可读格式? - Doug
应用您的示例会导致从const char*const byte*的转换错误。(byte*) message.c_str()是正确的转换方式。 - 3isenHeim

4

你的代码将从你提供给字符串构造函数的缓冲区中期望一个以 null 结尾的字符串!这意味着结果几乎肯定是错误的。

为了强制执行摘要大小,使用以下方法:

return std::string((char*)abDigest, CryptoPP::SHA256::DIGESTSIZE);

此外,在打印时,以下内容可以正确地生成字符串 "abc" 的测试向量 BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD

std::string string_to_hex(const std::string& input)
{
  static const char* const lut = "0123456789ABCDEF";
  size_t len = input.length();

  std::string output;
  output.reserve(2 * len);
  for (size_t i = 0; i < len; ++i)
  {
    const unsigned char c = input[i];
    output.push_back(lut[c >> 4]);
    output.push_back(lut[c & 15]);
  }
  return output;
}

std::string SHA256(std::string data)
{
  CryptoPP::byte const* pbData = (CryptoPP::byte*)data.data();
  unsigned int nDataLen = data.length();
  CryptoPP::byte abDigest[CryptoPP::SHA256::DIGESTSIZE];

  CryptoPP::SHA256().CalculateDigest(abDigest, pbData, nDataLen);

  // return string((char*)abDigest);  -- BAD!!!
  return std::string((char*)abDigest, CryptoPP::SHA256::DIGESTSIZE);
}

void test_cryptopp() {
  std::cout << string_to_hex(SHA256("abc")) << std::endl;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接