【问题标题】:Mimic this Erlang code behaviour in Javascript在 Javascript 中模仿这个 Erlang 代码行为
【发布时间】:2015-02-18 11:57:31
【问题描述】:

我正在尝试在 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).

我设法使用谷歌 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);

【问题讨论】:

  • 可能很傻,但你确定使用相同的时间戳
  • 我尝试使用秒、毫秒和微秒,但结果总是与 erlang 中的不一样..
  • 恐怕问题在于“>”在Erlang中的含义。恐怕它不等于简单的javascript字符串连接
  • @mlorini: 这个“>”代码正是你需要的,这就是连接。

标签: javascript erlang


【解决方案1】:

您的代码存在三个问题。

首先: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 中,您只有微秒。不过,当您使用静态整数对其进行测试时,这无关紧要。

【讨论】:

  • @mlorini hash.toString() 创建十六进制字符串表示。您可以使用lists:flatten([io_lib:format("~2.16.0b", [Byte]) || &lt;&lt;Byte:8&gt;&gt; &lt;= Hash]). 在 erlang 中获取它
  • 我认为@mlorini 想要相反 - 用 JS 创建 Erlang 表示。 @Łukasz:你知道吗,如何在 binary_to_list 之后将 JS 单词列表转换为 Erlang 字符串?
  • 完全正确。我想要相反的!
  • @mlorini 抱歉,在这里找到了您的问题的答案:stackoverflow.com/a/3195961/4169859 但我不确定它将如何处理非 ascii 值...
  • @tkowal 是的,多亏了你的建议,这个小提琴在 javascript 中产生了与 erlang 对应的相同字节序列:jsfiddle.net/ou0wknwv/2
【解决方案2】:

两件事:

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

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

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

【讨论】:

  • 是的,我的意思是同时运行这个函数。当然,为了测试,我使用固定值作为时间戳。
【解决方案3】:

该算法可以生成与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¶

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-14
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多