Source for file totp.php

Documentation is available at totp.php

  1. <?php
  2. /**
  3.  * @package    FrameworkOnFramework
  4.  * @subpackage encrypt
  5.  * @copyright  Copyright (C) 2010 - 2012 Akeeba Ltd. All rights reserved.
  6.  * @license    GNU General Public License version 2 or later; see LICENSE.txt
  7.  */
  8. defined('_JEXEC'or die;
  9.  
  10. /**
  11.  * This class provides an RFC6238-compliant Time-based One Time Passwords,
  12.  * compatible with Google Authenticator (with PassCodeLength = 6 and TimePeriod = 30).
  13.  *
  14.  * @package  FrameworkOnFramework
  15.  * @since    1.0
  16.  */
  17. {
  18.     private $_passCodeLength 6;
  19.  
  20.     private $_pinModulo;
  21.  
  22.     private $_secretLength 10;
  23.  
  24.     private $_timeStep 30;
  25.  
  26.     /**
  27.      * Initialises an RFC6238-compatible TOTP generator. Please note that this
  28.      * class does not implement the constraint in the last paragraph of ยง5.2
  29.      * of RFC6238. It's up to you to ensure that the same user/device does not
  30.      * retry validation within the same Time Step.
  31.      *
  32.      * @param   int  $timeStep        The Time Step (in seconds). Use 30 to be compatible with Google Authenticator.
  33.      * @param   int  $passCodeLength  The generated passcode length. Default: 6 digits.
  34.      * @param   int  $secretLength    The length of the secret key. Default: 10 bytes (80 bits).
  35.      */
  36.     public function __construct($timeStep 30$passCodeLength 6$secretLength 10)
  37.     {
  38.         $this->_timeStep       $timeStep;
  39.         $this->_passCodeLength $passCodeLength;
  40.         $this->_secretLength   $secretLength;
  41.         $this->_pinModulo      pow(10$this->_passCodeLength);
  42.     }
  43.  
  44.     /**
  45.      * Get the time period based on the $time timestamp and the Time Step
  46.      * defined. If $time is skipped or set to null the current timestamp will
  47.      * be used.
  48.      *
  49.      * @param   int|null $time  Timestamp
  50.      *
  51.      * @return  int  The time period since the UNIX Epoch
  52.      */
  53.     public function getPeriod($time null)
  54.     {
  55.         if (is_null($time))
  56.         {
  57.             $time time();
  58.         }
  59.  
  60.         $period floor($time $this->_timeStep);
  61.  
  62.         return $period;
  63.     }
  64.  
  65.     /**
  66.      * Check is the given passcode $code is a valid TOTP generated using secret
  67.      * key $secret
  68.      *
  69.      * @param   string  $secret  The Base32-encoded secret key
  70.      * @param   string  $code    The passcode to check
  71.      *
  72.      * @return boolean True if the code is valid
  73.      */
  74.     public function checkCode($secret$code)
  75.     {
  76.         $time $this->getPeriod();
  77.  
  78.         for ($i = -1$i <= 1$i++)
  79.         {
  80.             if ($this->getCode($secret$time $i== $code)
  81.             {
  82.                 return true;
  83.             }
  84.         }
  85.  
  86.         return false;
  87.     }
  88.  
  89.     /**
  90.      * Gets the TOTP passcode for a given secret key $secret and a given UNIX
  91.      * timestamp $time
  92.      *
  93.      * @param   string  $secret  The Base32-encoded secret key
  94.      * @param   int     $time    UNIX timestamp
  95.      *
  96.      * @return string 
  97.      */
  98.     public function getCode($secret$time null)
  99.     {
  100.         $period $this->getPeriod($time);
  101.         $base32 new FOFEncryptBase32;
  102.         $secret $base32->decode($secret);
  103.  
  104.         $time pack("N"$period);
  105.         $time str_pad($time8chr(0)STR_PAD_LEFT);
  106.  
  107.         $hash hash_hmac('sha1'$time$secrettrue);
  108.         $offset ord(substr($hash-1));
  109.         $offset $offset 0xF;
  110.  
  111.         $truncatedHash $this->hashToInt($hash$offset0x7FFFFFFF;
  112.         $pinValue str_pad($truncatedHash $this->_pinModulo$this->_passCodeLength"0"STR_PAD_LEFT);
  113.  
  114.         return $pinValue;
  115.     }
  116.  
  117.     /**
  118.      * Extracts a part of a hash as an integer
  119.      *
  120.      * @param   string  $bytes  The hash
  121.      * @param   string  $start  The char to start from (0 = first char)
  122.      *
  123.      * @return  string 
  124.      */
  125.     protected function hashToInt($bytes$start)
  126.     {
  127.         $input substr($bytes$startstrlen($bytes$start);
  128.         $val2 unpack("N"substr($input04));
  129.  
  130.         return $val2[1];
  131.     }
  132.  
  133.     /**
  134.      * Returns a QR code URL for easy setup of TOTP apps like Google Authenticator
  135.      *
  136.      * @param   string  $user      User
  137.      * @param   string  $hostname  Hostname
  138.      * @param   string  $secret    Secret string
  139.      *
  140.      * @return  string 
  141.      */
  142.     public function getUrl($user$hostname$secret)
  143.     {
  144.         $url sprintf("otpauth://totp/%s@%s?secret=%s"$user$hostname$secret);
  145.         $encoder "https://chart.googleapis.com/chart?chs=200x200&chld=Q|2&cht=qr&chl=";
  146.         $encoderURL $encoder urlencode($url);
  147.  
  148.         return $encoderURL;
  149.     }
  150.  
  151.     /**
  152.      * Generates a (semi-)random Secret Key for TOTP generation
  153.      *
  154.      * @return  string 
  155.      */
  156.     public function generateSecret()
  157.     {
  158.         $secret "";
  159.  
  160.         for ($i 1$i <= $this->_secretLength$i++)
  161.         {
  162.             $c rand(0255);
  163.             $secret .= pack("c"$c);
  164.         }
  165.  
  166.         $base32 new FOFEncryptBase32;
  167.  
  168.         return $base32->encode($secret);
  169.     }
  170. }

Documentation generated on Tue, 19 Nov 2013 15:15:56 +0100 by phpDocumentor 1.4.3