diff --git a/lib/Providers/Qr/BaseHTTPQRCodeProvider.php b/lib/Providers/Qr/BaseHTTPQRCodeProvider.php index 5cb3add..32d5f9d 100644 --- a/lib/Providers/Qr/BaseHTTPQRCodeProvider.php +++ b/lib/Providers/Qr/BaseHTTPQRCodeProvider.php @@ -9,7 +9,7 @@ abstract class BaseHTTPQRCodeProvider implements IQRCodeProvider protected function getContent($url) { $curlhandle = curl_init(); - + curl_setopt_array($curlhandle, array( CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, @@ -20,8 +20,8 @@ abstract class BaseHTTPQRCodeProvider implements IQRCodeProvider CURLOPT_USERAGENT => 'TwoFactorAuth' )); $data = curl_exec($curlhandle); - + curl_close($curlhandle); return $data; } -} \ No newline at end of file +} diff --git a/lib/Providers/Qr/IQRCodeProvider.php b/lib/Providers/Qr/IQRCodeProvider.php index 83ed67b..36310bd 100644 --- a/lib/Providers/Qr/IQRCodeProvider.php +++ b/lib/Providers/Qr/IQRCodeProvider.php @@ -6,4 +6,4 @@ interface IQRCodeProvider { public function getQRCodeImage($qrtext, $size); public function getMimeType(); -} \ No newline at end of file +} diff --git a/lib/Providers/Qr/ImageChartsQRCodeProvider.php b/lib/Providers/Qr/ImageChartsQRCodeProvider.php index cc094c3..ab1ecf3 100644 --- a/lib/Providers/Qr/ImageChartsQRCodeProvider.php +++ b/lib/Providers/Qr/ImageChartsQRCodeProvider.php @@ -3,37 +3,38 @@ namespace RobThree\Auth\Providers\Qr; // https://image-charts.com -class ImageChartsQRCodeProvider extends BaseHTTPQRCodeProvider +class ImageChartsQRCodeProvider extends BaseHTTPQRCodeProvider { public $errorcorrectionlevel; public $margin; - function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 1) + public function __construct($verifyssl = false, $errorcorrectionlevel = 'L', $margin = 1) { - if (!is_bool($verifyssl)) - throw new \QRException('VerifySSL must be bool'); + if (!is_bool($verifyssl)) { + throw new QRException('VerifySSL must be bool'); + } $this->verifyssl = $verifyssl; - + $this->errorcorrectionlevel = $errorcorrectionlevel; $this->margin = $margin; } - - public function getMimeType() + + public function getMimeType() { return 'image/png'; } - - public function getQRCodeImage($qrtext, $size) + + public function getQRCodeImage($qrtext, $size) { return $this->getContent($this->getUrl($qrtext, $size)); } - - public function getUrl($qrtext, $size) + + public function getUrl($qrtext, $size) { return 'https://image-charts.com/chart?cht=qr' - . '&chs=' . ceil($size/2) . 'x' . ceil($size/2) + . '&chs=' . ceil($size / 2) . 'x' . ceil($size / 2) . '&chld=' . $this->errorcorrectionlevel . '|' . $this->margin . '&chl=' . rawurlencode($qrtext); } -} \ No newline at end of file +} diff --git a/lib/Providers/Qr/QRException.php b/lib/Providers/Qr/QRException.php index c28e829..4e75f77 100644 --- a/lib/Providers/Qr/QRException.php +++ b/lib/Providers/Qr/QRException.php @@ -1,5 +1,7 @@ verifyssl = $verifyssl; - + $this->errorcorrectionlevel = $errorcorrectionlevel; $this->margin = $margin; $this->qzone = $qzone; @@ -26,37 +27,36 @@ class QRServerProvider extends BaseHTTPQRCodeProvider $this->color = $color; $this->format = $format; } - - public function getMimeType() + + public function getMimeType() { - switch (strtolower($this->format)) - { - case 'png': + switch (strtolower($this->format)) { + case 'png': return 'image/png'; - case 'gif': + case 'gif': return 'image/gif'; - case 'jpg': - case 'jpeg': + case 'jpg': + case 'jpeg': return 'image/jpeg'; - case 'svg': + case 'svg': return 'image/svg+xml'; - case 'eps': + case 'eps': return 'application/postscript'; } - throw new \QRException(sprintf('Unknown MIME-type: %s', $this->format)); + throw new QRException(sprintf('Unknown MIME-type: %s', $this->format)); } - - public function getQRCodeImage($qrtext, $size) + + public function getQRCodeImage($qrtext, $size) { return $this->getContent($this->getUrl($qrtext, $size)); } - - private function decodeColor($value) + + private function decodeColor($value) { return vsprintf('%d-%d-%d', sscanf($value, "%02x%02x%02x")); } - - public function getUrl($qrtext, $size) + + public function getUrl($qrtext, $size) { return 'https://api.qrserver.com/v1/create-qr-code/' . '?size=' . $size . 'x' . $size @@ -68,4 +68,4 @@ class QRServerProvider extends BaseHTTPQRCodeProvider . '&format=' . strtolower($this->format) . '&data=' . rawurlencode($qrtext); } -} \ No newline at end of file +} diff --git a/lib/Providers/Qr/QRicketProvider.php b/lib/Providers/Qr/QRicketProvider.php index 59e27cc..ce28c6c 100644 --- a/lib/Providers/Qr/QRicketProvider.php +++ b/lib/Providers/Qr/QRicketProvider.php @@ -3,7 +3,7 @@ namespace RobThree\Auth\Providers\Qr; // http://qrickit.com/qrickit_apps/qrickit_api.php -class QRicketProvider extends BaseHTTPQRCodeProvider +class QRicketProvider extends BaseHTTPQRCodeProvider { public $errorcorrectionlevel; public $margin; @@ -12,36 +12,35 @@ class QRicketProvider extends BaseHTTPQRCodeProvider public $color; public $format; - function __construct($errorcorrectionlevel = 'L', $bgcolor = 'ffffff', $color = '000000', $format = 'p') + public function __construct($errorcorrectionlevel = 'L', $bgcolor = 'ffffff', $color = '000000', $format = 'p') { $this->verifyssl = false; - + $this->errorcorrectionlevel = $errorcorrectionlevel; $this->bgcolor = $bgcolor; $this->color = $color; $this->format = $format; } - - public function getMimeType() + + public function getMimeType() { - switch (strtolower($this->format)) - { - case 'p': + switch (strtolower($this->format)) { + case 'p': return 'image/png'; - case 'g': + case 'g': return 'image/gif'; - case 'j': + case 'j': return 'image/jpeg'; } - throw new \QRException(sprintf('Unknown MIME-type: %s', $this->format)); + throw new QRException(sprintf('Unknown MIME-type: %s', $this->format)); } - - public function getQRCodeImage($qrtext, $size) + + public function getQRCodeImage($qrtext, $size) { return $this->getContent($this->getUrl($qrtext, $size)); } - - public function getUrl($qrtext, $size) + + public function getUrl($qrtext, $size) { return 'http://qrickit.com/api/qr' . '?qrsize=' . $size @@ -51,4 +50,4 @@ class QRicketProvider extends BaseHTTPQRCodeProvider . '&t=' . strtolower($this->format) . '&d=' . rawurlencode($qrtext); } -} \ No newline at end of file +} diff --git a/lib/Providers/Rng/CSRNGProvider.php b/lib/Providers/Rng/CSRNGProvider.php index 8dba7fc..3ee02c8 100644 --- a/lib/Providers/Rng/CSRNGProvider.php +++ b/lib/Providers/Rng/CSRNGProvider.php @@ -4,11 +4,13 @@ namespace RobThree\Auth\Providers\Rng; class CSRNGProvider implements IRNGProvider { - public function getRandomBytes($bytecount) { + public function getRandomBytes($bytecount) + { return random_bytes($bytecount); // PHP7+ } - - public function isCryptographicallySecure() { + + public function isCryptographicallySecure() + { return true; } -} \ No newline at end of file +} diff --git a/lib/Providers/Rng/HashRNGProvider.php b/lib/Providers/Rng/HashRNGProvider.php index eb42577..4af311b 100644 --- a/lib/Providers/Rng/HashRNGProvider.php +++ b/lib/Providers/Rng/HashRNGProvider.php @@ -1,28 +1,33 @@ algorithm = $algorithm; } - - public function getRandomBytes($bytecount) { + + public function getRandomBytes($bytecount) + { $result = ''; $hash = mt_rand(); for ($i = 0; $i < $bytecount; $i++) { - $hash = hash($this->algorithm, $hash.mt_rand(), true); - $result .= $hash[mt_rand(0, strlen($hash)-1)]; + $hash = hash($this->algorithm, $hash . mt_rand(), true); + $result .= $hash[mt_rand(0, strlen($hash) - 1)]; } return $result; } - - public function isCryptographicallySecure() { + + public function isCryptographicallySecure() + { return false; } } diff --git a/lib/Providers/Rng/IRNGProvider.php b/lib/Providers/Rng/IRNGProvider.php index 6be2800..f2026e1 100644 --- a/lib/Providers/Rng/IRNGProvider.php +++ b/lib/Providers/Rng/IRNGProvider.php @@ -6,4 +6,4 @@ interface IRNGProvider { public function getRandomBytes($bytecount); public function isCryptographicallySecure(); -} \ No newline at end of file +} diff --git a/lib/Providers/Rng/MCryptRNGProvider.php b/lib/Providers/Rng/MCryptRNGProvider.php index 0eeab2c..5f7e7c3 100644 --- a/lib/Providers/Rng/MCryptRNGProvider.php +++ b/lib/Providers/Rng/MCryptRNGProvider.php @@ -5,19 +5,23 @@ namespace RobThree\Auth\Providers\Rng; class MCryptRNGProvider implements IRNGProvider { private $source; - - function __construct($source = MCRYPT_DEV_URANDOM) { + + public function __construct($source = MCRYPT_DEV_URANDOM) + { $this->source = $source; } - - public function getRandomBytes($bytecount) { + + public function getRandomBytes($bytecount) + { $result = @mcrypt_create_iv($bytecount, $this->source); - if ($result === false) - throw new \RNGException('mcrypt_create_iv returned an invalid value'); + if ($result === false) { + throw new RNGException('mcrypt_create_iv returned an invalid value'); + } return $result; } - - public function isCryptographicallySecure() { + + public function isCryptographicallySecure() + { return true; } -} \ No newline at end of file +} diff --git a/lib/Providers/Rng/OpenSSLRNGProvider.php b/lib/Providers/Rng/OpenSSLRNGProvider.php index dc66c64..99e2112 100644 --- a/lib/Providers/Rng/OpenSSLRNGProvider.php +++ b/lib/Providers/Rng/OpenSSLRNGProvider.php @@ -5,21 +5,26 @@ namespace RobThree\Auth\Providers\Rng; class OpenSSLRNGProvider implements IRNGProvider { private $requirestrong; - - function __construct($requirestrong = true) { + + public function __construct($requirestrong = true) + { $this->requirestrong = $requirestrong; } - - public function getRandomBytes($bytecount) { + + public function getRandomBytes($bytecount) + { $result = openssl_random_pseudo_bytes($bytecount, $crypto_strong); - if ($this->requirestrong && ($crypto_strong === false)) - throw new \RNGException('openssl_random_pseudo_bytes returned non-cryptographically strong value'); - if ($result === false) - throw new \RNGException('openssl_random_pseudo_bytes returned an invalid value'); + if ($this->requirestrong && ($crypto_strong === false)) { + throw new RNGException('openssl_random_pseudo_bytes returned non-cryptographically strong value'); + } + if ($result === false) { + throw new RNGException('openssl_random_pseudo_bytes returned an invalid value'); + } return $result; } - - public function isCryptographicallySecure() { + + public function isCryptographicallySecure() + { return $this->requirestrong; } -} \ No newline at end of file +} diff --git a/lib/Providers/Rng/RNGException.php b/lib/Providers/Rng/RNGException.php index eb5e913..f9a11ac 100644 --- a/lib/Providers/Rng/RNGException.php +++ b/lib/Providers/Rng/RNGException.php @@ -1,5 +1,7 @@ url = $url; $this->expectedtimeformat = $expectedtimeformat; @@ -34,7 +36,8 @@ class HttpTimeProvider implements ITimeProvider } } - public function getTime() { + public function getTime() + { try { $context = stream_context_create($this->options); $fd = fopen($this->url, 'rb', false, $context); @@ -42,8 +45,9 @@ class HttpTimeProvider implements ITimeProvider fclose($fd); foreach ($headers['wrapper_data'] as $h) { - if (strcasecmp(substr($h, 0, 5), 'Date:') === 0) - return \DateTime::createFromFormat($this->expectedtimeformat, trim(substr($h,5)))->getTimestamp(); + if (strcasecmp(substr($h, 0, 5), 'Date:') === 0) { + return DateTime::createFromFormat($this->expectedtimeformat, trim(substr($h, 5)))->getTimestamp(); + } } throw new \Exception('Invalid or no "Date:" header found'); } catch (\Exception $ex) { diff --git a/lib/Providers/Time/ITimeProvider.php b/lib/Providers/Time/ITimeProvider.php index a3b87a2..3d417fe 100644 --- a/lib/Providers/Time/ITimeProvider.php +++ b/lib/Providers/Time/ITimeProvider.php @@ -5,4 +5,4 @@ namespace RobThree\Auth\Providers\Time; interface ITimeProvider { public function getTime(); -} \ No newline at end of file +} diff --git a/lib/Providers/Time/LocalMachineTimeProvider.php b/lib/Providers/Time/LocalMachineTimeProvider.php index 572cedc..2fe6846 100644 --- a/lib/Providers/Time/LocalMachineTimeProvider.php +++ b/lib/Providers/Time/LocalMachineTimeProvider.php @@ -2,8 +2,10 @@ namespace RobThree\Auth\Providers\Time; -class LocalMachineTimeProvider implements ITimeProvider { - public function getTime() { +class LocalMachineTimeProvider implements ITimeProvider +{ + public function getTime() + { return time(); } -} \ No newline at end of file +} diff --git a/lib/Providers/Time/NTPTimeProvider.php b/lib/Providers/Time/NTPTimeProvider.php index d69a3a6..072b7d4 100644 --- a/lib/Providers/Time/NTPTimeProvider.php +++ b/lib/Providers/Time/NTPTimeProvider.php @@ -11,20 +11,23 @@ class NTPTimeProvider implements ITimeProvider public $port; public $timeout; - function __construct($host = 'time.google.com', $port = 123, $timeout = 1) + public function __construct($host = 'time.google.com', $port = 123, $timeout = 1) { $this->host = $host; - if (!is_int($port) || $port <= 0 || $port > 65535) + if (!is_int($port) || $port <= 0 || $port > 65535) { throw new \TimeException('Port must be 0 < port < 65535'); + } $this->port = $port; - if (!is_int($timeout) || $timeout < 0) + if (!is_int($timeout) || $timeout < 0) { throw new \TimeException('Timeout must be >= 0'); + } $this->timeout = $timeout; } - public function getTime() { + public function getTime() + { try { /* Create a socket and connect to NTP server */ $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); @@ -36,8 +39,9 @@ class NTPTimeProvider implements ITimeProvider socket_send($sock, $msg, strlen($msg), 0); /* Receive response and close socket */ - if (socket_recv($sock, $recv, 48, MSG_WAITALL) === false) + if (socket_recv($sock, $recv, 48, MSG_WAITALL) === false) { throw new \Exception(socket_strerror(socket_last_error($sock))); + } socket_close($sock); /* Interpret response */ @@ -46,9 +50,8 @@ class NTPTimeProvider implements ITimeProvider /* NTP is number of seconds since 0000 UT on 1 January 1900 Unix time is seconds since 0000 UT on 1 January 1970 */ return $timestamp - 2208988800; - } - catch (Exception $ex) { - throw new \TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->host, $ex->getMessage())); + } catch (\Exception $ex) { + throw new TimeException(sprintf('Unable to retrieve time from %s (%s)', $this->host, $ex->getMessage())); } } } diff --git a/lib/TwoFactorAuth.php b/lib/TwoFactorAuth.php index 7bc067d..dde4cd1 100644 --- a/lib/TwoFactorAuth.php +++ b/lib/TwoFactorAuth.php @@ -1,9 +1,18 @@ issuer = $issuer; - if (!is_int($digits) || $digits <= 0) + if (!is_int($digits) || $digits <= 0) { throw new TwoFactorAuthException('Digits must be int > 0'); + } $this->digits = $digits; - if (!is_int($period) || $period <= 0) + if (!is_int($period) || $period <= 0) { throw new TwoFactorAuthException('Period must be int > 0'); + } $this->period = $period; $algorithm = strtolower(trim($algorithm)); - if (!in_array($algorithm, self::$_supportedalgos)) + if (!in_array($algorithm, self::$_supportedalgos)) { throw new TwoFactorAuthException('Unsupported algorithm: ' . $algorithm); + } $this->algorithm = $algorithm; $this->qrcodeprovider = $qrcodeprovider; $this->rngprovider = $rngprovider; @@ -51,12 +63,14 @@ class TwoFactorAuth { $secret = ''; $bytes = ceil($bits / 5); //We use 5 bits of each byte (since we have a 32-character 'alphabet' / BASE32) - $rngprovider = $this->getRngprovider(); - if ($requirecryptosecure && !$rngprovider->isCryptographicallySecure()) + $rngprovider = $this->getRngProvider(); + if ($requirecryptosecure && !$rngprovider->isCryptographicallySecure()) { throw new TwoFactorAuthException('RNG provider is not cryptographically secure'); + } $rnd = $rngprovider->getRandomBytes($bytes); - for ($i = 0; $i < $bytes; $i++) + for ($i = 0; $i < $bytes; $i++) { $secret .= self::$_base32[ord($rnd[$i]) & 31]; //Mask out left 3 bits for 0-31 values + } return $secret; } @@ -101,16 +115,18 @@ class TwoFactorAuth /** * Timing-attack safe comparison of 2 codes (see http://blog.ircmaxell.com/2014/11/its-all-about-time.html) */ - private function codeEquals($safe, $user) { + private function codeEquals($safe, $user) + { if (function_exists('hash_equals')) { return hash_equals($safe, $user); } // 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)) { + if (strlen($safe) === strlen($user)) { $result = 0; - for ($i = 0; $i < strlen($safe); $i++) + for ($i = 0; $i < strlen($safe); $i++) { $result |= (ord($safe[$i]) ^ ord($user[$i])); + } return $result === 0; } return false; @@ -121,8 +137,9 @@ class TwoFactorAuth */ public function getQRCodeImageAsDataUri($label, $secret, $size = 200) { - if (!is_int($size) || $size <= 0) + if (!is_int($size) || $size <= 0) { throw new TwoFactorAuthException('Size must be int > 0'); + } $qrcodeprovider = $this->getQrCodeProvider(); return 'data:' @@ -136,26 +153,30 @@ class TwoFactorAuth */ public function ensureCorrectTime(array $timeproviders = null, $leniency = 5) { - if ($timeproviders != null && !is_array($timeproviders)) + if ($timeproviders !== null && !is_array($timeproviders)) { throw new TwoFactorAuthException('No timeproviders specified'); + } - if ($timeproviders == null) + if ($timeproviders === null) { $timeproviders = array( - new Providers\Time\NTPTimeProvider(), - new Providers\Time\HttpTimeProvider() + new NTPTimeProvider(), + new HttpTimeProvider() ); + } // Get default time provider $timeprovider = $this->getTimeProvider(); // Iterate specified time providers foreach ($timeproviders as $t) { - if (!($t instanceof ITimeProvider)) + if (!($t instanceof ITimeProvider)) { throw new TwoFactorAuthException('Object does not implement ITimeProvider'); + } // Get time from default time provider and compare to specific time provider and throw if time difference is more than specified number of seconds leniency - if (abs($timeprovider->getTime() - $t->getTime()) > $leniency) + if (abs($timeprovider->getTime() - $t->getTime()) > $leniency) { throw new TwoFactorAuthException(sprintf('Time for timeprovider is off by more than %d seconds when compared to %s', $leniency, get_class($t))); + } } } @@ -184,23 +205,27 @@ class TwoFactorAuth private function base32Decode($value) { - if (strlen($value)==0) return ''; + if (strlen($value) == 0) { + return ''; + } - if (preg_match('/[^'.preg_quote(self::$_base32dict).']/', $value) !== 0) + if (preg_match('/[^' . preg_quote(self::$_base32dict) . ']/', $value) !== 0) { throw new TwoFactorAuthException('Invalid base32 string'); + } $buffer = ''; - foreach (str_split($value) as $char) - { - if ($char !== '=') + foreach (str_split($value) as $char) { + if ($char !== '=') { $buffer .= str_pad(decbin(self::$_base32lookup[$char]), 5, 0, STR_PAD_LEFT); + } } $length = strlen($buffer); $blocks = trim(chunk_split(substr($buffer, 0, $length - ($length % 8)), 8, ' ')); $output = ''; - foreach (explode(' ', $blocks) as $block) + foreach (explode(' ', $blocks) as $block) { $output .= chr(bindec(str_pad($block, 8, 0, STR_PAD_RIGHT))); + } return $output; } @@ -212,7 +237,7 @@ class TwoFactorAuth { // Set default QR Code provider if none was specified if (null === $this->qrcodeprovider) { - return $this->qrcodeprovider = new Providers\Qr\QRServerProvider(); + return $this->qrcodeprovider = new QRServerProvider(); } return $this->qrcodeprovider; } @@ -221,22 +246,22 @@ class TwoFactorAuth * @return IRNGProvider * @throws TwoFactorAuthException */ - public function getRngprovider() + public function getRngProvider() { if (null !== $this->rngprovider) { return $this->rngprovider; } if (function_exists('random_bytes')) { - return $this->rngprovider = new Providers\Rng\CSRNGProvider(); + return $this->rngprovider = new CSRNGProvider(); } if (function_exists('mcrypt_create_iv')) { - return $this->rngprovider = new Providers\Rng\MCryptRNGProvider(); + return $this->rngprovider = new MCryptRNGProvider(); } if (function_exists('openssl_random_pseudo_bytes')) { - return $this->rngprovider = new Providers\Rng\OpenSSLRNGProvider(); + return $this->rngprovider = new OpenSSLRNGProvider(); } if (function_exists('hash')) { - return $this->rngprovider = new Providers\Rng\HashRNGProvider(); + return $this->rngprovider = new HashRNGProvider(); } throw new TwoFactorAuthException('Unable to find a suited RNGProvider'); } @@ -249,8 +274,8 @@ class TwoFactorAuth { // Set default time provider if none was specified if (null === $this->timeprovider) { - return $this->timeprovider = new Providers\Time\LocalMachineTimeProvider(); + return $this->timeprovider = new LocalMachineTimeProvider(); } return $this->timeprovider; } -} \ No newline at end of file +} diff --git a/lib/TwoFactorAuthException.php b/lib/TwoFactorAuthException.php index af51b74..bce8370 100644 --- a/lib/TwoFactorAuthException.php +++ b/lib/TwoFactorAuthException.php @@ -4,4 +4,4 @@ namespace RobThree\Auth; use Exception; -class TwoFactorAuthException extends \Exception {} \ No newline at end of file +class TwoFactorAuthException extends Exception {}