summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Riesen <chris.riesen@gmail.com>2012-06-16 17:52:59 +0200
committerChristian Riesen <chris.riesen@gmail.com>2012-06-16 17:52:59 +0200
commitf2d067a2076142bf385d31df81b6b21093dbe47f (patch)
tree9ea9196958659dfe228fb5e27c82ebab808dfd95
parent2fea54288f85c87f9ea97fda67a8e4e8460f44cc (diff)
downloadotp-f2d067a2076142bf385d31df81b6b21093dbe47f.zip
otp-f2d067a2076142bf385d31df81b6b21093dbe47f.tar.gz
otp-f2d067a2076142bf385d31df81b6b21093dbe47f.tar.bz2
Added additional checking for otp counter
-rw-r--r--src/Otp/Otp.php182
-rw-r--r--tests/Otp/OtpTest.php15
2 files changed, 106 insertions, 91 deletions
diff --git a/src/Otp/Otp.php b/src/Otp/Otp.php
index b88e889..59aee18 100644
--- a/src/Otp/Otp.php
+++ b/src/Otp/Otp.php
@@ -67,73 +67,77 @@ class Otp implements OtpInterface
*/
protected $algorithm = 'sha1';
- /* (non-PHPdoc)
- * @see Otp.OtpInterface::hotp()
- */
- public function hotp($secret, $counter)
- {
- $hash = hash_hmac(
- $this->algorithm,
- $this->getBinaryCounter($counter),
- $secret,
- true
- );
-
- return str_pad($this->truncate($hash), $this->digits, '0', STR_PAD_LEFT);
- }
-
- /* (non-PHPdoc)
- * @see Otp.OtpInterface::totp()
- */
- public function totp($secret, $timecounter = null)
- {
- if (is_null($timecounter)) {
- $timecounter = $this->getTimecounter();
- }
-
- return $this->hotp($secret, $timecounter);
- }
-
- /* (non-PHPdoc)
- * @see Otp.OtpInterface::checkHotp()
- */
- public function checkHotp($secret, $counter, $key)
- {
- return $this->safeCompare($this->hotp($secret, $counter), $key);
- }
-
- /* (non-PHPdoc)
- * @see Otp.OtpInterface::checkTotp()
- */
- public function checkTotp($secret, $key)
- {
- // Counter comes from time now
- // Also we check the current timestamp as well as previous and future ones
- // according to $timerange
- $timecounter = $this->getTimecounter();
-
- $start = $timecounter - ($this->timerange);
- $end = $timecounter + ($this->timerange);
-
- // We first try the current, as it is the most likely to work
- if ($this->safeCompare($this->totp($secret, $timecounter), $key)) {
- return true;
- }
-
- // Well, that didn't work, so try the others
- for ($t = $start; $t <= $end; $t = $t + 1) {
- if ($t == $timecounter) {
- // Already tried that one
- continue;
- }
-
- if ($this->safeCompare($this->totp($secret, $t), $key)) {
- return true;
- }
+ /* (non-PHPdoc)
+ * @see Otp.OtpInterface::hotp()
+ */
+ public function hotp($secret, $counter)
+ {
+ if (!is_numeric($counter)) {
+ throw new \InvalidArgumentException('Counter must be integer');
}
-
- // if none worked, then return false
- return false;
+
+ $hash = hash_hmac(
+ $this->algorithm,
+ $this->getBinaryCounter($counter),
+ $secret,
+ true
+ );
+
+ return str_pad($this->truncate($hash), $this->digits, '0', STR_PAD_LEFT);
+ }
+
+ /* (non-PHPdoc)
+ * @see Otp.OtpInterface::totp()
+ */
+ public function totp($secret, $timecounter = null)
+ {
+ if (is_null($timecounter)) {
+ $timecounter = $this->getTimecounter();
+ }
+
+ return $this->hotp($secret, $timecounter);
+ }
+
+ /* (non-PHPdoc)
+ * @see Otp.OtpInterface::checkHotp()
+ */
+ public function checkHotp($secret, $counter, $key)
+ {
+ return $this->safeCompare($this->hotp($secret, $counter), $key);
+ }
+
+ /* (non-PHPdoc)
+ * @see Otp.OtpInterface::checkTotp()
+ */
+ public function checkTotp($secret, $key)
+ {
+ // Counter comes from time now
+ // Also we check the current timestamp as well as previous and future ones
+ // according to $timerange
+ $timecounter = $this->getTimecounter();
+
+ $start = $timecounter - ($this->timerange);
+ $end = $timecounter + ($this->timerange);
+
+ // We first try the current, as it is the most likely to work
+ if ($this->safeCompare($this->totp($secret, $timecounter), $key)) {
+ return true;
+ }
+
+ // Well, that didn't work, so try the others
+ for ($t = $start; $t <= $end; $t = $t + 1) {
+ if ($t == $timecounter) {
+ // Already tried that one
+ continue;
+ }
+
+ if ($this->safeCompare($this->totp($secret, $t), $key)) {
+ return true;
+ }
+ }
+
+ // if none worked, then return false
+ return false;
}
/**
@@ -146,10 +150,10 @@ class Otp implements OtpInterface
* @return \Otp\Otp
*/
- /*
- * This has been disabled since it does not bring the expected results
- * according to the RFC test vectors for sha256 or sha512.
- * Until that is fixed, the algorithm simply stays at sha1.
+ /*
+ * This has been disabled since it does not bring the expected results
+ * according to the RFC test vectors for sha256 or sha512.
+ * Until that is fixed, the algorithm simply stays at sha1.
* Google Authenticator does not support sha256 and sha512 at the moment.
*
@@ -198,10 +202,10 @@ class Otp implements OtpInterface
*
* @return integer
*/
- public function getPeriod()
- {
- return $this->period;
- }
+ public function getPeriod()
+ {
+ return $this->period;
+ }
/**
* Setting number of otp digits
@@ -226,9 +230,9 @@ class Otp implements OtpInterface
*
* @return integer
*/
- public function getDigits()
- {
- return $this->digits;
+ public function getDigits()
+ {
+ return $this->digits;
}
/**
@@ -252,8 +256,8 @@ class Otp implements OtpInterface
* @return integer Time counter
*/
protected function getTimecounter()
- {
- return floor(time() / $this->period);
+ {
+ return floor(time() / $this->period);
}
/**
@@ -267,13 +271,13 @@ class Otp implements OtpInterface
*/
protected function truncate($hash)
{
- $offset = ord($hash[19]) & 0xf;
-
+ $offset = ord($hash[19]) & 0xf;
+
return (
- ((ord($hash[$offset+0]) & 0x7f) << 24 ) |
- ((ord($hash[$offset+1]) & 0xff) << 16 ) |
- ((ord($hash[$offset+2]) & 0xff) << 8 ) |
- (ord($hash[$offset+3]) & 0xff)
+ ((ord($hash[$offset+0]) & 0x7f) << 24 ) |
+ ((ord($hash[$offset+1]) & 0xff) << 16 ) |
+ ((ord($hash[$offset+2]) & 0xff) << 8 ) |
+ (ord($hash[$offset+3]) & 0xff)
) % pow(10, $this->digits);
}
@@ -298,11 +302,11 @@ class Otp implements OtpInterface
// time differences in sha1 creation, all you know is that a longer
// input takes longer to hash, not how long the actual compared value is
$result = 0;
-
- for ($i = 0; $i < 40; $i++) {
- $result |= ord($sha1a[$i]) ^ ord($sha1b[$i]);
+
+ for ($i = 0; $i < 40; $i++) {
+ $result |= ord($sha1a[$i]) ^ ord($sha1b[$i]);
}
-
+
return $result == 0;
}
diff --git a/tests/Otp/OtpTest.php b/tests/Otp/OtpTest.php
index 81ac3cf..109ced8 100644
--- a/tests/Otp/OtpTest.php
+++ b/tests/Otp/OtpTest.php
@@ -18,6 +18,8 @@ class OtpTest extends \PHPUnit_Framework_TestCase
*/
private $Otp;
+ private $secret = "12345678901234567890";
+
/**
* Prepares the environment before running a test.
*/
@@ -47,7 +49,7 @@ class OtpTest extends \PHPUnit_Framework_TestCase
*/
public function testHotpRfc()
{
- $secret = "12345678901234567890";
+ $secret = $this->secret;
$this->assertEquals('755224', $this->Otp->hotp($secret, 0));
$this->assertEquals('287082', $this->Otp->hotp($secret, 1));
@@ -71,7 +73,7 @@ class OtpTest extends \PHPUnit_Framework_TestCase
*/
public function testTotpRfc()
{
- $secret = "12345678901234567890";
+ $secret = $this->secret;
// Test vectors are in 8 digits
$this->Otp->setDigits(8);
@@ -111,5 +113,14 @@ class OtpTest extends \PHPUnit_Framework_TestCase
$this->assertEquals('47863826', $this->Otp->hotp($secret, floor(20000000000/30)), 'sha512 with time 20000000000');
*/
}
+
+ /**
+ * @expectedException InvalidArgumentException
+ * @expectedExceptionMessage Counter must be integer
+ */
+ public function testHotpInvalidCounter()
+ {
+ $this->Otp->hotp($this->secret, 'a');
+ }
}