我意识到这里有很多问题,但是在仔细研究了大部分之后,我还没有真正看到能解决我问题的任何东西。
在以下输入上使用SHA256,我得到正确的输出:
var canonString = 'GET\n'+
'/\n'+
'Action=ListUsers&Version=2010-05-08\n'+
'content-type:application/x-www-form-urlencoded; charset=utf-8\n'+
'host:iam.amazonaws.com\n'+
'x-amz-date:20150830T123600Z\n'+
'\n'+
'content-type;host;x-amz-date\n'+
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855';
console.log(CryptoJS.SHA256(canonString).toString()); //returns the expected value of f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59
因此SHA256可以正常工作。同样,在以下输入上使用Hmac-SHA256,我得到正确的响应:
var kDate = CryptoJS.HmacSHA256("20150830", "AWS4wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY");
var kRegion = CryptoJS.HmacSHA256('us-east-1', kDate);
var kService = CryptoJS.HmacSHA256('iam', kRegion);
var kSigning = CryptoJS.HmacSHA256("aws4_request", kService);
console.log(kSigning.toString()); //returns the expected value of c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9
因此,此Hmac-SHA256函数可在此输入上正常工作。但是,在以下输入中,Hmac-SHA256不会返回预期的输出。
var stringToSign = 'AWS4-HMAC-SHA256\n'+
'20150830T123600Z\n'+
'20150830/us-east-1/iam/aws4_request\n'+
CryptoJS.SHA256(canonString).toString();
CryptoJS.HmacSHA256(kSigning.toString(), stringToSign); //Returns 8a96b6691875490d30d05731cc9aa26be1fd64cf611ed929753b6498075aa886
//Expected value is 5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7
//Trying in opposite order just in case
CryptoJS.HmacSHA256(stringToSign, kSigning.toString()); //Returns fe52b221b5173b501c9863cec59554224072ca34c1c827ec5fb8a257f97637b1
//Still not expected value which is 5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7
因此,我的stringToSign明显出问题了,我不知道这是什么。我当时认为换行符被解释为两个不同的字符,而不仅仅是一个字符。但是,像'\\ n'一样转义也不能解决问题!我在这里茫然。这是我一直关注的两个文档(doc1 doc2)。有谁知道为什么我无法获得预期的输出?
答案 0 :(得分:1)
请记住,sha256摘要是字节序列:它不是“普通字符串”。看起来CryptoJS为了方便起见将真正的sha256摘要转换为其他内容,因此不要这样做,那么您就很好了。
使用Node的crypto
库(它是内置API)而不是CryptoJS(它具有绝对糟糕的文档,因此使用它是有问题的):
const crypto = require("crypto");
function HMAC(key, text) {
return crypto.createHmac("sha256", key).update(text).digest();
}
然后我们形成规范哈希:
const canonString = [
'GET',
'/',
'Action=ListUsers&Version=2010-05-08',
'content-type:application/x-www-form-urlencoded; charset=utf-8',
'host:iam.amazonaws.com',
'x-amz-date:20150830T123600Z',
'',
'content-type;host;x-amz-date',
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
].join('\n');
// note: plain hash, not a secret-key-seeded hash
const canonHash = crypto.createHash("sha256").update(canonString).digest();
console.log("Canonical hash is :", canonHash.toString('hex'));
这将产生f536975d06c0309214f805bb90ccff089219ecd68b2577efef23edd43b7e1a59
。然后,我们继续:
const kSecret = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY";
const kDate = HMAC("AWS4" + kSecret,"20150830");
const kRegion = HMAC(kDate,"us-east-1");
const kService = HMAC(kRegion,"iam");
const kSigning = HMAC(kService,"aws4_request");
console.log("kSigning hash is :", kSigning.toString('hex'));
产生c4afb1cc5771d871763a393e44b703571b55cc28424d1a5e86da6ed3c154a4b9
的地方:请注意,我们不进行任何十六进制转换,因为十六进制摘要不是不是 sha256摘要,所以它是一个完全不同的字符串。我们只转换为十六进制字符串以使摘要在控制台日志中清晰可见。
然后终于:
const stringToSign = [
'AWS4-HMAC-SHA256',
'20150830T123600Z',
'20150830/us-east-1/iam/aws4_request',
canonHash.toString('hex')
].join('\n');
const signed = HMAC(kSigning, stringToSign);
console.log("Final signed hash is:", signed.toString('hex'));
哪个产生5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7
。请注意,根据链接到的页面中的说明,我们必须将规范哈希值转换为十六进制字符串,但我们不触摸{{1 }}摘要,必须保留一个真实的sha256字节字符串。