189 lines
5.7 KiB
PHP
189 lines
5.7 KiB
PHP
|
|
<?php
|
||
|
|
namespace DynCom\mysyde\common\classes;
|
||
|
|
/**
|
||
|
|
* A class to handle secure encryption and decryption of arbitrary data
|
||
|
|
*
|
||
|
|
* Note that this is not just straight encryption. It also has a few other
|
||
|
|
* features in it to make the encrypted data far more secure. Note that any
|
||
|
|
* other implementations used to decrypt data will have to do the same exact
|
||
|
|
* operations.
|
||
|
|
*
|
||
|
|
* Security Benefits:
|
||
|
|
*
|
||
|
|
* - Uses Key stretching
|
||
|
|
* - Hides the Initialization Vector
|
||
|
|
* - Does HMAC verification of source data
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
class Encryption
|
||
|
|
{
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @var string $cipher The mcrypt cipher to use for this instance
|
||
|
|
*/
|
||
|
|
protected $cipher = '';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @var int $mode The mcrypt cipher mode to use
|
||
|
|
*/
|
||
|
|
protected $mode = '';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @var int $rounds The number of rounds to feed into PBKDF2 for key generation
|
||
|
|
*/
|
||
|
|
protected $rounds = 100;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Constructor!
|
||
|
|
*
|
||
|
|
* @param string $cipher The MCRYPT_* cypher to use for this instance
|
||
|
|
* @param int $mode The MCRYPT_MODE_* mode to use for this instance
|
||
|
|
* @param int $rounds The number of PBKDF2 rounds to do on the key
|
||
|
|
*/
|
||
|
|
public function __construct($cipher, $mode, $rounds = 100)
|
||
|
|
{
|
||
|
|
$this->cipher = $cipher;
|
||
|
|
$this->mode = $mode;
|
||
|
|
$this->rounds = (int)$rounds;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Decrypt the data with the provided key
|
||
|
|
*
|
||
|
|
* @param string $data The encrypted datat to decrypt
|
||
|
|
* @param string $key The key to use for decryption
|
||
|
|
*
|
||
|
|
* @returns string|false The returned string if decryption is successful
|
||
|
|
* false if it is not
|
||
|
|
*/
|
||
|
|
// public function decrypt($data, $key)
|
||
|
|
// {
|
||
|
|
// $salt = substr($data, 0, 128);
|
||
|
|
// $enc = substr($data, 128, -64);
|
||
|
|
// $mac = substr($data, -64);
|
||
|
|
|
||
|
|
// list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
|
||
|
|
|
||
|
|
// if (!hash_equals(hash_hmac('sha512', $enc, $macKey, true), $mac)) {
|
||
|
|
// return false;
|
||
|
|
// }
|
||
|
|
|
||
|
|
// $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);
|
||
|
|
|
||
|
|
// $data = $this->unpad($dec);
|
||
|
|
|
||
|
|
// return $data;
|
||
|
|
// }
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Encrypt the supplied data using the supplied key
|
||
|
|
*
|
||
|
|
* @param string $data The data to encrypt
|
||
|
|
* @param string $key The key to encrypt with
|
||
|
|
*
|
||
|
|
* @returns string The encrypted data
|
||
|
|
*/
|
||
|
|
// public function encrypt($data, $key)
|
||
|
|
// {
|
||
|
|
// $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
|
||
|
|
// list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);
|
||
|
|
|
||
|
|
// $data = $this->pad($data);
|
||
|
|
|
||
|
|
// $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);
|
||
|
|
|
||
|
|
// $mac = hash_hmac('sha512', $enc, $macKey, true);
|
||
|
|
// return $salt . $enc . $mac;
|
||
|
|
// }
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Generates a set of keys given a random salt and a master key
|
||
|
|
*
|
||
|
|
* @param string $salt A random string to change the keys each encryption
|
||
|
|
* @param string $key The supplied key to encrypt with
|
||
|
|
*
|
||
|
|
* @returns array An array of keys (a cipher key, a mac key, and a IV)
|
||
|
|
*/
|
||
|
|
protected function getKeys($salt, $key)
|
||
|
|
{
|
||
|
|
// $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
|
||
|
|
// $keySize = mcrypt_get_key_size($this->cipher, $this->mode);
|
||
|
|
$length = 2 * $keySize + $ivSize;
|
||
|
|
|
||
|
|
$key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);
|
||
|
|
|
||
|
|
$cipherKey = substr($key, 0, $keySize);
|
||
|
|
$macKey = substr($key, $keySize, $keySize);
|
||
|
|
$iv = substr($key, 2 * $keySize);
|
||
|
|
return array($cipherKey, $macKey, $iv);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Stretch the key using the PBKDF2 algorithm
|
||
|
|
*
|
||
|
|
* @see http://en.wikipedia.org/wiki/PBKDF2
|
||
|
|
*
|
||
|
|
* @param string $algo The algorithm to use
|
||
|
|
* @param string $key The key to stretch
|
||
|
|
* @param string $salt A random salt
|
||
|
|
* @param int $rounds The number of rounds to derive
|
||
|
|
* @param int $length The length of the output key
|
||
|
|
*
|
||
|
|
* @returns string The derived key.
|
||
|
|
*/
|
||
|
|
protected function pbkdf2($algo, $key, $salt, $rounds, $length)
|
||
|
|
{
|
||
|
|
$size = strlen(hash($algo, '', true));
|
||
|
|
$len = ceil($length / $size);
|
||
|
|
$result = '';
|
||
|
|
for ($i = 1; $i <= $len; $i++) {
|
||
|
|
$tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
|
||
|
|
$res = $tmp;
|
||
|
|
for ($j = 1; $j < $rounds; $j++) {
|
||
|
|
$tmp = hash_hmac($algo, $tmp, $key, true);
|
||
|
|
$res ^= $tmp;
|
||
|
|
}
|
||
|
|
$result .= $res;
|
||
|
|
}
|
||
|
|
return substr($result, 0, $length);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param $data
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
protected function pad($data)
|
||
|
|
{
|
||
|
|
// $length = mcrypt_get_block_size($this->cipher, $this->mode);
|
||
|
|
$padAmount = $length - strlen($data) % $length;
|
||
|
|
if ($padAmount == 0) {
|
||
|
|
$padAmount = $length;
|
||
|
|
}
|
||
|
|
return $data . str_repeat(chr($padAmount), $padAmount);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param $data
|
||
|
|
* @return bool|string
|
||
|
|
*/
|
||
|
|
protected function unpad($data)
|
||
|
|
{
|
||
|
|
// $length = mcrypt_get_block_size($this->cipher, $this->mode);
|
||
|
|
$last = ord($data[strlen($data) - 1]);
|
||
|
|
if ($last > $length) return false;
|
||
|
|
if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return substr($data, 0, -1 * $last);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param $a
|
||
|
|
* @param $b
|
||
|
|
* @return bool
|
||
|
|
*/
|
||
|
|
function hash_equals($a, $b) {
|
||
|
|
// $key = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
|
||
|
|
return hash_hmac('sha512', $a, $key) === hash_hmac('sha512', $b, $key);
|
||
|
|
}
|
||
|
|
}
|