使用OpenSSL计算HMAC_SHA1哈希值的代码问题排查
HMAC_SHA1计算结果不符的代码错误排查
我用下面的C++代码计算HMAC_SHA1哈希值,但结果和在线工具不一致:代码运行结果是d916b4c2d277319bbf18076c158f0cbcf6c3bc57,在线工具结果是71482b292f2b2a47b3eca6dad5e7350566d60963,就算移除字符串里的转义字符,结果还是不匹配,求排查代码问题。
原代码
int computeHMACSHA1Hash(const char* unhashedcstr, char* hashedcstr, const char* key, int returncode) { string hashed; size_t unhashlength = strlen(unhashedcstr); char* nonconstunhashcstr = new char[unhashlength]; strcpy_s(nonconstunhashcstr, unhashlength + 1, unhashedcstr); unsigned char* pixels = reinterpret_cast<unsigned char*>(nonconstunhashcstr); returncode = 0; HMAC_CTX* context = HMAC_CTX_new(); size_t unhashedstrlength = sizeof(unhashedcstr); if (context != NULL) { if (HMAC_Init_ex(context, key, strlen(key), EVP_sha1(), NULL)) { if (HMAC_Update(context, pixels, unhashedstrlength)) { unsigned char hash[EVP_MAX_MD_SIZE]; unsigned int lengthOfHash = 0; if (HMAC_Final(context, hash, &lengthOfHash)) { std::stringstream ss; for (unsigned int i = 0; i < lengthOfHash; ++i) { ss << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i]; } hashed = ss.str(); size_t outputSize = hashed.length() + 1; // +1 for null terminator strcpy_s(hashedcstr, outputSize, hashed.c_str()); returncode = 0; } else { returncode = 7; } } else { returncode = 6; } } else { returncode = 5; } HMAC_CTX_free(context); } else { returncode = 4; } return returncode; } int main() { const char* unhashedcstr = "a=services&l=v1&p=open&k=SD58292829&i=20200918125249803&n=2124&t=1600404769&f={\"invoiceCode\": \"11111\",\"invoiceNo\": \"2222\",\"inTaxAmount\": \"\",\"exTaxAmount\": \"\"}"; char* hashedcstr = new char[100]; int returncode = 0; const char* key = "SD886A11B0EE428F"; int result = computeHMACSHA1Hash(unhashedcstr, hashedcstr, key, returncode); return 0; }
错误原因及修正
1. 核心错误:错误计算待哈希字符串长度
代码里这一行完全错误:
size_t unhashedstrlength = sizeof(unhashedcstr);
unhashedcstr是const char*类型的指针,sizeof得到的是指针本身的大小(32位系统是4字节,64位是8字节),而非字符串的实际长度。这导致HMAC_Update只处理了字符串的前4/8个字符,结果自然和在线工具完全不符。
修正:直接用之前已经计算好的unhashlength,或者重新调用strlen(unhashedcstr):
size_t unhashedstrlength = unhashlength;
2. 多余的内存分配与内存泄漏
代码里把const char*转成char*再转unsigned char*完全没必要,HMAC_Update接受const unsigned char*类型,可以直接把unhashedcstr强转过去,不需要额外分配内存。而且原代码里分配的nonconstunhashcstr没有释放,会造成内存泄漏。
修正:删掉内存分配相关代码,直接用原字符串:
const unsigned char* pixels = reinterpret_cast<const unsigned char*>(unhashedcstr);
3. 返回码参数传递错误
returncode是按值传递的,函数内部修改它不会影响外面的变量。如果需要让外部拿到错误码,应该改成引用传递:
int computeHMACSHA1Hash(const char* unhashedcstr, char* hashedcstr, const char* key, int& returncode)
修正后的完整代码
#include <string> #include <sstream> #include <iomanip> #include <openssl/hmac.h> int computeHMACSHA1Hash(const char* unhashedcstr, char* hashedcstr, const char* key, int& returncode) { std::string hashed; returncode = 0; size_t unhashlength = strlen(unhashedcstr); const unsigned char* input_data = reinterpret_cast<const unsigned char*>(unhashedcstr); HMAC_CTX* context = HMAC_CTX_new(); if (context != NULL) { if (HMAC_Init_ex(context, key, strlen(key), EVP_sha1(), NULL)) { if (HMAC_Update(context, input_data, unhashlength)) { unsigned char hash[EVP_MAX_MD_SIZE]; unsigned int lengthOfHash = 0; if (HMAC_Final(context, hash, &lengthOfHash)) { std::stringstream ss; for (unsigned int i = 0; i < lengthOfHash; ++i) { ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]); } hashed = ss.str(); size_t outputSize = hashed.length() + 1; strcpy_s(hashedcstr, outputSize, hashed.c_str()); returncode = 0; } else { returncode = 7; } } else { returncode = 6; } } else { returncode = 5; } HMAC_CTX_free(context); } else { returncode = 4; } return returncode; } int main() { const char* unhashedcstr = "a=services&l=v1&p=open&k=SD58292829&i=20200918125249803&n=2124&t=1600404769&f={\"invoiceCode\": \"11111\",\"invoiceNo\": \"2222\",\"inTaxAmount\": \"\",\"exTaxAmount\": \"\"}"; char* hashedcstr = new char[100]; int returncode = 0; const char* key = "SD886A11B0EE428F"; int result = computeHMACSHA1Hash(unhashedcstr, hashedcstr, key, returncode); // 可添加输出语句验证结果:printf("%s\n", hashedcstr); delete[] hashedcstr; // 记得释放内存 return 0; }
修正后运行结果会和在线工具一致,得到71482b292f2b2a47b3eca6dad5e7350566d60963。
内容的提问来源于stack exchange,提问作者DonoWall
相关产品推荐
相关产品推荐

