2015-03-03 69 views
0

我有一段代码应该计算文件的SHA256。我正在按块读取文件块,并使用EVP_DigestUpdate作为块。当我用文件来测试代码,有内容OpenSSL SHA256错误的结果

Test Message Hello World

在Windows

,它给我的97b2bc0cd1c3849436c6532d9c8de85456e1ce926d1e872a1e9b76a33183655f SHA256值,但该值应该是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保存文件时,计算出的校验和不同。如何处理这个?

+0

您的示例输入应该是'Test Message \ nHello World \ n'。 – Phylogenesis 2015-03-03 09:27:15

+0

请再次参考问题。我已经更新了细节。 – Pant 2015-03-03 09:30:33

回答

1

看来问题与我在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; 

至于更早的校验和错误,问题如何窗口被关联保持换行。如Zangetsu所示,Windows正在将文本文件制作为CRLF,但我之前提到的linux和站点使用的是LF。因此校验和值有所不同。对于文本以外的文件,例如dll,代码现在按字符串计算正确的校验和

1

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

但是,无论创建哪个文件,校验和都是相同的。

注:您的代码工作正常:)