Joshua Hirst
Joshua Hirst

Reputation: 61

Why is my signature different from Amazons example? (C++/REST/Authorization Signature Version 4)

I am following the examples given on this page and I end up getting the correct signature using the details given here .

My problem is I get the signature ced6826de92d2bdeed8f846f0bf508e8559e98e4b0199114b84c54174deb456c correctly but, as soon as I use the same methods and change the variables for the GET example on this page, it gives me signature c2eb7ddb12cb2c46489fdf97947e68b24c3716 instead of f0e8bdb87c964420e857bd35b5d6ed310bd44f0170aba48dd91039c6036bdb41.

This is C++ code using openSSL for HMAC and SHA256 hashing.

The Test function

void Test3()
{
	std::string date = std::string("20130524");
	std::string region = std::string("us-east-1");
	std::string service = std::string("s3");
	std::string request = std::string("aws4_request");

	std::string key = std::string("AWS4wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY");

	unsigned char* signingKey = EncodeHMACSHA256_2(EncodeHMACSHA256_2(EncodeHMACSHA256_2(EncodeHMACSHA256_2((unsigned char*)key.c_str(), &date), &region), &service), &request);

	std::string stringToSign = std::string();
	stringToSign.append("AWS4-HMAC-SHA256\n");
	stringToSign.append("20130524T000000Z\n");
	stringToSign.append("20130524/us-east-1/s3/aws4_request\n");
	stringToSign.append("7344ae5b7ee6c3e7e6b0fe0640412a37625d1fbfff95c48bbb2dc43964946972");

	// Create signature
	unsigned char* signature = EncodeHMACSHA256_2(signingKey, &stringToSign);

	// to hex
	std::string sigHex = ToHex(signature);
}

HMAC function

unsigned char* EncodeHMACSHA256_2(unsigned char* key, std::string* value)
{
	const unsigned char* dataToHash = (unsigned char*)value->c_str();

	// Initialise HMAC
	HMAC_CTX HMAC;
	unsigned int hmaclength = 64;		// Length of the resulting SHA256 hash
	unsigned char* hmachash = (unsigned char*)malloc(sizeof(char) * hmaclength);
	memset(hmachash, 0, hmaclength);

	// Digest the key and message using SHA256
	HMAC_CTX_init(&HMAC);
	HMAC_Init(&HMAC, key, strlen((char*)key), EVP_sha256());
	HMAC_Update(&HMAC, dataToHash, strlen((char*)dataToHash));
	HMAC_Final(&HMAC, hmachash, &hmaclength);
	HMAC_CTX_cleanup(&HMAC);

	return hmachash;
}

Hex Function

std::string ToHex(unsigned char* value)
{
	int len = strlen((char*)value);
	std::stringstream stream;

	for (int i = 0; i < len; i++)
	{
		char tmpStr[3] = { 0 };
		int res = sprintf(tmpStr, "%02x", value[i]);
		stream << tmpStr;
	}

	return stream.str();
}

Upvotes: 2

Views: 1487

Answers (2)

Ashwin
Ashwin

Reputation: 521

We can alternatively use vector if you are using C++11. The pros of using vector is you dont have to keep track of the memory deallocation.

I have an implementation of the same here - HMAC SHA256 in C++ (DynamoDB)

Upvotes: 0

Joshua Hirst
Joshua Hirst

Reputation: 61

The HMAC function was causing the problem, I was converting the unsigned char * to a char * and taking that length which, would end as soon as it hit a zero thus giving a different length. Changed the function to include a length for the key and value.

The HMAC length was changed from 64 to 32 and passed 32 into the function for the key length.

To warn other people on the examples given on Amazon website, beware that the string to sign date is not in ISO format its the same date and time that you pass in the date header i.e. Mon, 06 October etc...

Upvotes: 4

Related Questions