Exemple #1
1
 /**
  * @param int $length
  * @return string
  */
 public static function generateSecret($length = 20)
 {
     $security = new Security();
     $full = Base32::encode($security->generateRandomString($length));
     return substr($full, 0, $length);
 }
 public function calculateCode($secret, $timeSlice = null)
 {
     // If we haven't been fed a timeSlice, then get one.
     // It looks a bit unclean doing it like this, but it allows us to write testable code
     $timeSlice = $timeSlice ? $timeSlice : $this->getTimeSlice();
     // Packs the timeslice as a "unsigned long" (always 32 bit, big endian byte order)
     $timeSlice = pack("N", $timeSlice);
     // Then pad it with the null terminator
     $timeSlice = str_pad($timeSlice, 8, chr(0), STR_PAD_LEFT);
     // Hash it with SHA1. The spec does offer the idea of other algorithms, but notes that the authenticator is currently
     // ignoring it...
     $hash = hash_hmac("SHA1", $timeSlice, Base32::decode($secret), true);
     // Last 4 bits are an offset apparently
     $offset = ord(substr($hash, -1)) & 0xf;
     // Grab the last 4 bytes
     $result = substr($hash, $offset, 4);
     // Unpack it again
     $value = unpack('N', $result)[1];
     // Only 32 bits
     $value = $value & 0x7fffffff;
     // Modulo down to the right number of digits
     $modulo = pow(10, $this->codeLength);
     // Finally, pad out the string with 0s
     return str_pad($value % $modulo, $this->codeLength, '0', STR_PAD_LEFT);
 }
Exemple #3
0
 public function twoFactor(array $envData)
 {
     $userId = self::getUserId($envData['common_name']);
     // use username field to specify OTP type, for now we only support 'totp'
     $otpType = $envData['username'];
     if ('totp' !== $otpType) {
         throw new TwoFactorException('invalid OTP type specified in username field');
     }
     $otpKey = $envData['password'];
     // validate the OTP key
     if (0 === preg_match('/^[0-9]{6}$/', $otpKey)) {
         throw new TwoFactorException('invalid OTP key format specified');
     }
     $dataDir = sprintf('%s/data/%s', $this->baseDir, $envData['INSTANCE_ID']);
     if (false === ($otpSecret = @file_get_contents(sprintf('%s/users/otp_secrets/%s', $dataDir, $userId)))) {
         throw new TwoFactorException('no OTP secret registered');
     }
     $otp = new Otp();
     if ($otp->checkTotp(Base32::decode($otpSecret), $otpKey)) {
         if (false === $this->otpLog->record($userId, $otpKey, time())) {
             throw new TwoFactorException('OTP replayed');
         }
     } else {
         throw new TwoFactorException('invalid OTP key');
     }
 }
 /**
  * @param Seed|string|null
  * @param ITimestampProvider|int|null
  * @param int
  * @throws \Exception
  */
 public function __construct($seed = NULL, $timestamp = NULL, $period = 30)
 {
     if ($seed === NULL) {
         $this->seed = Seed::generate();
     } elseif (is_string($seed) && ($decoded = Base32::decode($seed)) !== '') {
         $this->seed = new Seed($decoded);
     } elseif ($seed instanceof Seed) {
         $this->seed = $seed;
     } else {
         throw new \Exception('Seed must be valid base32 encoded string or instance of Seed.');
     }
     if ($timestamp === NULL) {
         $this->timestampProvider = SystemTimestampProvider::getInstance();
     } elseif (is_int($timestamp) || ctype_digit($timestamp)) {
         $this->timestampProvider = new ConstantTimestampProvider((int) $timestamp);
     } elseif ($timestamp instanceof ITimestampProvider) {
         $this->timestampProvider = $timestamp;
     } else {
         throw new \Exception('Timestamp must be integer or instance of ITimestampProvider.');
     }
     if ((is_int($period) || ctype_digit($period)) && $period > 0) {
         $this->period = (int) $period;
     } else {
         throw new \Exception('Period must be integer greater then 0.');
     }
 }
