Reputation: 1
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;
}
I tried the code above to calculating the HMAC SHA1 hash value for a content, but compared the results on https://www.freeformatter.com/hmac-generator.html#before-output it looks like I didn't do it right. I'm not sure what I have done wrong though. Any help would be appreciated.
It turned out the result was "d916b4c2d277319bbf18076c158f0cbcf6c3bc57"
, while on the website https://www.freeformatter.com/hmac-generator.html#before-output, the result was "71482b292f2b2a47b3eca6dad5e7350566d60963"
. Even when I tried using the string "a=services&l=v1&p=open&k=SD58292829&i=20200918125249803&n=2124&t=1600404769&f={"invoiceCode": "11111","invoiceNo": "2222","inTaxAmount": "","exTaxAmount": ""}"
which removed the escape characters, the result was "09be98b6129c149e685ed57a1d19651a602cda0d"
. It didn't match the correct one.
Is there anything wrong with my code?
Upvotes: 0
Views: 141
Reputation: 2509
Your hash is calculated over the bytes a=se
, which are the first four bytes of the whole input string. Thus, you get d916b4c2d277319bbf18076c158f0cbcf6c3bc57
instead of the 09be98b6129c149e685ed57a1d19651a602cda0d
that would correspond to the whole string.
The reason is this:
size_t unhashedstrlength = sizeof(unhashedcstr);
Here, sizeof(unhashedcstr)
is the size of the unhashedcstr
pointer itself (which is of type const char*
), not the size of the null-terminated C-style string this unhashedcstr
pointer is pointing to. You are compiling a 32-bit program, so the size of a pointer is 4 bytes. Thus, unhashedstrlength
is 4.
To get the length of the C-style string, you can do this instead:
size_t unhashedstrlength = strlen(unhashedcstr);
But just as a comment, in modern C++, you should avoid using raw pointers (such as const char*
, char*
, unsigned char*
), C functions (like strlen()
, strcpy_s()
) and manual memory management (new
/ delete
and new[]
/ delete[]
). You should prefer to use std::string
and/or std::vector<unsigned char>
instead, wherever possible. When you need to pass a buffer's address to an API function, you can use std::string::data()
, std::vector::data()
, or more generally, std::data()
.
By the way, you currently leak memory: you dynamically allocate buffers using new[]
, but you never deallocate those (using delete[]
). So that memory is released by the OS only after the program exits. This is called a memory leak.
Upvotes: 1