OpenSSL SHA256 错误结果
OpenSSL SHA256 Wrong result
我有以下一段代码可以计算文件的 SHA256
。我正在逐块读取文件并使用 EVP_DigestUpdate
作为块。当我使用包含 content
的文件测试代码时
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
函数生成正确的散列值和 return 作为字符串的值?平台是 Windows.
编辑: 看来问题是因为 CRLF
问题。由于Windows在使用\r\n
保存文件时,计算出的校验和不同。如何处理?
MS-DOS 使用CR-LF 约定,所以基本上在windows 中保存文件时,\r\n
对回车符return 和换行符有效。在线测试时(由您提供),只有 \n
个字符生效。
因此,要么你必须检查字符串中 Test Message\r\nHello World\r\n
的校验和,这相当于在 windows 中创建和读取文件(如上所述),这里就是这种情况。
但是,无论在何处创建的文件的校验和都是相同的。
注意:您的代码工作正常:)
问题似乎与我传入的长度值有关 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
,代码现在将正确的校验和计算为字符串
我有以下一段代码可以计算文件的 SHA256
。我正在逐块读取文件并使用 EVP_DigestUpdate
作为块。当我使用包含 content
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
函数生成正确的散列值和 return 作为字符串的值?平台是 Windows.
编辑: 看来问题是因为 CRLF
问题。由于Windows在使用\r\n
保存文件时,计算出的校验和不同。如何处理?
MS-DOS 使用CR-LF 约定,所以基本上在windows 中保存文件时,\r\n
对回车符return 和换行符有效。在线测试时(由您提供),只有 \n
个字符生效。
因此,要么你必须检查字符串中 Test Message\r\nHello World\r\n
的校验和,这相当于在 windows 中创建和读取文件(如上所述),这里就是这种情况。
但是,无论在何处创建的文件的校验和都是相同的。
注意:您的代码工作正常:)
问题似乎与我传入的长度值有关 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
,代码现在将正确的校验和计算为字符串