Exemple #5
0
 /**
  * @param string|null $secret
  */
 private function setSecret($secret)
 {
     Assertion::nullOrString($secret, 'The secret must be a string or null.');
     if (null === $secret) {
         $secret = trim(Base32::encode(random_bytes(32)), '=');
     }
     $this->parameters['secret'] = $secret;
 }
 /**
  * @expectedException \SURFnet\VPN\Server\Exception\TwoFactorException
  * @expectedExceptionMessage OTP replayed
  */
 public function testTwoFactorReplay()
 {
     $o = new Otp();
     $otpKey = $o->totp(Base32::decode('QPXDFE7G7VNRR4BH'));
     $c = new TwoFactor(__DIR__, $this->otpLog);
     $c->twoFactor(['INSTANCE_ID' => 'vpn.example', 'POOL_ID' => 'internet', 'common_name' => 'foo_xyz', 'username' => 'totp', 'password' => $otpKey]);
     // replay
     $c->twoFactor(['INSTANCE_ID' => 'vpn.example', 'POOL_ID' => 'internet', 'common_name' => 'foo_xyz', 'username' => 'totp', 'password' => $otpKey]);
 }
 public static function generate($ext = '')
 {
     // Generate UUIDv4
     $bytes = random_bytes(16);
     $bytes[6] = chr(0x4 << 4 | ord($bytes[6]) & 0xf);
     $bytes[8] = chr(ord($bytes[8]) & 0x3f | 0x80);
     $base32 = rtrim(Base32::encode($bytes), '=');
     $base32 = strtolower($base32);
     $filename = $base32 . ($ext != '' ? '.' . $ext : '');
     return $filename;
 }
Exemple #8
0
 public function tfaEnableAction()
 {
     if (!$this->session2FA->secretCode) {
         $this->session2FA->secretCode = Base32::encode(random_bytes(256));
     }
     $totp = new \OTPHP\TOTP('Zource', $this->session2FA->secretCode);
     if ($this->getRequest()->isPost()) {
         $code = $this->getRequest()->getPost('code');
         var_dump($totp->verify($code));
     }
     return new ViewModel(['secretCode' => $this->session2FA->secretCode]);
 }
 /**
  * Encoder tests, reverse of the decodes
  */
 public function testEncode()
 {
     // RFC test vectors say that empty string returns empty string
     $this->assertEquals('', Base32::encode(''));
     // these strings are taken from the RFC
     $this->assertEquals('MY======', Base32::encode('f'));
     $this->assertEquals('MZXQ====', Base32::encode('fo'));
     $this->assertEquals('MZXW6===', Base32::encode('foo'));
     $this->assertEquals('MZXW6YQ=', Base32::encode('foob'));
     $this->assertEquals('MZXW6YTB', Base32::encode('fooba'));
     $this->assertEquals('MZXW6YTBOI======', Base32::encode('foobar'));
 }
 /**
  * Ajout de $secret en DB et activation l'authentification à 2 facteurs
  */
 public function totp_post(Request $request)
 {
     $otp = new Otp();
     $secret = session()->get('secret');
     $key = $request->get("code");
     $user = $this->auth->user();
     if ($otp->checkTotp(Base32::decode($secret), $key)) {
         DB::table('users')->where('id', $user->id)->update(array('totp_key' => $secret));
         Session::forget('code');
         return redirect(url('profil'))->with('success', 'L\'authentification à 2 facteurs à bien été activer');
     } else {
         return redirect(url('profil/totp'))->with('error', 'Ce code ne correspond pas, veuillez recommencer l\'opération');
     }
 }
 /**
  * Get the code from the time and secret
  *
  * @param string   $secret
  * @param int|null $time
  *
  * @return string
  */
 public function getCode($secret, $time = null)
 {
     if (!$time) {
         $time = floor(time() / 30);
     }
     $secret = Base32::decode($secret);
     $time = pack('N', $time);
     $time = str_pad($time, 8, chr(0), STR_PAD_LEFT);
     $hash = hash_hmac('sha1', $time, $secret, true);
     $offset = ord(substr($hash, -1));
     $offset = $offset & 0xf;
     $tHash = $this->hashToInt($hash, $offset) & 0x7fffffff;
     $pin = str_pad($tHash % $this->pinModulo, 6, "0", STR_PAD_LEFT);
     return $pin;
 }
Exemple #12
0
 public function store()
 {
     $response = array();
     $otp = new Otp();
     $secret = Input::get('s');
     $key = Input::get('txCodigo');
     if ($otp->checkTotp(Base32::decode($secret), $key, 0)) {
         DB::table('authusuarios')->where('usuarioid', Auth::user()->usuarioid)->update(['twostepsecret' => $secret]);
         $response['result'] = true;
         return json_encode($response);
     } else {
         $response['result'] = false;
         return json_encode($response);
     }
 }
