AWS Signature Version 4 S3 Upload using Node.js

2019-07-23 08:17发布

问题:

I've been following the AWS example on how to generate a V4 HMAC signature. I've done this successfully in Java but I'm trying to get it to work in Node/JavaScript. When I use my code I generate all the correct intermediary keys in their 1st example below but on the next example when given the test StringToSign the same code that generated the correct intermediary keys fails to generate the supposed correct signature.

Correct Intermediary Keys:

secretkey = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
dateStamp = '20120215'
regionName = 'us-east-1'
serviceName = 'iam'

kSecret  = '41575334774a616c725855746e46454d492f4b374d44454e472b62507852666943594558414d504c454b4559'
kDate    = '969fbb94feb542b71ede6f87fe4d5fa29c789342b0f407474670f0c2489e0a0d'
kRegion  = '69daa0209cd9c5ff5c8ced464a696fd4252e981430b10e3d3fd8e2f197d7a70c'
kService = 'f72cfd46f26bc4643f06a11eabb6c0ba18780c19a8da0c31ace671265e3c87fa'
kSigning = 'f4780e2d9f65fa895f9c67b32ce1baf0b0d8a43505a000a1a9e090d414db404d'

http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html.

Fails With the Following Input

secretkey = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY'
dateStamp = '20151229'
regionName = 'us-east-1'
serviceName = 's3'

StringToSign eyAiZXhwaXJhdGlvbiI6ICIyMDE1LTEyLTMwVDEyOjAwOjAwLjAwMFoiLA0KICAiY29uZGl0aW9ucyI6IFsNCiAgICB7ImJ1Y2tldCI6ICJzaWd2NGV4YW1wbGVidWNrZXQifSwNCiAgICBbInN0YXJ0cy13aXRoIiwgIiRrZXkiLCAidXNlci91c2VyMS8iXSwNCiAgICB7ImFjbCI6ICJwdWJsaWMtcmVhZCJ9LA0KICAgIHsic3VjY2Vzc19hY3Rpb25fcmVkaXJlY3QiOiAiaHR0cDovL3NpZ3Y0ZXhhbXBsZWJ1Y2tldC5zMy5hbWF6b25hd3MuY29tL3N1Y2Nlc3NmdWxfdXBsb2FkLmh0bWwifSwNCiAgICBbInN0YXJ0cy13aXRoIiwgIiRDb250ZW50LVR5cGUiLCAiaW1hZ2UvIl0sDQogICAgeyJ4LWFtei1tZXRhLXV1aWQiOiAiMTQzNjUxMjM2NTEyNzQifSwNCiAgICB7IngtYW16LXNlcnZlci1zaWRlLWVuY3J5cHRpb24iOiAiQUVTMjU2In0sDQogICAgWyJzdGFydHMtd2l0aCIsICIkeC1hbXotbWV0YS10YWciLCAiIl0sDQoNCiAgICB7IngtYW16LWNyZWRlbnRpYWwiOiAiQUtJQUlPU0ZPRE5ON0VYQU1QTEUvMjAxNTEyMjkvdXMtZWFzdC0xL3MzL2F3czRfcmVxdWVzdCJ9LA0KICAgIHsieC1hbXotYWxnb3JpdGhtIjogIkFXUzQtSE1BQy1TSEEyNTYifSwNCiAgICB7IngtYW16LWRhdGUiOiAiMjAxNTEyMjlUMDAwMDAwWiIgfQ0KICBdDQp9

Correct Signature: 46503978d3596de22955b4b18d6dfb1d54e8c5958727d5bdcd02cc1119c60fc9 My Signature: e7318f0bfd7d86fb9ba81c314f62192ee2baf7273792ef01ffafeb430fc2fb68

http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html

My Code

var crypto = require("crypto-js")

module.exports.getSignatureKey = function(key, dateStamp, regionName, serviceName) {
    var kSecret = "AWS4" + key
    var kDate = crypto.HmacSHA256(dateStamp, kSecret)
    var kRegion = crypto.HmacSHA256(regionName, kDate)
    var kService = crypto.HmacSHA256(serviceName, kRegion)
    var kSigning = crypto.HmacSHA256("aws4_request", kService)
    return kSigning;
}

module.exports.sign = function(signatureKey,stringToSign) {
    var unencodedSignature = crypto.HmacSHA256(stringToSign,signatureKey)
    return unencodedSignature
}

module.exports.getSignature = function(stringToSign,secretKey,dateStamp,regionName, serviceName) {
    var signingKey = this.getSignatureKey(secretKey,dateStamp,regionName,serviceName)

    return this.sign(signingKey,stringToSign)
}

回答1:

The AWS example in the second link has the wrong signature. Using my solution I am able to successfully upload to s3.

Something else to consider is that the crypto-js node library outputs the signatures already in hex. Theres no need to do a manual conversion yourself as you would if you we in Java using the example code they provide.