2017-02-03 8 views
1

TOTP(Time Based One Time Password)を作成するJavaScript関数があります。 これでPHPを使用して、同じTOTPをサーバーで作成する必要がありました。 JavaScriptで同じロジックをPHPでコーディングしました。 便宜上、私はJavaScriptのフィドルとPHPフィドルを作成しました。したがって、コードを比較して出力を見ることができます。HMAC Javascript関数がPHPと異なる結果を返しました

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) { 
 
\t  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ライブラリは、HEX形式でtimeをとります。また、PHPでは、hash_hmac関数の中に置かれたとき、時間はHEX形式になります。
  • secretkey)は、jsSHAに入れられたTEXT形式です。 PHPでも。

実際には、ポイントはPHPでjavascriptのjsSHAライブラリと同じ結果になっています。 私は何かが欠けていると確信しています。私はずっとずっと試してきたし、Googleでさえ答えを知らない。

+2

第三者サービスではなく、ご質問に直接コードを投稿してください。 – Narf

答えて

3

あなたはjsSHAライブラリ入力がここで16進数文字列であることを伝える:

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

は、しかし、あなたはhash_hmac()コール内の前/ PHP側で同等の何もしていません。つまり、jsSHAは生のバイナリデータを取得し、PHPのhash_hmac()はリテラル文字列 "0000000002f3e3c9"を取得します。
当然、同じ結果が得られません。

hash_hmac()に渡す前にhex2bin()~に適用してください。

+0

ありがとう、これは答えでした。 +1 – user2190492

関連する問題