Exemple #13
0
 public static function getCode($secret, $timeSlice = null)
 {
     if ($timeSlice === null) {
         $timeSlice = floor(time() / self::TIME_STEP);
     }
     $secretKey = \Base32\Base32::decode($secret);
     $binaryTimestamp = pack('N*', 0) . pack('N*', $timeSlice);
     $hmac = hash_hmac('SHA1', $binaryTimestamp, $secretKey, true);
     $offset = ord(substr($hmac, -1)) & 0xf;
     $part = substr($hmac, $offset, 4);
     $unpack_value_array = unpack('N', $part);
     $unpack_value = $unpack_value_array[1];
     $seed = $unpack_value & 0x7fffffff;
     $pow = pow(10, self::CODE_LENGTH);
     return str_pad($seed % $pow, self::CODE_LENGTH, '0', STR_PAD_LEFT);
 }
 public function authenticate($username, $password, $htop_value)
 {
     if (isset($this->credentials[$username])) {
         list($user_password, $user_htop_secret) = $this->credentials[$username];
         if ($user_password === $password) {
             $otp = new Otp();
             if ($otp->checkTotp(Base32::decode($user_htop_secret), $htop_value)) {
                 $this->session->username = $username;
                 $this->session->valid_host = $_SERVER['HTTP_HOST'];
                 $this->session->authenticated = true;
                 return true;
             }
         }
     }
     return false;
 }
Exemple #15
0
 /**
  * Onion constructor.
  * @param string $onionHost
  */
 public function __construct($onionHost)
 {
     $array = explode(".", $onionHost);
     if (count($array) !== 2) {
         throw new \InvalidArgumentException('Malformed onion address');
     }
     list($ident, $onion) = $array;
     if ($onion !== 'onion') {
         throw new \InvalidArgumentException('Malformed onion address');
     }
     $decoded = Base32::decode($ident);
     if (strlen($decoded) !== 10) {
         throw new \InvalidArgumentException('Malformed onion address');
     }
     $this->identifier = $decoded;
     $this->host = $onionHost;
 }
 /**
  * Create an OTP URI for use with Google Authenticator.
  *
  * Note that this is not a URI for the QR code used by Google Authenticator.
  * The URI produced by this method is used as the actual content of the QR
  * code, and follows a special set of conventions understood by Google
  * Authenticator, and other OTP apps.
  *
  * @param string                          $type          The otp type identifier.
  * @param string                          $parameters    Additional URI parameters.
  * @param HotpBasedConfigurationInterface $configuration The OTP configuration.
  * @param OtpSharedParametersInterface    $shared        The shared parameters.
  * @param string                          $label         The label for the account.
  * @param string|null                     $issuer        The issuer name.
  * @param boolean|null                    $issuerInLabel True if legacy issuer support should be enabled by prefixing the label with the issuer name.
  *
  * @return string The OTP URI.
  */
 protected function buildUri($type, $parameters, HotpBasedConfigurationInterface $configuration, OtpSharedParametersInterface $shared, $label, $issuer = null, $issuerInLabel = null)
 {
     if (null === $issuerInLabel) {
         $issuerInLabel = false;
     }
     if (6 !== $configuration->digits()) {
         $parameters .= '&digits=' . rawurlencode($configuration->digits());
     }
     if (HotpHashAlgorithm::SHA1() !== $configuration->algorithm()) {
         $parameters .= '&algorithm=' . rawurlencode($configuration->algorithm()->value());
     }
     $legacyIssuer = '';
     if (null !== $issuer) {
         if ($issuerInLabel) {
             $legacyIssuer = rawurlencode($issuer) . ':';
         }
         $parameters .= '&issuer=' . rawurlencode($issuer);
     }
     return sprintf('otpauth://%s/%s%s?secret=%s%s', rawurlencode($type), $legacyIssuer, rawurlencode($label), rawurlencode(Base32::encode($shared->secret())), $parameters);
 }
 /**
  * @param Parser $parser
  * @return Ipv4|Ipv6|Onion
  * @throws \BitWasp\Buffertools\Exceptions\ParserOutOfRange
  * @throws \Exception
  */
 public function fromParser(Parser $parser)
 {
     $buffer = $parser->readBytes(16);
     $binary = $buffer->getBinary();
     if (Onion::MAGIC === substr($binary, 0, strlen(Onion::MAGIC))) {
         $addr = strtolower(Base32::encode($buffer->slice(strlen(Onion::MAGIC))->getBinary())) . '.onion';
         $ip = new Onion($addr);
     } elseif (Ipv4::MAGIC === substr($binary, 0, strlen(Ipv4::MAGIC))) {
         $end = $buffer->slice(strlen(Ipv4::MAGIC), 4);
         $ip = new Ipv4(long2ip($end->getInt()));
     } else {
         $addr = [];
         foreach (str_split($binary, 2) as $segment) {
             $addr[] = bin2hex($segment);
         }
         $addr = implode(":", $addr);
         $ip = new Ipv6($addr);
     }
     return $ip;
 }
