Hmac-SHA256没有返回预期的哈希值

时间:2018-10-03 19:10:13

标签: javascript amazon-web-services hash sha256 hmac

我意识到这里有很多问题,但是在仔细研究了大部分之后,我还没有真正看到能解决我问题的任何东西。

在以下输入上使用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)。有谁知道为什么我无法获得预期的输出?

1 个答案:

答案 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字节字符串。