在Javascript中模仿这个Erlang代码行为

时间:2015-02-18 11:57:32

标签: javascript erlang

我试图在Javascript中获取以下generate_hash erlang函数返回的相同值

-define(b2l(V), binary_to_list(V)).
-define(l2b(V), list_to_binary(V)).

generate_hash(User, Secret, TimeStamp) ->
    SessionData = User ++ ":" ++ erlang:integer_to_list(TimeStamp, 16),
    Hash = crypto:sha_mac(Secret, SessionData),
    base64:encode(SessionData ++ ":" ++ ?b2l(Hash)).

make_time() ->
    {NowMS, NowS, _} = erlang:now(),
    NowMS * 1000000 + NowS.

以这种方式在erlang中调用此函数:

Username = "username" 
Secret = ?l2b("secret"),
UserSalt = "usersalt",
CurrentTime = make_time(),
Hash = generate_hash( ?b2l(UserName), <<Secret/binary, UserSalt/binary>>, CurrentTime).

我设法使用google CryptoJS库计算哈希,但base64返回的值与erlang中返回的值不匹配

<script src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-sha1.js"></script>

function generate_hash(User, Secret, TimeStamp) {
    var SessionData = User + ":" + parseInt(TimeStamp,16);
    var hash = CryptoJS.HmacSHA1(Secret,SessionData);
    return atob(SessionData + ":" + hash.toString())
}

var Hash = generate_hash( "username", "secret"+"usersalt", new Date().getTime())

alert(Hash);

3 个答案:

答案 0 :(得分:2)

您的代码中存在三个问题。

首先:CryptoJS.HmacSHA1(Secret,SessionData);的论点被颠倒了。它应该是CryptoJS.HmacSHA1(SessionData, Secret);

您可以在JS控制台中查看:

var hash = CryptoJS.HmacSHA1("b", "a");
0: 1717011798
1: -2038285946
2: -931908057
3: 823367506
4: 21804555

现在,转到Erlang控制台并输入:

crypto:sha_mac(<<"a">>, <<"b">>).
<<102,87,133,86,134,130,57,134,200,116,54,39,49,19,151,82,1,76,182,11>>
binary:encode_unsigned(1717011798).
<<102,87,133,86>>
binary:encode_unsigned(21804555).
<<1,76,182,11>>

我不知道有符号整数的等效方法,但事实证明,更改参数的顺序会给出相同的二进制值。

第二个问题是hash.toString(),我的例子后面的内容是:

hash = CryptoJS.HmacSHA1("b", "a");
hash.toString();
"6657855686823986c874362731139752014cb60b"

而Erlang二进制列表将导致:

Str = binary_to_list(Hash).
[102,87,133,86,134,130,57,134,200,116,54,39,49,19,151,82,1,76,182,11]
io:format("~s", [Str]).
fWV9Èt6'1^SR^AL¶^K

我不确定toString对word数组的作用,但这会弄乱最终的结果。

第三个问题是,new Date().getTime()将以毫秒为单位返回时间,而在Erlang中,则有微秒。但是,当您使用静态整数测试时,这应该无关紧要。

答案 1 :(得分:0)

两件事:

  1. 上面的Erlang代码中的make_time函数返回自Unix纪元以来的的数量,而Javascript方法getTime返回毫秒

    除此之外,由于您可能没有在同一秒内运行这两个功能,因此您将获得不同的时间戳,因此无论如何都会有不同的哈希值。

  2. Javascript函数parseInt解析一个字符串并返回一个整数,而Erlang函数integer_to_list取一个整数并将其转换为字符串(在Erlang中,字符串表示为列表,因此这个名字)。您可能希望改为使用toString方法。

答案 2 :(得分:0)

该算法可以生成erlang对应生成的相同字节序列:

var ret = [];

var hash = CryptoJS.HmacSHA1("b","a").words;
angular.forEach(hash,function(v){
    var pos = v>=0, last=ret.length;
    for(v=pos?v:v>>>0; v>0; v=Math.floor(v/256)) {
        ret.splice(last, 0, v%256);
    }
});
console.info(ret);
console.info(String.fromCharCode.apply(String,ret));

以上输出:

[102, 87, 133, 86, 134, 130, 57, 134, 200, 116, 54, 39, 49, 19, 151, 82, 1, 76, 182, 11]
fWV9Èt6'1RL¶