primo commit
This commit is contained in:
239
libraries/f0f/encrypt/aes.php
Normal file
239
libraries/f0f/encrypt/aes.php
Normal file
@ -0,0 +1,239 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FrameworkOnFramework
|
||||
* @subpackage encrypt
|
||||
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
// Protect from unauthorized access
|
||||
defined('F0F_INCLUDED') or die;
|
||||
|
||||
/**
|
||||
* A simple implementation of AES-128, AES-192 and AES-256 encryption using the
|
||||
* high performance mcrypt library.
|
||||
*
|
||||
* @package FrameworkOnFramework
|
||||
* @since 1.0
|
||||
*/
|
||||
class F0FEncryptAes
|
||||
{
|
||||
/** @var string The AES cipher to use (this is an mcrypt identifier, not the bit strength) */
|
||||
private $_cipherType = 0;
|
||||
|
||||
/** @var string Cipher mode. Can be CBC or ECB. We recommend using CBC */
|
||||
private $_cipherMode = 0;
|
||||
|
||||
/** @var string The cipher key (password) */
|
||||
private $_keyString = '';
|
||||
|
||||
/**
|
||||
* Initialise the AES encryption object
|
||||
*
|
||||
* @param string $key The encryption key (password). It can be a raw key (32 bytes) or a passphrase.
|
||||
* @param int $strength Bit strength (128, 192 or 256)
|
||||
* @param string $mode Ecnryption mode. Can be ebc or cbc. We recommend using cbc.
|
||||
*/
|
||||
public function __construct($key, $strength = 256, $mode = 'cbc')
|
||||
{
|
||||
$this->_keyString = $key;
|
||||
|
||||
switch ($strength)
|
||||
{
|
||||
case 256:
|
||||
default:
|
||||
$this->_cipherType = MCRYPT_RIJNDAEL_256;
|
||||
break;
|
||||
|
||||
case 192:
|
||||
$this->_cipherType = MCRYPT_RIJNDAEL_192;
|
||||
break;
|
||||
|
||||
case 128:
|
||||
$this->_cipherType = MCRYPT_RIJNDAEL_128;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (strtoupper($mode))
|
||||
{
|
||||
case 'ECB':
|
||||
$this->_cipherMode = MCRYPT_MODE_ECB;
|
||||
break;
|
||||
|
||||
case 'CBC':
|
||||
$this->_cipherMode = MCRYPT_MODE_CBC;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts a string using AES
|
||||
*
|
||||
* @param string $stringToEncrypt The plaintext to encrypt
|
||||
* @param bool $base64encoded Should I Base64-encode the result?
|
||||
*
|
||||
* @return string The cryptotext. Please note that the first 16 bytes of
|
||||
* the raw string is the IV (initialisation vector) which
|
||||
* is necessary for decoding the string.
|
||||
*/
|
||||
public function encryptString($stringToEncrypt, $base64encoded = true)
|
||||
{
|
||||
if (strlen($this->_keyString) != 32)
|
||||
{
|
||||
$key = hash('sha256', $this->_keyString, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = $this->_keyString;
|
||||
}
|
||||
|
||||
// Set up the IV (Initialization Vector)
|
||||
$iv_size = mcrypt_get_iv_size($this->_cipherType, $this->_cipherMode);
|
||||
$iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_URANDOM);
|
||||
|
||||
if (empty($iv))
|
||||
{
|
||||
$iv = mcrypt_create_iv($iv_size, MCRYPT_DEV_RANDOM);
|
||||
}
|
||||
|
||||
if (empty($iv))
|
||||
{
|
||||
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
|
||||
}
|
||||
|
||||
// Encrypt the data
|
||||
$cipherText = mcrypt_encrypt($this->_cipherType, $key, $stringToEncrypt, $this->_cipherMode, $iv);
|
||||
|
||||
// Prepend the IV to the ciphertext
|
||||
$cipherText = $iv . $cipherText;
|
||||
|
||||
// Optionally pass the result through Base64 encoding
|
||||
if ($base64encoded)
|
||||
{
|
||||
$cipherText = base64_encode($cipherText);
|
||||
}
|
||||
|
||||
// Return the result
|
||||
return $cipherText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a ciphertext into a plaintext string using AES
|
||||
*
|
||||
* @param string $stringToDecrypt The ciphertext to decrypt. The first 16 bytes of the raw string must contain the IV (initialisation vector).
|
||||
* @param bool $base64encoded Should I Base64-decode the data before decryption?
|
||||
*
|
||||
* @return string The plain text string
|
||||
*/
|
||||
public function decryptString($stringToDecrypt, $base64encoded = true)
|
||||
{
|
||||
if (strlen($this->_keyString) != 32)
|
||||
{
|
||||
$key = hash('sha256', $this->_keyString, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
$key = $this->_keyString;
|
||||
}
|
||||
|
||||
if ($base64encoded)
|
||||
{
|
||||
$stringToDecrypt = base64_decode($stringToDecrypt);
|
||||
}
|
||||
|
||||
// Calculate the IV size
|
||||
$iv_size = mcrypt_get_iv_size($this->_cipherType, $this->_cipherMode);
|
||||
|
||||
// Extract IV
|
||||
$iv = substr($stringToDecrypt, 0, $iv_size);
|
||||
$stringToDecrypt = substr($stringToDecrypt, $iv_size);
|
||||
|
||||
// Decrypt the data
|
||||
$plainText = mcrypt_decrypt($this->_cipherType, $key, $stringToDecrypt, $this->_cipherMode, $iv);
|
||||
|
||||
return $plainText;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is AES encryption supported by this PHP installation?
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
if (!function_exists('mcrypt_get_key_size'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('mcrypt_get_iv_size'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('mcrypt_create_iv'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('mcrypt_encrypt'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('mcrypt_decrypt'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('mcrypt_list_algorithms'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('hash'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('hash_algos'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('base64_encode'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!function_exists('base64_decode'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$algorightms = mcrypt_list_algorithms();
|
||||
|
||||
if (!in_array('rijndael-128', $algorightms))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!in_array('rijndael-192', $algorightms))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!in_array('rijndael-256', $algorightms))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$algorightms = hash_algos();
|
||||
|
||||
if (!in_array('sha256', $algorightms))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
222
libraries/f0f/encrypt/base32.php
Normal file
222
libraries/f0f/encrypt/base32.php
Normal file
@ -0,0 +1,222 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FrameworkOnFramework
|
||||
* @subpackage encrypt
|
||||
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
defined('F0F_INCLUDED') or die;
|
||||
|
||||
/**
|
||||
* F0FEncryptBase32
|
||||
*
|
||||
* @package FrameworkOnFramework
|
||||
* @since 1.0
|
||||
*/
|
||||
class F0FEncryptBase32
|
||||
{
|
||||
/**
|
||||
* CSRFC3548
|
||||
*
|
||||
* The character set as defined by RFC3548
|
||||
* @link http://www.ietf.org/rfc/rfc3548.txt
|
||||
*/
|
||||
const CSRFC3548 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
||||
|
||||
/**
|
||||
* str2bin
|
||||
*
|
||||
* Converts any ascii string to a binary string
|
||||
*
|
||||
* @param string $str The string you want to convert
|
||||
*
|
||||
* @return string String of 0's and 1's
|
||||
*/
|
||||
private function str2bin($str)
|
||||
{
|
||||
$chrs = unpack('C*', $str);
|
||||
|
||||
return vsprintf(str_repeat('%08b', count($chrs)), $chrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* bin2str
|
||||
*
|
||||
* Converts a binary string to an ascii string
|
||||
*
|
||||
* @param string $str The string of 0's and 1's you want to convert
|
||||
*
|
||||
* @return string The ascii output
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function bin2str($str)
|
||||
{
|
||||
if (strlen($str) % 8 > 0)
|
||||
{
|
||||
throw new Exception('Length must be divisible by 8');
|
||||
}
|
||||
|
||||
if (!preg_match('/^[01]+$/', $str))
|
||||
{
|
||||
throw new Exception('Only 0\'s and 1\'s are permitted');
|
||||
}
|
||||
|
||||
preg_match_all('/.{8}/', $str, $chrs);
|
||||
$chrs = array_map('bindec', $chrs[0]);
|
||||
|
||||
// I'm just being slack here
|
||||
array_unshift($chrs, 'C*');
|
||||
|
||||
return call_user_func_array('pack', $chrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* fromBin
|
||||
*
|
||||
* Converts a correct binary string to base32
|
||||
*
|
||||
* @param string $str The string of 0's and 1's you want to convert
|
||||
*
|
||||
* @return string String encoded as base32
|
||||
*
|
||||
* @throws exception
|
||||
*/
|
||||
private function fromBin($str)
|
||||
{
|
||||
if (strlen($str) % 8 > 0)
|
||||
{
|
||||
throw new Exception('Length must be divisible by 8');
|
||||
}
|
||||
|
||||
if (!preg_match('/^[01]+$/', $str))
|
||||
{
|
||||
throw new Exception('Only 0\'s and 1\'s are permitted');
|
||||
}
|
||||
|
||||
// Base32 works on the first 5 bits of a byte, so we insert blanks to pad it out
|
||||
$str = preg_replace('/(.{5})/', '000$1', $str);
|
||||
|
||||
// We need a string divisible by 5
|
||||
$length = strlen($str);
|
||||
$rbits = $length & 7;
|
||||
|
||||
if ($rbits > 0)
|
||||
{
|
||||
// Excessive bits need to be padded
|
||||
$ebits = substr($str, $length - $rbits);
|
||||
$str = substr($str, 0, $length - $rbits);
|
||||
$str .= "000$ebits" . str_repeat('0', 5 - strlen($ebits));
|
||||
}
|
||||
|
||||
preg_match_all('/.{8}/', $str, $chrs);
|
||||
$chrs = array_map(array($this, '_mapcharset'), $chrs[0]);
|
||||
|
||||
return join('', $chrs);
|
||||
}
|
||||
|
||||
/**
|
||||
* toBin
|
||||
*
|
||||
* Accepts a base32 string and returns an ascii binary string
|
||||
*
|
||||
* @param string $str The base32 string to convert
|
||||
*
|
||||
* @return string Ascii binary string
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function toBin($str)
|
||||
{
|
||||
if (!preg_match('/^[' . self::CSRFC3548 . ']+$/', $str))
|
||||
{
|
||||
throw new Exception('Must match character set');
|
||||
}
|
||||
|
||||
// Convert the base32 string back to a binary string
|
||||
$str = join('', array_map(array($this, '_mapbin'), str_split($str)));
|
||||
|
||||
// Remove the extra 0's we added
|
||||
$str = preg_replace('/000(.{5})/', '$1', $str);
|
||||
|
||||
// Unpad if nessicary
|
||||
$length = strlen($str);
|
||||
$rbits = $length & 7;
|
||||
|
||||
if ($rbits > 0)
|
||||
{
|
||||
$str = substr($str, 0, $length - $rbits);
|
||||
}
|
||||
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* fromString
|
||||
*
|
||||
* Convert any string to a base32 string
|
||||
* This should be binary safe...
|
||||
*
|
||||
* @param string $str The string to convert
|
||||
*
|
||||
* @return string The converted base32 string
|
||||
*/
|
||||
public function encode($str)
|
||||
{
|
||||
return $this->fromBin($this->str2bin($str));
|
||||
}
|
||||
|
||||
/**
|
||||
* toString
|
||||
*
|
||||
* Convert any base32 string to a normal sctring
|
||||
* This should be binary safe...
|
||||
*
|
||||
* @param string $str The base32 string to convert
|
||||
*
|
||||
* @return string The normal string
|
||||
*/
|
||||
public function decode($str)
|
||||
{
|
||||
$str = strtoupper($str);
|
||||
|
||||
return $this->bin2str($this->tobin($str));
|
||||
}
|
||||
|
||||
/**
|
||||
* _mapcharset
|
||||
*
|
||||
* Used with array_map to map the bits from a binary string
|
||||
* directly into a base32 character set
|
||||
*
|
||||
* @param string $str The string of 0's and 1's you want to convert
|
||||
*
|
||||
* @return string Resulting base32 character
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
private function _mapcharset($str)
|
||||
{
|
||||
// Huh!
|
||||
$x = self::CSRFC3548;
|
||||
|
||||
return $x[bindec($str)];
|
||||
}
|
||||
|
||||
/**
|
||||
* _mapbin
|
||||
*
|
||||
* Used with array_map to map the characters from a base32
|
||||
* character set directly into a binary string
|
||||
*
|
||||
* @param string $chr The caracter to map
|
||||
*
|
||||
* @return string String of 0's and 1's
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
private function _mapbin($chr)
|
||||
{
|
||||
return sprintf('%08b', strpos(self::CSRFC3548, $chr));
|
||||
}
|
||||
}
|
||||
181
libraries/f0f/encrypt/totp.php
Normal file
181
libraries/f0f/encrypt/totp.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
/**
|
||||
* @package FrameworkOnFramework
|
||||
* @subpackage encrypt
|
||||
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
defined('F0F_INCLUDED') or die;
|
||||
|
||||
/**
|
||||
* This class provides an RFC6238-compliant Time-based One Time Passwords,
|
||||
* compatible with Google Authenticator (with PassCodeLength = 6 and TimePeriod = 30).
|
||||
*
|
||||
* @package FrameworkOnFramework
|
||||
* @since 1.0
|
||||
*/
|
||||
class F0FEncryptTotp
|
||||
{
|
||||
private $_passCodeLength = 6;
|
||||
|
||||
private $_pinModulo;
|
||||
|
||||
private $_secretLength = 10;
|
||||
|
||||
private $_timeStep = 30;
|
||||
|
||||
private $_base32 = null;
|
||||
|
||||
/**
|
||||
* Initialises an RFC6238-compatible TOTP generator. Please note that this
|
||||
* class does not implement the constraint in the last paragraph of §5.2
|
||||
* of RFC6238. It's up to you to ensure that the same user/device does not
|
||||
* retry validation within the same Time Step.
|
||||
*
|
||||
* @param int $timeStep The Time Step (in seconds). Use 30 to be compatible with Google Authenticator.
|
||||
* @param int $passCodeLength The generated passcode length. Default: 6 digits.
|
||||
* @param int $secretLength The length of the secret key. Default: 10 bytes (80 bits).
|
||||
* @param Object $base32 The base32 en/decrypter
|
||||
*/
|
||||
public function __construct($timeStep = 30, $passCodeLength = 6, $secretLength = 10, $base32=null)
|
||||
{
|
||||
$this->_timeStep = $timeStep;
|
||||
$this->_passCodeLength = $passCodeLength;
|
||||
$this->_secretLength = $secretLength;
|
||||
$this->_pinModulo = pow(10, $this->_passCodeLength);
|
||||
|
||||
if (is_null($base32))
|
||||
{
|
||||
$this->_base32 = new F0FEncryptBase32;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_base32 = $base32;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the time period based on the $time timestamp and the Time Step
|
||||
* defined. If $time is skipped or set to null the current timestamp will
|
||||
* be used.
|
||||
*
|
||||
* @param int|null $time Timestamp
|
||||
*
|
||||
* @return int The time period since the UNIX Epoch
|
||||
*/
|
||||
public function getPeriod($time = null)
|
||||
{
|
||||
if (is_null($time))
|
||||
{
|
||||
$time = time();
|
||||
}
|
||||
|
||||
$period = floor($time / $this->_timeStep);
|
||||
|
||||
return $period;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check is the given passcode $code is a valid TOTP generated using secret
|
||||
* key $secret
|
||||
*
|
||||
* @param string $secret The Base32-encoded secret key
|
||||
* @param string $code The passcode to check
|
||||
*
|
||||
* @return boolean True if the code is valid
|
||||
*/
|
||||
public function checkCode($secret, $code)
|
||||
{
|
||||
$time = $this->getPeriod();
|
||||
|
||||
for ($i = -1; $i <= 1; $i++)
|
||||
{
|
||||
if ($this->getCode($secret, ($time + $i) * $this->_timeStep) == $code)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the TOTP passcode for a given secret key $secret and a given UNIX
|
||||
* timestamp $time
|
||||
*
|
||||
* @param string $secret The Base32-encoded secret key
|
||||
* @param int $time UNIX timestamp
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCode($secret, $time = null)
|
||||
{
|
||||
$period = $this->getPeriod($time);
|
||||
$secret = $this->_base32->decode($secret);
|
||||
|
||||
$time = pack("N", $period);
|
||||
$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;
|
||||
|
||||
$truncatedHash = $this->hashToInt($hash, $offset) & 0x7FFFFFFF;
|
||||
$pinValue = str_pad($truncatedHash % $this->_pinModulo, $this->_passCodeLength, "0", STR_PAD_LEFT);
|
||||
|
||||
return $pinValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts a part of a hash as an integer
|
||||
*
|
||||
* @param string $bytes The hash
|
||||
* @param string $start The char to start from (0 = first char)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function hashToInt($bytes, $start)
|
||||
{
|
||||
$input = substr($bytes, $start, strlen($bytes) - $start);
|
||||
$val2 = unpack("N", substr($input, 0, 4));
|
||||
|
||||
return $val2[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a QR code URL for easy setup of TOTP apps like Google Authenticator
|
||||
*
|
||||
* @param string $user User
|
||||
* @param string $hostname Hostname
|
||||
* @param string $secret Secret string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUrl($user, $hostname, $secret)
|
||||
{
|
||||
$url = sprintf("otpauth://totp/%s@%s?secret=%s", $user, $hostname, $secret);
|
||||
$encoder = "https://chart.googleapis.com/chart?chs=200x200&chld=Q|2&cht=qr&chl=";
|
||||
$encoderURL = $encoder . urlencode($url);
|
||||
|
||||
return $encoderURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a (semi-)random Secret Key for TOTP generation
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generateSecret()
|
||||
{
|
||||
$secret = "";
|
||||
|
||||
for ($i = 1; $i <= $this->_secretLength; $i++)
|
||||
{
|
||||
$c = rand(0, 255);
|
||||
$secret .= pack("c", $c);
|
||||
}
|
||||
$base32 = new F0FEncryptBase32;
|
||||
|
||||
return $this->_base32->encode($secret);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user