2015-03-03 78 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中創建和讀取文件(如上所述),在這裏就是這種情況。

但是,無論創建哪個文件,校驗和都是相同的。

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