372 changes: 212 additions & 160 deletions libraries/phpseclib/Crypt/Base.php

Large diffs are not rendered by default.

27 changes: 20 additions & 7 deletions libraries/phpseclib/Crypt/Random.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,28 @@ class Random
* microoptimizations because this function has the potential of being called a huge number of times.
* eg. for RSA key generation.
*
* @param Integer $length
* @return String
* @param int $length
* @return string
*/
public static function string($length)
static function string($length)
{
if (version_compare(PHP_VERSION, '7.0.0', '>=')) {
try {
return \random_bytes($length);
} catch (\Throwable $e) {
// If a sufficient source of randomness is unavailable, random_bytes() will throw an
// object that implements the Throwable interface (Exception, TypeError, Error).
// We don't actually need to do anything here. The string() method should just continue
// as normal. Note, however, that if we don't have a sufficient source of randomness for
// random_bytes(), most of the other calls here will fail too, so we'll end up using
// the PHP implementation.
}
}

if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
// method 1. prior to PHP 5.3 this would call rand() on windows hence the function_exists('class_alias') call.
// ie. class_alias is a function that was introduced in PHP 5.3
if (function_exists('mcrypt_create_iv') && function_exists('class_alias')) {
if (extension_loaded('mcrypt') && function_exists('class_alias')) {
return mcrypt_create_iv($length);
}
// method 2. openssl_random_pseudo_bytes was introduced in PHP 5.3.0 but prior to PHP 5.3.4 there was,
Expand All @@ -72,12 +85,12 @@ public static function string($length)
// https://github.com/php/php-src/blob/7014a0eb6d1611151a286c0ff4f2238f92c120d6/win32/winutil.c#L80
//
// we're calling it, all the same, in the off chance that the mcrypt extension is not available
if (function_exists('openssl_random_pseudo_bytes') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
if (extension_loaded('openssl') && version_compare(PHP_VERSION, '5.3.4', '>=')) {
return openssl_random_pseudo_bytes($length);
}
} else {
// method 1. the fastest
if (function_exists('openssl_random_pseudo_bytes')) {
if (extension_loaded('openssl')) {
return openssl_random_pseudo_bytes($length);
}
// method 2
Expand All @@ -95,7 +108,7 @@ public static function string($length)
// surprisingly slower than method 2. maybe that's because mcrypt_create_iv does a bunch of error checking that we're
// not doing. regardless, this'll only be called if this PHP script couldn't open /dev/urandom due to open_basedir
// restrictions or some such
if (function_exists('mcrypt_create_iv')) {
if (extension_loaded('mcrypt')) {
return mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
}
}
Expand Down
225 changes: 63 additions & 162 deletions libraries/phpseclib/Crypt/Rijndael.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
*
* PHP version 5
*
* If {@link \phpseclib\Crypt\Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
* {@link \phpseclib\Crypt\Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link \phpseclib\Crypt\Rijndael::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
* If {@link self::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
* {@link self::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
* {@link self::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
* 136-bits it'll be null-padded to 192-bits and 192 bits will be the key length until
* {@link \phpseclib\Crypt\Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
* {@link self::setKey() setKey()} is called, again, at which point, it'll be recalculated.
*
* Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
* does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
Expand Down Expand Up @@ -65,28 +65,18 @@
*/
class Rijndael extends Base
{
/**
* The default password key_size used by setPassword()
*
* @see \phpseclib\Crypt\Base::password_key_size
* @see \phpseclib\Crypt\Base::setPassword()
* @var Integer
* @access private
*/
var $password_key_size = 16;

/**
* The mcrypt specific name of the cipher
*
* Mcrypt is useable for 128/192/256-bit $block_size/$key_size. For 160/224 not.
* Mcrypt is useable for 128/192/256-bit $block_size/$key_length. For 160/224 not.
* \phpseclib\Crypt\Rijndael determines automatically whether mcrypt is useable
* or not for the current $block_size/$key_size.
* or not for the current $block_size/$key_length.
* In case of, $cipher_name_mcrypt will be set dynamically at run time accordingly.
*
* @see \phpseclib\Crypt\Base::cipher_name_mcrypt
* @see \phpseclib\Crypt\Base::engine
* @see isValidEngine()
* @var String
* @see self::isValidEngine()
* @var string
* @access private
*/
var $cipher_name_mcrypt = 'rijndael-128';
Expand All @@ -96,43 +86,34 @@ class Rijndael extends Base
*
* @see \phpseclib\Crypt\Base::password_default_salt
* @see \phpseclib\Crypt\Base::setPassword()
* @var String
* @var string
* @access private
*/
var $password_default_salt = 'phpseclib';

/**
* Has the key length explicitly been set or should it be derived from the key, itself?
*
* @see setKeyLength()
* @var Boolean
* @access private
*/
var $explicit_key_length = false;

/**
* The Key Schedule
*
* @see _setup()
* @var Array
* @see self::_setup()
* @var array
* @access private
*/
var $w;

/**
* The Inverse Key Schedule
*
* @see _setup()
* @var Array
* @see self::_setup()
* @var array
* @access private
*/
var $dw;

/**
* The Block Length divided by 32
*
* @see setBlockLength()
* @var Integer
* @see self::setBlockLength()
* @var int
* @access private
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
* because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
Expand All @@ -142,23 +123,23 @@ class Rijndael extends Base
var $Nb = 4;

/**
* The Key Length
* The Key Length (in bytes)
*
* @see setKeyLength()
* @var Integer
* @see self::setKeyLength()
* @var int
* @access private
* @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $Nk
* because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
* derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
* because the encryption / decryption / key schedule creation requires this number and not $key_length. We could
* derive this from $key_length or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
* of that, we'll just precompute it once.
*/
var $key_size = 16;
var $key_length = 16;

/**
* The Key Length divided by 32
*
* @see setKeyLength()
* @var Integer
* @see self::setKeyLength()
* @var int
* @access private
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
*/
Expand All @@ -167,7 +148,7 @@ class Rijndael extends Base
/**
* The Number of Rounds
*
* @var Integer
* @var int
* @access private
* @internal The max value is 14, the min value is 10.
*/
Expand All @@ -176,85 +157,21 @@ class Rijndael extends Base
/**
* Shift offsets
*
* @var Array
* @var array
* @access private
*/
var $c;

/**
* Holds the last used key- and block_size information
*
* @var Array
* @var array
* @access private
*/
var $kl;

/**
* Default Constructor.
*
* Determines whether or not the mcrypt extension should be used.
*
* $mode could be:
*
* - \phpseclib\Crypt\Base::MODE_ECB
*
* - \phpseclib\Crypt\Base::MODE_CBC
*
* - \phpseclib\Crypt\Base::MODE_CTR
*
* - \phpseclib\Crypt\Base::MODE_CFB
*
* - \phpseclib\Crypt\Base::MODE_OFB
*
* If not explictly set, \phpseclib\Crypt\Base::MODE_CBC will be used.
*
* @see \phpseclib\Crypt\Base::Crypt_Base()
* @param optional Integer $mode
* @access public
/**
* Sets the key.
*
* Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
* whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length
* up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
* excess bits.
*
* If the key is not explicitly set, it'll be assumed to be all null bytes.
*
* Note: 160/224-bit keys must explicitly set by setKeyLength(), otherwise they will be round/pad up to 192/256 bits.
*
* @see \phpseclib\Crypt\Base:setKey()
* @see setKeyLength()
* @access public
* @param String $key
*/
function setKey($key)
{
if (!$this->explicit_key_length) {
$length = strlen($key);
switch (true) {
case $length <= 16:
$this->key_size = 16;
break;
case $length <= 20:
$this->key_size = 20;
break;
case $length <= 24:
$this->key_size = 24;
break;
case $length <= 28:
$this->key_size = 28;
break;
default:
$this->key_size = 32;
}
}
parent::setKey($key);
}

/**
* Sets the key length
* Sets the key length.
*
* Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
Expand All @@ -271,30 +188,28 @@ function setKey($key)
* This results then in slower encryption.
*
* @access public
* @param Integer $length
* @param int $length
*/
function setKeyLength($length)
{
switch (true) {
case $length == 160:
$this->key_size = 20;
break;
case $length == 224:
$this->key_size = 28;
break;
case $length <= 128:
$this->key_size = 16;
$this->key_length = 16;
break;
case $length <= 160:
$this->key_length = 20;
break;
case $length <= 192:
$this->key_size = 24;
$this->key_length = 24;
break;
case $length <= 224:
$this->key_length = 28;
break;
default:
$this->key_size = 32;
$this->key_length = 32;
}

$this->explicit_key_length = true;
$this->changed = true;
$this->_setEngine();
parent::setKeyLength($length);
}

/**
Expand All @@ -304,7 +219,7 @@ function setKeyLength($length)
* 128. If the length is greater than 128 and invalid, it will be rounded down to the closest valid amount.
*
* @access public
* @param Integer $length
* @param int $length
*/
function setBlockLength($length)
{
Expand All @@ -325,10 +240,10 @@ function setBlockLength($length)
*
* This is mainly just a wrapper to set things up for \phpseclib\Crypt\Base::isValidEngine()
*
* @see \phpseclib\Crypt\Base::Crypt_Base()
* @param Integer $engine
* @see \phpseclib\Crypt\Base::__construct()
* @param int $engine
* @access public
* @return Boolean
* @return bool
*/
function isValidEngine($engine)
{
Expand All @@ -337,12 +252,12 @@ function isValidEngine($engine)
if ($this->block_size != 16) {
return false;
}
$this->cipher_name_openssl_ecb = 'aes-' . ($this->key_size << 3) . '-ecb';
$this->cipher_name_openssl = 'aes-' . ($this->key_size << 3) . '-' . $this->_openssl_translate_mode();
$this->cipher_name_openssl_ecb = 'aes-' . ($this->key_length << 3) . '-ecb';
$this->cipher_name_openssl = 'aes-' . ($this->key_length << 3) . '-' . $this->_openssl_translate_mode();
break;
case self::ENGINE_MCRYPT:
$this->cipher_name_mcrypt = 'rijndael-' . ($this->block_size << 3);
if ($this->key_size % 8) { // is it a 160/224-bit key?
if ($this->key_length % 8) { // is it a 160/224-bit key?
// mcrypt is not usable for them, only for 128/192/256-bit keys
return false;
}
Expand All @@ -351,24 +266,12 @@ function isValidEngine($engine)
return parent::isValidEngine($engine);
}

/**
* Setup the \phpseclib\Crypt\Base::ENGINE_MCRYPT $engine
*
* @see \phpseclib\Crypt\Base::_setupMcrypt()
* @access private
*/
function _setupMcrypt()
{
$this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0");
parent::_setupMcrypt();
}

/**
* Encrypts a block
*
* @access private
* @param String $in
* @return String
* @param string $in
* @return string
*/
function _encryptBlock($in)
{
Expand Down Expand Up @@ -468,8 +371,8 @@ function _encryptBlock($in)
* Decrypts a block
*
* @access private
* @param String $in
* @return String
* @param string $in
* @return string
*/
function _decryptBlock($in)
{
Expand Down Expand Up @@ -573,15 +476,13 @@ function _setupKey()
0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
);

$this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, "\0");

if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_size === $this->kl['key_size'] && $this->block_size === $this->kl['block_size']) {
if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->key_length === $this->kl['key_length'] && $this->block_size === $this->kl['block_size']) {
// already expanded
return;
}
$this->kl = array('key' => $this->key, 'key_size' => $this->key_size, 'block_size' => $this->block_size);
$this->kl = array('key' => $this->key, 'key_length' => $this->key_length, 'block_size' => $this->block_size);

$this->Nk = $this->key_size >> 2;
$this->Nk = $this->key_length >> 2;
// see Rijndael-ammended.pdf#page=44
$this->Nr = max($this->Nk, $this->Nb) + 6;

Expand Down Expand Up @@ -673,13 +574,13 @@ function _setupKey()
* Performs S-Box substitutions
*
* @access private
* @param Integer $word
* @param int $word
*/
function _subWord($word)
{
static $sbox;
if (empty($sbox)) {
list(,,,, $sbox) = $this->_getTables();
list(, , , , $sbox) = $this->_getTables();
}

return $sbox[$word & 0x000000FF] |
Expand All @@ -691,11 +592,11 @@ function _subWord($word)
/**
* Provides the mixColumns and sboxes tables
*
* @see Crypt_Rijndael:_encryptBlock()
* @see Crypt_Rijndael:_setupInlineCrypt()
* @see Crypt_Rijndael:_subWord()
* @see self::_encryptBlock()
* @see self::_setupInlineCrypt()
* @see self::_subWord()
* @access private
* @return Array &$tables
* @return array &$tables
*/
function &_getTables()
{
Expand Down Expand Up @@ -780,11 +681,11 @@ function &_getTables()
/**
* Provides the inverse mixColumns and inverse sboxes tables
*
* @see Crypt_Rijndael:_decryptBlock()
* @see Crypt_Rijndael:_setupInlineCrypt()
* @see Crypt_Rijndael:_setupKey()
* @see self::_decryptBlock()
* @see self::_setupInlineCrypt()
* @see self::_setupKey()
* @access private
* @return Array &$tables
* @return array &$tables
*/
function &_getInvTables()
{
Expand Down Expand Up @@ -878,7 +779,7 @@ function _setupInlineCrypt()
// We create max. 10 hi-optimized code for memory reason. Means: For each $key one ultra fast inline-crypt function.
// (Currently, for Crypt_Rijndael/AES, one generated $lambda_function cost on php5.5@32bit ~80kb unfreeable mem and ~130kb on php5.5@64bit)
// After that, we'll still create very fast optimized code but not the hi-ultimative code, for each $mode one.
$gen_hi_opt_code = (bool)( count($lambda_functions) < 10 );
$gen_hi_opt_code = (bool)(count($lambda_functions) < 10);

// Generation of a uniqe hash for our generated code
$code_hash = "Crypt_Rijndael, {$this->mode}, {$this->Nr}, {$this->Nb}";
Expand Down