You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 03:40:44