Reputation: 20492
A few years ago I wrote some C++ code to sign on to AWS ( Amazon Web Service ). It worked fine at the time. I haven't used it for a while, and now it does not work.
"com.amazon.coral.service#InvalidSignatureException"
I think I have narrowed it down to the hashing function. This unit test fails:
TEST( aws_hash )
{
// unit test the hashing function used for AWS authentication
// sample input and expected results from Signature Version 4 Test Suite
// https://docs.aws.amazon.com/general/latest/gr/signature-v4-test-suite.html
// specifically the get-vanilla-query
// note that this is step 1 of the signing process an does not involve the secret key.
// input string
std::string query =
"GET / HTTP/1.1\n"
"Host:example.amazonaws.com\n"
"X-Amz-Date:20150830T123600Z";
// calculate hash of input
SHA256 sha256;
std::string thehash = sha256( query );
// expected hash value from test suite
// ( last line of get-vanilla-query.creq )
std::string expected = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
// did we get the expected hash?
CHECK_EQUAL( expected, thehash );
}
Outputs:
C:\unit_test\main.cpp(47): error: Failure in aws_hash:
Expected e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
but was 509955df496ae2f4fdc25af95ccf5406099e4a2556523b7ed80f4fab21ac1869
The code for the hashing function I am using can be seen at https://github.com/JamesBremner/sha256
Is there some change I should be aware of?
Is there something wrong with my unit test?
Upvotes: 0
Views: 622
Reputation: 179154
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
This is the SHA-256 hash of an empty string (see https://crypto.stackexchange.com/a/26135/25027).
Signature V4 is entirely different from Signature V2. You hash the body first (the HTTP request body, which does not include the headers), using the value shown when there is no request body.
There is no part of the actual input to Signature V4 that coresponds to your // input string
.
That is an example of the HTTP request that you will be sending, but it is not something that goes directly into the signing algorithm.
The canonical request structure is this:
CanonicalRequest =
HTTPRequestMethod + '\n' +
CanonicalURI + '\n' +
CanonicalQueryString + '\n' +
CanonicalHeaders + '\n' +
SignedHeaders + '\n' +
HexEncode(Hash(RequestPayload))
Here, in HexEncode(Hash(RequestPayload))
, RequestPayload
refers only to the request body -- not the headers. When there's no body, empty string is used, and the hash of an empty string is the value shown.
Upvotes: 1