1

Below is the code I'm running from apex execute.

Error received - signature mismatch error...

Able to authenticate using postman

String formattedDateString = Datetime.now().formatgmt('yyyyMMdd\'T\'HHmmss\'Z\'');


Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof('******Access token******'),blob.valueof('********Secret Key***********'));

//Blob mac = Crypto.generateMac('HMACSHA1', blob.valueof(''),blob.valueof('********Secret Key***********'));


String HashedPayload = EncodingUtil.converttohex(mac);



/***** CanonicalReq  ***********/


String CanonicalReq='GET\n\n'+

EncodingUtil.urlEncode('prefix','UTF-8')+'='+EncodingUtil.urlEncode('0011N000018jlXtQAI/a001N00001MxTp9QAF','UTF-8')+'\n'+

'content-type:application/x-www-form-urlencoded\n'+

'host:'***Bucket name***'+.s3-us-east-2.amazonaws.com\n'+

'x-amz-content-sha256:'+HashedPayload+'\n'+

'x-amz-date:'+formattedDateString+'\n'+

'content-type;host;x-amz-content-sha256;x-amz-date\n'+

HashedPayload;


/*******************************/


/******** StringToSign *********/

String StringToSign='AWS4-HMAC-SHA256\n'+formattedDateString+'\\us-east-2\\s3\\aws4_request\n'+EncodingUtil.converttohex(Crypto.generateDigest('SHA256',Blob.valueOf(CanonicalReq)));

/*******************************/


/******** signingKey *********/


Blob  signingKey= Crypto.generateMac('HMACSHA256',Crypto.generateMac('HMACSHA256',Crypto.generateMac('HMACSHA256',Crypto.generateMac('HMACSHA256',Crypto.generateMac('HMACSHA256',blob.valueOf('AWS4'+'******Access token******'),Blob.valueOf('20180811')),Blob.valueOf('us-east-2')),Blob.valueOf('s3')), Blob.valueOf('aws4_request')),Blob.valueOf(StringToSign));


/*******************************/


/***********sign****************/

String sign = EncodingUtil.convertToHex(Crypto.generateMac('hmacSHA256', Blob.valueOf(stringToSign), signingKey));

/********************************/


HttpRequest req = new HttpRequest();

req.setMethod('GET');

req.setEndpoint('https://***Bucket name***.s3-us-east-2.amazonaws.com?prefix=0011N000018jlXtQAI/a001N00001MxTp9QAF');

req.setHeader('Host','***Bucket name***.s3-us-east-2.amazonaws.com');

req.setHeader('Content-Type', 'application/x-www-form-urlencoded');

req.setHeader('X-Amz-Date', formattedDateString);

String authHeader = 'AWS4-HMAC-SHA256 Credential=******Access token******/20180811/us-east-2/s3/aws4_request, SignedHeaders=;content-type;x-amz-content-sha256;host;x-amz-date, Signature='+sign;


req.setHeader('Authorization',authHeader);

req.setHeader('x-amz-content-sha256','STREAMING-AWS4-HMAC-SHA256-PAYLOAD');

Http http = new Http();

HTTPResponse res = http.send(req);

System.debug('*Resp:' + String.ValueOF(res.getBody()));

System.debug('RESPONSE STRING: ' + res.toString());

System.debug('RESPONSE STATUS: ' + res.getStatus());

System.debug('STATUS_CODE: ' + res.getStatusCode());

Error in Response:

The request signature we calculated does not match the signature you provided. Check your key and signing method

Can anybody help me in knowing the flaws I'm having inside my code.

1

Your "StringToSign" is incorrect. You're meant to use "/", not "\", for the third line in the string.

String StringToSign='AWS4-HMAC-SHA256\n'+formattedDateString+'\nus-east-2/s3/aws4_request\n'+EncodingUtil.converttohex(Crypto.generateDigest('SHA256',Blob.valueOf(CanonicalReq)));

Your Host name may be incorrect. The host name we use is specifically:

<bucket-name>.s3.amazonaws.com

At no point do you use HMACSHA1 during the signing process. Every step should use HMACSHA256 instead.


The signing key algorithm uses four HMACSHA256 calls, not five. Here's an example from my own code:

    signingKey = Crypto.generateMac('hmacSHA256', Blob.valueOf('aws4_request'),
        Crypto.generateMac('hmacSHA256', Blob.valueOf(service),
            Crypto.generateMac('hmacSHA256', Blob.valueOf(region),
                Crypto.generateMac('hmacSHA256', Blob.valueOf(requestTime.formatGMT('yyyyMMdd')), Blob.valueOf('AWS4'+secretKey))
            )
        )
    );

It appears that authHeader is set incorrectly; SignedHeaders has an extraneous leading ; character. You'll want to read more in the documentation.


STREAMING-AWS4-HMAC-SHA256-PAYLOAD isn't going to work if you try and do this directly in Apex Code. Don't bother trying. Instead, you can use the multi-part file upload process. This is a three step process: Start a new multi-part request, upload each chunk, finish the multi-part request. I did code my version this way initially, and found it... unpleasant to do in Apex Code. We ultimately ended up not needing it in the end after we changed our code to work in Lightning.


There may be other issues pending, but these are the ones I see immediately.

Considering the number of AWS questions that have gone up recently, I strongly suggest you read the AWS S4 Signing documentation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.