<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>密码验证 &#8211; LPC影子技术分享</title>
	<atom:link href="https://www.mudbest.com/tag/%e5%af%86%e7%a0%81%e9%aa%8c%e8%af%81/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.mudbest.com</link>
	<description>行影不离,忘之却步.</description>
	<lastBuildDate>Mon, 01 Oct 2012 08:26:56 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1.2</generator>
	<item>
		<title>Google TOTP Two-factor Authentication(两次验证密码) for PHP</title>
		<link>https://www.mudbest.com/google-totp-two-factor-authentication%e4%b8%a4%e6%ac%a1%e9%aa%8c%e8%af%81%e5%af%86%e7%a0%81-for-php/</link>
		
		<dc:creator><![CDATA[hkshadow]]></dc:creator>
		<pubDate>Mon, 12 Mar 2012 02:09:37 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[分享]]></category>
		<category><![CDATA[Authentication]]></category>
		<category><![CDATA[google Authentication]]></category>
		<category><![CDATA[密码验证]]></category>
		<guid isPermaLink="false">http://www.mudbest.com/?p=908</guid>

					<description><![CDATA[谷歌在今年年初公布的2因子认证（2FA）的G-邮件提供了一个为Android，iPhone和黑莓的应用程序名为 ... <a title="Google TOTP Two-factor Authentication(两次验证密码) for PHP" class="read-more" href="https://www.mudbest.com/google-totp-two-factor-authentication%e4%b8%a4%e6%ac%a1%e9%aa%8c%e8%af%81%e5%af%86%e7%a0%81-for-php/" aria-label="阅读 Google TOTP Two-factor Authentication(两次验证密码) for PHP">阅读更多</a>]]></description>
										<content:encoded><![CDATA[<p><a title="谷歌2FA解释" href="https://www.google.com/support/accounts/bin/static.py?page=guide.cs&amp;guide=1056283&amp;topic=1056284" rel="nofollow" target="_blank">谷歌</a>在今年年初<a title="谷歌2FA解释" href="https://www.google.com/support/accounts/bin/static.py?page=guide.cs&amp;guide=1056283&amp;topic=1056284" rel="nofollow" target="_blank">公布的2因子认证（2FA）</a>的G-邮件提供了一个为Android，iPhone和黑莓的应用程序名为Google的Authenticator生成一个时间登录令牌。 这篇文章将展示如何实现谷歌2FA Web应用程序，以防止被盗的凭据。</p>
<p><a href="http://www.mudbest.com/908.action/googleauthenticator1" rel="attachment wp-att-909"><img decoding="async" title="googleauthenticator1" src="http://www.mudbest.com/wp-content/uploads/2012/03/googleauthenticator1.png" alt="" width="174" height="174" /></a>谷歌验证器是基于<a title="的RFC 4226" href="http://translate.googleusercontent.com/translate_c?hl=zh-CN&amp;ie=UTF8&amp;prev=_t&amp;rurl=translate.google.com.hk&amp;sl=en&amp;tl=zh-CN&amp;u=http://www.ietf.org/rfc/rfc4226.txt&amp;usg=ALkJrhjuuMlys698YGlrRMYUksQqS_mjUw" rel="nofollow" target="_blank">RFC 4226</a> -基于时间的一次性密码（TOTP）这是使用16位基32（ <a title="的RFC 4648" href="http://translate.googleusercontent.com/translate_c?hl=zh-CN&amp;ie=UTF8&amp;prev=_t&amp;rurl=translate.google.com.hk&amp;sl=en&amp;tl=zh-CN&amp;u=http://tools.ietf.org/html/rfc4648&amp;usg=ALkJrhhDHXC5w3ERc7shGODu59YsstALjQ" rel="nofollow" target="_blank">RFC 4648</a> ）编码的种子值初始化。 TOTP使用的初始种子可以进入谷歌通过使用QR码相机或通过键盘的Authenticator。 谷歌还提供了<a title="谷歌的PAM模块2FA" href="https://code.google.com/p/google-authenticator/wiki/PamModuleInstructions" rel="nofollow" target="_blank">一个PAM模块，</a>允许用户集成的sshd 2FA。</p>
<p>可以写一个模块，以支持在任何语言的Google TOTP &#8211; 写PHP库唯一需要注意的是缺乏一个RFC 4648兼容的基地32解码功能。 32基本功能是需要解码的初始种子。 这可能是最棘手的部分实施谷歌的2FA。 可以使用以下功能：<span id="more-908"></span></p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
function base32_decode($b32) {
  $lut = array(&quot;A&quot; =&gt; 0,       &quot;B&quot; =&gt; 1,
               &quot;C&quot; =&gt; 2,       &quot;D&quot; =&gt; 3,
               &quot;E&quot; =&gt; 4,       &quot;F&quot; =&gt; 5,
               &quot;G&quot; =&gt; 6,       &quot;H&quot; =&gt; 7,
               &quot;I&quot; =&gt; 8,       &quot;J&quot; =&gt; 9,
               &quot;K&quot; =&gt; 10,      &quot;L&quot; =&gt; 11,
               &quot;M&quot; =&gt; 12,      &quot;N&quot; =&gt; 13,
               &quot;O&quot; =&gt; 14,      &quot;P&quot; =&gt; 15,
               &quot;Q&quot; =&gt; 16,      &quot;R&quot; =&gt; 17,
               &quot;S&quot; =&gt; 18,      &quot;T&quot; =&gt; 19,
               &quot;U&quot; =&gt; 20,      &quot;V&quot; =&gt; 21,
               &quot;W&quot; =&gt; 22,      &quot;X&quot; =&gt; 23,
               &quot;Y&quot; =&gt; 24,      &quot;Z&quot; =&gt; 25,
               &quot;2&quot; =&gt; 26,      &quot;3&quot; =&gt; 27,
               &quot;4&quot; =&gt; 28,      &quot;5&quot; =&gt; 29,
               &quot;6&quot; =&gt; 30,      &quot;7&quot; =&gt; 31
  );

  $b32    = strtoupper($b32);
  $l      = strlen($b32);
  $n      = 0;
  $j      = 0;
  $binary = &quot;&quot;;

  for ($i = 0; $i &lt; $l; $i++) {

       $n = $n &lt;&lt; 5;
       $n = $n + $lut&#x5B;$b32&#x5B;$i]];
       $j = $j + 5;

       if ($j &gt;= 8) {
           $j = $j - 8;
           $binary .= chr(($n &amp; (0xFF &lt;&lt; $j)) &gt;&gt; $j);
       }
  }

  return $binary;
}
?&gt;
</pre>
<p>这个二进制的数据值将被用来生成一个时间标记，以及当前的Unix时间戳在一个SHA1哈希。除以30，口令每30秒改变的Unix时间戳记（基于计数器的当然就是一次换一个啦）。</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
function get_timestamp() {
   return floor(microtime(true)/30);
}
?&gt;
</pre>
<p>但是不能只是直入SHA1功能从get_timestamp传递的数量，首先需要的时间戳记将减少到8个字节的二进制字符串，由于数据包不支持64位的整数，我们用两个32位无符号整数，以弥补二进制形式。</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
$binary_timestamp = pack('N*', 0) . pack('N*', $timestamp);
?&gt;
</pre>
<p>一旦你有二进制的seed和你有二进制时间戳传递到他们的“hash_mhac”功能。这给你一个20字节的SHA1字符串。</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
$hash = hash_hmac ('sha1', $binary_timestamp, $binary_key, true);
?&gt;
</pre>
<p>进行哈希处理根据RFC4226获得一次性密码。</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
$offset = ord($hash&#x5B;19]) &amp; 0xf;

$OTP = (
   ((ord($hash&#x5B;$offset+0]) &amp; 0x7f) &lt;&lt; 24 ) |
    ((ord($hash&#x5B;$offset+1]) &amp; 0xff) &lt;&lt; 16 ) |
    ((ord($hash&#x5B;$offset+2]) &amp; 0xff) &lt;&lt; 8 ) |
    (ord($hash&#x5B;$offset+3]) &amp; 0xff)
   ) % pow(10, 6);

?&gt;
</pre>
<p><strong>现在TOTP应该包含您的一次性密码。但是仍然有些小问题，如果你想使用这个应用程序，可能有以下的小问题：</strong></p>
<p>  您的客户端和服务器的时钟可能不同步 &#8211; 这可能意味着，当你来检查您的令牌生成的用户，它会失败。这是你可以规定，客户端和服务器的时钟必须是在完美的同步，或者你需要创建一个函数，检查对那些令牌+ / &#8211; 当前服务器时间2分钟。这将允许您的客户端和服务器出长达2分钟，但显然增加了机会，使攻击者能够正确猜测一个时间令牌。</p>
<p>  如果没有次数上限，用户可以在猜测令牌，它可能会以蛮力一次性令牌。</p>
<p>  如果seed太小了，攻击者可以拦截一些令牌，它可能会蛮力的种子值，允许攻击者产生新的一次性令牌。出于这个原因，谷歌执行最低的16个字符或80位的种子长度。</p>
<p>  如果令牌没有标记为无效，因为它已被用于尽快截获令牌的攻击者可能能够快速重新获得。</p>
<p>  Google Authenticator: Seed value &#8216;PEHMPSDNLXIOG65U&#8217;</p>
<p>  在这里有一个PHP类，实现谷歌TOTP。针对蛮力攻击其失踪的保护，但其他功能齐全。</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php
&lt;?
/**
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt;.
 *
 * PHP Google two-factor authentication module.
 *
 * See http://www.idontplaydarts.com/2011/07/google-totp-two-factor-authentication-for-php/
 * for more details
 *
 * @author Phil
 **/

class Google2FA {

	const keyRegeneration 	= 30;	// Interval between key regeneration
	const otpLength		= 6;	// Length of the Token generated

	private static $lut = array(	// Lookup needed for Base32 encoding
		&quot;A&quot; =&gt; 0,	&quot;B&quot; =&gt; 1,
		&quot;C&quot; =&gt; 2,	&quot;D&quot; =&gt; 3,
		&quot;E&quot; =&gt; 4,	&quot;F&quot; =&gt; 5,
		&quot;G&quot; =&gt; 6,	&quot;H&quot; =&gt; 7,
		&quot;I&quot; =&gt; 8,	&quot;J&quot; =&gt; 9,
		&quot;K&quot; =&gt; 10,	&quot;L&quot; =&gt; 11,
		&quot;M&quot; =&gt; 12,	&quot;N&quot; =&gt; 13,
		&quot;O&quot; =&gt; 14,	&quot;P&quot; =&gt; 15,
		&quot;Q&quot; =&gt; 16,	&quot;R&quot; =&gt; 17,
		&quot;S&quot; =&gt; 18,	&quot;T&quot; =&gt; 19,
		&quot;U&quot; =&gt; 20,	&quot;V&quot; =&gt; 21,
		&quot;W&quot; =&gt; 22,	&quot;X&quot; =&gt; 23,
		&quot;Y&quot; =&gt; 24,	&quot;Z&quot; =&gt; 25,
		&quot;2&quot; =&gt; 26,	&quot;3&quot; =&gt; 27,
		&quot;4&quot; =&gt; 28,	&quot;5&quot; =&gt; 29,
		&quot;6&quot; =&gt; 30,	&quot;7&quot; =&gt; 31
	);

	/**
	 * Generates a 16 digit secret key in base32 format
	 * @return string
	 **/
	public static function generate_secret_key($length = 16) {
		$b32 	= &quot;234567QWERTYUIOPASDFGHJKLZXCVBNM&quot;;
		$s 	= &quot;&quot;;

		for ($i = 0; $i &lt; $length; $i++)
			$s .= $b32&#x5B;rand(0,31)];

		return $s;
	}

	/**
	 * Returns the current Unix Timestamp devided by the keyRegeneration
	 * period.
	 * @return integer
	 **/
	public static function get_timestamp() {
		return floor(microtime(true)/self::keyRegeneration);
	}

	/**
	 * Decodes a base32 string into a binary string.
	 **/
	public static function base32_decode($b32) {

		$b32 	= strtoupper($b32);

		if (!preg_match('/^&#x5B;ABCDEFGHIJKLMNOPQRSTUVWXYZ234567]+$/', $b32, $match))
			throw new Exception('Invalid characters in the base32 string.');

		$l 	= strlen($b32);
		$n	= 0;
		$j	= 0;
		$binary = &quot;&quot;;

		for ($i = 0; $i &lt; $l; $i++) {

			$n = $n &lt;&lt; 5; 				// Move buffer left by 5 to make room
			$n = $n + self::$lut&#x5B;$b32&#x5B;$i]]; 	// Add value into buffer
			$j = $j + 5;				// Keep track of number of bits in buffer

			if ($j &gt;= 8) {
				$j = $j - 8;
				$binary .= chr(($n &amp; (0xFF &lt;&lt; $j)) &gt;&gt; $j);
			}
		}

		return $binary;
	}

	/**
	 * Takes the secret key and the timestamp and returns the one time
	 * password.
	 *
	 * @param binary $key - Secret key in binary form.
	 * @param integer $counter - Timestamp as returned by get_timestamp.
	 * @return string
	 **/
	public static function oath_hotp($key, $counter)
	{
	    if (strlen($key) &lt; 8)
		throw new Exception('Secret key is too short. Must be at least 16 base 32 characters');

	    $bin_counter = pack('N*', 0) . pack('N*', $counter);		// Counter must be 64-bit int
	    $hash 	 = hash_hmac ('sha1', $bin_counter, $key, true);

	    return str_pad(self::oath_truncate($hash), self::otpLength, '0', STR_PAD_LEFT);
	}

	/**
	 * Verifys a user inputted key against the current timestamp. Checks $window
	 * keys either side of the timestamp.
	 *
	 * @param string $b32seed
	 * @param string $key - User specified key
	 * @param integer $window
	 * @param boolean $useTimeStamp
	 * @return boolean
	 **/
	public static function verify_key($b32seed, $key, $window = 4, $useTimeStamp = true) {

		$timeStamp = self::get_timestamp();

		if ($useTimeStamp !== true) $timeStamp = (int)$useTimeStamp;

		$binarySeed = self::base32_decode($b32seed);

		for ($ts = $timeStamp - $window; $ts &lt;= $timeStamp + $window; $ts++)
			if (self::oath_hotp($binarySeed, $ts) == $key)
				return true;

		return false;

	}

	/**
	 * Extracts the OTP from the SHA1 hash.
	 * @param binary $hash
	 * @return integer
	 **/
	public static function oath_truncate($hash)
	{
	    $offset = ord($hash&#x5B;19]) &amp; 0xf;

	    return (
	        ((ord($hash&#x5B;$offset+0]) &amp; 0x7f) &lt;&lt; 24 ) |
	        ((ord($hash&#x5B;$offset+1]) &amp; 0xff) &lt;&lt; 16 ) |
	        ((ord($hash&#x5B;$offset+2]) &amp; 0xff) &lt;&lt; 8 ) |
	        (ord($hash&#x5B;$offset+3]) &amp; 0xff)
	    ) % pow(10, self::otpLength);
	}



}

$InitalizationKey = &quot;PEHMPSDNLXIOG65U&quot;;					// Set the inital key

$TimeStamp	  = Google2FA::get_timestamp();
$secretkey 	  = Google2FA::base32_decode($InitalizationKey);	// Decode it into binary
$otp       	  = Google2FA::oath_hotp($secretkey, $TimeStamp);	// Get current token

echo(&quot;Init key: $InitalizationKey\n&quot;);
echo(&quot;Timestamp: $TimeStamp\n&quot;);
echo(&quot;One time password: $otp\n&quot;);

// Use this to verify a key as it allows for some time drift.

$result = Google2FA::verify_key($InitalizationKey, &quot;123456&quot;);

var_dump($result);
?&gt;
</pre>
<p>你可以检查其工作由安装谷歌的Authenticator应用QR码和扫描的权利 &#8211; 由应用程序生成的代码应匹配类生成的代码。</p>
<p>这个function Google2FA::verify_key 应该用来验证用户一次令牌，因为它允许客户端时钟漂移2分钟服务器时间两侧。</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
