【问题标题】:HMAC Javascript function has different result than the PHPHMAC Javascript 函数的结果与 PHP 不同
【发布时间】:2017-02-03 16:52:34
【问题描述】:

我有一个创建基于时间的一次性密码 (TOTP) 的 javascript 函数。 现在我必须使用 PHP 在服务器上创建相同的 TOTP。 我在 PHP 中编写了与我的 javascript 函数中相同的逻辑。 为方便起见,我创建了一个 javascript fiddle 和一个 PHP fiddle。因此,您可以比较代码并查看输出。

Javascript 版本:(小提琴:https://jsfiddle.net/rrfk4ey9/1/

var TOTP = function() {
    var dec2hex = function(s) {
        return (s < 15.5 ? "0" : "") + Math.round(s).toString(16);
    };
    var hex2dec = function(s) {
        return parseInt(s, 16);
    };
    var leftpad = function(s, l, p) {
        if(l + 1 >= s.length) {
            s = Array(l + 1 - s.length).join(p) + s;
        }
        return s;
    };
 
    this.getOTP = function(secret) {
        try {
            var epoch = Math.round(new Date().getTime() / 1000.0);
            
            // For testing, we take a fixed time. (same as in PHP version).
            var time = "0000000002f3e3c9";//leftpad(dec2hex(Math.floor(epoch / 30)), 16, "0");
            
            document.getElementById("key").innerHTML = secret;
            document.getElementById("time").innerHTML = time;
            
            var hmacObj = new jsSHA(time, "HEX");
            var hmac = hmacObj.getHMAC(secret, "TEXT", "SHA-1", "HEX");
            
            document.getElementById("hmac-out").innerHTML = hmac;
            
            var offset = hex2dec(hmac.substring(hmac.length - 1));
            var otp = (hex2dec(hmac.substr(offset * 2, 8)) & hex2dec("7fffffff")) + "";
            otp = (otp).substr(otp.length - 6, 6);
            
        } catch (error) {
	    alert("Error: " + error);
            throw error;
        }
        
        return otp;
    };
 
};
var totpObj = new TOTP();
  document.getElementById("result").innerHTML = totpObj.getOTP("someSecret");
output {
  font-family: monospace;
  white-space: pre;
}
#result {
  color: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsSHA/1.6.0/sha.js"></script>
<body>
<aside>This snippet uses external library <b>jsSHA</b> version <b>1.6.0</b></aside>
<hr />
<output>
  <div>Key:  <b id="key"></b></div>
  <div>Time: <b id="time"></b></div>
  <div>HMAC: <b id="hmac-out"></b></div>
  <div>code: <b id="result"></b></div>
</output>

</body>

PHP 版本: (http://ideone.com/s0Bwqu)

<?php
function leftPad($in, $len, $str) {

    return str_pad($in, $len, $str, STR_PAD_LEFT);
}

$key = "someSecret";

$epoch = time();
// For testing, we take a fixed time. (same as in JS version).
$time = "0000000002f3e3c9";//leftPad(dechex(floor($epoch / 30)), 16, "0");
echo "Key:     " . $key . "\n";
echo "Time:    " . $time . "\n";

$hmac = hash_hmac("sha1", $time, $key, false);
echo "HMAC:    " . $hmac . "\n";

$offset = hexdec(substr($hmac, strlen($hmac) - 1));
$otp = (hexdec(substr($hmac, $offset * 2, 8)) & hexdec("7fffffff")) . "";
$otp = substr($otp, strlen($otp) - 6, 6);

echo "Code:    " . $otp . "\n";

?>

这会产生:

Key:     someSecret
Time:    0000000002f3e3c9
HMAC:    5dcab54740bdca71e706c7e38a5c59fec3cb9c1a
Code:    094428

请注意,在两个版本(JS 和 PHP)中,timekey 是相同的。 HMAC 不同,所以在我的理解中,问题就从这里开始了。 javascript 版本是我第一个创建的,并且被证明可以正常工作。

我很确定问题是由 jsSHA 库的行为引起的。 所以我提出了一些观点:

  • jsSHA 库采用十六进制格式的time。同样在 PHP 中,当放入 hash_hmac 函数时,时间是 HEX 格式。
  • secretkey)采用 jsSHA 格式的文本格式。也在 PHP 中。

实际上,关键是在 PHP 中获得与在 javascript 中的 jsSHA 库相同的结果。 我确定我错过了一些东西。一直在尝试,连谷歌都不知道答案。

【问题讨论】:

  • 请直接在您的问题中发布代码,而不是通过第三方服务。

标签: php security encryption hash encoding


【解决方案1】:

您在这里告诉 jsSHA 库输入是十六进制字符串:

var hmacObj = new jsSHA(time, "HEX");

但是在hash_hmac() 调用之前/内部,您没有在 PHP 端执行任何等效操作。这意味着 jsSHA 获取原始二进制数据,而 PHP 的 hash_hmac() 获取文字字符串“0000000002f3e3c9”。
当然,这不会产生相同的结果。

hex2bin() 应用于$time,然后将其传递给hash_hmac()

【讨论】:

  • 谢谢,这就是答案。 +1
猜你喜欢
  • 1970-01-01
  • 2012-10-12
  • 2018-08-30
  • 1970-01-01
  • 2018-05-25
  • 2019-01-08
  • 1970-01-01
  • 1970-01-01
  • 2018-12-06
相关资源
最近更新 更多