Exemple #18
0
 public function totp(Request $request)
 {
     $user_id = session()->get('user_id');
     $key = $request->get("code");
     if (empty($user_id)) {
         return redirect('/auth/login');
     }
     $otp = new Otp();
     $user = User::where('id', $user_id)->first();
     if ($key) {
         if ($otp->checkTotp(Base32::decode($user->totp_key), $key)) {
             $this->auth->login($user, $request->has('remember'));
             return redirect()->intended($this->redirectPath());
         } else {
             return redirect(url('totp'))->with('error', 'Ce code ne correspond pas, veuillez recommencer l\'opération');
         }
     }
     return view('auth.totp')->with('error', 'Ce compte à activer \'authentification à 2 facteurs');
 }
Exemple #19
0
 /**
  * @throws \InvalidArgumentException
  *
  * @return string
  */
 private function getDecodedSecret()
 {
     $secret = Base32::decode($this->getSecret());
     return $secret;
 }
Exemple #20
0
 public function setSecret($value)
 {
     if (strlen($value) !== $this->secretLength) {
         throw new InvalidConfigException('Otp::setSecret length is not equal to ' . $this->secretLength . ' ([\'length\'] component settenings)');
     } elseif (strlen(Base32::decode($value)) < 1) {
         throw new InvalidConfigException('Otp::setSecret incorect, encode as Base32');
     }
     $this->otp->setSecret($value);
     $this->_secret = $value;
 }
Exemple #21
0
 /**
  * Check 2FA
  *
  * @access public
  */
 public function check()
 {
     $user = $this->getUser();
     $this->checkCurrentUser($user);
     $otp = new Otp();
     $values = $this->request->getValues();
     if (!empty($values['code']) && $otp->checkTotp(Base32::decode($user['twofactor_secret']), $values['code'])) {
         $this->sessionStorage->postAuth['validated'] = true;
         $this->flash->success(t('The two factor authentication code is valid.'));
         $this->response->redirect($this->helper->url->to('app', 'index'));
     } else {
         $this->flash->failure(t('The two factor authentication code is not valid.'));
         $this->response->redirect($this->helper->url->to('twofactor', 'code'));
     }
 }
 public function makeTOTP($provider = null)
 {
     /***
      * Assign a user a multifactor authentication code
      *
      * @param string $provider The provider giving 2FA.
      * @return array with the status in the key "status", errors in "error" and "human_error",
      * username in "username", and provisioning data in "uri"
      ***/
     if (empty($this->username)) {
         $this->getUser();
         # We MUST have this properly assigned
         if (empty($this->username)) {
             return array('status' => false, 'error' => 'Unable to get user.');
         }
     }
     if ($this->getSecret() !== false) {
         return array('status' => false, 'error' => '2FA has already been enabled for this user.', 'human_error' => "You've already enabled 2-factor authentication.", 'username' => $this->username);
     }
     try {
         if (!class_exists('Stronghash')) {
             require_once dirname(__FILE__) . '/../core/stronghash/php-stronghash.php';
         }
         $salt = Stronghash::createSalt();
         require_once dirname(__FILE__) . '/../base32/src/Base32/Base32.php';
         $secret = Base32::encode($salt);
         ## The resulting provisioning URI should now be sent to the user
         ## Flag should be set server-side indicating the change id pending
         $l = $this->openDB();
         $query = 'UPDATE `' . $this->getTable() . '` SET `' . $this->tmpColumn . "`='{$secret}' WHERE `" . $this->userColumn . "`='" . $this->username . "'";
         $r = mysqli_query($l, $query);
         if ($r === false) {
             return array('status' => false, 'human_error' => 'Database error', 'error' => mysqli_error($l));
         }
         # The data was saved correctly
         # Let's create the provisioning stuff!
         self::doLoadOTP();
         $totp = new OTPHP\TOTP($secret);
         $totp->setDigest($this->getDigest());
         $totp->setLabel($this->username);
         $totp->setIssuer($provider);
         $uri = $totp->getProvisioningURI($label, $provider);
         # iPhones don't actually accept the full, valid URI
         $unsafe_uri = urldecode($uri);
         $uri_args = explode('?', $unsafe_uri);
         $iphone_uri = $uri_args[0] . '?';
         $iphone_args = array();
         $iphone_safe_args = array('secret', 'issuer');
         foreach (explode('&', $uri_args[1]) as $paramval) {
             $pv = explode('=', $paramval);
             $param = $pv[0];
             $val = $pv[1];
             if (in_array($param, $iphone_safe_args)) {
                 $iphone_args[] = $param . '=' . $val;
             }
         }
         $iphone_uri .= implode('&', $iphone_args);
         /* $iphone32 = str_replace("=","",$secret_part[1]); */
         /* $iphone_uri = $secret_part[0]."secret=".$iphone32; #still no good */
         $retarr = self::generateQR($iphone_uri);
         # Let's get a human-readable secret
         $human_secret0 = str_replace('=', '', $secret);
         $i = 0;
         $human_secret = '';
         foreach (str_split($human_secret0) as $char) {
             $human_secret .= $char;
             ++$i;
             if ($i == 4) {
                 $human_secret .= ' ';
                 $i = 0;
             }
         }
         $retarr['secret'] = $secret;
         $retarr['human_secret'] = $human_secret;
         $retarr['username'] = $this->username;
         return $retarr;
     } catch (Exception $e) {
         return array('status' => false, 'human_error' => 'Unexpected error in makeTOTP', 'error' => $e->getMessage(), 'username' => $this->username, 'provider' => $provider, 'label' => $totp->getLabel(), 'uri' => $uri, 'secret' => $secret);
     }
 }
