Hmac-SHA256 未返回预期的哈希值
Hmac-SHA256 not returning expected hash
我知道这里有很多关于此的问题,但在浏览了大部分问题后,我还没有真正看到任何解决我的问题的方法。
在以下输入上使用 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 没有 return 预期的输出。
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)。有谁知道为什么我得不到预期的输出?
记住 sha256 摘要是一个字节序列:它不是 "normal string"。为了方便起见,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
,但这只是因为我们使用 .toString('hex')
将其记录为十六进制字符串:真实 值仍然是一个字节序列。
然后我们继续:
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
:再次注意,这仅在 toString('hex')
之后用于控制台日志记录。 sha256 字节摘要 kSigning
本身 不是 十六进制字符串。
然后最后:
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
,请注意,我们 必须 将规范哈希转换为十六进制字符串以用于签名目的,而不仅仅是日志记录,按照中的说明您 link 访问的页面。但是,我们仍然 不 触及 kSigning
摘要,它仍然是一个真正的 sha256 字节序列。
我知道这里有很多关于此的问题,但在浏览了大部分问题后,我还没有真正看到任何解决我的问题的方法。
在以下输入上使用 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 没有 return 预期的输出。
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)。有谁知道为什么我得不到预期的输出?
记住 sha256 摘要是一个字节序列:它不是 "normal string"。为了方便起见,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
,但这只是因为我们使用 .toString('hex')
将其记录为十六进制字符串:真实 值仍然是一个字节序列。
然后我们继续:
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
:再次注意,这仅在 toString('hex')
之后用于控制台日志记录。 sha256 字节摘要 kSigning
本身 不是 十六进制字符串。
然后最后:
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
,请注意,我们 必须 将规范哈希转换为十六进制字符串以用于签名目的,而不仅仅是日志记录,按照中的说明您 link 访问的页面。但是,我们仍然 不 触及 kSigning
摘要,它仍然是一个真正的 sha256 字节序列。