【问题标题】:OpenSSL SHA256 Wrong resultOpenSSL SHA256 错误结果
【发布时间】:2015-03-03 19:07:11
【问题描述】:

我有以下代码应该计算文件的SHA256。我正在逐块读取文件并使用EVP_DigestUpdate 作为块。当我使用包含内容的文件测试代码时

Test Message Hello World

在 Windows 中,它给我的 SHA256 值为97b2bc0cd1c3849436c6532d9c8de85456e1ce926d1e872a1e9b76a33183655f,但该值应该是318b20b83a6730b928c46163a2a1cefee4466132731c95c39613acb547ccb715,可以验证here too

代码如下:

#include <openssl\evp.h>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdio>
const int MAX_BUFFER_SIZE = 1024;
std::string FileChecksum(std::string, std::string);
int main()
{
    std::string checksum = FileChecksum("C:\\Users\\Dell\\Downloads\\somefile.txt","sha256");
    std::cout << checksum << std::endl;
    return 0;
}

std::string FileChecksum(std::string file_path, std::string algorithm)
{
     EVP_MD_CTX *mdctx;
     const EVP_MD *md;
     unsigned char md_value[EVP_MAX_MD_SIZE];
     int i;
     unsigned int md_len;

     OpenSSL_add_all_digests();
     md = EVP_get_digestbyname(algorithm.c_str());

     if(!md) {
            printf("Unknown message digest %s\n",algorithm);
            exit(1);
     }

     mdctx = EVP_MD_CTX_create();
     std::ifstream readfile(file_path,std::ifstream::in|std::ifstream::binary);
     if(!readfile.is_open())
     {
         std::cout << "COuldnot open file\n";
         return 0;
     }
     readfile.seekg(0, std::ios::end);
     long filelen = readfile.tellg();
     std::cout << "LEN IS " << filelen << std::endl;
     readfile.seekg(0, std::ios::beg);
     if(filelen == -1)
     {
         std::cout << "Return Null \n";
         return 0;
     }

     EVP_DigestInit_ex(mdctx, md, NULL);
     long temp_fil = filelen;
     while(!readfile.eof() && readfile.is_open() && temp_fil>0)
     {

         int bufferS = (temp_fil < MAX_BUFFER_SIZE) ? temp_fil : MAX_BUFFER_SIZE;
         char *buffer = new char[bufferS+1];
         buffer[bufferS] = 0;
         readfile.read(buffer, bufferS);
         std::cout << strlen(buffer) << std::endl;
         EVP_DigestUpdate(mdctx, buffer, strlen(buffer));
         temp_fil -= bufferS;
         delete[] buffer;
     }
     EVP_DigestFinal_ex(mdctx, md_value, &md_len);
     EVP_MD_CTX_destroy(mdctx);

     printf("Digest is: ");
     //char *checksum_msg = new char[md_len];
     //int cx(0);
     for(i = 0; i < md_len; i++)
     {
        //_snprintf(checksum_msg+cx,md_len-cx,"%02x",md_value[i]);
         printf("%02x", md_value[i]);
     }
     //std::string res(checksum_msg);
     //delete[] checksum_msg;

     printf("\n");

     /* Call this once before exit. */
     EVP_cleanup();
     return "";
}

我尝试使用_snprintf 将程序生成的哈希写入字符串,但没有成功。如何生成正确的哈希并将值作为字符串从FileChecksum 函数返回?平台是 Windows。

编辑:问题似乎是因为CRLF 问题。由于 Windows 使用\r\n 保存文件,计算的校验和是不同的。如何处理?

【问题讨论】:

  • 您的示例输入应该是Test Message\nHello World\n
  • 请再次参考问题。我已经更新了详细信息。

标签: c++ windows openssl sha


【解决方案1】:

MS-DOS 使用 CR-LF 约定,所以基本上在 Windows 中保存文件时,\r\n 对回车和换行生效。在在线测试时(由您提供),只有\n 字符生效。 因此,要么您必须检查字符串中Test Message\r\nHello World\r\n 的校验和,这相当于在 Windows 中创建和读取文件(如上所示),这里就是这种情况。

但是,无论在何处创建的文件的校验和都是相同的。

注意:您的代码运行良好 :)

【讨论】:

    【解决方案2】:

    问题似乎与我在EVP_DigestUpdate 中传递的长度值有关。我从strlen 传递了值,但是用bufferS 替换它确实解决了这个问题。 代码修改为:

    while(!readfile.eof() && readfile.is_open() && temp_fil>0)
    {
      int bufferS = (temp_fil < MAX_BUFFER_SIZE) ? temp_fil : MAX_BUFFER_SIZE;
      char *buffer = new char[bufferS+1];
      buffer[bufferS] = 0;
      readfile.read(buffer, bufferS);
      EVP_DigestUpdate(mdctx, buffer, bufferS);
      temp_fil -= bufferS;
      delete[] buffer;
    }
    

    为了发送校验和字符串,我将代码修改为:

    EVP_DigestFinal_ex(mdctx, md_value, &md_len);
    EVP_MD_CTX_destroy(mdctx);
    char str[128] = { 0 };
    char *ptr = str;
    std::string ret;
    for(i = 0; i < md_len; i++)
     {
        //_snprintf(checksum_msg+cx,md_len-cx,"%02x",md_value[i]);
         sprintf(ptr,"%02x", md_value[i]);
         ptr += 2;
     }
    
    ret = str;
    /* Call this once before exit. */
    EVP_cleanup();
    return ret;
    

    至于前面的错误校验和,问题与 windows 如何保持换行有关。正如Zangetsu 所建议的那样,Windows 将文本文件制作为CRLF,但linux 和我之前提到的站点使用的是LF。因此校验和值存在差异。对于文本以外的文件,例如dll,代码现在将正确的校验和计算为字符串

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-27
      • 2012-07-29
      • 1970-01-01
      • 2017-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多