Compare commits

...

8 Commits

Author SHA1 Message Date
Rob Janssen 52cbcf7579 * Removed stupid typo 2015-04-30 14:39:06 +02:00
Rob Janssen 1f9008c217 Update composer.json 2015-04-30 12:58:15 +02:00
RobThree 955e9b0b03 * Fix for possible timing-attack in verifyCode() method 2015-04-30 12:53:21 +02:00
Rob Janssen 1d0a9432e6 Update README.md 2015-04-06 20:52:43 +02:00
RobThree 3b3e723bea * More variable names improved 2015-04-06 20:35:23 +02:00
RobThree f1a729c9ed * Better variable naming 2015-04-06 20:29:16 +02:00
Rob Janssen 98d3f2a21b Update .travis.yml 2015-03-25 23:59:07 +01:00
Rob Janssen 8976cf138e Update README.md 2015-03-23 09:30:46 +01:00
6 changed files with 50 additions and 35 deletions
+1 -1
View File
@@ -8,4 +8,4 @@ php:
- 7 - 7
- hhvm - hhvm
script: phpunit tests script: phpunit --coverage-text tests
+4 -7
View File
@@ -1,6 +1,6 @@
# ![Logo](https://raw.githubusercontent.com/RobThree/TwoFactorAuth/master/logo.png) TwoFactorAuth class for PHP # ![Logo](https://raw.githubusercontent.com/RobThree/TwoFactorAuth/master/logo.png) TwoFactorAuth class for PHP
[![Build status](https://img.shields.io/travis/RobThree/TwoFactorAuth.svg?style=flat-square)](https://travis-ci.org/RobThree/TwoFactorAuth/) [![Latest Stable Version](https://img.shields.io/packagist/v/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![License](https://img.shields.io/packagist/l/robthree/twofactorauth.svg?style=flat-square)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![HHVM Status](https://img.shields.io/hhvm/RobThree/TwoFactorAuth.svg?style=flat-square)](http://hhvm.h4cc.de/package/robthree/twofactorauth) [![PayPal donate button](http://img.shields.io/badge/paypal-donate-orange.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MB5M2SQLP636 "Keep me off the streets") [![Build status](https://img.shields.io/travis/RobThree/TwoFactorAuth.svg?style=flat-square)](https://travis-ci.org/RobThree/TwoFactorAuth/) [![Latest Stable Version](https://img.shields.io/packagist/v/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![License](https://img.shields.io/packagist/l/robthree/twofactorauth.svg?style=flat-square)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/robthree/twofactorauth.svg?style=flat-square)](https://packagist.org/packages/robthree/twofactorauth) [![HHVM Status](https://img.shields.io/hhvm/RobThree/TwoFactorAuth.svg?style=flat-square)](http://hhvm.h4cc.de/package/robthree/twofactorauth) [![Code Climate](https://img.shields.io/codeclimate/github/RobThree/TwoFactorAuth.svg?style=flat-square)](https://codeclimate.com/github/RobThree/TwoFactorAuth) [![PayPal donate button](http://img.shields.io/badge/paypal-donate-orange.svg?style=flat-square)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=6MB5M2SQLP636 "Keep me off the streets")
PHP class for [two-factor (or multi-factor) authentication](http://en.wikipedia.org/wiki/Multi-factor_authentication) using [TOTP](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) and [QR-codes](http://en.wikipedia.org/wiki/QR_code). Inspired by, based on but most importantly an *improvement* on '[PHPGangsta/GoogleAuthenticator](https://github.com/PHPGangsta/GoogleAuthenticator)'. PHP class for [two-factor (or multi-factor) authentication](http://en.wikipedia.org/wiki/Multi-factor_authentication) using [TOTP](http://en.wikipedia.org/wiki/Time-based_One-time_Password_Algorithm) and [QR-codes](http://en.wikipedia.org/wiki/QR_code). Inspired by, based on but most importantly an *improvement* on '[PHPGangsta/GoogleAuthenticator](https://github.com/PHPGangsta/GoogleAuthenticator)'.
@@ -16,12 +16,9 @@ PHP class for [two-factor (or multi-factor) authentication](http://en.wikipedia.
## Installation ## Installation
````json Run the following command:
"require": {
"robthree/twofactorauth": "1.0" `php composer.phar require robthree/twofactorauth`
}
````
And run `php composer update`
## Quick start ## Quick start
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "robthree/twofactorauth", "name": "robthree/twofactorauth",
"description": "Two Factor Authentication", "description": "Two Factor Authentication",
"version": "1.0", "version": "1.1",
"type": "library", "type": "library",
"keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ], "keywords": [ "Authentication", "Two Factor Authentication", "Multi Factor Authentication", "TFA", "MFA", "PHP", "Authenticator", "Authy" ],
"homepage": "https://github.com/RobThree/TwoFactorAuth", "homepage": "https://github.com/RobThree/TwoFactorAuth",
-1
View File
@@ -6,7 +6,6 @@
<body> <body>
<ol> <ol>
<?php <?php
error_reporting(-1);
require_once 'loader.php'; require_once 'loader.php';
Loader::register('../lib','RobThree\\Auth'); Loader::register('../lib','RobThree\\Auth');
+4 -4
View File
@@ -8,9 +8,9 @@ abstract class BaseHTTPQRCodeProvider implements IQRCodeProvider
protected function getContent($url) protected function getContent($url)
{ {
$ch = curl_init(); $curlhandle = curl_init();
curl_setopt_array($ch, array( curl_setopt_array($curlhandle, array(
CURLOPT_URL => $url, CURLOPT_URL => $url,
CURLOPT_FOLLOWLOCATION => true, CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3, CURLOPT_MAXREDIRS => 3,
@@ -21,9 +21,9 @@ abstract class BaseHTTPQRCodeProvider implements IQRCodeProvider
CURLOPT_SSL_VERIFYPEER => $this->verifyssl, CURLOPT_SSL_VERIFYPEER => $this->verifyssl,
CURLOPT_USERAGENT => 'TwoFactorAuth' CURLOPT_USERAGENT => 'TwoFactorAuth'
)); ));
$data = curl_exec($ch); $data = curl_exec($curlhandle);
curl_close($ch); curl_close($curlhandle);
return $data; return $data;
} }
} }
+40 -21
View File
@@ -87,11 +87,11 @@ class TwoFactorAuth
{ {
$secretkey = $this->base32Decode($secret); $secretkey = $this->base32Decode($secret);
$ts = "\0\0\0\0" . pack('N*', $this->getTimeSlice($this->getTime($time))); // Pack time into binary string $timestamp = "\0\0\0\0" . pack('N*', $this->getTimeSlice($this->getTime($time))); // Pack time into binary string
$hm = hash_hmac($this->algorithm, $ts, $secretkey, true); // Hash it with users secret key $hashhmac = hash_hmac($this->algorithm, $timestamp, $secretkey, true); // Hash it with users secret key
$hashpart = substr($hm, ord(substr($hm, -1)) & 0x0F, 4); // Use last nibble of result as index/offset and grab 4 bytes of the result $hashpart = substr($hashhmac, ord(substr($hashhmac, -1)) & 0x0F, 4); // Use last nibble of result as index/offset and grab 4 bytes of the result
$value = unpack('N', $hashpart); // Unpack binary value $value = unpack('N', $hashpart); // Unpack binary value
$value = $value[1] & 0x7FFFFFFF; // Drop MSB, keep only 31 bits $value = $value[1] & 0x7FFFFFFF; // Drop MSB, keep only 31 bits
return str_pad($value % pow(10, $this->digits), $this->digits, '0', STR_PAD_LEFT); return str_pad($value % pow(10, $this->digits), $this->digits, '0', STR_PAD_LEFT);
} }
@@ -101,13 +101,32 @@ class TwoFactorAuth
*/ */
public function verifyCode($secret, $code, $discrepancy = 1, $time = null) public function verifyCode($secret, $code, $discrepancy = 1, $time = null)
{ {
$t = $this->getTime($time); $result = false;
for ($i = -$discrepancy; $i <= $discrepancy; $i++) $timetamp = $this->getTime($time);
{
if (strcmp($this->getCode($secret, $t + ($i * $this->period)), $code) === 0)
return true;
}
// To keep safe from timing-attachs we iterate *all* possible codes even though we already may have verified a code is correct
for ($i = -$discrepancy; $i <= $discrepancy; $i++)
$result |= $this->codeEquals($this->getCode($secret, $timetamp + ($i * $this->period)), $code);
return $result;
}
/**
* Timing-attack safe comparison of 2 codes (see http://blog.ircmaxell.com/2014/11/its-all-about-time.html)
*/
private function codeEquals($safe, $user) {
if (function_exists('hash_equals')) {
return hash_equals($safe, $user);
} else {
// In general, it's not possible to prevent length leaks. So it's OK to leak the length. The important part is that
// we don't leak information about the difference of the two strings.
if (strlen($safe)===strlen($user)) {
$result = 0;
for ($i = 0; $i < strlen($safe); $i++)
$result |= (ord($safe[$i]) ^ ord($user[$i]));
return $result === 0;
}
}
return false; return false;
} }
@@ -155,19 +174,19 @@ class TwoFactorAuth
if (preg_match('/[^'.preg_quote(self::$_base32dict).']/', $value) !== 0) if (preg_match('/[^'.preg_quote(self::$_base32dict).']/', $value) !== 0)
throw new TwoFactorAuthException('Invalid base32 string'); throw new TwoFactorAuthException('Invalid base32 string');
$s = ''; $buffer = '';
foreach (str_split($value) as $c) foreach (str_split($value) as $char)
{ {
if ($c !== '=') if ($char !== '=')
$s .= str_pad(decbin(self::$_base32lookup[$c]), 5, 0, STR_PAD_LEFT); $buffer .= str_pad(decbin(self::$_base32lookup[$char]), 5, 0, STR_PAD_LEFT);
} }
$l = strlen($s); $length = strlen($buffer);
$r = trim(chunk_split(substr($s, 0, $l - ($l % 8)), 8, ' ')); $blocks = trim(chunk_split(substr($buffer, 0, $length - ($length % 8)), 8, ' '));
$o = ''; $output = '';
foreach (explode(' ', $r) as $b) foreach (explode(' ', $blocks) as $block)
$o .= chr(bindec(str_pad($b, 8, 0, STR_PAD_RIGHT))); $output .= chr(bindec(str_pad($block, 8, 0, STR_PAD_RIGHT)));
return $o; return $output;
} }
} }