Exemple #23
0
 /**
  * Encode a string to Base32.
  *
  * @param $string
  * @return mixed
  */
 public function toBase32($string)
 {
     $encoded = Base32::encode($string);
     return str_replace('=', '', $encoded);
 }
 /**
  * Create a 64 bit secret string
  * @return string
  */
 private function createSecret()
 {
     return Base32::encode(random_bytes(64));
 }
Exemple #25
0
 public function fromBase32String()
 {
     return Base32::decode($this->digest);
 }
Exemple #26
0
 public function __toString()
 {
     $id = \Base32\Base32::decode(strtoupper(str_replace('-', '', $this->_id)));
     return pack('N', strlen($id)) . $id . pack('N', count($this->_addresses)) . implode('', $this->_addresses);
 }
Exemple #27
0
 /**
  * Returns the binary value of the base32 encoded secret skey
  * 
  * @return binary secret key
  */
 public function decode_key()
 {
     return \Base32\Base32::decode($this->skey);
 }
Exemple #28
0
<?php

use cebe\pulse\discover\Address;
use cebe\pulse\discover\Device;
use cebe\pulse\discover\DiscoveryManager;
use cebe\pulse\discover\Packet;
require __DIR__ . '/vendor/autoload.php';
$loop = React\EventLoop\Factory::create();
// config
// generates a random node ID, should be replaced with a real hash of the TLS cert
$id = rtrim(\Base32\Base32::encode(hash('sha256', rand() . microtime(true), true)), '=');
$servicePort = rand(1337, 32000);
// setup
$discoveryManager = new DiscoveryManager($id);
$discoveryManager->servicePort = $servicePort;
$discoveryManager->start($loop);
// TCP Server
$socket = new React\Socket\Server($loop);
$socket->on('connection', function ($conn) {
    //    $conn->write("Hello there!\n");
    //    $conn->write("Welcome to this amazing server!\n");
    //    $conn->write("Here's a tip: don't say anything.\n");
    echo "connection from " . $conn->getRemoteAddress() . "\n";
    $conn->on('data', function ($data) use($conn) {
        echo "{$data}\n";
        $conn->close();
    });
});
$socket->listen($servicePort);
$loop->run();
 /**
  * Validates a TOTP request.
  *
  * @todo Prevent TOTP replay attack.
  * @param string $key The TOTP token sent in.
  * @param string $secret The TOTP secret.
  * @return bool
  */
 public function validateTOTP($key, $secret)
 {
     $otp = new Otp();
     return $otp->checkTotp(Base32::decode($secret), $key);
 }
Exemple #30
0
 public function __toString()
 {
     return Base32::encode($this->value);
 }