Home > OS >  Signature Does not Match AWS S3 using Javascript Scripting
Signature Does not Match AWS S3 using Javascript Scripting

Time:08-26

I was trying to write a code in Js for GET request via REST API. I am trying to generate signature using the shared key and access key provided by me


 var https = require('https');
 var crypto = require('crypto');
 
 function sign(key, message) {
   return crypto.createHmac('sha256', key).update(message).digest();
 }
 
 function getSignatureKey(key, dateStamp, regionName, serviceName) {
   kDate = sign('AWS4'   key, dateStamp);
   kRegion = sign(kDate, regionName);
   kService = sign(kRegion, serviceName);
   kSigning = sign(kService, 'aws4_request');
   return kSigning;
 }
 
 // values retrieved from Cognito Federation
 accessKey = "MYACCESSKEY";
 secretKey = "my/sharedkey";
 
 region = "us-east-1";
 serviceName = "s3";
 
 // ex 20180518T210317Z
 var now = new Date();
 amzdate = now.toJSON().replace(/[-:]/g, "").replace(/\.[0-9]*/, "");
 datestamp = now.toJSON().replace(/-/g, "").replace(/T.*/, "");
 
 // prepare to send an HTTP request to https://your-api-gateway.execute-api.eu-west-2.amazonaws.com/stage/secure/endpoint
 apiMethod = "GET";
 apiHost = "my_host_name.com";
apiEndpoint="/bucket_name/object_name";

 apiQueryString = "";
 canonicalHeaders = "host:"   apiHost   "\nx-amz-date:"   amzdate  "\n";
   //"\nx-amz-security-token:"   sessionToken   "\n"
 signedHeaders = "host;x-amz-date;";
 payloadHash = crypto.createHash('sha256').update('').digest('hex');
 canonicalRequest = apiMethod   "\n"   apiEndpoint   "\n"   apiQueryString  
   "\n"   canonicalHeaders   "\n"   signedHeaders   "\n"   payloadHash;
 console.log('preparing to invoke canonical request:');
 console.log(canonicalRequest);
 
 // ************* TASK 2: CREATE THE STRING TO SIGN*************
 // Match the algorithm to the hashing algorithm you use, either SHA-1 or
 // SHA-256 (recommended)
 algorithm = 'AWS4-HMAC-SHA256';
 credentialScope = datestamp   '/'   region   '/'   serviceName   '/'  
   'aws4_request';
 stringToSign = algorithm   '\n'   amzdate   '\n'   credentialScope   '\n'  
   crypto.createHash('sha256').update(canonicalRequest).digest('hex');
 
 // ************* TASK 3: CALCULATE THE SIGNATURE *************
 // Create the signing key using the function defined above.
 signingKey = getSignatureKey(secretKey, datestamp, region, serviceName);
 // Sign the string_to_sign using the signing_key
 signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest(
   'hex');
 
 
 // ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
 // The signing information can be either in a query string value or in
 // a header named Authorization. This code shows how to use a header.
 // Create authorization header and add to request headers
 authorizationHeader = algorithm   ' '   'Credential='   accessKey   '/'  
   credentialScope   ', '   'SignedHeaders='   signedHeaders   ', '  
   'Signature='   signature;
 
   process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0

 var options = {
   method: apiMethod,
   host: apiHost,
   path: apiEndpoint,
   headers: {
     'X-Amz-Date': amzdate,
     'Authorization': authorizationHeader
   }
 };
 
 callback = function(response) {
   var str = '';
 
   //another chunk of data has been recieved, so append it to `str`
   response.on('data', function(chunk) {
     str  = chunk;
   });
   console.log("CALLBACK",str);

   //the whole response has been recieved, so we just print it out here
   response.on('end', function() {
     console.log('Complete: '   str);
   });
 }
 console.log(options);
 https.request(options, callback).end();

I am getting signature mismatch error.

Complete: <?xml version="1.0" encoding="UTF-8" standalone="yes"?><Error><Code>SignatureDoesNotMatch</Code><Resource>archivestorage/objectNameNotDecodedYet</Resource>
<Message>The request signature we calculated does not match the signature you provided. Check your secret access key and signing method.
</Message></Error>

Same header are passed via postman and it is working fine. see this Can somebody help me out where I am making mistake ? Thanks in advance

CodePudding user response:

It got fixed.

I missed "X-Amz-Content-Sha256" as header.

Once I supplied "X-Amz-Content-Sha256": payloadHash and requested the data, It worked like a charm .

Sharing the code. It will be the first working code that I found in internet.

/** The following is a NodeJS port of the AWS SigV4 signing sample code (Python) to NodeJS
 *  The addition of the Authorization header has been informed by the use of Postman
 *  For more information see the following documentation:
 *  http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
 */

 var https = require('https');
 var crypto = require('crypto');
 
 function sign(key, message) {
   return crypto.createHmac('sha256', key).update(message).digest();
 }
 
 function getSignatureKey(key, dateStamp, regionName, serviceName) {
   kDate = sign('AWS4'   key, dateStamp);
   kRegion = sign(kDate, regionName);
   kService = sign(kRegion, serviceName);
   kSigning = sign(kService, 'aws4_request');
   return kSigning;
 }
 
 // values retrieved from Cognito Federation
 accessKey = "MYACCESSKEY";
 secretKey = "my/sharedkey";

 
 //sessionToken = "";
 
 region = "us-east-1";
 serviceName = "s3";
 
 // ex 20180518T210317Z
 var now = new Date();
 amzdate = now.toJSON().replace(/[-:]/g, "").replace(/\.[0-9]*/, "");
 datestamp = now.toJSON().replace(/-/g, "").replace(/T.*/, "");
 
 // prepare to send an HTTP request to https://your-api-gateway.execute-api.eu-west-2.amazonaws.com/stage/secure/endpoint
 apiMethod = "GET";
 apiHost = "my_host_name.com";
 apiEndpoint="/bucket_name/object_name";

 apiQueryString = "";
 canonicalHeaders = "host:"   apiHost   "\nx-amz-date:"   amzdate  "\n";
   //"\nx-amz-security-token:"   sessionToken   "\n"
 signedHeaders = "host;x-amz-date;";
 payloadHash = crypto.createHash('sha256').update('').digest('hex');
 canonicalRequest = apiMethod   "\n"   apiEndpoint   "\n"   apiQueryString  
   "\n"   canonicalHeaders   "\n"   signedHeaders   "\n"   payloadHash;
 console.log('preparing to invoke canonical request:');
 console.log(canonicalRequest);
 
 // ************* TASK 2: CREATE THE STRING TO SIGN*************
 // Match the algorithm to the hashing algorithm you use, either SHA-1 or
 // SHA-256 (recommended)
 algorithm = 'AWS4-HMAC-SHA256';
 credentialScope = datestamp   '/'   region   '/'   serviceName   '/'  
   'aws4_request';
 stringToSign = algorithm   '\n'   amzdate   '\n'   credentialScope   '\n'  
   crypto.createHash('sha256').update(canonicalRequest).digest('hex');
 
 // ************* TASK 3: CALCULATE THE SIGNATURE *************
 // Create the signing key using the function defined above.
 signingKey = getSignatureKey(secretKey, datestamp, region, serviceName);
 //console.log("BEFORE SIGNATURE:",signingKey);
 // Sign the string_to_sign using the signing_key
 signature = crypto.createHmac('sha256', signingKey).update(stringToSign).digest(
   'hex');
   
   //console.log("ALGORITHM",algorithm);
   //console.log("SIGNATURE:",signature);
   //console.log("X-AMZ-DATE",amzdate);
   //console.log("X-AMZ-CRDENTIAL",Credential);
 
 // ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
 // The signing information can be either in a query string value or in
 // a header named Authorization. This code shows how to use a header.
 // Create authorization header and add to request headers
 authorizationHeader = algorithm   ' '   'Credential='   accessKey   '/'  
   credentialScope   ', '   'SignedHeaders='   signedHeaders   ', '  
   'Signature='   signature;
   //'5e838e45edf32f084705619603ba0acb77961658fedb9a570c771919c9dcf60a';
 
   //console.log("AUTH header ",authorizationHeader);
   process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0

 
 var options = {
   method: apiMethod,
   host: apiHost,
   path: apiEndpoint,
   headers: {
    "X-Amz-Content-Sha256": payloadHash,
    "X-Amz-Date": amzdate,
    "Authorization": authorizationHeader
   }
 };
 
 callback = function(response) {
   var str = '';
 
   //another chunk of data has been recieved, so append it to `str`
   response.on('data', function(chunk) {
     str  = chunk;
   });
   console.log("CALLBACK",str);

   //the whole response has been recieved, so we just print it out here
   response.on('end', function() {
     console.log('Complete: '   str);
   });
 }
 console.log(options);
 https.request(options, callback).end();
  • Related