Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Saransaran/php-class-project
  • sibidharan/php-class-project
  • Madhan1024/php-class-project
  • GopiKrishnan/photogram
  • Mhd_khalid/php-class-project
  • At_muthu__/php-class-project
  • jaganbhaskar155/php-class-project
  • hariharanrd/php-class-project
  • jasper715/php-class-project
  • hanuRakesh/photogram-project-main
  • Yuvaraj21/photogram
  • ram_rogers/php-class-project
  • Hihelloboy/php-class-project
  • Nadarajan/php-class-project
  • srisanthosh156/php-class-project
  • Buvaneshwaran.k/php-class-project
  • umarfarooq07/php-class-project
  • Dhanaprakash/php-class-project
  • jashwanth142003/php-class-project
  • Esakkiraja/php-class-project
  • Boomi/php-class-project
  • Kishore2071/php-class-project
  • Ram123raj/php-class-project
  • aswinkumar27/php-class-project
  • dhilipdhilip9655/php-class-project
  • Manikandam143/php-class-project
  • VikramS/php-class-project
  • ArnoldSam/php-class-project
  • gowthamapandi0008/php-class-project
  • d.barath7639/php-class-project
  • shyalandran/php-class-project
  • kiruba_432/php-class-project
  • razakias001/php-class-project
  • kannan.b2745/php-class-project
  • sathish236tsk/php-class-project
  • rii/php-class-project
  • jonathajh4k/php-class-project
  • Neelagandan_G/php-class-project
  • Tholkappiar2003/php-class-project
  • kamaleshselvam75/php-class-project
  • devapriyan/php-class-project
  • sanojahamed/php-class-project
  • rizwankendo/php-class-project
  • senthamilselvan18000/php-class-project
  • rajeshd01/php-class-project
  • Florence/php-class-project
  • vishnu191299/php-class-project
  • Rakeshrakki/php-class-project
  • sanjay057/php-class-project
  • amarsanthoshsanthosh/photogram-project-cp
  • md_ashmar/php-class-project
  • k.nandhishwaran777k/php-class-project
52 results
Show changes
Showing
with 6781 additions and 0 deletions
<?php
/**
* Raw Signature Handler
*
* PHP version 5
*
* Handles signatures as arrays
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\Common\Formats\Signature;
use phpseclib3\Math\BigInteger;
/**
* Raw Signature Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class Raw
{
/**
* Loads a signature
*
* @param array $sig
* @return array|bool
*/
public static function load($sig)
{
switch (true) {
case !is_array($sig):
case !isset($sig['r']) || !isset($sig['s']):
case !$sig['r'] instanceof BigInteger:
case !$sig['s'] instanceof BigInteger:
return false;
}
return [
'r' => $sig['r'],
's' => $sig['s']
];
}
/**
* Returns a signature in the appropriate format
*
* @param \phpseclib3\Math\BigInteger $r
* @param \phpseclib3\Math\BigInteger $s
* @return string
*/
public static function save(BigInteger $r, BigInteger $s)
{
return compact('r', 's');
}
}
<?php
/**
* PrivateKey interface
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\Common;
/**
* PrivateKey interface
*
* @author Jim Wigginton <terrafrost@php.net>
*/
interface PrivateKey
{
public function sign($message);
//public function decrypt($ciphertext);
public function getPublicKey();
public function toString($type, array $options = []);
/**
* @param string|false $password
* @return mixed
*/
public function withPassword($password = false);
}
<?php
/**
* PublicKey interface
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2009 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\Common;
/**
* PublicKey interface
*
* @author Jim Wigginton <terrafrost@php.net>
*/
interface PublicKey
{
public function verify($message, $signature);
//public function encrypt($plaintext);
public function toString($type, array $options = []);
public function getFingerprint($algorithm);
}
<?php
/**
* Base Class for all stream ciphers
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\Common;
/**
* Base Class for all stream cipher classes
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class StreamCipher extends SymmetricKey
{
/**
* Block Length of the cipher
*
* Stream ciphers do not have a block size
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::block_size
* @var int
*/
protected $block_size = 0;
/**
* Default Constructor.
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
* @return \phpseclib3\Crypt\Common\StreamCipher
*/
public function __construct()
{
parent::__construct('stream');
}
/**
* Stream ciphers not use an IV
*
* @return bool
*/
public function usesIV()
{
return false;
}
}
<?php
/**
* Base Class for all \phpseclib3\Crypt\* cipher classes
*
* PHP version 5
*
* Internally for phpseclib developers:
* If you plan to add a new cipher class, please note following rules:
*
* - The new \phpseclib3\Crypt\* cipher class should extend \phpseclib3\Crypt\Common\SymmetricKey
*
* - Following methods are then required to be overridden/overloaded:
*
* - encryptBlock()
*
* - decryptBlock()
*
* - setupKey()
*
* - All other methods are optional to be overridden/overloaded
*
* - Look at the source code of the current ciphers how they extend \phpseclib3\Crypt\Common\SymmetricKey
* and take one of them as a start up for the new cipher class.
*
* - Please read all the other comments/notes/hints here also for each class var/method
*
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\Common;
use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Blowfish;
use phpseclib3\Crypt\Hash;
use phpseclib3\Exception\BadDecryptionException;
use phpseclib3\Exception\BadModeException;
use phpseclib3\Exception\InconsistentSetupException;
use phpseclib3\Exception\InsufficientSetupException;
use phpseclib3\Exception\UnsupportedAlgorithmException;
use phpseclib3\Math\BigInteger;
use phpseclib3\Math\BinaryField;
use phpseclib3\Math\PrimeField;
/**
* Base Class for all \phpseclib3\Crypt\* cipher classes
*
* @author Jim Wigginton <terrafrost@php.net>
* @author Hans-Juergen Petrich <petrich@tronic-media.com>
*/
abstract class SymmetricKey
{
/**
* Encrypt / decrypt using the Counter mode.
*
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
*/
const MODE_CTR = -1;
/**
* Encrypt / decrypt using the Electronic Code Book mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
*/
const MODE_ECB = 1;
/**
* Encrypt / decrypt using the Code Book Chaining mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
*/
const MODE_CBC = 2;
/**
* Encrypt / decrypt using the Cipher Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
*/
const MODE_CFB = 3;
/**
* Encrypt / decrypt using the Cipher Feedback mode (8bit)
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
*/
const MODE_CFB8 = 7;
/**
* Encrypt / decrypt using the Output Feedback mode (8bit)
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
*/
const MODE_OFB8 = 8;
/**
* Encrypt / decrypt using the Output Feedback mode.
*
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
*/
const MODE_OFB = 4;
/**
* Encrypt / decrypt using Galois/Counter mode.
*
* @link https://en.wikipedia.org/wiki/Galois/Counter_Mode
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
*/
const MODE_GCM = 5;
/**
* Encrypt / decrypt using streaming mode.
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
*/
const MODE_STREAM = 6;
/**
* Mode Map
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
*/
const MODE_MAP = [
'ctr' => self::MODE_CTR,
'ecb' => self::MODE_ECB,
'cbc' => self::MODE_CBC,
'cfb' => self::MODE_CFB,
'cfb8' => self::MODE_CFB8,
'ofb' => self::MODE_OFB,
'ofb8' => self::MODE_OFB8,
'gcm' => self::MODE_GCM,
'stream' => self::MODE_STREAM
];
/**
* Base value for the internal implementation $engine switch
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
*/
const ENGINE_INTERNAL = 1;
/**
* Base value for the eval() implementation $engine switch
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
*/
const ENGINE_EVAL = 2;
/**
* Base value for the mcrypt implementation $engine switch
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
*/
const ENGINE_MCRYPT = 3;
/**
* Base value for the openssl implementation $engine switch
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
*/
const ENGINE_OPENSSL = 4;
/**
* Base value for the libsodium implementation $engine switch
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
*/
const ENGINE_LIBSODIUM = 5;
/**
* Base value for the openssl / gcm implementation $engine switch
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::__construct()
*/
const ENGINE_OPENSSL_GCM = 6;
/**
* Engine Reverse Map
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::getEngine()
*/
const ENGINE_MAP = [
self::ENGINE_INTERNAL => 'PHP',
self::ENGINE_EVAL => 'Eval',
self::ENGINE_MCRYPT => 'mcrypt',
self::ENGINE_OPENSSL => 'OpenSSL',
self::ENGINE_LIBSODIUM => 'libsodium',
self::ENGINE_OPENSSL_GCM => 'OpenSSL (GCM)'
];
/**
* The Encryption Mode
*
* @see self::__construct()
* @var int
*/
protected $mode;
/**
* The Block Length of the block cipher
*
* @var int
*/
protected $block_size = 16;
/**
* The Key
*
* @see self::setKey()
* @var string
*/
protected $key = false;
/**
* HMAC Key
*
* @see self::setupGCM()
* @var ?string
*/
protected $hKey = false;
/**
* The Initialization Vector
*
* @see self::setIV()
* @var string
*/
protected $iv = false;
/**
* A "sliding" Initialization Vector
*
* @see self::enableContinuousBuffer()
* @see self::clearBuffers()
* @var string
*/
protected $encryptIV;
/**
* A "sliding" Initialization Vector
*
* @see self::enableContinuousBuffer()
* @see self::clearBuffers()
* @var string
*/
protected $decryptIV;
/**
* Continuous Buffer status
*
* @see self::enableContinuousBuffer()
* @var bool
*/
protected $continuousBuffer = false;
/**
* Encryption buffer for CTR, OFB and CFB modes
*
* @see self::encrypt()
* @see self::clearBuffers()
* @var array
*/
protected $enbuffer;
/**
* Decryption buffer for CTR, OFB and CFB modes
*
* @see self::decrypt()
* @see self::clearBuffers()
* @var array
*/
protected $debuffer;
/**
* mcrypt resource for encryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see self::encrypt()
* @var resource
*/
private $enmcrypt;
/**
* mcrypt resource for decryption
*
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
*
* @see self::decrypt()
* @var resource
*/
private $demcrypt;
/**
* Does the enmcrypt resource need to be (re)initialized?
*
* @see \phpseclib3\Crypt\Twofish::setKey()
* @see \phpseclib3\Crypt\Twofish::setIV()
* @var bool
*/
private $enchanged = true;
/**
* Does the demcrypt resource need to be (re)initialized?
*
* @see \phpseclib3\Crypt\Twofish::setKey()
* @see \phpseclib3\Crypt\Twofish::setIV()
* @var bool
*/
private $dechanged = true;
/**
* mcrypt resource for CFB mode
*
* mcrypt's CFB mode, in (and only in) buffered context,
* is broken, so phpseclib implements the CFB mode by it self,
* even when the mcrypt php extension is available.
*
* In order to do the CFB-mode work (fast) phpseclib
* use a separate ECB-mode mcrypt resource.
*
* @link http://phpseclib.sourceforge.net/cfb-demo.phps
* @see self::encrypt()
* @see self::decrypt()
* @see self::setupMcrypt()
* @var resource
*/
private $ecb;
/**
* Optimizing value while CFB-encrypting
*
* Only relevant if $continuousBuffer enabled
* and $engine == self::ENGINE_MCRYPT
*
* It's faster to re-init $enmcrypt if
* $buffer bytes > $cfb_init_len than
* using the $ecb resource furthermore.
*
* This value depends of the chosen cipher
* and the time it would be needed for it's
* initialization [by mcrypt_generic_init()]
* which, typically, depends on the complexity
* on its internaly Key-expanding algorithm.
*
* @see self::encrypt()
* @var int
*/
protected $cfb_init_len = 600;
/**
* Does internal cipher state need to be (re)initialized?
*
* @see self::setKey()
* @see self::setIV()
* @see self::disableContinuousBuffer()
* @var bool
*/
protected $changed = true;
/**
* Does Eval engie need to be (re)initialized?
*
* @see self::setup()
* @var bool
*/
protected $nonIVChanged = true;
/**
* Padding status
*
* @see self::enablePadding()
* @var bool
*/
private $padding = true;
/**
* Is the mode one that is paddable?
*
* @see self::__construct()
* @var bool
*/
private $paddable = false;
/**
* Holds which crypt engine internaly should be use,
* which will be determined automatically on __construct()
*
* Currently available $engines are:
* - self::ENGINE_LIBSODIUM (very fast, php-extension: libsodium, extension_loaded('libsodium') required)
* - self::ENGINE_OPENSSL_GCM (very fast, php-extension: openssl, extension_loaded('openssl') required)
* - self::ENGINE_OPENSSL (very fast, php-extension: openssl, extension_loaded('openssl') required)
* - self::ENGINE_MCRYPT (fast, php-extension: mcrypt, extension_loaded('mcrypt') required)
* - self::ENGINE_EVAL (medium, pure php-engine, no php-extension required)
* - self::ENGINE_INTERNAL (slower, pure php-engine, no php-extension required)
*
* @see self::setEngine()
* @see self::encrypt()
* @see self::decrypt()
* @var int
*/
protected $engine;
/**
* Holds the preferred crypt engine
*
* @see self::setEngine()
* @see self::setPreferredEngine()
* @var int
*/
private $preferredEngine;
/**
* The mcrypt specific name of the cipher
*
* Only used if $engine == self::ENGINE_MCRYPT
*
* @link http://www.php.net/mcrypt_module_open
* @link http://www.php.net/mcrypt_list_algorithms
* @see self::setupMcrypt()
* @var string
*/
protected $cipher_name_mcrypt;
/**
* The openssl specific name of the cipher
*
* Only used if $engine == self::ENGINE_OPENSSL
*
* @link http://www.php.net/openssl-get-cipher-methods
* @var string
*/
protected $cipher_name_openssl;
/**
* The openssl specific name of the cipher in ECB mode
*
* If OpenSSL does not support the mode we're trying to use (CTR)
* it can still be emulated with ECB mode.
*
* @link http://www.php.net/openssl-get-cipher-methods
* @var string
*/
protected $cipher_name_openssl_ecb;
/**
* The default salt used by setPassword()
*
* @see self::setPassword()
* @var string
*/
private $password_default_salt = 'phpseclib/salt';
/**
* The name of the performance-optimized callback function
*
* Used by encrypt() / decrypt()
* only if $engine == self::ENGINE_INTERNAL
*
* @see self::encrypt()
* @see self::decrypt()
* @see self::setupInlineCrypt()
* @var Callback
*/
protected $inline_crypt;
/**
* If OpenSSL can be used in ECB but not in CTR we can emulate CTR
*
* @see self::openssl_ctr_process()
* @var bool
*/
private $openssl_emulate_ctr = false;
/**
* Don't truncate / null pad key
*
* @see self::clearBuffers()
* @var bool
*/
private $skip_key_adjustment = false;
/**
* Has the key length explicitly been set or should it be derived from the key, itself?
*
* @see self::setKeyLength()
* @var bool
*/
protected $explicit_key_length = false;
/**
* Hash subkey for GHASH
*
* @see self::setupGCM()
* @see self::ghash()
* @var BinaryField\Integer
*/
private $h;
/**
* Additional authenticated data
*
* @var string
*/
protected $aad = '';
/**
* Authentication Tag produced after a round of encryption
*
* @var string
*/
protected $newtag = false;
/**
* Authentication Tag to be verified during decryption
*
* @var string
*/
protected $oldtag = false;
/**
* GCM Binary Field
*
* @see self::__construct()
* @see self::ghash()
* @var BinaryField
*/
private static $gcmField;
/**
* Poly1305 Prime Field
*
* @see self::enablePoly1305()
* @see self::poly1305()
* @var PrimeField
*/
private static $poly1305Field;
/**
* Flag for using regular vs "safe" intval
*
* @see self::initialize_static_variables()
* @var boolean
*/
protected static $use_reg_intval;
/**
* Poly1305 Key
*
* @see self::setPoly1305Key()
* @see self::poly1305()
* @var string
*/
protected $poly1305Key;
/**
* Poly1305 Flag
*
* @see self::setPoly1305Key()
* @see self::enablePoly1305()
* @var boolean
*/
protected $usePoly1305 = false;
/**
* The Original Initialization Vector
*
* GCM uses the nonce to build the IV but we want to be able to distinguish between nonce-derived
* IV's and user-set IV's
*
* @see self::setIV()
* @var string
*/
private $origIV = false;
/**
* Nonce
*
* Only used with GCM. We could re-use setIV() but nonce's can be of a different length and
* toggling between GCM and other modes could be more complicated if we re-used setIV()
*
* @see self::setNonce()
* @var string
*/
protected $nonce = false;
/**
* Default Constructor.
*
* $mode could be:
*
* - ecb
*
* - cbc
*
* - ctr
*
* - cfb
*
* - cfb8
*
* - ofb
*
* - ofb8
*
* - gcm
*
* @param string $mode
* @throws BadModeException if an invalid / unsupported mode is provided
*/
public function __construct($mode)
{
$mode = strtolower($mode);
// necessary because of 5.6 compatibility; we can't do isset(self::MODE_MAP[$mode]) in 5.6
$map = self::MODE_MAP;
if (!isset($map[$mode])) {
throw new BadModeException('No valid mode has been specified');
}
$mode = self::MODE_MAP[$mode];
// $mode dependent settings
switch ($mode) {
case self::MODE_ECB:
case self::MODE_CBC:
$this->paddable = true;
break;
case self::MODE_CTR:
case self::MODE_CFB:
case self::MODE_CFB8:
case self::MODE_OFB:
case self::MODE_OFB8:
case self::MODE_STREAM:
$this->paddable = false;
break;
case self::MODE_GCM:
if ($this->block_size != 16) {
throw new BadModeException('GCM is only valid for block ciphers with a block size of 128 bits');
}
if (!isset(self::$gcmField)) {
self::$gcmField = new BinaryField(128, 7, 2, 1, 0);
}
$this->paddable = false;
break;
default:
throw new BadModeException('No valid mode has been specified');
}
$this->mode = $mode;
static::initialize_static_variables();
}
/**
* Initialize static variables
*/
protected static function initialize_static_variables()
{
if (!isset(self::$use_reg_intval)) {
switch (true) {
// PHP_OS & "\xDF\xDF\xDF" == strtoupper(substr(PHP_OS, 0, 3)), but a lot faster
case (PHP_OS & "\xDF\xDF\xDF") === 'WIN':
case (php_uname('m') & "\xDF\xDF\xDF") != 'ARM':
case defined('PHP_INT_SIZE') && PHP_INT_SIZE == 8:
self::$use_reg_intval = true;
break;
case (php_uname('m') & "\xDF\xDF\xDF") == 'ARM':
switch (true) {
/* PHP 7.0.0 introduced a bug that affected 32-bit ARM processors:
https://github.com/php/php-src/commit/716da71446ebbd40fa6cf2cea8a4b70f504cc3cd
altho the changelogs make no mention of it, this bug was fixed with this commit:
https://github.com/php/php-src/commit/c1729272b17a1fe893d1a54e423d3b71470f3ee8
affected versions of PHP are: 7.0.x, 7.1.0 - 7.1.23 and 7.2.0 - 7.2.11 */
case PHP_VERSION_ID >= 70000 && PHP_VERSION_ID <= 70123:
case PHP_VERSION_ID >= 70200 && PHP_VERSION_ID <= 70211:
self::$use_reg_intval = false;
break;
default:
self::$use_reg_intval = true;
}
}
}
}
/**
* Sets the initialization vector.
*
* setIV() is not required when ecb or gcm modes are being used.
*
* {@internal Can be overwritten by a sub class, but does not have to be}
*
* @param string $iv
* @throws \LengthException if the IV length isn't equal to the block size
* @throws \BadMethodCallException if an IV is provided when one shouldn't be
*/
public function setIV($iv)
{
if ($this->mode == self::MODE_ECB) {
throw new \BadMethodCallException('This mode does not require an IV.');
}
if ($this->mode == self::MODE_GCM) {
throw new \BadMethodCallException('Use setNonce instead');
}
if (!$this->usesIV()) {
throw new \BadMethodCallException('This algorithm does not use an IV.');
}
if (strlen($iv) != $this->block_size) {
throw new \LengthException('Received initialization vector of size ' . strlen($iv) . ', but size ' . $this->block_size . ' is required');
}
$this->iv = $this->origIV = $iv;
$this->changed = true;
}
/**
* Enables Poly1305 mode.
*
* Once enabled Poly1305 cannot be disabled.
*
* @throws \BadMethodCallException if Poly1305 is enabled whilst in GCM mode
*/
public function enablePoly1305()
{
if ($this->mode == self::MODE_GCM) {
throw new \BadMethodCallException('Poly1305 cannot be used in GCM mode');
}
$this->usePoly1305 = true;
}
/**
* Enables Poly1305 mode.
*
* Once enabled Poly1305 cannot be disabled. If $key is not passed then an attempt to call createPoly1305Key
* will be made.
*
* @param string $key optional
* @throws \LengthException if the key isn't long enough
* @throws \BadMethodCallException if Poly1305 is enabled whilst in GCM mode
*/
public function setPoly1305Key($key = null)
{
if ($this->mode == self::MODE_GCM) {
throw new \BadMethodCallException('Poly1305 cannot be used in GCM mode');
}
if (!is_string($key) || strlen($key) != 32) {
throw new \LengthException('The Poly1305 key must be 32 bytes long (256 bits)');
}
if (!isset(self::$poly1305Field)) {
// 2^130-5
self::$poly1305Field = new PrimeField(new BigInteger('3fffffffffffffffffffffffffffffffb', 16));
}
$this->poly1305Key = $key;
$this->usePoly1305 = true;
}
/**
* Sets the nonce.
*
* setNonce() is only required when gcm is used
*
* @param string $nonce
* @throws \BadMethodCallException if an nonce is provided when one shouldn't be
*/
public function setNonce($nonce)
{
if ($this->mode != self::MODE_GCM) {
throw new \BadMethodCallException('Nonces are only used in GCM mode.');
}
$this->nonce = $nonce;
$this->setEngine();
}
/**
* Sets additional authenticated data
*
* setAAD() is only used by gcm or in poly1305 mode
*
* @param string $aad
* @throws \BadMethodCallException if mode isn't GCM or if poly1305 isn't being utilized
*/
public function setAAD($aad)
{
if ($this->mode != self::MODE_GCM && !$this->usePoly1305) {
throw new \BadMethodCallException('Additional authenticated data is only utilized in GCM mode or with Poly1305');
}
$this->aad = $aad;
}
/**
* Returns whether or not the algorithm uses an IV
*
* @return bool
*/
public function usesIV()
{
return $this->mode != self::MODE_GCM && $this->mode != self::MODE_ECB;
}
/**
* Returns whether or not the algorithm uses a nonce
*
* @return bool
*/
public function usesNonce()
{
return $this->mode == self::MODE_GCM;
}
/**
* Returns the current key length in bits
*
* @return int
*/
public function getKeyLength()
{
return $this->key_length << 3;
}
/**
* Returns the current block length in bits
*
* @return int
*/
public function getBlockLength()
{
return $this->block_size << 3;
}
/**
* Returns the current block length in bytes
*
* @return int
*/
public function getBlockLengthInBytes()
{
return $this->block_size;
}
/**
* Sets the key length.
*
* Keys with explicitly set lengths need to be treated accordingly
*
* @param int $length
*/
public function setKeyLength($length)
{
$this->explicit_key_length = $length >> 3;
if (is_string($this->key) && strlen($this->key) != $this->explicit_key_length) {
$this->key = false;
throw new InconsistentSetupException('Key has already been set and is not ' . $this->explicit_key_length . ' bytes long');
}
}
/**
* Sets the key.
*
* The min/max length(s) of the key depends on the cipher which is used.
* If the key not fits the length(s) of the cipher it will paded with null bytes
* up to the closest valid key length. If the key is more than max length,
* we trim the excess bits.
*
* If the key is not explicitly set, it'll be assumed to be all null bytes.
*
* {@internal Could, but not must, extend by the child Crypt_* class}
*
* @param string $key
*/
public function setKey($key)
{
if ($this->explicit_key_length !== false && strlen($key) != $this->explicit_key_length) {
throw new InconsistentSetupException('Key length has already been set to ' . $this->explicit_key_length . ' bytes and this key is ' . strlen($key) . ' bytes');
}
$this->key = $key;
$this->key_length = strlen($key);
$this->setEngine();
}
/**
* Sets the password.
*
* Depending on what $method is set to, setPassword()'s (optional) parameters are as follows:
* {@link http://en.wikipedia.org/wiki/PBKDF2 pbkdf2} or pbkdf1:
* $hash, $salt, $count, $dkLen
*
* Where $hash (default = sha1) currently supports the following hashes: see: Crypt/Hash.php
* {@link https://en.wikipedia.org/wiki/Bcrypt bcypt}:
* $salt, $rounds, $keylen
*
* This is a modified version of bcrypt used by OpenSSH.
*
* {@internal Could, but not must, extend by the child Crypt_* class}
*
* @see Crypt/Hash.php
* @param string $password
* @param string $method
* @param string[] ...$func_args
* @throws \LengthException if pbkdf1 is being used and the derived key length exceeds the hash length
* @throws \RuntimeException if bcrypt is being used and a salt isn't provided
* @return bool
*/
public function setPassword($password, $method = 'pbkdf2', ...$func_args)
{
$key = '';
$method = strtolower($method);
switch ($method) {
case 'bcrypt':
if (!isset($func_args[2])) {
throw new \RuntimeException('A salt must be provided for bcrypt to work');
}
$salt = $func_args[0];
$rounds = isset($func_args[1]) ? $func_args[1] : 16;
$keylen = isset($func_args[2]) ? $func_args[2] : $this->key_length;
$key = Blowfish::bcrypt_pbkdf($password, $salt, $keylen + $this->block_size, $rounds);
$this->setKey(substr($key, 0, $keylen));
$this->setIV(substr($key, $keylen));
return true;
case 'pkcs12': // from https://tools.ietf.org/html/rfc7292#appendix-B.2
case 'pbkdf1':
case 'pbkdf2':
// Hash function
$hash = isset($func_args[0]) ? strtolower($func_args[0]) : 'sha1';
$hashObj = new Hash();
$hashObj->setHash($hash);
// WPA and WPA2 use the SSID as the salt
$salt = isset($func_args[1]) ? $func_args[1] : $this->password_default_salt;
// RFC2898#section-4.2 uses 1,000 iterations by default
// WPA and WPA2 use 4,096.
$count = isset($func_args[2]) ? $func_args[2] : 1000;
// Keylength
if (isset($func_args[3])) {
if ($func_args[3] <= 0) {
throw new \LengthException('Derived key length cannot be longer 0 or less');
}
$dkLen = $func_args[3];
} else {
$key_length = $this->explicit_key_length !== false ? $this->explicit_key_length : $this->key_length;
$dkLen = $method == 'pbkdf1' ? 2 * $key_length : $key_length;
}
switch (true) {
case $method == 'pkcs12':
/*
In this specification, however, all passwords are created from
BMPStrings with a NULL terminator. This means that each character in
the original BMPString is encoded in 2 bytes in big-endian format
(most-significant byte first). There are no Unicode byte order
marks. The 2 bytes produced from the last character in the BMPString
are followed by 2 additional bytes with the value 0x00.
-- https://tools.ietf.org/html/rfc7292#appendix-B.1
*/
$password = "\0" . chunk_split($password, 1, "\0") . "\0";
/*
This standard specifies 3 different values for the ID byte mentioned
above:
1. If ID=1, then the pseudorandom bits being produced are to be used
as key material for performing encryption or decryption.
2. If ID=2, then the pseudorandom bits being produced are to be used
as an IV (Initial Value) for encryption or decryption.
3. If ID=3, then the pseudorandom bits being produced are to be used
as an integrity key for MACing.
*/
// Construct a string, D (the "diversifier"), by concatenating v/8
// copies of ID.
$blockLength = $hashObj->getBlockLengthInBytes();
$d1 = str_repeat(chr(1), $blockLength);
$d2 = str_repeat(chr(2), $blockLength);
$s = '';
if (strlen($salt)) {
while (strlen($s) < $blockLength) {
$s .= $salt;
}
}
$s = substr($s, 0, $blockLength);
$p = '';
if (strlen($password)) {
while (strlen($p) < $blockLength) {
$p .= $password;
}
}
$p = substr($p, 0, $blockLength);
$i = $s . $p;
$this->setKey(self::pkcs12helper($dkLen, $hashObj, $i, $d1, $count));
if ($this->usesIV()) {
$this->setIV(self::pkcs12helper($this->block_size, $hashObj, $i, $d2, $count));
}
return true;
case $method == 'pbkdf1':
if ($dkLen > $hashObj->getLengthInBytes()) {
throw new \LengthException('Derived key length cannot be longer than the hash length');
}
$t = $password . $salt;
for ($i = 0; $i < $count; ++$i) {
$t = $hashObj->hash($t);
}
$key = substr($t, 0, $dkLen);
$this->setKey(substr($key, 0, $dkLen >> 1));
if ($this->usesIV()) {
$this->setIV(substr($key, $dkLen >> 1));
}
return true;
case !in_array($hash, hash_algos()):
$i = 1;
$hashObj->setKey($password);
while (strlen($key) < $dkLen) {
$f = $u = $hashObj->hash($salt . pack('N', $i++));
for ($j = 2; $j <= $count; ++$j) {
$u = $hashObj->hash($u);
$f ^= $u;
}
$key .= $f;
}
$key = substr($key, 0, $dkLen);
break;
default:
$key = hash_pbkdf2($hash, $password, $salt, $count, $dkLen, true);
}
break;
default:
throw new UnsupportedAlgorithmException($method . ' is not a supported password hashing method');
}
$this->setKey($key);
return true;
}
/**
* PKCS#12 KDF Helper Function
*
* As discussed here:
*
* {@link https://tools.ietf.org/html/rfc7292#appendix-B}
*
* @see self::setPassword()
* @param int $n
* @param \phpseclib3\Crypt\Hash $hashObj
* @param string $i
* @param string $d
* @param int $count
* @return string $a
*/
private static function pkcs12helper($n, $hashObj, $i, $d, $count)
{
static $one;
if (!isset($one)) {
$one = new BigInteger(1);
}
$blockLength = $hashObj->getBlockLength() >> 3;
$c = ceil($n / $hashObj->getLengthInBytes());
$a = '';
for ($j = 1; $j <= $c; $j++) {
$ai = $d . $i;
for ($k = 0; $k < $count; $k++) {
$ai = $hashObj->hash($ai);
}
$b = '';
while (strlen($b) < $blockLength) {
$b .= $ai;
}
$b = substr($b, 0, $blockLength);
$b = new BigInteger($b, 256);
$newi = '';
for ($k = 0; $k < strlen($i); $k += $blockLength) {
$temp = substr($i, $k, $blockLength);
$temp = new BigInteger($temp, 256);
$temp->setPrecision($blockLength << 3);
$temp = $temp->add($b);
$temp = $temp->add($one);
$newi .= $temp->toBytes(false);
}
$i = $newi;
$a .= $ai;
}
return substr($a, 0, $n);
}
/**
* Encrypts a message.
*
* $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other cipher
* implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
* necessary are discussed in the following
* URL:
*
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
*
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
* strlen($plaintext) will still need to be a multiple of the block size, however, arbitrary values can be added to make it that
* length.
*
* {@internal Could, but not must, extend by the child Crypt_* class}
*
* @see self::decrypt()
* @param string $plaintext
* @return string $ciphertext
*/
public function encrypt($plaintext)
{
if ($this->paddable) {
$plaintext = $this->pad($plaintext);
}
$this->setup();
if ($this->mode == self::MODE_GCM) {
$oldIV = $this->iv;
Strings::increment_str($this->iv);
$cipher = new static('ctr');
$cipher->setKey($this->key);
$cipher->setIV($this->iv);
$ciphertext = $cipher->encrypt($plaintext);
$s = $this->ghash(
self::nullPad128($this->aad) .
self::nullPad128($ciphertext) .
self::len64($this->aad) .
self::len64($ciphertext)
);
$cipher->encryptIV = $this->iv = $this->encryptIV = $this->decryptIV = $oldIV;
$this->newtag = $cipher->encrypt($s);
return $ciphertext;
}
if (isset($this->poly1305Key)) {
$cipher = clone $this;
unset($cipher->poly1305Key);
$this->usePoly1305 = false;
$ciphertext = $cipher->encrypt($plaintext);
$this->newtag = $this->poly1305($ciphertext);
return $ciphertext;
}
if ($this->engine === self::ENGINE_OPENSSL) {
switch ($this->mode) {
case self::MODE_STREAM:
return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
case self::MODE_ECB:
return openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
case self::MODE_CBC:
$result = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->encryptIV);
if ($this->continuousBuffer) {
$this->encryptIV = substr($result, -$this->block_size);
}
return $result;
case self::MODE_CTR:
return $this->openssl_ctr_process($plaintext, $this->encryptIV, $this->enbuffer);
case self::MODE_CFB:
// cfb loosely routines inspired by openssl's:
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
$ciphertext = '';
if ($this->continuousBuffer) {
$iv = &$this->encryptIV;
$pos = &$this->enbuffer['pos'];
} else {
$iv = $this->encryptIV;
$pos = 0;
}
$len = strlen($plaintext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $this->block_size - $pos;
if ($len >= $max) {
$i = $max;
$len -= $max;
$pos = 0;
} else {
$i = $len;
$pos += $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
$plaintext = substr($plaintext, $i);
}
$overflow = $len % $this->block_size;
if ($overflow) {
$ciphertext .= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$iv = Strings::pop($ciphertext, $this->block_size);
$size = $len - $overflow;
$block = $iv ^ substr($plaintext, -$overflow);
$iv = substr_replace($iv, $block, 0, $overflow);
$ciphertext .= $block;
$pos = $overflow;
} elseif ($len) {
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$iv = substr($ciphertext, -$this->block_size);
}
return $ciphertext;
case self::MODE_CFB8:
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->encryptIV);
if ($this->continuousBuffer) {
if (($len = strlen($ciphertext)) >= $this->block_size) {
$this->encryptIV = substr($ciphertext, -$this->block_size);
} else {
$this->encryptIV = substr($this->encryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
}
}
return $ciphertext;
case self::MODE_OFB8:
$ciphertext = '';
$len = strlen($plaintext);
$iv = $this->encryptIV;
for ($i = 0; $i < $len; ++$i) {
$xor = openssl_encrypt($iv, $this->cipher_name_openssl_ecb, $this->key, $this->openssl_options, $this->decryptIV);
$ciphertext .= $plaintext[$i] ^ $xor;
$iv = substr($iv, 1) . $xor[0];
}
if ($this->continuousBuffer) {
$this->encryptIV = $iv;
}
break;
case self::MODE_OFB:
return $this->openssl_ofb_process($plaintext, $this->encryptIV, $this->enbuffer);
}
}
if ($this->engine === self::ENGINE_MCRYPT) {
set_error_handler(function () {
});
if ($this->enchanged) {
mcrypt_generic_init($this->enmcrypt, $this->key, $this->getIV($this->encryptIV));
$this->enchanged = false;
}
// re: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
// using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
// rewritten CFB implementation the above outputs the same thing twice.
if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
$block_size = $this->block_size;
$iv = &$this->encryptIV;
$pos = &$this->enbuffer['pos'];
$len = strlen($plaintext);
$ciphertext = '';
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len -= $max;
$pos = 0;
} else {
$i = $len;
$pos += $len;
$len = 0;
}
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
$this->enbuffer['enmcrypt_init'] = true;
}
if ($len >= $block_size) {
if ($this->enbuffer['enmcrypt_init'] === false || $len > $this->cfb_init_len) {
if ($this->enbuffer['enmcrypt_init'] === true) {
mcrypt_generic_init($this->enmcrypt, $this->key, $iv);
$this->enbuffer['enmcrypt_init'] = false;
}
$ciphertext .= mcrypt_generic($this->enmcrypt, substr($plaintext, $i, $len - $len % $block_size));
$iv = substr($ciphertext, -$block_size);
$len %= $block_size;
} else {
while ($len >= $block_size) {
$iv = mcrypt_generic($this->ecb, $iv) ^ substr($plaintext, $i, $block_size);
$ciphertext .= $iv;
$len -= $block_size;
$i += $block_size;
}
}
}
if ($len) {
$iv = mcrypt_generic($this->ecb, $iv);
$block = $iv ^ substr($plaintext, -$len);
$iv = substr_replace($iv, $block, 0, $len);
$ciphertext .= $block;
$pos = $len;
}
restore_error_handler();
return $ciphertext;
}
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->enmcrypt, $this->key, $this->getIV($this->encryptIV));
}
restore_error_handler();
return $ciphertext;
}
if ($this->engine === self::ENGINE_EVAL) {
$inline = $this->inline_crypt;
return $inline('encrypt', $plaintext);
}
$buffer = &$this->enbuffer;
$block_size = $this->block_size;
$ciphertext = '';
switch ($this->mode) {
case self::MODE_ECB:
for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
$ciphertext .= $this->encryptBlock(substr($plaintext, $i, $block_size));
}
break;
case self::MODE_CBC:
$xor = $this->encryptIV;
for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
$block = substr($plaintext, $i, $block_size);
$block = $this->encryptBlock($block ^ $xor);
$xor = $block;
$ciphertext .= $block;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
}
break;
case self::MODE_CTR:
$xor = $this->encryptIV;
if (strlen($buffer['ciphertext'])) {
for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
$buffer['ciphertext'] .= $this->encryptBlock($xor);
Strings::increment_str($xor);
}
$key = Strings::shift($buffer['ciphertext'], $block_size);
$ciphertext .= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
$block = substr($plaintext, $i, $block_size);
$key = $this->encryptBlock($xor);
Strings::increment_str($xor);
$ciphertext .= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
}
}
break;
case self::MODE_CFB:
// cfb loosely routines inspired by openssl's:
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
if ($this->continuousBuffer) {
$iv = &$this->encryptIV;
$pos = &$buffer['pos'];
} else {
$iv = $this->encryptIV;
$pos = 0;
}
$len = strlen($plaintext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len -= $max;
$pos = 0;
} else {
$i = $len;
$pos += $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
$ciphertext = substr($iv, $orig_pos) ^ $plaintext;
$iv = substr_replace($iv, $ciphertext, $orig_pos, $i);
}
while ($len >= $block_size) {
$iv = $this->encryptBlock($iv) ^ substr($plaintext, $i, $block_size);
$ciphertext .= $iv;
$len -= $block_size;
$i += $block_size;
}
if ($len) {
$iv = $this->encryptBlock($iv);
$block = $iv ^ substr($plaintext, $i);
$iv = substr_replace($iv, $block, 0, $len);
$ciphertext .= $block;
$pos = $len;
}
break;
case self::MODE_CFB8:
$ciphertext = '';
$len = strlen($plaintext);
$iv = $this->encryptIV;
for ($i = 0; $i < $len; ++$i) {
$ciphertext .= ($c = $plaintext[$i] ^ $this->encryptBlock($iv));
$iv = substr($iv, 1) . $c;
}
if ($this->continuousBuffer) {
if ($len >= $block_size) {
$this->encryptIV = substr($ciphertext, -$block_size);
} else {
$this->encryptIV = substr($this->encryptIV, $len - $block_size) . substr($ciphertext, -$len);
}
}
break;
case self::MODE_OFB8:
$ciphertext = '';
$len = strlen($plaintext);
$iv = $this->encryptIV;
for ($i = 0; $i < $len; ++$i) {
$xor = $this->encryptBlock($iv);
$ciphertext .= $plaintext[$i] ^ $xor;
$iv = substr($iv, 1) . $xor[0];
}
if ($this->continuousBuffer) {
$this->encryptIV = $iv;
}
break;
case self::MODE_OFB:
$xor = $this->encryptIV;
if (strlen($buffer['xor'])) {
for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['xor'])) {
$xor = $this->encryptBlock($xor);
$buffer['xor'] .= $xor;
}
$key = Strings::shift($buffer['xor'], $block_size);
$ciphertext .= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
$xor = $this->encryptBlock($xor);
$ciphertext .= substr($plaintext, $i, $block_size) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
}
}
break;
case self::MODE_STREAM:
$ciphertext = $this->encryptBlock($plaintext);
break;
}
return $ciphertext;
}
/**
* Decrypts a message.
*
* If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
* it is.
*
* {@internal Could, but not must, extend by the child Crypt_* class}
*
* @see self::encrypt()
* @param string $ciphertext
* @return string $plaintext
* @throws \LengthException if we're inside a block cipher and the ciphertext length is not a multiple of the block size
*/
public function decrypt($ciphertext)
{
if ($this->paddable && strlen($ciphertext) % $this->block_size) {
throw new \LengthException('The ciphertext length (' . strlen($ciphertext) . ') needs to be a multiple of the block size (' . $this->block_size . ')');
}
$this->setup();
if ($this->mode == self::MODE_GCM || isset($this->poly1305Key)) {
if ($this->oldtag === false) {
throw new InsufficientSetupException('Authentication Tag has not been set');
}
if (isset($this->poly1305Key)) {
$newtag = $this->poly1305($ciphertext);
} else {
$oldIV = $this->iv;
Strings::increment_str($this->iv);
$cipher = new static('ctr');
$cipher->setKey($this->key);
$cipher->setIV($this->iv);
$plaintext = $cipher->decrypt($ciphertext);
$s = $this->ghash(
self::nullPad128($this->aad) .
self::nullPad128($ciphertext) .
self::len64($this->aad) .
self::len64($ciphertext)
);
$cipher->encryptIV = $this->iv = $this->encryptIV = $this->decryptIV = $oldIV;
$newtag = $cipher->encrypt($s);
}
if ($this->oldtag != substr($newtag, 0, strlen($newtag))) {
$cipher = clone $this;
unset($cipher->poly1305Key);
$this->usePoly1305 = false;
$plaintext = $cipher->decrypt($ciphertext);
$this->oldtag = false;
throw new BadDecryptionException('Derived authentication tag and supplied authentication tag do not match');
}
$this->oldtag = false;
return $plaintext;
}
if ($this->engine === self::ENGINE_OPENSSL) {
switch ($this->mode) {
case self::MODE_STREAM:
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
break;
case self::MODE_ECB:
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
break;
case self::MODE_CBC:
$offset = $this->block_size;
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->decryptIV);
if ($this->continuousBuffer) {
$this->decryptIV = substr($ciphertext, -$offset, $this->block_size);
}
break;
case self::MODE_CTR:
$plaintext = $this->openssl_ctr_process($ciphertext, $this->decryptIV, $this->debuffer);
break;
case self::MODE_CFB:
// cfb loosely routines inspired by openssl's:
// {@link http://cvs.openssl.org/fileview?f=openssl/crypto/modes/cfb128.c&v=1.3.2.2.2.1}
$plaintext = '';
if ($this->continuousBuffer) {
$iv = &$this->decryptIV;
$pos = &$this->debuffer['pos'];
} else {
$iv = $this->decryptIV;
$pos = 0;
}
$len = strlen($ciphertext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $this->block_size - $pos;
if ($len >= $max) {
$i = $max;
$len -= $max;
$pos = 0;
} else {
$i = $len;
$pos += $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $this->blocksize
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
$ciphertext = substr($ciphertext, $i);
}
$overflow = $len % $this->block_size;
if ($overflow) {
$plaintext .= openssl_decrypt(substr($ciphertext, 0, -$overflow), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
if ($len - $overflow) {
$iv = substr($ciphertext, -$overflow - $this->block_size, -$overflow);
}
$iv = openssl_encrypt(str_repeat("\0", $this->block_size), $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$plaintext .= $iv ^ substr($ciphertext, -$overflow);
$iv = substr_replace($iv, substr($ciphertext, -$overflow), 0, $overflow);
$pos = $overflow;
} elseif ($len) {
$plaintext .= openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);
$iv = substr($ciphertext, -$this->block_size);
}
break;
case self::MODE_CFB8:
$plaintext = openssl_decrypt($ciphertext, $this->cipher_name_openssl, $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->decryptIV);
if ($this->continuousBuffer) {
if (($len = strlen($ciphertext)) >= $this->block_size) {
$this->decryptIV = substr($ciphertext, -$this->block_size);
} else {
$this->decryptIV = substr($this->decryptIV, $len - $this->block_size) . substr($ciphertext, -$len);
}
}
break;
case self::MODE_OFB8:
$plaintext = '';
$len = strlen($ciphertext);
$iv = $this->decryptIV;
for ($i = 0; $i < $len; ++$i) {
$xor = openssl_encrypt($iv, $this->cipher_name_openssl_ecb, $this->key, $this->openssl_options, $this->decryptIV);
$plaintext .= $ciphertext[$i] ^ $xor;
$iv = substr($iv, 1) . $xor[0];
}
if ($this->continuousBuffer) {
$this->decryptIV = $iv;
}
break;
case self::MODE_OFB:
$plaintext = $this->openssl_ofb_process($ciphertext, $this->decryptIV, $this->debuffer);
}
return $this->paddable ? $this->unpad($plaintext) : $plaintext;
}
if ($this->engine === self::ENGINE_MCRYPT) {
set_error_handler(function () {
});
$block_size = $this->block_size;
if ($this->dechanged) {
mcrypt_generic_init($this->demcrypt, $this->key, $this->getIV($this->decryptIV));
$this->dechanged = false;
}
if ($this->mode == self::MODE_CFB && $this->continuousBuffer) {
$iv = &$this->decryptIV;
$pos = &$this->debuffer['pos'];
$len = strlen($ciphertext);
$plaintext = '';
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len -= $max;
$pos = 0;
} else {
$i = $len;
$pos += $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
}
if ($len >= $block_size) {
$cb = substr($ciphertext, $i, $len - $len % $block_size);
$plaintext .= mcrypt_generic($this->ecb, $iv . $cb) ^ $cb;
$iv = substr($cb, -$block_size);
$len %= $block_size;
}
if ($len) {
$iv = mcrypt_generic($this->ecb, $iv);
$plaintext .= $iv ^ substr($ciphertext, -$len);
$iv = substr_replace($iv, substr($ciphertext, -$len), 0, $len);
$pos = $len;
}
restore_error_handler();
return $plaintext;
}
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
if (!$this->continuousBuffer) {
mcrypt_generic_init($this->demcrypt, $this->key, $this->getIV($this->decryptIV));
}
restore_error_handler();
return $this->paddable ? $this->unpad($plaintext) : $plaintext;
}
if ($this->engine === self::ENGINE_EVAL) {
$inline = $this->inline_crypt;
return $inline('decrypt', $ciphertext);
}
$block_size = $this->block_size;
$buffer = &$this->debuffer;
$plaintext = '';
switch ($this->mode) {
case self::MODE_ECB:
for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
$plaintext .= $this->decryptBlock(substr($ciphertext, $i, $block_size));
}
break;
case self::MODE_CBC:
$xor = $this->decryptIV;
for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
$block = substr($ciphertext, $i, $block_size);
$plaintext .= $this->decryptBlock($block) ^ $xor;
$xor = $block;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
}
break;
case self::MODE_CTR:
$xor = $this->decryptIV;
if (strlen($buffer['ciphertext'])) {
for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
$block = substr($ciphertext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
$buffer['ciphertext'] .= $this->encryptBlock($xor);
Strings::increment_str($xor);
}
$key = Strings::shift($buffer['ciphertext'], $block_size);
$plaintext .= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
$block = substr($ciphertext, $i, $block_size);
$key = $this->encryptBlock($xor);
Strings::increment_str($xor);
$plaintext .= $block ^ $key;
}
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) % $block_size) {
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
}
}
break;
case self::MODE_CFB:
if ($this->continuousBuffer) {
$iv = &$this->decryptIV;
$pos = &$buffer['pos'];
} else {
$iv = $this->decryptIV;
$pos = 0;
}
$len = strlen($ciphertext);
$i = 0;
if ($pos) {
$orig_pos = $pos;
$max = $block_size - $pos;
if ($len >= $max) {
$i = $max;
$len -= $max;
$pos = 0;
} else {
$i = $len;
$pos += $len;
$len = 0;
}
// ie. $i = min($max, $len), $len-= $i, $pos+= $i, $pos%= $blocksize
$plaintext = substr($iv, $orig_pos) ^ $ciphertext;
$iv = substr_replace($iv, substr($ciphertext, 0, $i), $orig_pos, $i);
}
while ($len >= $block_size) {
$iv = $this->encryptBlock($iv);
$cb = substr($ciphertext, $i, $block_size);
$plaintext .= $iv ^ $cb;
$iv = $cb;
$len -= $block_size;
$i += $block_size;
}
if ($len) {
$iv = $this->encryptBlock($iv);
$plaintext .= $iv ^ substr($ciphertext, $i);
$iv = substr_replace($iv, substr($ciphertext, $i), 0, $len);
$pos = $len;
}
break;
case self::MODE_CFB8:
$plaintext = '';
$len = strlen($ciphertext);
$iv = $this->decryptIV;
for ($i = 0; $i < $len; ++$i) {
$plaintext .= $ciphertext[$i] ^ $this->encryptBlock($iv);
$iv = substr($iv, 1) . $ciphertext[$i];
}
if ($this->continuousBuffer) {
if ($len >= $block_size) {
$this->decryptIV = substr($ciphertext, -$block_size);
} else {
$this->decryptIV = substr($this->decryptIV, $len - $block_size) . substr($ciphertext, -$len);
}
}
break;
case self::MODE_OFB8:
$plaintext = '';
$len = strlen($ciphertext);
$iv = $this->decryptIV;
for ($i = 0; $i < $len; ++$i) {
$xor = $this->encryptBlock($iv);
$plaintext .= $ciphertext[$i] ^ $xor;
$iv = substr($iv, 1) . $xor[0];
}
if ($this->continuousBuffer) {
$this->decryptIV = $iv;
}
break;
case self::MODE_OFB:
$xor = $this->decryptIV;
if (strlen($buffer['xor'])) {
for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
$block = substr($ciphertext, $i, $block_size);
if (strlen($block) > strlen($buffer['xor'])) {
$xor = $this->encryptBlock($xor);
$buffer['xor'] .= $xor;
}
$key = Strings::shift($buffer['xor'], $block_size);
$plaintext .= $block ^ $key;
}
} else {
for ($i = 0; $i < strlen($ciphertext); $i += $block_size) {
$xor = $this->encryptBlock($xor);
$plaintext .= substr($ciphertext, $i, $block_size) ^ $xor;
}
$key = $xor;
}
if ($this->continuousBuffer) {
$this->decryptIV = $xor;
if ($start = strlen($ciphertext) % $block_size) {
$buffer['xor'] = substr($key, $start) . $buffer['xor'];
}
}
break;
case self::MODE_STREAM:
$plaintext = $this->decryptBlock($ciphertext);
break;
}
return $this->paddable ? $this->unpad($plaintext) : $plaintext;
}
/**
* Get the authentication tag
*
* Only used in GCM or Poly1305 mode
*
* @see self::encrypt()
* @param int $length optional
* @return string
* @throws \LengthException if $length isn't of a sufficient length
* @throws \RuntimeException if GCM mode isn't being used
*/
public function getTag($length = 16)
{
if ($this->mode != self::MODE_GCM && !$this->usePoly1305) {
throw new \BadMethodCallException('Authentication tags are only utilized in GCM mode or with Poly1305');
}
if ($this->newtag === false) {
throw new \BadMethodCallException('A tag can only be returned after a round of encryption has been performed');
}
// the tag is 128-bits. it can't be greater than 16 bytes because that's bigger than the tag is. if it
// were 0 you might as well be doing CTR and less than 4 provides minimal security that could be trivially
// easily brute forced.
// see https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=36
// for more info
if ($length < 4 || $length > 16) {
throw new \LengthException('The authentication tag must be between 4 and 16 bytes long');
}
return $length == 16 ?
$this->newtag :
substr($this->newtag, 0, $length);
}
/**
* Sets the authentication tag
*
* Only used in GCM mode
*
* @see self::decrypt()
* @param string $tag
* @throws \LengthException if $length isn't of a sufficient length
* @throws \RuntimeException if GCM mode isn't being used
*/
public function setTag($tag)
{
if ($this->usePoly1305 && !isset($this->poly1305Key) && method_exists($this, 'createPoly1305Key')) {
$this->createPoly1305Key();
}
if ($this->mode != self::MODE_GCM && !$this->usePoly1305) {
throw new \BadMethodCallException('Authentication tags are only utilized in GCM mode or with Poly1305');
}
$length = strlen($tag);
if ($length < 4 || $length > 16) {
throw new \LengthException('The authentication tag must be between 4 and 16 bytes long');
}
$this->oldtag = $tag;
}
/**
* Get the IV
*
* mcrypt requires an IV even if ECB is used
*
* @see self::encrypt()
* @see self::decrypt()
* @param string $iv
* @return string
*/
protected function getIV($iv)
{
return $this->mode == self::MODE_ECB ? str_repeat("\0", $this->block_size) : $iv;
}
/**
* OpenSSL CTR Processor
*
* PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
* for CTR is the same for both encrypting and decrypting this function is re-used by both SymmetricKey::encrypt()
* and SymmetricKey::decrypt(). Also, OpenSSL doesn't implement CTR for all of it's symmetric ciphers so this
* function will emulate CTR with ECB when necessary.
*
* @see self::encrypt()
* @see self::decrypt()
* @param string $plaintext
* @param string $encryptIV
* @param array $buffer
* @return string
*/
private function openssl_ctr_process($plaintext, &$encryptIV, &$buffer)
{
$ciphertext = '';
$block_size = $this->block_size;
$key = $this->key;
if ($this->openssl_emulate_ctr) {
$xor = $encryptIV;
if (strlen($buffer['ciphertext'])) {
for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
$block = substr($plaintext, $i, $block_size);
if (strlen($block) > strlen($buffer['ciphertext'])) {
$buffer['ciphertext'] .= openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
}
Strings::increment_str($xor);
$otp = Strings::shift($buffer['ciphertext'], $block_size);
$ciphertext .= $block ^ $otp;
}
} else {
for ($i = 0; $i < strlen($plaintext); $i += $block_size) {
$block = substr($plaintext, $i, $block_size);
$otp = openssl_encrypt($xor, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
Strings::increment_str($xor);
$ciphertext .= $block ^ $otp;
}
}
if ($this->continuousBuffer) {
$encryptIV = $xor;
if ($start = strlen($plaintext) % $block_size) {
$buffer['ciphertext'] = substr($key, $start) . $buffer['ciphertext'];
}
}
return $ciphertext;
}
if (strlen($buffer['ciphertext'])) {
$ciphertext = $plaintext ^ Strings::shift($buffer['ciphertext'], strlen($plaintext));
$plaintext = substr($plaintext, strlen($ciphertext));
if (!strlen($plaintext)) {
return $ciphertext;
}
}
$overflow = strlen($plaintext) % $block_size;
if ($overflow) {
$plaintext2 = Strings::pop($plaintext, $overflow); // ie. trim $plaintext to a multiple of $block_size and put rest of $plaintext in $plaintext2
$encrypted = openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
$temp = Strings::pop($encrypted, $block_size);
$ciphertext .= $encrypted . ($plaintext2 ^ $temp);
if ($this->continuousBuffer) {
$buffer['ciphertext'] = substr($temp, $overflow);
$encryptIV = $temp;
}
} elseif (!strlen($buffer['ciphertext'])) {
$ciphertext .= openssl_encrypt($plaintext . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
$temp = Strings::pop($ciphertext, $block_size);
if ($this->continuousBuffer) {
$encryptIV = $temp;
}
}
if ($this->continuousBuffer) {
$encryptIV = openssl_decrypt($encryptIV, $this->cipher_name_openssl_ecb, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING);
if ($overflow) {
Strings::increment_str($encryptIV);
}
}
return $ciphertext;
}
/**
* OpenSSL OFB Processor
*
* PHP's OpenSSL bindings do not operate in continuous mode so we'll wrap around it. Since the keystream
* for OFB is the same for both encrypting and decrypting this function is re-used by both SymmetricKey::encrypt()
* and SymmetricKey::decrypt().
*
* @see self::encrypt()
* @see self::decrypt()
* @param string $plaintext
* @param string $encryptIV
* @param array $buffer
* @return string
*/
private function openssl_ofb_process($plaintext, &$encryptIV, &$buffer)
{
if (strlen($buffer['xor'])) {
$ciphertext = $plaintext ^ $buffer['xor'];
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
$plaintext = substr($plaintext, strlen($ciphertext));
} else {
$ciphertext = '';
}
$block_size = $this->block_size;
$len = strlen($plaintext);
$key = $this->key;
$overflow = $len % $block_size;
if (strlen($plaintext)) {
if ($overflow) {
$ciphertext .= openssl_encrypt(substr($plaintext, 0, -$overflow) . str_repeat("\0", $block_size), $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
$xor = Strings::pop($ciphertext, $block_size);
if ($this->continuousBuffer) {
$encryptIV = $xor;
}
$ciphertext .= Strings::shift($xor, $overflow) ^ substr($plaintext, -$overflow);
if ($this->continuousBuffer) {
$buffer['xor'] = $xor;
}
} else {
$ciphertext = openssl_encrypt($plaintext, $this->cipher_name_openssl, $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $encryptIV);
if ($this->continuousBuffer) {
$encryptIV = substr($ciphertext, -$block_size) ^ substr($plaintext, -$block_size);
}
}
}
return $ciphertext;
}
/**
* phpseclib <-> OpenSSL Mode Mapper
*
* May need to be overwritten by classes extending this one in some cases
*
* @return string
*/
protected function openssl_translate_mode()
{
switch ($this->mode) {
case self::MODE_ECB:
return 'ecb';
case self::MODE_CBC:
return 'cbc';
case self::MODE_CTR:
case self::MODE_GCM:
return 'ctr';
case self::MODE_CFB:
return 'cfb';
case self::MODE_CFB8:
return 'cfb8';
case self::MODE_OFB:
return 'ofb';
}
}
/**
* Pad "packets".
*
* Block ciphers working by encrypting between their specified [$this->]block_size at a time
* If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
* pad the input so that it is of the proper length.
*
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
* transmitted separately)
*
* @see self::disablePadding()
*/
public function enablePadding()
{
$this->padding = true;
}
/**
* Do not pad packets.
*
* @see self::enablePadding()
*/
public function disablePadding()
{
$this->padding = false;
}
/**
* Treat consecutive "packets" as if they are a continuous buffer.
*
* Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
* will yield different outputs:
*
* <code>
* echo $rijndael->encrypt(substr($plaintext, 0, 16));
* echo $rijndael->encrypt(substr($plaintext, 16, 16));
* </code>
* <code>
* echo $rijndael->encrypt($plaintext);
* </code>
*
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
* another, as demonstrated with the following:
*
* <code>
* $rijndael->encrypt(substr($plaintext, 0, 16));
* echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
* </code>
* <code>
* echo $rijndael->decrypt($rijndael->encrypt(substr($plaintext, 16, 16)));
* </code>
*
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
*
* Put another way, when the continuous buffer is enabled, the state of the \phpseclib3\Crypt\*() object changes after each
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
* however, they are also less intuitive and more likely to cause you problems.
*
* {@internal Could, but not must, extend by the child Crypt_* class}
*
* @see self::disableContinuousBuffer()
*/
public function enableContinuousBuffer()
{
if ($this->mode == self::MODE_ECB) {
return;
}
if ($this->mode == self::MODE_GCM) {
throw new \BadMethodCallException('This mode does not run in continuous mode');
}
$this->continuousBuffer = true;
$this->setEngine();
}
/**
* Treat consecutive packets as if they are a discontinuous buffer.
*
* The default behavior.
*
* {@internal Could, but not must, extend by the child Crypt_* class}
*
* @see self::enableContinuousBuffer()
*/
public function disableContinuousBuffer()
{
if ($this->mode == self::MODE_ECB) {
return;
}
if (!$this->continuousBuffer) {
return;
}
$this->continuousBuffer = false;
$this->setEngine();
}
/**
* Test for engine validity
*
* @see self::__construct()
* @param int $engine
* @return bool
*/
protected function isValidEngineHelper($engine)
{
switch ($engine) {
case self::ENGINE_OPENSSL:
$this->openssl_emulate_ctr = false;
$result = $this->cipher_name_openssl &&
extension_loaded('openssl');
if (!$result) {
return false;
}
$methods = openssl_get_cipher_methods();
if (in_array($this->cipher_name_openssl, $methods)) {
return true;
}
// not all of openssl's symmetric cipher's support ctr. for those
// that don't we'll emulate it
switch ($this->mode) {
case self::MODE_CTR:
if (in_array($this->cipher_name_openssl_ecb, $methods)) {
$this->openssl_emulate_ctr = true;
return true;
}
}
return false;
case self::ENGINE_MCRYPT:
set_error_handler(function () {
});
$result = $this->cipher_name_mcrypt &&
extension_loaded('mcrypt') &&
in_array($this->cipher_name_mcrypt, mcrypt_list_algorithms());
restore_error_handler();
return $result;
case self::ENGINE_EVAL:
return method_exists($this, 'setupInlineCrypt');
case self::ENGINE_INTERNAL:
return true;
}
return false;
}
/**
* Test for engine validity
*
* @see self::__construct()
* @param string $engine
* @return bool
*/
public function isValidEngine($engine)
{
static $reverseMap;
if (!isset($reverseMap)) {
$reverseMap = array_map('strtolower', self::ENGINE_MAP);
$reverseMap = array_flip($reverseMap);
}
$engine = strtolower($engine);
if (!isset($reverseMap[$engine])) {
return false;
}
return $this->isValidEngineHelper($reverseMap[$engine]);
}
/**
* Sets the preferred crypt engine
*
* Currently, $engine could be:
*
* - libsodium[very fast]
*
* - OpenSSL [very fast]
*
* - mcrypt [fast]
*
* - Eval [slow]
*
* - PHP [slowest]
*
* If the preferred crypt engine is not available the fastest available one will be used
*
* @see self::__construct()
* @param string $engine
*/
public function setPreferredEngine($engine)
{
static $reverseMap;
if (!isset($reverseMap)) {
$reverseMap = array_map('strtolower', self::ENGINE_MAP);
$reverseMap = array_flip($reverseMap);
}
$engine = is_string($engine) ? strtolower($engine) : '';
$this->preferredEngine = isset($reverseMap[$engine]) ? $reverseMap[$engine] : self::ENGINE_LIBSODIUM;
$this->setEngine();
}
/**
* Returns the engine currently being utilized
*
* @see self::setEngine()
*/
public function getEngine()
{
return self::ENGINE_MAP[$this->engine];
}
/**
* Sets the engine as appropriate
*
* @see self::__construct()
*/
protected function setEngine()
{
$this->engine = null;
$candidateEngines = [
self::ENGINE_LIBSODIUM,
self::ENGINE_OPENSSL_GCM,
self::ENGINE_OPENSSL,
self::ENGINE_MCRYPT,
self::ENGINE_EVAL
];
if (isset($this->preferredEngine)) {
$temp = [$this->preferredEngine];
$candidateEngines = array_merge(
$temp,
array_diff($candidateEngines, $temp)
);
}
foreach ($candidateEngines as $engine) {
if ($this->isValidEngineHelper($engine)) {
$this->engine = $engine;
break;
}
}
if (!$this->engine) {
$this->engine = self::ENGINE_INTERNAL;
}
if ($this->engine != self::ENGINE_MCRYPT && $this->enmcrypt) {
set_error_handler(function () {
});
// Closing the current mcrypt resource(s). _mcryptSetup() will, if needed,
// (re)open them with the module named in $this->cipher_name_mcrypt
mcrypt_module_close($this->enmcrypt);
mcrypt_module_close($this->demcrypt);
$this->enmcrypt = null;
$this->demcrypt = null;
if ($this->ecb) {
mcrypt_module_close($this->ecb);
$this->ecb = null;
}
restore_error_handler();
}
$this->changed = $this->nonIVChanged = true;
}
/**
* Encrypts a block
*
* Note: Must be extended by the child \phpseclib3\Crypt\* class
*
* @param string $in
* @return string
*/
abstract protected function encryptBlock($in);
/**
* Decrypts a block
*
* Note: Must be extended by the child \phpseclib3\Crypt\* class
*
* @param string $in
* @return string
*/
abstract protected function decryptBlock($in);
/**
* Setup the key (expansion)
*
* Only used if $engine == self::ENGINE_INTERNAL
*
* Note: Must extend by the child \phpseclib3\Crypt\* class
*
* @see self::setup()
*/
abstract protected function setupKey();
/**
* Setup the self::ENGINE_INTERNAL $engine
*
* (re)init, if necessary, the internal cipher $engine and flush all $buffers
* Used (only) if $engine == self::ENGINE_INTERNAL
*
* _setup() will be called each time if $changed === true
* typically this happens when using one or more of following public methods:
*
* - setKey()
*
* - setIV()
*
* - disableContinuousBuffer()
*
* - First run of encrypt() / decrypt() with no init-settings
*
* {@internal setup() is always called before en/decryption.}
*
* {@internal Could, but not must, extend by the child Crypt_* class}
*
* @see self::setKey()
* @see self::setIV()
* @see self::disableContinuousBuffer()
*/
protected function setup()
{
if (!$this->changed) {
return;
}
$this->changed = false;
if ($this->usePoly1305 && !isset($this->poly1305Key) && method_exists($this, 'createPoly1305Key')) {
$this->createPoly1305Key();
}
$this->enbuffer = $this->debuffer = ['ciphertext' => '', 'xor' => '', 'pos' => 0, 'enmcrypt_init' => true];
//$this->newtag = $this->oldtag = false;
if ($this->usesNonce()) {
if ($this->nonce === false) {
throw new InsufficientSetupException('No nonce has been defined');
}
if ($this->mode == self::MODE_GCM && !in_array($this->engine, [self::ENGINE_LIBSODIUM, self::ENGINE_OPENSSL_GCM])) {
$this->setupGCM();
}
} else {
$this->iv = $this->origIV;
}
if ($this->iv === false && !in_array($this->mode, [self::MODE_STREAM, self::MODE_ECB])) {
if ($this->mode != self::MODE_GCM || !in_array($this->engine, [self::ENGINE_LIBSODIUM, self::ENGINE_OPENSSL_GCM])) {
throw new InsufficientSetupException('No IV has been defined');
}
}
if ($this->key === false) {
throw new InsufficientSetupException('No key has been defined');
}
$this->encryptIV = $this->decryptIV = $this->iv;
switch ($this->engine) {
case self::ENGINE_MCRYPT:
$this->enchanged = $this->dechanged = true;
set_error_handler(function () {
});
if (!isset($this->enmcrypt)) {
static $mcrypt_modes = [
self::MODE_CTR => 'ctr',
self::MODE_ECB => MCRYPT_MODE_ECB,
self::MODE_CBC => MCRYPT_MODE_CBC,
self::MODE_CFB => 'ncfb',
self::MODE_CFB8 => MCRYPT_MODE_CFB,
self::MODE_OFB => MCRYPT_MODE_NOFB,
self::MODE_OFB8 => MCRYPT_MODE_OFB,
self::MODE_STREAM => MCRYPT_MODE_STREAM,
];
$this->demcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
$this->enmcrypt = mcrypt_module_open($this->cipher_name_mcrypt, '', $mcrypt_modes[$this->mode], '');
// we need the $ecb mcrypt resource (only) in MODE_CFB with enableContinuousBuffer()
// to workaround mcrypt's broken ncfb implementation in buffered mode
// see: {@link http://phpseclib.sourceforge.net/cfb-demo.phps}
if ($this->mode == self::MODE_CFB) {
$this->ecb = mcrypt_module_open($this->cipher_name_mcrypt, '', MCRYPT_MODE_ECB, '');
}
} // else should mcrypt_generic_deinit be called?
if ($this->mode == self::MODE_CFB) {
mcrypt_generic_init($this->ecb, $this->key, str_repeat("\0", $this->block_size));
}
restore_error_handler();
break;
case self::ENGINE_INTERNAL:
$this->setupKey();
break;
case self::ENGINE_EVAL:
if ($this->nonIVChanged) {
$this->setupKey();
$this->setupInlineCrypt();
}
}
$this->nonIVChanged = false;
}
/**
* Pads a string
*
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
* $this->block_size - (strlen($text) % $this->block_size) bytes are added, each of which is equal to
* chr($this->block_size - (strlen($text) % $this->block_size)
*
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
* and padding will, hence forth, be enabled.
*
* @see self::unpad()
* @param string $text
* @throws \LengthException if padding is disabled and the plaintext's length is not a multiple of the block size
* @return string
*/
protected function pad($text)
{
$length = strlen($text);
if (!$this->padding) {
if ($length % $this->block_size == 0) {
return $text;
} else {
throw new \LengthException("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size}). Try enabling padding.");
}
}
$pad = $this->block_size - ($length % $this->block_size);
return str_pad($text, $length + $pad, chr($pad));
}
/**
* Unpads a string.
*
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
* and false will be returned.
*
* @see self::pad()
* @param string $text
* @throws \LengthException if the ciphertext's length is not a multiple of the block size
* @return string
*/
protected function unpad($text)
{
if (!$this->padding) {
return $text;
}
$length = ord($text[strlen($text) - 1]);
if (!$length || $length > $this->block_size) {
throw new BadDecryptionException("The ciphertext has an invalid padding length ($length) compared to the block size ({$this->block_size})");
}
return substr($text, 0, -$length);
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* Stores the created (or existing) callback function-name
* in $this->inline_crypt
*
* Internally for phpseclib developers:
*
* _setupInlineCrypt() would be called only if:
*
* - $this->engine === self::ENGINE_EVAL
*
* - each time on _setup(), after(!) _setupKey()
*
*
* This ensures that _setupInlineCrypt() has always a
* full ready2go initializated internal cipher $engine state
* where, for example, the keys already expanded,
* keys/block_size calculated and such.
*
* It is, each time if called, the responsibility of _setupInlineCrypt():
*
* - to set $this->inline_crypt to a valid and fully working callback function
* as a (faster) replacement for encrypt() / decrypt()
*
* - NOT to create unlimited callback functions (for memory reasons!)
* no matter how often _setupInlineCrypt() would be called. At some
* point of amount they must be generic re-useable.
*
* - the code of _setupInlineCrypt() it self,
* and the generated callback code,
* must be, in following order:
* - 100% safe
* - 100% compatible to encrypt()/decrypt()
* - using only php5+ features/lang-constructs/php-extensions if
* compatibility (down to php4) or fallback is provided
* - readable/maintainable/understandable/commented and... not-cryptic-styled-code :-)
* - >= 10% faster than encrypt()/decrypt() [which is, by the way,
* the reason for the existence of _setupInlineCrypt() :-)]
* - memory-nice
* - short (as good as possible)
*
* Note: - _setupInlineCrypt() is using _createInlineCryptFunction() to create the full callback function code.
* - In case of using inline crypting, _setupInlineCrypt() must extend by the child \phpseclib3\Crypt\* class.
* - The following variable names are reserved:
* - $_* (all variable names prefixed with an underscore)
* - $self (object reference to it self. Do not use $this, but $self instead)
* - $in (the content of $in has to en/decrypt by the generated code)
* - The callback function should not use the 'return' statement, but en/decrypt'ing the content of $in only
*
* {@internal If a Crypt_* class providing inline crypting it must extend _setupInlineCrypt()}
*
* @see self::setup()
* @see self::createInlineCryptFunction()
* @see self::encrypt()
* @see self::decrypt()
*/
//protected function setupInlineCrypt();
/**
* Creates the performance-optimized function for en/decrypt()
*
* Internally for phpseclib developers:
*
* _createInlineCryptFunction():
*
* - merge the $cipher_code [setup'ed by _setupInlineCrypt()]
* with the current [$this->]mode of operation code
*
* - create the $inline function, which called by encrypt() / decrypt()
* as its replacement to speed up the en/decryption operations.
*
* - return the name of the created $inline callback function
*
* - used to speed up en/decryption
*
*
*
* The main reason why can speed up things [up to 50%] this way are:
*
* - using variables more effective then regular.
* (ie no use of expensive arrays but integers $k_0, $k_1 ...
* or even, for example, the pure $key[] values hardcoded)
*
* - avoiding 1000's of function calls of ie _encryptBlock()
* but inlining the crypt operations.
* in the mode of operation for() loop.
*
* - full loop unroll the (sometimes key-dependent) rounds
* avoiding this way ++$i counters and runtime-if's etc...
*
* The basic code architectur of the generated $inline en/decrypt()
* lambda function, in pseudo php, is:
*
* <code>
* +----------------------------------------------------------------------------------------------+
* | callback $inline = create_function: |
* | lambda_function_0001_crypt_ECB($action, $text) |
* | { |
* | INSERT PHP CODE OF: |
* | $cipher_code['init_crypt']; // general init code. |
* | // ie: $sbox'es declarations used for |
* | // encrypt and decrypt'ing. |
* | |
* | switch ($action) { |
* | case 'encrypt': |
* | INSERT PHP CODE OF: |
* | $cipher_code['init_encrypt']; // encrypt sepcific init code. |
* | ie: specified $key or $box |
* | declarations for encrypt'ing. |
* | |
* | foreach ($ciphertext) { |
* | $in = $block_size of $ciphertext; |
* | |
* | INSERT PHP CODE OF: |
* | $cipher_code['encrypt_block']; // encrypt's (string) $in, which is always: |
* | // strlen($in) == $this->block_size |
* | // here comes the cipher algorithm in action |
* | // for encryption. |
* | // $cipher_code['encrypt_block'] has to |
* | // encrypt the content of the $in variable |
* | |
* | $plaintext .= $in; |
* | } |
* | return $plaintext; |
* | |
* | case 'decrypt': |
* | INSERT PHP CODE OF: |
* | $cipher_code['init_decrypt']; // decrypt sepcific init code |
* | ie: specified $key or $box |
* | declarations for decrypt'ing. |
* | foreach ($plaintext) { |
* | $in = $block_size of $plaintext; |
* | |
* | INSERT PHP CODE OF: |
* | $cipher_code['decrypt_block']; // decrypt's (string) $in, which is always |
* | // strlen($in) == $this->block_size |
* | // here comes the cipher algorithm in action |
* | // for decryption. |
* | // $cipher_code['decrypt_block'] has to |
* | // decrypt the content of the $in variable |
* | $ciphertext .= $in; |
* | } |
* | return $ciphertext; |
* | } |
* | } |
* +----------------------------------------------------------------------------------------------+
* </code>
*
* See also the \phpseclib3\Crypt\*::_setupInlineCrypt()'s for
* productive inline $cipher_code's how they works.
*
* Structure of:
* <code>
* $cipher_code = [
* 'init_crypt' => (string) '', // optional
* 'init_encrypt' => (string) '', // optional
* 'init_decrypt' => (string) '', // optional
* 'encrypt_block' => (string) '', // required
* 'decrypt_block' => (string) '' // required
* ];
* </code>
*
* @see self::setupInlineCrypt()
* @see self::encrypt()
* @see self::decrypt()
* @param array $cipher_code
* @return string (the name of the created callback function)
*/
protected function createInlineCryptFunction($cipher_code)
{
$block_size = $this->block_size;
// optional
$init_crypt = isset($cipher_code['init_crypt']) ? $cipher_code['init_crypt'] : '';
$init_encrypt = isset($cipher_code['init_encrypt']) ? $cipher_code['init_encrypt'] : '';
$init_decrypt = isset($cipher_code['init_decrypt']) ? $cipher_code['init_decrypt'] : '';
// required
$encrypt_block = $cipher_code['encrypt_block'];
$decrypt_block = $cipher_code['decrypt_block'];
// Generating mode of operation inline code,
// merged with the $cipher_code algorithm
// for encrypt- and decryption.
switch ($this->mode) {
case self::MODE_ECB:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_plaintext_len = strlen($_text);
for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
$in = substr($_text, $_i, ' . $block_size . ');
' . $encrypt_block . '
$_ciphertext.= $in;
}
return $_ciphertext;
';
$decrypt = $init_decrypt . '
$_plaintext = "";
$_text = str_pad($_text, strlen($_text) + (' . $block_size . ' - strlen($_text) % ' . $block_size . ') % ' . $block_size . ', chr(0));
$_ciphertext_len = strlen($_text);
for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
$in = substr($_text, $_i, ' . $block_size . ');
' . $decrypt_block . '
$_plaintext.= $in;
}
return $this->unpad($_plaintext);
';
break;
case self::MODE_CTR:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_plaintext_len = strlen($_text);
$_xor = $this->encryptIV;
$_buffer = &$this->enbuffer;
if (strlen($_buffer["ciphertext"])) {
for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
$_block = substr($_text, $_i, ' . $block_size . ');
if (strlen($_block) > strlen($_buffer["ciphertext"])) {
$in = $_xor;
' . $encrypt_block . '
\phpseclib3\Common\Functions\Strings::increment_str($_xor);
$_buffer["ciphertext"].= $in;
}
$_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["ciphertext"], ' . $block_size . ');
$_ciphertext.= $_block ^ $_key;
}
} else {
for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
$_block = substr($_text, $_i, ' . $block_size . ');
$in = $_xor;
' . $encrypt_block . '
\phpseclib3\Common\Functions\Strings::increment_str($_xor);
$_key = $in;
$_ciphertext.= $_block ^ $_key;
}
}
if ($this->continuousBuffer) {
$this->encryptIV = $_xor;
if ($_start = $_plaintext_len % ' . $block_size . ') {
$_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
}
}
return $_ciphertext;
';
$decrypt = $init_encrypt . '
$_plaintext = "";
$_ciphertext_len = strlen($_text);
$_xor = $this->decryptIV;
$_buffer = &$this->debuffer;
if (strlen($_buffer["ciphertext"])) {
for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
$_block = substr($_text, $_i, ' . $block_size . ');
if (strlen($_block) > strlen($_buffer["ciphertext"])) {
$in = $_xor;
' . $encrypt_block . '
\phpseclib3\Common\Functions\Strings::increment_str($_xor);
$_buffer["ciphertext"].= $in;
}
$_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["ciphertext"], ' . $block_size . ');
$_plaintext.= $_block ^ $_key;
}
} else {
for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
$_block = substr($_text, $_i, ' . $block_size . ');
$in = $_xor;
' . $encrypt_block . '
\phpseclib3\Common\Functions\Strings::increment_str($_xor);
$_key = $in;
$_plaintext.= $_block ^ $_key;
}
}
if ($this->continuousBuffer) {
$this->decryptIV = $_xor;
if ($_start = $_ciphertext_len % ' . $block_size . ') {
$_buffer["ciphertext"] = substr($_key, $_start) . $_buffer["ciphertext"];
}
}
return $_plaintext;
';
break;
case self::MODE_CFB:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_buffer = &$this->enbuffer;
if ($this->continuousBuffer) {
$_iv = &$this->encryptIV;
$_pos = &$_buffer["pos"];
} else {
$_iv = $this->encryptIV;
$_pos = 0;
}
$_len = strlen($_text);
$_i = 0;
if ($_pos) {
$_orig_pos = $_pos;
$_max = ' . $block_size . ' - $_pos;
if ($_len >= $_max) {
$_i = $_max;
$_len-= $_max;
$_pos = 0;
} else {
$_i = $_len;
$_pos+= $_len;
$_len = 0;
}
$_ciphertext = substr($_iv, $_orig_pos) ^ $_text;
$_iv = substr_replace($_iv, $_ciphertext, $_orig_pos, $_i);
}
while ($_len >= ' . $block_size . ') {
$in = $_iv;
' . $encrypt_block . ';
$_iv = $in ^ substr($_text, $_i, ' . $block_size . ');
$_ciphertext.= $_iv;
$_len-= ' . $block_size . ';
$_i+= ' . $block_size . ';
}
if ($_len) {
$in = $_iv;
' . $encrypt_block . '
$_iv = $in;
$_block = $_iv ^ substr($_text, $_i);
$_iv = substr_replace($_iv, $_block, 0, $_len);
$_ciphertext.= $_block;
$_pos = $_len;
}
return $_ciphertext;
';
$decrypt = $init_encrypt . '
$_plaintext = "";
$_buffer = &$this->debuffer;
if ($this->continuousBuffer) {
$_iv = &$this->decryptIV;
$_pos = &$_buffer["pos"];
} else {
$_iv = $this->decryptIV;
$_pos = 0;
}
$_len = strlen($_text);
$_i = 0;
if ($_pos) {
$_orig_pos = $_pos;
$_max = ' . $block_size . ' - $_pos;
if ($_len >= $_max) {
$_i = $_max;
$_len-= $_max;
$_pos = 0;
} else {
$_i = $_len;
$_pos+= $_len;
$_len = 0;
}
$_plaintext = substr($_iv, $_orig_pos) ^ $_text;
$_iv = substr_replace($_iv, substr($_text, 0, $_i), $_orig_pos, $_i);
}
while ($_len >= ' . $block_size . ') {
$in = $_iv;
' . $encrypt_block . '
$_iv = $in;
$cb = substr($_text, $_i, ' . $block_size . ');
$_plaintext.= $_iv ^ $cb;
$_iv = $cb;
$_len-= ' . $block_size . ';
$_i+= ' . $block_size . ';
}
if ($_len) {
$in = $_iv;
' . $encrypt_block . '
$_iv = $in;
$_plaintext.= $_iv ^ substr($_text, $_i);
$_iv = substr_replace($_iv, substr($_text, $_i), 0, $_len);
$_pos = $_len;
}
return $_plaintext;
';
break;
case self::MODE_CFB8:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_len = strlen($_text);
$_iv = $this->encryptIV;
for ($_i = 0; $_i < $_len; ++$_i) {
$in = $_iv;
' . $encrypt_block . '
$_ciphertext .= ($_c = $_text[$_i] ^ $in);
$_iv = substr($_iv, 1) . $_c;
}
if ($this->continuousBuffer) {
if ($_len >= ' . $block_size . ') {
$this->encryptIV = substr($_ciphertext, -' . $block_size . ');
} else {
$this->encryptIV = substr($this->encryptIV, $_len - ' . $block_size . ') . substr($_ciphertext, -$_len);
}
}
return $_ciphertext;
';
$decrypt = $init_encrypt . '
$_plaintext = "";
$_len = strlen($_text);
$_iv = $this->decryptIV;
for ($_i = 0; $_i < $_len; ++$_i) {
$in = $_iv;
' . $encrypt_block . '
$_plaintext .= $_text[$_i] ^ $in;
$_iv = substr($_iv, 1) . $_text[$_i];
}
if ($this->continuousBuffer) {
if ($_len >= ' . $block_size . ') {
$this->decryptIV = substr($_text, -' . $block_size . ');
} else {
$this->decryptIV = substr($this->decryptIV, $_len - ' . $block_size . ') . substr($_text, -$_len);
}
}
return $_plaintext;
';
break;
case self::MODE_OFB8:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_len = strlen($_text);
$_iv = $this->encryptIV;
for ($_i = 0; $_i < $_len; ++$_i) {
$in = $_iv;
' . $encrypt_block . '
$_ciphertext.= $_text[$_i] ^ $in;
$_iv = substr($_iv, 1) . $in[0];
}
if ($this->continuousBuffer) {
$this->encryptIV = $_iv;
}
return $_ciphertext;
';
$decrypt = $init_encrypt . '
$_plaintext = "";
$_len = strlen($_text);
$_iv = $this->decryptIV;
for ($_i = 0; $_i < $_len; ++$_i) {
$in = $_iv;
' . $encrypt_block . '
$_plaintext.= $_text[$_i] ^ $in;
$_iv = substr($_iv, 1) . $in[0];
}
if ($this->continuousBuffer) {
$this->decryptIV = $_iv;
}
return $_plaintext;
';
break;
case self::MODE_OFB:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_plaintext_len = strlen($_text);
$_xor = $this->encryptIV;
$_buffer = &$this->enbuffer;
if (strlen($_buffer["xor"])) {
for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
$_block = substr($_text, $_i, ' . $block_size . ');
if (strlen($_block) > strlen($_buffer["xor"])) {
$in = $_xor;
' . $encrypt_block . '
$_xor = $in;
$_buffer["xor"].= $_xor;
}
$_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["xor"], ' . $block_size . ');
$_ciphertext.= $_block ^ $_key;
}
} else {
for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
$in = $_xor;
' . $encrypt_block . '
$_xor = $in;
$_ciphertext.= substr($_text, $_i, ' . $block_size . ') ^ $_xor;
}
$_key = $_xor;
}
if ($this->continuousBuffer) {
$this->encryptIV = $_xor;
if ($_start = $_plaintext_len % ' . $block_size . ') {
$_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
}
}
return $_ciphertext;
';
$decrypt = $init_encrypt . '
$_plaintext = "";
$_ciphertext_len = strlen($_text);
$_xor = $this->decryptIV;
$_buffer = &$this->debuffer;
if (strlen($_buffer["xor"])) {
for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
$_block = substr($_text, $_i, ' . $block_size . ');
if (strlen($_block) > strlen($_buffer["xor"])) {
$in = $_xor;
' . $encrypt_block . '
$_xor = $in;
$_buffer["xor"].= $_xor;
}
$_key = \phpseclib3\Common\Functions\Strings::shift($_buffer["xor"], ' . $block_size . ');
$_plaintext.= $_block ^ $_key;
}
} else {
for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
$in = $_xor;
' . $encrypt_block . '
$_xor = $in;
$_plaintext.= substr($_text, $_i, ' . $block_size . ') ^ $_xor;
}
$_key = $_xor;
}
if ($this->continuousBuffer) {
$this->decryptIV = $_xor;
if ($_start = $_ciphertext_len % ' . $block_size . ') {
$_buffer["xor"] = substr($_key, $_start) . $_buffer["xor"];
}
}
return $_plaintext;
';
break;
case self::MODE_STREAM:
$encrypt = $init_encrypt . '
$_ciphertext = "";
' . $encrypt_block . '
return $_ciphertext;
';
$decrypt = $init_decrypt . '
$_plaintext = "";
' . $decrypt_block . '
return $_plaintext;
';
break;
// case self::MODE_CBC:
default:
$encrypt = $init_encrypt . '
$_ciphertext = "";
$_plaintext_len = strlen($_text);
$in = $this->encryptIV;
for ($_i = 0; $_i < $_plaintext_len; $_i+= ' . $block_size . ') {
$in = substr($_text, $_i, ' . $block_size . ') ^ $in;
' . $encrypt_block . '
$_ciphertext.= $in;
}
if ($this->continuousBuffer) {
$this->encryptIV = $in;
}
return $_ciphertext;
';
$decrypt = $init_decrypt . '
$_plaintext = "";
$_text = str_pad($_text, strlen($_text) + (' . $block_size . ' - strlen($_text) % ' . $block_size . ') % ' . $block_size . ', chr(0));
$_ciphertext_len = strlen($_text);
$_iv = $this->decryptIV;
for ($_i = 0; $_i < $_ciphertext_len; $_i+= ' . $block_size . ') {
$in = $_block = substr($_text, $_i, ' . $block_size . ');
' . $decrypt_block . '
$_plaintext.= $in ^ $_iv;
$_iv = $_block;
}
if ($this->continuousBuffer) {
$this->decryptIV = $_iv;
}
return $this->unpad($_plaintext);
';
break;
}
// Before discrediting this, please read the following:
// @see https://github.com/phpseclib/phpseclib/issues/1293
// @see https://github.com/phpseclib/phpseclib/pull/1143
eval('$func = function ($_action, $_text) { ' . $init_crypt . 'if ($_action == "encrypt") { ' . $encrypt . ' } else { ' . $decrypt . ' }};');
return \Closure::bind($func, $this, static::class);
}
/**
* Convert float to int
*
* On ARM CPUs converting floats to ints doesn't always work
*
* @param string $x
* @return int
*/
protected static function safe_intval($x)
{
if (is_int($x)) {
return $x;
}
if (self::$use_reg_intval) {
return PHP_INT_SIZE == 4 && PHP_VERSION_ID >= 80100 ? intval($x) : $x;
}
return (fmod($x, 0x80000000) & 0x7FFFFFFF) |
((fmod(floor($x / 0x80000000), 2) & 1) << 31);
}
/**
* eval()'able string for in-line float to int
*
* @return string
*/
protected static function safe_intval_inline()
{
if (self::$use_reg_intval) {
return PHP_INT_SIZE == 4 && PHP_VERSION_ID >= 80100 ? 'intval(%s)' : '%s';
}
$safeint = '(is_int($temp = %s) ? $temp : (fmod($temp, 0x80000000) & 0x7FFFFFFF) | ';
return $safeint . '((fmod(floor($temp / 0x80000000), 2) & 1) << 31))';
}
/**
* Sets up GCM parameters
*
* See steps 1-2 of https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=23
* for more info
*
*/
private function setupGCM()
{
// don't keep on re-calculating $this->h
if (!$this->h || $this->hKey != $this->key) {
$cipher = new static('ecb');
$cipher->setKey($this->key);
$cipher->disablePadding();
$this->h = self::$gcmField->newInteger(
Strings::switchEndianness($cipher->encrypt("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"))
);
$this->hKey = $this->key;
}
if (strlen($this->nonce) == 12) {
$this->iv = $this->nonce . "\0\0\0\1";
} else {
$this->iv = $this->ghash(
self::nullPad128($this->nonce) . str_repeat("\0", 8) . self::len64($this->nonce)
);
}
}
/**
* Performs GHASH operation
*
* See https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=20
* for more info
*
* @see self::decrypt()
* @see self::encrypt()
* @param string $x
* @return string
*/
private function ghash($x)
{
$h = $this->h;
$y = ["\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"];
$x = str_split($x, 16);
$n = 0;
// the switchEndianness calls are necessary because the multiplication algorithm in BinaryField/Integer
// interprets strings as polynomials in big endian order whereas in GCM they're interpreted in little
// endian order per https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf#page=19.
// big endian order is what binary field elliptic curves use per http://www.secg.org/sec1-v2.pdf#page=18.
// we could switchEndianness here instead of in the while loop but doing so in the while loop seems like it
// might be slightly more performant
//$x = Strings::switchEndianness($x);
foreach ($x as $xn) {
$xn = Strings::switchEndianness($xn);
$t = $y[$n] ^ $xn;
$temp = self::$gcmField->newInteger($t);
$y[++$n] = $temp->multiply($h)->toBytes();
$y[$n] = substr($y[$n], 1);
}
$y[$n] = Strings::switchEndianness($y[$n]);
return $y[$n];
}
/**
* Returns the bit length of a string in a packed format
*
* @see self::decrypt()
* @see self::encrypt()
* @see self::setupGCM()
* @param string $str
* @return string
*/
private static function len64($str)
{
return "\0\0\0\0" . pack('N', 8 * strlen($str));
}
/**
* NULL pads a string to be a multiple of 128
*
* @see self::decrypt()
* @see self::encrypt()
* @see self::setupGCM()
* @param string $str
* @return string
*/
protected static function nullPad128($str)
{
$len = strlen($str);
return $str . str_repeat("\0", 16 * ceil($len / 16) - $len);
}
/**
* Calculates Poly1305 MAC
*
* On my system ChaCha20, with libsodium, takes 0.5s. With this custom Poly1305 implementation
* it takes 1.2s.
*
* @see self::decrypt()
* @see self::encrypt()
* @param string $text
* @return string
*/
protected function poly1305($text)
{
$s = $this->poly1305Key; // strlen($this->poly1305Key) == 32
$r = Strings::shift($s, 16);
$r = strrev($r);
$r &= "\x0f\xff\xff\xfc\x0f\xff\xff\xfc\x0f\xff\xff\xfc\x0f\xff\xff\xff";
$s = strrev($s);
$r = self::$poly1305Field->newInteger(new BigInteger($r, 256));
$s = self::$poly1305Field->newInteger(new BigInteger($s, 256));
$a = self::$poly1305Field->newInteger(new BigInteger());
$blocks = str_split($text, 16);
foreach ($blocks as $block) {
$n = strrev($block . chr(1));
$n = self::$poly1305Field->newInteger(new BigInteger($n, 256));
$a = $a->add($n);
$a = $a->multiply($r);
}
$r = $a->toBigInteger()->add($s->toBigInteger());
$mask = "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF";
return strrev($r->toBytes()) & $mask;
}
/**
* Return the mode
*
* You can do $obj instanceof AES or whatever to get the cipher but you can't do that to get the mode
*
* @return string
*/
public function getMode()
{
return array_flip(self::MODE_MAP)[$this->mode];
}
/**
* Is the continuous buffer enabled?
*
* @return boolean
*/
public function continuousBufferEnabled()
{
return $this->continuousBuffer;
}
}
<?php
/**
* Fingerprint Trait for Public Keys
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\Common\Traits;
use phpseclib3\Crypt\Hash;
/**
* Fingerprint Trait for Private Keys
*
* @author Jim Wigginton <terrafrost@php.net>
*/
trait Fingerprint
{
/**
* Returns the public key's fingerprint
*
* The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is
* no public key currently loaded, false is returned.
* Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716)
*
* @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
* for invalid values.
* @return mixed
*/
public function getFingerprint($algorithm = 'md5')
{
$type = self::validatePlugin('Keys', 'OpenSSH', 'savePublicKey');
if ($type === false) {
return false;
}
$key = $this->toString('OpenSSH', ['binary' => true]);
if ($key === false) {
return false;
}
switch ($algorithm) {
case 'sha256':
$hash = new Hash('sha256');
$base = base64_encode($hash->hash($key));
return substr($base, 0, strlen($base) - 1);
case 'md5':
return substr(chunk_split(md5($key), 2, ':'), 0, -1);
default:
return false;
}
}
}
<?php
/**
* Password Protected Trait for Private Keys
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\Common\Traits;
/**
* Password Protected Trait for Private Keys
*
* @author Jim Wigginton <terrafrost@php.net>
*/
trait PasswordProtected
{
/**
* Password
*
* @var string|bool
*/
private $password = false;
/**
* Sets the password
*
* Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
* Or rather, pass in $password such that empty($password) && !is_string($password) is true.
*
* @see self::createKey()
* @see self::load()
* @param string|bool $password
*/
public function withPassword($password = false)
{
$new = clone $this;
$new->password = $password;
return $new;
}
}
<?php
/**
* Pure-PHP implementation of DES.
*
* Uses mcrypt, if available, and an internal implementation, otherwise.
*
* PHP version 5
*
* Useful resources are as follows:
*
* - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
* - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
* - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
*
* Here's a short example of how to use this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* $des = new \phpseclib3\Crypt\DES('ctr');
*
* $des->setKey('abcdefgh');
*
* $size = 10 * 1024;
* $plaintext = '';
* for ($i = 0; $i < $size; $i++) {
* $plaintext.= 'a';
* }
*
* echo $des->decrypt($des->encrypt($plaintext));
* ?>
* </code>
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2007 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt;
use phpseclib3\Crypt\Common\BlockCipher;
use phpseclib3\Exception\BadModeException;
/**
* Pure-PHP implementation of DES.
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class DES extends BlockCipher
{
/**
* Contains $keys[self::ENCRYPT]
*
* @see \phpseclib3\Crypt\DES::setupKey()
* @see \phpseclib3\Crypt\DES::processBlock()
*/
const ENCRYPT = 0;
/**
* Contains $keys[self::DECRYPT]
*
* @see \phpseclib3\Crypt\DES::setupKey()
* @see \phpseclib3\Crypt\DES::processBlock()
*/
const DECRYPT = 1;
/**
* Block Length of the cipher
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::block_size
* @var int
*/
protected $block_size = 8;
/**
* Key Length (in bytes)
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::setKeyLength()
* @var int
*/
protected $key_length = 8;
/**
* The mcrypt specific name of the cipher
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::cipher_name_mcrypt
* @var string
*/
protected $cipher_name_mcrypt = 'des';
/**
* The OpenSSL names of the cipher / modes
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::openssl_mode_names
* @var array
*/
protected $openssl_mode_names = [
self::MODE_ECB => 'des-ecb',
self::MODE_CBC => 'des-cbc',
self::MODE_CFB => 'des-cfb',
self::MODE_OFB => 'des-ofb'
// self::MODE_CTR is undefined for DES
];
/**
* Optimizing value while CFB-encrypting
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::cfb_init_len
* @var int
*/
protected $cfb_init_len = 500;
/**
* Switch for DES/3DES encryption
*
* Used only if $engine == self::ENGINE_INTERNAL
*
* @see self::setupKey()
* @see self::processBlock()
* @var int
*/
protected $des_rounds = 1;
/**
* max possible size of $key
*
* @see self::setKey()
* @var string
*/
protected $key_length_max = 8;
/**
* The Key Schedule
*
* @see self::setupKey()
* @var array
*/
private $keys;
/**
* Key Cache "key"
*
* @see self::setupKey()
* @var array
*/
private $kl;
/**
* Shuffle table.
*
* For each byte value index, the entry holds an 8-byte string
* with each byte containing all bits in the same state as the
* corresponding bit in the index value.
*
* @see self::processBlock()
* @see self::setupKey()
* @var array
*/
protected static $shuffle = [
"\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\xFF",
"\x00\x00\x00\x00\x00\x00\xFF\x00", "\x00\x00\x00\x00\x00\x00\xFF\xFF",
"\x00\x00\x00\x00\x00\xFF\x00\x00", "\x00\x00\x00\x00\x00\xFF\x00\xFF",
"\x00\x00\x00\x00\x00\xFF\xFF\x00", "\x00\x00\x00\x00\x00\xFF\xFF\xFF",
"\x00\x00\x00\x00\xFF\x00\x00\x00", "\x00\x00\x00\x00\xFF\x00\x00\xFF",
"\x00\x00\x00\x00\xFF\x00\xFF\x00", "\x00\x00\x00\x00\xFF\x00\xFF\xFF",
"\x00\x00\x00\x00\xFF\xFF\x00\x00", "\x00\x00\x00\x00\xFF\xFF\x00\xFF",
"\x00\x00\x00\x00\xFF\xFF\xFF\x00", "\x00\x00\x00\x00\xFF\xFF\xFF\xFF",
"\x00\x00\x00\xFF\x00\x00\x00\x00", "\x00\x00\x00\xFF\x00\x00\x00\xFF",
"\x00\x00\x00\xFF\x00\x00\xFF\x00", "\x00\x00\x00\xFF\x00\x00\xFF\xFF",
"\x00\x00\x00\xFF\x00\xFF\x00\x00", "\x00\x00\x00\xFF\x00\xFF\x00\xFF",
"\x00\x00\x00\xFF\x00\xFF\xFF\x00", "\x00\x00\x00\xFF\x00\xFF\xFF\xFF",
"\x00\x00\x00\xFF\xFF\x00\x00\x00", "\x00\x00\x00\xFF\xFF\x00\x00\xFF",
"\x00\x00\x00\xFF\xFF\x00\xFF\x00", "\x00\x00\x00\xFF\xFF\x00\xFF\xFF",
"\x00\x00\x00\xFF\xFF\xFF\x00\x00", "\x00\x00\x00\xFF\xFF\xFF\x00\xFF",
"\x00\x00\x00\xFF\xFF\xFF\xFF\x00", "\x00\x00\x00\xFF\xFF\xFF\xFF\xFF",
"\x00\x00\xFF\x00\x00\x00\x00\x00", "\x00\x00\xFF\x00\x00\x00\x00\xFF",
"\x00\x00\xFF\x00\x00\x00\xFF\x00", "\x00\x00\xFF\x00\x00\x00\xFF\xFF",
"\x00\x00\xFF\x00\x00\xFF\x00\x00", "\x00\x00\xFF\x00\x00\xFF\x00\xFF",
"\x00\x00\xFF\x00\x00\xFF\xFF\x00", "\x00\x00\xFF\x00\x00\xFF\xFF\xFF",
"\x00\x00\xFF\x00\xFF\x00\x00\x00", "\x00\x00\xFF\x00\xFF\x00\x00\xFF",
"\x00\x00\xFF\x00\xFF\x00\xFF\x00", "\x00\x00\xFF\x00\xFF\x00\xFF\xFF",
"\x00\x00\xFF\x00\xFF\xFF\x00\x00", "\x00\x00\xFF\x00\xFF\xFF\x00\xFF",
"\x00\x00\xFF\x00\xFF\xFF\xFF\x00", "\x00\x00\xFF\x00\xFF\xFF\xFF\xFF",
"\x00\x00\xFF\xFF\x00\x00\x00\x00", "\x00\x00\xFF\xFF\x00\x00\x00\xFF",
"\x00\x00\xFF\xFF\x00\x00\xFF\x00", "\x00\x00\xFF\xFF\x00\x00\xFF\xFF",
"\x00\x00\xFF\xFF\x00\xFF\x00\x00", "\x00\x00\xFF\xFF\x00\xFF\x00\xFF",
"\x00\x00\xFF\xFF\x00\xFF\xFF\x00", "\x00\x00\xFF\xFF\x00\xFF\xFF\xFF",
"\x00\x00\xFF\xFF\xFF\x00\x00\x00", "\x00\x00\xFF\xFF\xFF\x00\x00\xFF",
"\x00\x00\xFF\xFF\xFF\x00\xFF\x00", "\x00\x00\xFF\xFF\xFF\x00\xFF\xFF",
"\x00\x00\xFF\xFF\xFF\xFF\x00\x00", "\x00\x00\xFF\xFF\xFF\xFF\x00\xFF",
"\x00\x00\xFF\xFF\xFF\xFF\xFF\x00", "\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF",
"\x00\xFF\x00\x00\x00\x00\x00\x00", "\x00\xFF\x00\x00\x00\x00\x00\xFF",
"\x00\xFF\x00\x00\x00\x00\xFF\x00", "\x00\xFF\x00\x00\x00\x00\xFF\xFF",
"\x00\xFF\x00\x00\x00\xFF\x00\x00", "\x00\xFF\x00\x00\x00\xFF\x00\xFF",
"\x00\xFF\x00\x00\x00\xFF\xFF\x00", "\x00\xFF\x00\x00\x00\xFF\xFF\xFF",
"\x00\xFF\x00\x00\xFF\x00\x00\x00", "\x00\xFF\x00\x00\xFF\x00\x00\xFF",
"\x00\xFF\x00\x00\xFF\x00\xFF\x00", "\x00\xFF\x00\x00\xFF\x00\xFF\xFF",
"\x00\xFF\x00\x00\xFF\xFF\x00\x00", "\x00\xFF\x00\x00\xFF\xFF\x00\xFF",
"\x00\xFF\x00\x00\xFF\xFF\xFF\x00", "\x00\xFF\x00\x00\xFF\xFF\xFF\xFF",
"\x00\xFF\x00\xFF\x00\x00\x00\x00", "\x00\xFF\x00\xFF\x00\x00\x00\xFF",
"\x00\xFF\x00\xFF\x00\x00\xFF\x00", "\x00\xFF\x00\xFF\x00\x00\xFF\xFF",
"\x00\xFF\x00\xFF\x00\xFF\x00\x00", "\x00\xFF\x00\xFF\x00\xFF\x00\xFF",
"\x00\xFF\x00\xFF\x00\xFF\xFF\x00", "\x00\xFF\x00\xFF\x00\xFF\xFF\xFF",
"\x00\xFF\x00\xFF\xFF\x00\x00\x00", "\x00\xFF\x00\xFF\xFF\x00\x00\xFF",
"\x00\xFF\x00\xFF\xFF\x00\xFF\x00", "\x00\xFF\x00\xFF\xFF\x00\xFF\xFF",
"\x00\xFF\x00\xFF\xFF\xFF\x00\x00", "\x00\xFF\x00\xFF\xFF\xFF\x00\xFF",
"\x00\xFF\x00\xFF\xFF\xFF\xFF\x00", "\x00\xFF\x00\xFF\xFF\xFF\xFF\xFF",
"\x00\xFF\xFF\x00\x00\x00\x00\x00", "\x00\xFF\xFF\x00\x00\x00\x00\xFF",
"\x00\xFF\xFF\x00\x00\x00\xFF\x00", "\x00\xFF\xFF\x00\x00\x00\xFF\xFF",
"\x00\xFF\xFF\x00\x00\xFF\x00\x00", "\x00\xFF\xFF\x00\x00\xFF\x00\xFF",
"\x00\xFF\xFF\x00\x00\xFF\xFF\x00", "\x00\xFF\xFF\x00\x00\xFF\xFF\xFF",
"\x00\xFF\xFF\x00\xFF\x00\x00\x00", "\x00\xFF\xFF\x00\xFF\x00\x00\xFF",
"\x00\xFF\xFF\x00\xFF\x00\xFF\x00", "\x00\xFF\xFF\x00\xFF\x00\xFF\xFF",
"\x00\xFF\xFF\x00\xFF\xFF\x00\x00", "\x00\xFF\xFF\x00\xFF\xFF\x00\xFF",
"\x00\xFF\xFF\x00\xFF\xFF\xFF\x00", "\x00\xFF\xFF\x00\xFF\xFF\xFF\xFF",
"\x00\xFF\xFF\xFF\x00\x00\x00\x00", "\x00\xFF\xFF\xFF\x00\x00\x00\xFF",
"\x00\xFF\xFF\xFF\x00\x00\xFF\x00", "\x00\xFF\xFF\xFF\x00\x00\xFF\xFF",
"\x00\xFF\xFF\xFF\x00\xFF\x00\x00", "\x00\xFF\xFF\xFF\x00\xFF\x00\xFF",
"\x00\xFF\xFF\xFF\x00\xFF\xFF\x00", "\x00\xFF\xFF\xFF\x00\xFF\xFF\xFF",
"\x00\xFF\xFF\xFF\xFF\x00\x00\x00", "\x00\xFF\xFF\xFF\xFF\x00\x00\xFF",
"\x00\xFF\xFF\xFF\xFF\x00\xFF\x00", "\x00\xFF\xFF\xFF\xFF\x00\xFF\xFF",
"\x00\xFF\xFF\xFF\xFF\xFF\x00\x00", "\x00\xFF\xFF\xFF\xFF\xFF\x00\xFF",
"\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
"\xFF\x00\x00\x00\x00\x00\x00\x00", "\xFF\x00\x00\x00\x00\x00\x00\xFF",
"\xFF\x00\x00\x00\x00\x00\xFF\x00", "\xFF\x00\x00\x00\x00\x00\xFF\xFF",
"\xFF\x00\x00\x00\x00\xFF\x00\x00", "\xFF\x00\x00\x00\x00\xFF\x00\xFF",
"\xFF\x00\x00\x00\x00\xFF\xFF\x00", "\xFF\x00\x00\x00\x00\xFF\xFF\xFF",
"\xFF\x00\x00\x00\xFF\x00\x00\x00", "\xFF\x00\x00\x00\xFF\x00\x00\xFF",
"\xFF\x00\x00\x00\xFF\x00\xFF\x00", "\xFF\x00\x00\x00\xFF\x00\xFF\xFF",
"\xFF\x00\x00\x00\xFF\xFF\x00\x00", "\xFF\x00\x00\x00\xFF\xFF\x00\xFF",
"\xFF\x00\x00\x00\xFF\xFF\xFF\x00", "\xFF\x00\x00\x00\xFF\xFF\xFF\xFF",
"\xFF\x00\x00\xFF\x00\x00\x00\x00", "\xFF\x00\x00\xFF\x00\x00\x00\xFF",
"\xFF\x00\x00\xFF\x00\x00\xFF\x00", "\xFF\x00\x00\xFF\x00\x00\xFF\xFF",
"\xFF\x00\x00\xFF\x00\xFF\x00\x00", "\xFF\x00\x00\xFF\x00\xFF\x00\xFF",
"\xFF\x00\x00\xFF\x00\xFF\xFF\x00", "\xFF\x00\x00\xFF\x00\xFF\xFF\xFF",
"\xFF\x00\x00\xFF\xFF\x00\x00\x00", "\xFF\x00\x00\xFF\xFF\x00\x00\xFF",
"\xFF\x00\x00\xFF\xFF\x00\xFF\x00", "\xFF\x00\x00\xFF\xFF\x00\xFF\xFF",
"\xFF\x00\x00\xFF\xFF\xFF\x00\x00", "\xFF\x00\x00\xFF\xFF\xFF\x00\xFF",
"\xFF\x00\x00\xFF\xFF\xFF\xFF\x00", "\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF",
"\xFF\x00\xFF\x00\x00\x00\x00\x00", "\xFF\x00\xFF\x00\x00\x00\x00\xFF",
"\xFF\x00\xFF\x00\x00\x00\xFF\x00", "\xFF\x00\xFF\x00\x00\x00\xFF\xFF",
"\xFF\x00\xFF\x00\x00\xFF\x00\x00", "\xFF\x00\xFF\x00\x00\xFF\x00\xFF",
"\xFF\x00\xFF\x00\x00\xFF\xFF\x00", "\xFF\x00\xFF\x00\x00\xFF\xFF\xFF",
"\xFF\x00\xFF\x00\xFF\x00\x00\x00", "\xFF\x00\xFF\x00\xFF\x00\x00\xFF",
"\xFF\x00\xFF\x00\xFF\x00\xFF\x00", "\xFF\x00\xFF\x00\xFF\x00\xFF\xFF",
"\xFF\x00\xFF\x00\xFF\xFF\x00\x00", "\xFF\x00\xFF\x00\xFF\xFF\x00\xFF",
"\xFF\x00\xFF\x00\xFF\xFF\xFF\x00", "\xFF\x00\xFF\x00\xFF\xFF\xFF\xFF",
"\xFF\x00\xFF\xFF\x00\x00\x00\x00", "\xFF\x00\xFF\xFF\x00\x00\x00\xFF",
"\xFF\x00\xFF\xFF\x00\x00\xFF\x00", "\xFF\x00\xFF\xFF\x00\x00\xFF\xFF",
"\xFF\x00\xFF\xFF\x00\xFF\x00\x00", "\xFF\x00\xFF\xFF\x00\xFF\x00\xFF",
"\xFF\x00\xFF\xFF\x00\xFF\xFF\x00", "\xFF\x00\xFF\xFF\x00\xFF\xFF\xFF",
"\xFF\x00\xFF\xFF\xFF\x00\x00\x00", "\xFF\x00\xFF\xFF\xFF\x00\x00\xFF",
"\xFF\x00\xFF\xFF\xFF\x00\xFF\x00", "\xFF\x00\xFF\xFF\xFF\x00\xFF\xFF",
"\xFF\x00\xFF\xFF\xFF\xFF\x00\x00", "\xFF\x00\xFF\xFF\xFF\xFF\x00\xFF",
"\xFF\x00\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\x00\xFF\xFF\xFF\xFF\xFF\xFF",
"\xFF\xFF\x00\x00\x00\x00\x00\x00", "\xFF\xFF\x00\x00\x00\x00\x00\xFF",
"\xFF\xFF\x00\x00\x00\x00\xFF\x00", "\xFF\xFF\x00\x00\x00\x00\xFF\xFF",
"\xFF\xFF\x00\x00\x00\xFF\x00\x00", "\xFF\xFF\x00\x00\x00\xFF\x00\xFF",
"\xFF\xFF\x00\x00\x00\xFF\xFF\x00", "\xFF\xFF\x00\x00\x00\xFF\xFF\xFF",
"\xFF\xFF\x00\x00\xFF\x00\x00\x00", "\xFF\xFF\x00\x00\xFF\x00\x00\xFF",
"\xFF\xFF\x00\x00\xFF\x00\xFF\x00", "\xFF\xFF\x00\x00\xFF\x00\xFF\xFF",
"\xFF\xFF\x00\x00\xFF\xFF\x00\x00", "\xFF\xFF\x00\x00\xFF\xFF\x00\xFF",
"\xFF\xFF\x00\x00\xFF\xFF\xFF\x00", "\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF",
"\xFF\xFF\x00\xFF\x00\x00\x00\x00", "\xFF\xFF\x00\xFF\x00\x00\x00\xFF",
"\xFF\xFF\x00\xFF\x00\x00\xFF\x00", "\xFF\xFF\x00\xFF\x00\x00\xFF\xFF",
"\xFF\xFF\x00\xFF\x00\xFF\x00\x00", "\xFF\xFF\x00\xFF\x00\xFF\x00\xFF",
"\xFF\xFF\x00\xFF\x00\xFF\xFF\x00", "\xFF\xFF\x00\xFF\x00\xFF\xFF\xFF",
"\xFF\xFF\x00\xFF\xFF\x00\x00\x00", "\xFF\xFF\x00\xFF\xFF\x00\x00\xFF",
"\xFF\xFF\x00\xFF\xFF\x00\xFF\x00", "\xFF\xFF\x00\xFF\xFF\x00\xFF\xFF",
"\xFF\xFF\x00\xFF\xFF\xFF\x00\x00", "\xFF\xFF\x00\xFF\xFF\xFF\x00\xFF",
"\xFF\xFF\x00\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\x00\xFF\xFF\xFF\xFF\xFF",
"\xFF\xFF\xFF\x00\x00\x00\x00\x00", "\xFF\xFF\xFF\x00\x00\x00\x00\xFF",
"\xFF\xFF\xFF\x00\x00\x00\xFF\x00", "\xFF\xFF\xFF\x00\x00\x00\xFF\xFF",
"\xFF\xFF\xFF\x00\x00\xFF\x00\x00", "\xFF\xFF\xFF\x00\x00\xFF\x00\xFF",
"\xFF\xFF\xFF\x00\x00\xFF\xFF\x00", "\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF",
"\xFF\xFF\xFF\x00\xFF\x00\x00\x00", "\xFF\xFF\xFF\x00\xFF\x00\x00\xFF",
"\xFF\xFF\xFF\x00\xFF\x00\xFF\x00", "\xFF\xFF\xFF\x00\xFF\x00\xFF\xFF",
"\xFF\xFF\xFF\x00\xFF\xFF\x00\x00", "\xFF\xFF\xFF\x00\xFF\xFF\x00\xFF",
"\xFF\xFF\xFF\x00\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\x00\xFF\xFF\xFF\xFF",
"\xFF\xFF\xFF\xFF\x00\x00\x00\x00", "\xFF\xFF\xFF\xFF\x00\x00\x00\xFF",
"\xFF\xFF\xFF\xFF\x00\x00\xFF\x00", "\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF",
"\xFF\xFF\xFF\xFF\x00\xFF\x00\x00", "\xFF\xFF\xFF\xFF\x00\xFF\x00\xFF",
"\xFF\xFF\xFF\xFF\x00\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\x00\xFF\xFF\xFF",
"\xFF\xFF\xFF\xFF\xFF\x00\x00\x00", "\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF",
"\xFF\xFF\xFF\xFF\xFF\x00\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\x00\xFF\xFF",
"\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\x00\xFF",
"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"
];
/**
* IP mapping helper table.
*
* Indexing this table with each source byte performs the initial bit permutation.
*
* @var array
*/
protected static $ipmap = [
0x00, 0x10, 0x01, 0x11, 0x20, 0x30, 0x21, 0x31,
0x02, 0x12, 0x03, 0x13, 0x22, 0x32, 0x23, 0x33,
0x40, 0x50, 0x41, 0x51, 0x60, 0x70, 0x61, 0x71,
0x42, 0x52, 0x43, 0x53, 0x62, 0x72, 0x63, 0x73,
0x04, 0x14, 0x05, 0x15, 0x24, 0x34, 0x25, 0x35,
0x06, 0x16, 0x07, 0x17, 0x26, 0x36, 0x27, 0x37,
0x44, 0x54, 0x45, 0x55, 0x64, 0x74, 0x65, 0x75,
0x46, 0x56, 0x47, 0x57, 0x66, 0x76, 0x67, 0x77,
0x80, 0x90, 0x81, 0x91, 0xA0, 0xB0, 0xA1, 0xB1,
0x82, 0x92, 0x83, 0x93, 0xA2, 0xB2, 0xA3, 0xB3,
0xC0, 0xD0, 0xC1, 0xD1, 0xE0, 0xF0, 0xE1, 0xF1,
0xC2, 0xD2, 0xC3, 0xD3, 0xE2, 0xF2, 0xE3, 0xF3,
0x84, 0x94, 0x85, 0x95, 0xA4, 0xB4, 0xA5, 0xB5,
0x86, 0x96, 0x87, 0x97, 0xA6, 0xB6, 0xA7, 0xB7,
0xC4, 0xD4, 0xC5, 0xD5, 0xE4, 0xF4, 0xE5, 0xF5,
0xC6, 0xD6, 0xC7, 0xD7, 0xE6, 0xF6, 0xE7, 0xF7,
0x08, 0x18, 0x09, 0x19, 0x28, 0x38, 0x29, 0x39,
0x0A, 0x1A, 0x0B, 0x1B, 0x2A, 0x3A, 0x2B, 0x3B,
0x48, 0x58, 0x49, 0x59, 0x68, 0x78, 0x69, 0x79,
0x4A, 0x5A, 0x4B, 0x5B, 0x6A, 0x7A, 0x6B, 0x7B,
0x0C, 0x1C, 0x0D, 0x1D, 0x2C, 0x3C, 0x2D, 0x3D,
0x0E, 0x1E, 0x0F, 0x1F, 0x2E, 0x3E, 0x2F, 0x3F,
0x4C, 0x5C, 0x4D, 0x5D, 0x6C, 0x7C, 0x6D, 0x7D,
0x4E, 0x5E, 0x4F, 0x5F, 0x6E, 0x7E, 0x6F, 0x7F,
0x88, 0x98, 0x89, 0x99, 0xA8, 0xB8, 0xA9, 0xB9,
0x8A, 0x9A, 0x8B, 0x9B, 0xAA, 0xBA, 0xAB, 0xBB,
0xC8, 0xD8, 0xC9, 0xD9, 0xE8, 0xF8, 0xE9, 0xF9,
0xCA, 0xDA, 0xCB, 0xDB, 0xEA, 0xFA, 0xEB, 0xFB,
0x8C, 0x9C, 0x8D, 0x9D, 0xAC, 0xBC, 0xAD, 0xBD,
0x8E, 0x9E, 0x8F, 0x9F, 0xAE, 0xBE, 0xAF, 0xBF,
0xCC, 0xDC, 0xCD, 0xDD, 0xEC, 0xFC, 0xED, 0xFD,
0xCE, 0xDE, 0xCF, 0xDF, 0xEE, 0xFE, 0xEF, 0xFF
];
/**
* Inverse IP mapping helper table.
* Indexing this table with a byte value reverses the bit order.
*
* @var array
*/
protected static $invipmap = [
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
];
/**
* Pre-permuted S-box1
*
* Each box ($sbox1-$sbox8) has been vectorized, then each value pre-permuted using the
* P table: concatenation can then be replaced by exclusive ORs.
*
* @var array
*/
protected static $sbox1 = [
0x00808200, 0x00000000, 0x00008000, 0x00808202,
0x00808002, 0x00008202, 0x00000002, 0x00008000,
0x00000200, 0x00808200, 0x00808202, 0x00000200,
0x00800202, 0x00808002, 0x00800000, 0x00000002,
0x00000202, 0x00800200, 0x00800200, 0x00008200,
0x00008200, 0x00808000, 0x00808000, 0x00800202,
0x00008002, 0x00800002, 0x00800002, 0x00008002,
0x00000000, 0x00000202, 0x00008202, 0x00800000,
0x00008000, 0x00808202, 0x00000002, 0x00808000,
0x00808200, 0x00800000, 0x00800000, 0x00000200,
0x00808002, 0x00008000, 0x00008200, 0x00800002,
0x00000200, 0x00000002, 0x00800202, 0x00008202,
0x00808202, 0x00008002, 0x00808000, 0x00800202,
0x00800002, 0x00000202, 0x00008202, 0x00808200,
0x00000202, 0x00800200, 0x00800200, 0x00000000,
0x00008002, 0x00008200, 0x00000000, 0x00808002
];
/**
* Pre-permuted S-box2
*
* @var array
*/
protected static $sbox2 = [
0x40084010, 0x40004000, 0x00004000, 0x00084010,
0x00080000, 0x00000010, 0x40080010, 0x40004010,
0x40000010, 0x40084010, 0x40084000, 0x40000000,
0x40004000, 0x00080000, 0x00000010, 0x40080010,
0x00084000, 0x00080010, 0x40004010, 0x00000000,
0x40000000, 0x00004000, 0x00084010, 0x40080000,
0x00080010, 0x40000010, 0x00000000, 0x00084000,
0x00004010, 0x40084000, 0x40080000, 0x00004010,
0x00000000, 0x00084010, 0x40080010, 0x00080000,
0x40004010, 0x40080000, 0x40084000, 0x00004000,
0x40080000, 0x40004000, 0x00000010, 0x40084010,
0x00084010, 0x00000010, 0x00004000, 0x40000000,
0x00004010, 0x40084000, 0x00080000, 0x40000010,
0x00080010, 0x40004010, 0x40000010, 0x00080010,
0x00084000, 0x00000000, 0x40004000, 0x00004010,
0x40000000, 0x40080010, 0x40084010, 0x00084000
];
/**
* Pre-permuted S-box3
*
* @var array
*/
protected static $sbox3 = [
0x00000104, 0x04010100, 0x00000000, 0x04010004,
0x04000100, 0x00000000, 0x00010104, 0x04000100,
0x00010004, 0x04000004, 0x04000004, 0x00010000,
0x04010104, 0x00010004, 0x04010000, 0x00000104,
0x04000000, 0x00000004, 0x04010100, 0x00000100,
0x00010100, 0x04010000, 0x04010004, 0x00010104,
0x04000104, 0x00010100, 0x00010000, 0x04000104,
0x00000004, 0x04010104, 0x00000100, 0x04000000,
0x04010100, 0x04000000, 0x00010004, 0x00000104,
0x00010000, 0x04010100, 0x04000100, 0x00000000,
0x00000100, 0x00010004, 0x04010104, 0x04000100,
0x04000004, 0x00000100, 0x00000000, 0x04010004,
0x04000104, 0x00010000, 0x04000000, 0x04010104,
0x00000004, 0x00010104, 0x00010100, 0x04000004,
0x04010000, 0x04000104, 0x00000104, 0x04010000,
0x00010104, 0x00000004, 0x04010004, 0x00010100
];
/**
* Pre-permuted S-box4
*
* @var array
*/
protected static $sbox4 = [
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x00401040, 0x80400040, 0x80400000, 0x80001000,
0x00000000, 0x00401000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00400040, 0x80400000,
0x80000000, 0x00001000, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x80001000, 0x00001040,
0x80400040, 0x80000000, 0x00001040, 0x00400040,
0x00001000, 0x00401040, 0x80401040, 0x80000040,
0x00400040, 0x80400000, 0x00401000, 0x80401040,
0x80000040, 0x00000000, 0x00000000, 0x00401000,
0x00001040, 0x00400040, 0x80400040, 0x80000000,
0x80401000, 0x80001040, 0x80001040, 0x00000040,
0x80401040, 0x80000040, 0x80000000, 0x00001000,
0x80400000, 0x80001000, 0x00401040, 0x80400040,
0x80001000, 0x00001040, 0x00400000, 0x80401000,
0x00000040, 0x00400000, 0x00001000, 0x00401040
];
/**
* Pre-permuted S-box5
*
* @var array
*/
protected static $sbox5 = [
0x00000080, 0x01040080, 0x01040000, 0x21000080,
0x00040000, 0x00000080, 0x20000000, 0x01040000,
0x20040080, 0x00040000, 0x01000080, 0x20040080,
0x21000080, 0x21040000, 0x00040080, 0x20000000,
0x01000000, 0x20040000, 0x20040000, 0x00000000,
0x20000080, 0x21040080, 0x21040080, 0x01000080,
0x21040000, 0x20000080, 0x00000000, 0x21000000,
0x01040080, 0x01000000, 0x21000000, 0x00040080,
0x00040000, 0x21000080, 0x00000080, 0x01000000,
0x20000000, 0x01040000, 0x21000080, 0x20040080,
0x01000080, 0x20000000, 0x21040000, 0x01040080,
0x20040080, 0x00000080, 0x01000000, 0x21040000,
0x21040080, 0x00040080, 0x21000000, 0x21040080,
0x01040000, 0x00000000, 0x20040000, 0x21000000,
0x00040080, 0x01000080, 0x20000080, 0x00040000,
0x00000000, 0x20040000, 0x01040080, 0x20000080
];
/**
* Pre-permuted S-box6
*
* @var array
*/
protected static $sbox6 = [
0x10000008, 0x10200000, 0x00002000, 0x10202008,
0x10200000, 0x00000008, 0x10202008, 0x00200000,
0x10002000, 0x00202008, 0x00200000, 0x10000008,
0x00200008, 0x10002000, 0x10000000, 0x00002008,
0x00000000, 0x00200008, 0x10002008, 0x00002000,
0x00202000, 0x10002008, 0x00000008, 0x10200008,
0x10200008, 0x00000000, 0x00202008, 0x10202000,
0x00002008, 0x00202000, 0x10202000, 0x10000000,
0x10002000, 0x00000008, 0x10200008, 0x00202000,
0x10202008, 0x00200000, 0x00002008, 0x10000008,
0x00200000, 0x10002000, 0x10000000, 0x00002008,
0x10000008, 0x10202008, 0x00202000, 0x10200000,
0x00202008, 0x10202000, 0x00000000, 0x10200008,
0x00000008, 0x00002000, 0x10200000, 0x00202008,
0x00002000, 0x00200008, 0x10002008, 0x00000000,
0x10202000, 0x10000000, 0x00200008, 0x10002008
];
/**
* Pre-permuted S-box7
*
* @var array
*/
protected static $sbox7 = [
0x00100000, 0x02100001, 0x02000401, 0x00000000,
0x00000400, 0x02000401, 0x00100401, 0x02100400,
0x02100401, 0x00100000, 0x00000000, 0x02000001,
0x00000001, 0x02000000, 0x02100001, 0x00000401,
0x02000400, 0x00100401, 0x00100001, 0x02000400,
0x02000001, 0x02100000, 0x02100400, 0x00100001,
0x02100000, 0x00000400, 0x00000401, 0x02100401,
0x00100400, 0x00000001, 0x02000000, 0x00100400,
0x02000000, 0x00100400, 0x00100000, 0x02000401,
0x02000401, 0x02100001, 0x02100001, 0x00000001,
0x00100001, 0x02000000, 0x02000400, 0x00100000,
0x02100400, 0x00000401, 0x00100401, 0x02100400,
0x00000401, 0x02000001, 0x02100401, 0x02100000,
0x00100400, 0x00000000, 0x00000001, 0x02100401,
0x00000000, 0x00100401, 0x02100000, 0x00000400,
0x02000001, 0x02000400, 0x00000400, 0x00100001
];
/**
* Pre-permuted S-box8
*
* @var array
*/
protected static $sbox8 = [
0x08000820, 0x00000800, 0x00020000, 0x08020820,
0x08000000, 0x08000820, 0x00000020, 0x08000000,
0x00020020, 0x08020000, 0x08020820, 0x00020800,
0x08020800, 0x00020820, 0x00000800, 0x00000020,
0x08020000, 0x08000020, 0x08000800, 0x00000820,
0x00020800, 0x00020020, 0x08020020, 0x08020800,
0x00000820, 0x00000000, 0x00000000, 0x08020020,
0x08000020, 0x08000800, 0x00020820, 0x00020000,
0x00020820, 0x00020000, 0x08020800, 0x00000800,
0x00000020, 0x08020020, 0x00000800, 0x00020820,
0x08000800, 0x00000020, 0x08000020, 0x08020000,
0x08020020, 0x08000000, 0x00020000, 0x08000820,
0x00000000, 0x08020820, 0x00020020, 0x08000020,
0x08020000, 0x08000800, 0x08000820, 0x00000000,
0x08020820, 0x00020800, 0x00020800, 0x00000820,
0x00000820, 0x00020020, 0x08000000, 0x08020800
];
/**
* Default Constructor.
*
* @param string $mode
* @throws BadModeException if an invalid / unsupported mode is provided
*/
public function __construct($mode)
{
parent::__construct($mode);
if ($this->mode == self::MODE_STREAM) {
throw new BadModeException('Block ciphers cannot be ran in stream mode');
}
}
/**
* Test for engine validity
*
* This is mainly just a wrapper to set things up for \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::isValidEngine()
* @param int $engine
* @return bool
*/
protected function isValidEngineHelper($engine)
{
if ($this->key_length_max == 8) {
if ($engine == self::ENGINE_OPENSSL) {
// quoting https://www.openssl.org/news/openssl-3.0-notes.html, OpenSSL 3.0.1
// "Moved all variations of the EVP ciphers CAST5, BF, IDEA, SEED, RC2, RC4, RC5, and DES to the legacy provider"
// in theory openssl_get_cipher_methods() should catch this but, on GitHub Actions, at least, it does not
if (version_compare(preg_replace('#OpenSSL (\d+\.\d+\.\d+) .*#', '$1', OPENSSL_VERSION_TEXT), '3.0.1', '>=')) {
return false;
}
$this->cipher_name_openssl_ecb = 'des-ecb';
$this->cipher_name_openssl = 'des-' . $this->openssl_translate_mode();
}
}
return parent::isValidEngineHelper($engine);
}
/**
* Sets the key.
*
* Keys must be 64-bits long or 8 bytes long.
*
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::setKey()
* @param string $key
*/
public function setKey($key)
{
if (!($this instanceof TripleDES) && strlen($key) != 8) {
throw new \LengthException('Key of size ' . strlen($key) . ' not supported by this algorithm. Only keys of size 8 are supported');
}
// Sets the key
parent::setKey($key);
}
/**
* Encrypts a block
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::encryptBlock()
* @see \phpseclib3\Crypt\Common\SymmetricKey::encrypt()
* @see self::encrypt()
* @param string $in
* @return string
*/
protected function encryptBlock($in)
{
return $this->processBlock($in, self::ENCRYPT);
}
/**
* Decrypts a block
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::decryptBlock()
* @see \phpseclib3\Crypt\Common\SymmetricKey::decrypt()
* @see self::decrypt()
* @param string $in
* @return string
*/
protected function decryptBlock($in)
{
return $this->processBlock($in, self::DECRYPT);
}
/**
* Encrypts or decrypts a 64-bit block
*
* $mode should be either self::ENCRYPT or self::DECRYPT. See
* {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
* idea of what this function does.
*
* @see self::encryptBlock()
* @see self::decryptBlock()
* @param string $block
* @param int $mode
* @return string
*/
private function processBlock($block, $mode)
{
static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
if (!$sbox1) {
$sbox1 = array_map('intval', self::$sbox1);
$sbox2 = array_map('intval', self::$sbox2);
$sbox3 = array_map('intval', self::$sbox3);
$sbox4 = array_map('intval', self::$sbox4);
$sbox5 = array_map('intval', self::$sbox5);
$sbox6 = array_map('intval', self::$sbox6);
$sbox7 = array_map('intval', self::$sbox7);
$sbox8 = array_map('intval', self::$sbox8);
/* Merge $shuffle with $[inv]ipmap */
for ($i = 0; $i < 256; ++$i) {
$shuffleip[] = self::$shuffle[self::$ipmap[$i]];
$shuffleinvip[] = self::$shuffle[self::$invipmap[$i]];
}
}
$keys = $this->keys[$mode];
$ki = -1;
// Do the initial IP permutation.
$t = unpack('Nl/Nr', $block);
list($l, $r) = [$t['l'], $t['r']];
$block = ($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
// Extract L0 and R0.
$t = unpack('Nl/Nr', $block);
list($l, $r) = [$t['l'], $t['r']];
for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
// Perform the 16 steps.
for ($i = 0; $i < 16; $i++) {
// start of "the Feistel (F) function" - see the following URL:
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
// Merge key schedule.
$b1 = (($r >> 3) & 0x1FFFFFFF) ^ ($r << 29) ^ $keys[++$ki];
$b2 = (($r >> 31) & 0x00000001) ^ ($r << 1) ^ $keys[++$ki];
// S-box indexing.
$t = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
$sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ $l;
// end of "the Feistel (F) function"
$l = $r;
$r = $t;
}
// Last step should not permute L & R.
$t = $l;
$l = $r;
$r = $t;
}
// Perform the inverse IP permutation.
return ($shuffleinvip[($r >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleinvip[($l >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleinvip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleinvip[($l >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleinvip[($r >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleinvip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleinvip[ $r & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleinvip[ $l & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
}
/**
* Creates the key schedule
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::setupKey()
*/
protected function setupKey()
{
if (isset($this->kl['key']) && $this->key === $this->kl['key'] && $this->des_rounds === $this->kl['des_rounds']) {
// already expanded
return;
}
$this->kl = ['key' => $this->key, 'des_rounds' => $this->des_rounds];
static $shifts = [ // number of key bits shifted per round
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
];
static $pc1map = [
0x00, 0x00, 0x08, 0x08, 0x04, 0x04, 0x0C, 0x0C,
0x02, 0x02, 0x0A, 0x0A, 0x06, 0x06, 0x0E, 0x0E,
0x10, 0x10, 0x18, 0x18, 0x14, 0x14, 0x1C, 0x1C,
0x12, 0x12, 0x1A, 0x1A, 0x16, 0x16, 0x1E, 0x1E,
0x20, 0x20, 0x28, 0x28, 0x24, 0x24, 0x2C, 0x2C,
0x22, 0x22, 0x2A, 0x2A, 0x26, 0x26, 0x2E, 0x2E,
0x30, 0x30, 0x38, 0x38, 0x34, 0x34, 0x3C, 0x3C,
0x32, 0x32, 0x3A, 0x3A, 0x36, 0x36, 0x3E, 0x3E,
0x40, 0x40, 0x48, 0x48, 0x44, 0x44, 0x4C, 0x4C,
0x42, 0x42, 0x4A, 0x4A, 0x46, 0x46, 0x4E, 0x4E,
0x50, 0x50, 0x58, 0x58, 0x54, 0x54, 0x5C, 0x5C,
0x52, 0x52, 0x5A, 0x5A, 0x56, 0x56, 0x5E, 0x5E,
0x60, 0x60, 0x68, 0x68, 0x64, 0x64, 0x6C, 0x6C,
0x62, 0x62, 0x6A, 0x6A, 0x66, 0x66, 0x6E, 0x6E,
0x70, 0x70, 0x78, 0x78, 0x74, 0x74, 0x7C, 0x7C,
0x72, 0x72, 0x7A, 0x7A, 0x76, 0x76, 0x7E, 0x7E,
0x80, 0x80, 0x88, 0x88, 0x84, 0x84, 0x8C, 0x8C,
0x82, 0x82, 0x8A, 0x8A, 0x86, 0x86, 0x8E, 0x8E,
0x90, 0x90, 0x98, 0x98, 0x94, 0x94, 0x9C, 0x9C,
0x92, 0x92, 0x9A, 0x9A, 0x96, 0x96, 0x9E, 0x9E,
0xA0, 0xA0, 0xA8, 0xA8, 0xA4, 0xA4, 0xAC, 0xAC,
0xA2, 0xA2, 0xAA, 0xAA, 0xA6, 0xA6, 0xAE, 0xAE,
0xB0, 0xB0, 0xB8, 0xB8, 0xB4, 0xB4, 0xBC, 0xBC,
0xB2, 0xB2, 0xBA, 0xBA, 0xB6, 0xB6, 0xBE, 0xBE,
0xC0, 0xC0, 0xC8, 0xC8, 0xC4, 0xC4, 0xCC, 0xCC,
0xC2, 0xC2, 0xCA, 0xCA, 0xC6, 0xC6, 0xCE, 0xCE,
0xD0, 0xD0, 0xD8, 0xD8, 0xD4, 0xD4, 0xDC, 0xDC,
0xD2, 0xD2, 0xDA, 0xDA, 0xD6, 0xD6, 0xDE, 0xDE,
0xE0, 0xE0, 0xE8, 0xE8, 0xE4, 0xE4, 0xEC, 0xEC,
0xE2, 0xE2, 0xEA, 0xEA, 0xE6, 0xE6, 0xEE, 0xEE,
0xF0, 0xF0, 0xF8, 0xF8, 0xF4, 0xF4, 0xFC, 0xFC,
0xF2, 0xF2, 0xFA, 0xFA, 0xF6, 0xF6, 0xFE, 0xFE
];
// Mapping tables for the PC-2 transformation.
static $pc2mapc1 = [
0x00000000, 0x00000400, 0x00200000, 0x00200400,
0x00000001, 0x00000401, 0x00200001, 0x00200401,
0x02000000, 0x02000400, 0x02200000, 0x02200400,
0x02000001, 0x02000401, 0x02200001, 0x02200401
];
static $pc2mapc2 = [
0x00000000, 0x00000800, 0x08000000, 0x08000800,
0x00010000, 0x00010800, 0x08010000, 0x08010800,
0x00000000, 0x00000800, 0x08000000, 0x08000800,
0x00010000, 0x00010800, 0x08010000, 0x08010800,
0x00000100, 0x00000900, 0x08000100, 0x08000900,
0x00010100, 0x00010900, 0x08010100, 0x08010900,
0x00000100, 0x00000900, 0x08000100, 0x08000900,
0x00010100, 0x00010900, 0x08010100, 0x08010900,
0x00000010, 0x00000810, 0x08000010, 0x08000810,
0x00010010, 0x00010810, 0x08010010, 0x08010810,
0x00000010, 0x00000810, 0x08000010, 0x08000810,
0x00010010, 0x00010810, 0x08010010, 0x08010810,
0x00000110, 0x00000910, 0x08000110, 0x08000910,
0x00010110, 0x00010910, 0x08010110, 0x08010910,
0x00000110, 0x00000910, 0x08000110, 0x08000910,
0x00010110, 0x00010910, 0x08010110, 0x08010910,
0x00040000, 0x00040800, 0x08040000, 0x08040800,
0x00050000, 0x00050800, 0x08050000, 0x08050800,
0x00040000, 0x00040800, 0x08040000, 0x08040800,
0x00050000, 0x00050800, 0x08050000, 0x08050800,
0x00040100, 0x00040900, 0x08040100, 0x08040900,
0x00050100, 0x00050900, 0x08050100, 0x08050900,
0x00040100, 0x00040900, 0x08040100, 0x08040900,
0x00050100, 0x00050900, 0x08050100, 0x08050900,
0x00040010, 0x00040810, 0x08040010, 0x08040810,
0x00050010, 0x00050810, 0x08050010, 0x08050810,
0x00040010, 0x00040810, 0x08040010, 0x08040810,
0x00050010, 0x00050810, 0x08050010, 0x08050810,
0x00040110, 0x00040910, 0x08040110, 0x08040910,
0x00050110, 0x00050910, 0x08050110, 0x08050910,
0x00040110, 0x00040910, 0x08040110, 0x08040910,
0x00050110, 0x00050910, 0x08050110, 0x08050910,
0x01000000, 0x01000800, 0x09000000, 0x09000800,
0x01010000, 0x01010800, 0x09010000, 0x09010800,
0x01000000, 0x01000800, 0x09000000, 0x09000800,
0x01010000, 0x01010800, 0x09010000, 0x09010800,
0x01000100, 0x01000900, 0x09000100, 0x09000900,
0x01010100, 0x01010900, 0x09010100, 0x09010900,
0x01000100, 0x01000900, 0x09000100, 0x09000900,
0x01010100, 0x01010900, 0x09010100, 0x09010900,
0x01000010, 0x01000810, 0x09000010, 0x09000810,
0x01010010, 0x01010810, 0x09010010, 0x09010810,
0x01000010, 0x01000810, 0x09000010, 0x09000810,
0x01010010, 0x01010810, 0x09010010, 0x09010810,
0x01000110, 0x01000910, 0x09000110, 0x09000910,
0x01010110, 0x01010910, 0x09010110, 0x09010910,
0x01000110, 0x01000910, 0x09000110, 0x09000910,
0x01010110, 0x01010910, 0x09010110, 0x09010910,
0x01040000, 0x01040800, 0x09040000, 0x09040800,
0x01050000, 0x01050800, 0x09050000, 0x09050800,
0x01040000, 0x01040800, 0x09040000, 0x09040800,
0x01050000, 0x01050800, 0x09050000, 0x09050800,
0x01040100, 0x01040900, 0x09040100, 0x09040900,
0x01050100, 0x01050900, 0x09050100, 0x09050900,
0x01040100, 0x01040900, 0x09040100, 0x09040900,
0x01050100, 0x01050900, 0x09050100, 0x09050900,
0x01040010, 0x01040810, 0x09040010, 0x09040810,
0x01050010, 0x01050810, 0x09050010, 0x09050810,
0x01040010, 0x01040810, 0x09040010, 0x09040810,
0x01050010, 0x01050810, 0x09050010, 0x09050810,
0x01040110, 0x01040910, 0x09040110, 0x09040910,
0x01050110, 0x01050910, 0x09050110, 0x09050910,
0x01040110, 0x01040910, 0x09040110, 0x09040910,
0x01050110, 0x01050910, 0x09050110, 0x09050910
];
static $pc2mapc3 = [
0x00000000, 0x00000004, 0x00001000, 0x00001004,
0x00000000, 0x00000004, 0x00001000, 0x00001004,
0x10000000, 0x10000004, 0x10001000, 0x10001004,
0x10000000, 0x10000004, 0x10001000, 0x10001004,
0x00000020, 0x00000024, 0x00001020, 0x00001024,
0x00000020, 0x00000024, 0x00001020, 0x00001024,
0x10000020, 0x10000024, 0x10001020, 0x10001024,
0x10000020, 0x10000024, 0x10001020, 0x10001024,
0x00080000, 0x00080004, 0x00081000, 0x00081004,
0x00080000, 0x00080004, 0x00081000, 0x00081004,
0x10080000, 0x10080004, 0x10081000, 0x10081004,
0x10080000, 0x10080004, 0x10081000, 0x10081004,
0x00080020, 0x00080024, 0x00081020, 0x00081024,
0x00080020, 0x00080024, 0x00081020, 0x00081024,
0x10080020, 0x10080024, 0x10081020, 0x10081024,
0x10080020, 0x10080024, 0x10081020, 0x10081024,
0x20000000, 0x20000004, 0x20001000, 0x20001004,
0x20000000, 0x20000004, 0x20001000, 0x20001004,
0x30000000, 0x30000004, 0x30001000, 0x30001004,
0x30000000, 0x30000004, 0x30001000, 0x30001004,
0x20000020, 0x20000024, 0x20001020, 0x20001024,
0x20000020, 0x20000024, 0x20001020, 0x20001024,
0x30000020, 0x30000024, 0x30001020, 0x30001024,
0x30000020, 0x30000024, 0x30001020, 0x30001024,
0x20080000, 0x20080004, 0x20081000, 0x20081004,
0x20080000, 0x20080004, 0x20081000, 0x20081004,
0x30080000, 0x30080004, 0x30081000, 0x30081004,
0x30080000, 0x30080004, 0x30081000, 0x30081004,
0x20080020, 0x20080024, 0x20081020, 0x20081024,
0x20080020, 0x20080024, 0x20081020, 0x20081024,
0x30080020, 0x30080024, 0x30081020, 0x30081024,
0x30080020, 0x30080024, 0x30081020, 0x30081024,
0x00000002, 0x00000006, 0x00001002, 0x00001006,
0x00000002, 0x00000006, 0x00001002, 0x00001006,
0x10000002, 0x10000006, 0x10001002, 0x10001006,
0x10000002, 0x10000006, 0x10001002, 0x10001006,
0x00000022, 0x00000026, 0x00001022, 0x00001026,
0x00000022, 0x00000026, 0x00001022, 0x00001026,
0x10000022, 0x10000026, 0x10001022, 0x10001026,
0x10000022, 0x10000026, 0x10001022, 0x10001026,
0x00080002, 0x00080006, 0x00081002, 0x00081006,
0x00080002, 0x00080006, 0x00081002, 0x00081006,
0x10080002, 0x10080006, 0x10081002, 0x10081006,
0x10080002, 0x10080006, 0x10081002, 0x10081006,
0x00080022, 0x00080026, 0x00081022, 0x00081026,
0x00080022, 0x00080026, 0x00081022, 0x00081026,
0x10080022, 0x10080026, 0x10081022, 0x10081026,
0x10080022, 0x10080026, 0x10081022, 0x10081026,
0x20000002, 0x20000006, 0x20001002, 0x20001006,
0x20000002, 0x20000006, 0x20001002, 0x20001006,
0x30000002, 0x30000006, 0x30001002, 0x30001006,
0x30000002, 0x30000006, 0x30001002, 0x30001006,
0x20000022, 0x20000026, 0x20001022, 0x20001026,
0x20000022, 0x20000026, 0x20001022, 0x20001026,
0x30000022, 0x30000026, 0x30001022, 0x30001026,
0x30000022, 0x30000026, 0x30001022, 0x30001026,
0x20080002, 0x20080006, 0x20081002, 0x20081006,
0x20080002, 0x20080006, 0x20081002, 0x20081006,
0x30080002, 0x30080006, 0x30081002, 0x30081006,
0x30080002, 0x30080006, 0x30081002, 0x30081006,
0x20080022, 0x20080026, 0x20081022, 0x20081026,
0x20080022, 0x20080026, 0x20081022, 0x20081026,
0x30080022, 0x30080026, 0x30081022, 0x30081026,
0x30080022, 0x30080026, 0x30081022, 0x30081026
];
static $pc2mapc4 = [
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x00000000, 0x00100000, 0x00000008, 0x00100008,
0x00000200, 0x00100200, 0x00000208, 0x00100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x04000000, 0x04100000, 0x04000008, 0x04100008,
0x04000200, 0x04100200, 0x04000208, 0x04100208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x00002000, 0x00102000, 0x00002008, 0x00102008,
0x00002200, 0x00102200, 0x00002208, 0x00102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x04002000, 0x04102000, 0x04002008, 0x04102008,
0x04002200, 0x04102200, 0x04002208, 0x04102208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x00020000, 0x00120000, 0x00020008, 0x00120008,
0x00020200, 0x00120200, 0x00020208, 0x00120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x04020000, 0x04120000, 0x04020008, 0x04120008,
0x04020200, 0x04120200, 0x04020208, 0x04120208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x00022000, 0x00122000, 0x00022008, 0x00122008,
0x00022200, 0x00122200, 0x00022208, 0x00122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208,
0x04022000, 0x04122000, 0x04022008, 0x04122008,
0x04022200, 0x04122200, 0x04022208, 0x04122208
];
static $pc2mapd1 = [
0x00000000, 0x00000001, 0x08000000, 0x08000001,
0x00200000, 0x00200001, 0x08200000, 0x08200001,
0x00000002, 0x00000003, 0x08000002, 0x08000003,
0x00200002, 0x00200003, 0x08200002, 0x08200003
];
static $pc2mapd2 = [
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x00000000, 0x00100000, 0x00000800, 0x00100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x04000000, 0x04100000, 0x04000800, 0x04100800,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x00000004, 0x00100004, 0x00000804, 0x00100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x04000004, 0x04100004, 0x04000804, 0x04100804,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x00000200, 0x00100200, 0x00000A00, 0x00100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x04000200, 0x04100200, 0x04000A00, 0x04100A00,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x00000204, 0x00100204, 0x00000A04, 0x00100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x04000204, 0x04100204, 0x04000A04, 0x04100A04,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x00020000, 0x00120000, 0x00020800, 0x00120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x04020000, 0x04120000, 0x04020800, 0x04120800,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x00020004, 0x00120004, 0x00020804, 0x00120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x04020004, 0x04120004, 0x04020804, 0x04120804,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x00020200, 0x00120200, 0x00020A00, 0x00120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x04020200, 0x04120200, 0x04020A00, 0x04120A00,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x00020204, 0x00120204, 0x00020A04, 0x00120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04,
0x04020204, 0x04120204, 0x04020A04, 0x04120A04
];
static $pc2mapd3 = [
0x00000000, 0x00010000, 0x02000000, 0x02010000,
0x00000020, 0x00010020, 0x02000020, 0x02010020,
0x00040000, 0x00050000, 0x02040000, 0x02050000,
0x00040020, 0x00050020, 0x02040020, 0x02050020,
0x00002000, 0x00012000, 0x02002000, 0x02012000,
0x00002020, 0x00012020, 0x02002020, 0x02012020,
0x00042000, 0x00052000, 0x02042000, 0x02052000,
0x00042020, 0x00052020, 0x02042020, 0x02052020,
0x00000000, 0x00010000, 0x02000000, 0x02010000,
0x00000020, 0x00010020, 0x02000020, 0x02010020,
0x00040000, 0x00050000, 0x02040000, 0x02050000,
0x00040020, 0x00050020, 0x02040020, 0x02050020,
0x00002000, 0x00012000, 0x02002000, 0x02012000,
0x00002020, 0x00012020, 0x02002020, 0x02012020,
0x00042000, 0x00052000, 0x02042000, 0x02052000,
0x00042020, 0x00052020, 0x02042020, 0x02052020,
0x00000010, 0x00010010, 0x02000010, 0x02010010,
0x00000030, 0x00010030, 0x02000030, 0x02010030,
0x00040010, 0x00050010, 0x02040010, 0x02050010,
0x00040030, 0x00050030, 0x02040030, 0x02050030,
0x00002010, 0x00012010, 0x02002010, 0x02012010,
0x00002030, 0x00012030, 0x02002030, 0x02012030,
0x00042010, 0x00052010, 0x02042010, 0x02052010,
0x00042030, 0x00052030, 0x02042030, 0x02052030,
0x00000010, 0x00010010, 0x02000010, 0x02010010,
0x00000030, 0x00010030, 0x02000030, 0x02010030,
0x00040010, 0x00050010, 0x02040010, 0x02050010,
0x00040030, 0x00050030, 0x02040030, 0x02050030,
0x00002010, 0x00012010, 0x02002010, 0x02012010,
0x00002030, 0x00012030, 0x02002030, 0x02012030,
0x00042010, 0x00052010, 0x02042010, 0x02052010,
0x00042030, 0x00052030, 0x02042030, 0x02052030,
0x20000000, 0x20010000, 0x22000000, 0x22010000,
0x20000020, 0x20010020, 0x22000020, 0x22010020,
0x20040000, 0x20050000, 0x22040000, 0x22050000,
0x20040020, 0x20050020, 0x22040020, 0x22050020,
0x20002000, 0x20012000, 0x22002000, 0x22012000,
0x20002020, 0x20012020, 0x22002020, 0x22012020,
0x20042000, 0x20052000, 0x22042000, 0x22052000,
0x20042020, 0x20052020, 0x22042020, 0x22052020,
0x20000000, 0x20010000, 0x22000000, 0x22010000,
0x20000020, 0x20010020, 0x22000020, 0x22010020,
0x20040000, 0x20050000, 0x22040000, 0x22050000,
0x20040020, 0x20050020, 0x22040020, 0x22050020,
0x20002000, 0x20012000, 0x22002000, 0x22012000,
0x20002020, 0x20012020, 0x22002020, 0x22012020,
0x20042000, 0x20052000, 0x22042000, 0x22052000,
0x20042020, 0x20052020, 0x22042020, 0x22052020,
0x20000010, 0x20010010, 0x22000010, 0x22010010,
0x20000030, 0x20010030, 0x22000030, 0x22010030,
0x20040010, 0x20050010, 0x22040010, 0x22050010,
0x20040030, 0x20050030, 0x22040030, 0x22050030,
0x20002010, 0x20012010, 0x22002010, 0x22012010,
0x20002030, 0x20012030, 0x22002030, 0x22012030,
0x20042010, 0x20052010, 0x22042010, 0x22052010,
0x20042030, 0x20052030, 0x22042030, 0x22052030,
0x20000010, 0x20010010, 0x22000010, 0x22010010,
0x20000030, 0x20010030, 0x22000030, 0x22010030,
0x20040010, 0x20050010, 0x22040010, 0x22050010,
0x20040030, 0x20050030, 0x22040030, 0x22050030,
0x20002010, 0x20012010, 0x22002010, 0x22012010,
0x20002030, 0x20012030, 0x22002030, 0x22012030,
0x20042010, 0x20052010, 0x22042010, 0x22052010,
0x20042030, 0x20052030, 0x22042030, 0x22052030
];
static $pc2mapd4 = [
0x00000000, 0x00000400, 0x01000000, 0x01000400,
0x00000000, 0x00000400, 0x01000000, 0x01000400,
0x00000100, 0x00000500, 0x01000100, 0x01000500,
0x00000100, 0x00000500, 0x01000100, 0x01000500,
0x10000000, 0x10000400, 0x11000000, 0x11000400,
0x10000000, 0x10000400, 0x11000000, 0x11000400,
0x10000100, 0x10000500, 0x11000100, 0x11000500,
0x10000100, 0x10000500, 0x11000100, 0x11000500,
0x00080000, 0x00080400, 0x01080000, 0x01080400,
0x00080000, 0x00080400, 0x01080000, 0x01080400,
0x00080100, 0x00080500, 0x01080100, 0x01080500,
0x00080100, 0x00080500, 0x01080100, 0x01080500,
0x10080000, 0x10080400, 0x11080000, 0x11080400,
0x10080000, 0x10080400, 0x11080000, 0x11080400,
0x10080100, 0x10080500, 0x11080100, 0x11080500,
0x10080100, 0x10080500, 0x11080100, 0x11080500,
0x00000008, 0x00000408, 0x01000008, 0x01000408,
0x00000008, 0x00000408, 0x01000008, 0x01000408,
0x00000108, 0x00000508, 0x01000108, 0x01000508,
0x00000108, 0x00000508, 0x01000108, 0x01000508,
0x10000008, 0x10000408, 0x11000008, 0x11000408,
0x10000008, 0x10000408, 0x11000008, 0x11000408,
0x10000108, 0x10000508, 0x11000108, 0x11000508,
0x10000108, 0x10000508, 0x11000108, 0x11000508,
0x00080008, 0x00080408, 0x01080008, 0x01080408,
0x00080008, 0x00080408, 0x01080008, 0x01080408,
0x00080108, 0x00080508, 0x01080108, 0x01080508,
0x00080108, 0x00080508, 0x01080108, 0x01080508,
0x10080008, 0x10080408, 0x11080008, 0x11080408,
0x10080008, 0x10080408, 0x11080008, 0x11080408,
0x10080108, 0x10080508, 0x11080108, 0x11080508,
0x10080108, 0x10080508, 0x11080108, 0x11080508,
0x00001000, 0x00001400, 0x01001000, 0x01001400,
0x00001000, 0x00001400, 0x01001000, 0x01001400,
0x00001100, 0x00001500, 0x01001100, 0x01001500,
0x00001100, 0x00001500, 0x01001100, 0x01001500,
0x10001000, 0x10001400, 0x11001000, 0x11001400,
0x10001000, 0x10001400, 0x11001000, 0x11001400,
0x10001100, 0x10001500, 0x11001100, 0x11001500,
0x10001100, 0x10001500, 0x11001100, 0x11001500,
0x00081000, 0x00081400, 0x01081000, 0x01081400,
0x00081000, 0x00081400, 0x01081000, 0x01081400,
0x00081100, 0x00081500, 0x01081100, 0x01081500,
0x00081100, 0x00081500, 0x01081100, 0x01081500,
0x10081000, 0x10081400, 0x11081000, 0x11081400,
0x10081000, 0x10081400, 0x11081000, 0x11081400,
0x10081100, 0x10081500, 0x11081100, 0x11081500,
0x10081100, 0x10081500, 0x11081100, 0x11081500,
0x00001008, 0x00001408, 0x01001008, 0x01001408,
0x00001008, 0x00001408, 0x01001008, 0x01001408,
0x00001108, 0x00001508, 0x01001108, 0x01001508,
0x00001108, 0x00001508, 0x01001108, 0x01001508,
0x10001008, 0x10001408, 0x11001008, 0x11001408,
0x10001008, 0x10001408, 0x11001008, 0x11001408,
0x10001108, 0x10001508, 0x11001108, 0x11001508,
0x10001108, 0x10001508, 0x11001108, 0x11001508,
0x00081008, 0x00081408, 0x01081008, 0x01081408,
0x00081008, 0x00081408, 0x01081008, 0x01081408,
0x00081108, 0x00081508, 0x01081108, 0x01081508,
0x00081108, 0x00081508, 0x01081108, 0x01081508,
0x10081008, 0x10081408, 0x11081008, 0x11081408,
0x10081008, 0x10081408, 0x11081008, 0x11081408,
0x10081108, 0x10081508, 0x11081108, 0x11081508,
0x10081108, 0x10081508, 0x11081108, 0x11081508
];
$keys = [];
for ($des_round = 0; $des_round < $this->des_rounds; ++$des_round) {
// pad the key and remove extra characters as appropriate.
$key = str_pad(substr($this->key, $des_round * 8, 8), 8, "\0");
// Perform the PC/1 transformation and compute C and D.
$t = unpack('Nl/Nr', $key);
list($l, $r) = [$t['l'], $t['r']];
$key = (self::$shuffle[$pc1map[ $r & 0xFF]] & "\x80\x80\x80\x80\x80\x80\x80\x00") |
(self::$shuffle[$pc1map[($r >> 8) & 0xFF]] & "\x40\x40\x40\x40\x40\x40\x40\x00") |
(self::$shuffle[$pc1map[($r >> 16) & 0xFF]] & "\x20\x20\x20\x20\x20\x20\x20\x00") |
(self::$shuffle[$pc1map[($r >> 24) & 0xFF]] & "\x10\x10\x10\x10\x10\x10\x10\x00") |
(self::$shuffle[$pc1map[ $l & 0xFF]] & "\x08\x08\x08\x08\x08\x08\x08\x00") |
(self::$shuffle[$pc1map[($l >> 8) & 0xFF]] & "\x04\x04\x04\x04\x04\x04\x04\x00") |
(self::$shuffle[$pc1map[($l >> 16) & 0xFF]] & "\x02\x02\x02\x02\x02\x02\x02\x00") |
(self::$shuffle[$pc1map[($l >> 24) & 0xFF]] & "\x01\x01\x01\x01\x01\x01\x01\x00");
$key = unpack('Nc/Nd', $key);
$c = ( $key['c'] >> 4) & 0x0FFFFFFF;
$d = (($key['d'] >> 4) & 0x0FFFFFF0) | ($key['c'] & 0x0F);
$keys[$des_round] = [
self::ENCRYPT => [],
self::DECRYPT => array_fill(0, 32, 0)
];
for ($i = 0, $ki = 31; $i < 16; ++$i, $ki -= 2) {
$c <<= $shifts[$i];
$c = ($c | ($c >> 28)) & 0x0FFFFFFF;
$d <<= $shifts[$i];
$d = ($d | ($d >> 28)) & 0x0FFFFFFF;
// Perform the PC-2 transformation.
$cp = $pc2mapc1[ $c >> 24 ] | $pc2mapc2[($c >> 16) & 0xFF] |
$pc2mapc3[($c >> 8) & 0xFF] | $pc2mapc4[ $c & 0xFF];
$dp = $pc2mapd1[ $d >> 24 ] | $pc2mapd2[($d >> 16) & 0xFF] |
$pc2mapd3[($d >> 8) & 0xFF] | $pc2mapd4[ $d & 0xFF];
// Reorder: odd bytes/even bytes. Push the result in key schedule.
$val1 = ( $cp & intval(0xFF000000)) | (($cp << 8) & 0x00FF0000) |
(($dp >> 16) & 0x0000FF00) | (($dp >> 8) & 0x000000FF);
$val2 = (($cp << 8) & intval(0xFF000000)) | (($cp << 16) & 0x00FF0000) |
(($dp >> 8) & 0x0000FF00) | ( $dp & 0x000000FF);
$keys[$des_round][self::ENCRYPT][ ] = $val1;
$keys[$des_round][self::DECRYPT][$ki - 1] = $val1;
$keys[$des_round][self::ENCRYPT][ ] = $val2;
$keys[$des_round][self::DECRYPT][$ki ] = $val2;
}
}
switch ($this->des_rounds) {
case 3: // 3DES keys
$this->keys = [
self::ENCRYPT => array_merge(
$keys[0][self::ENCRYPT],
$keys[1][self::DECRYPT],
$keys[2][self::ENCRYPT]
),
self::DECRYPT => array_merge(
$keys[2][self::DECRYPT],
$keys[1][self::ENCRYPT],
$keys[0][self::DECRYPT]
)
];
break;
// case 1: // DES keys
default:
$this->keys = [
self::ENCRYPT => $keys[0][self::ENCRYPT],
self::DECRYPT => $keys[0][self::DECRYPT]
];
}
}
/**
* Setup the performance-optimized function for de/encrypt()
*
* @see \phpseclib3\Crypt\Common\SymmetricKey::setupInlineCrypt()
*/
protected function setupInlineCrypt()
{
// Engine configuration for:
// - DES ($des_rounds == 1) or
// - 3DES ($des_rounds == 3)
$des_rounds = $this->des_rounds;
$init_crypt = 'static $sbox1, $sbox2, $sbox3, $sbox4, $sbox5, $sbox6, $sbox7, $sbox8, $shuffleip, $shuffleinvip;
if (!$sbox1) {
$sbox1 = array_map("intval", self::$sbox1);
$sbox2 = array_map("intval", self::$sbox2);
$sbox3 = array_map("intval", self::$sbox3);
$sbox4 = array_map("intval", self::$sbox4);
$sbox5 = array_map("intval", self::$sbox5);
$sbox6 = array_map("intval", self::$sbox6);
$sbox7 = array_map("intval", self::$sbox7);
$sbox8 = array_map("intval", self::$sbox8);'
/* Merge $shuffle with $[inv]ipmap */ . '
for ($i = 0; $i < 256; ++$i) {
$shuffleip[] = self::$shuffle[self::$ipmap[$i]];
$shuffleinvip[] = self::$shuffle[self::$invipmap[$i]];
}
}
';
$k = [
self::ENCRYPT => $this->keys[self::ENCRYPT],
self::DECRYPT => $this->keys[self::DECRYPT]
];
$init_encrypt = '';
$init_decrypt = '';
// Creating code for en- and decryption.
$crypt_block = [];
foreach ([self::ENCRYPT, self::DECRYPT] as $c) {
/* Do the initial IP permutation. */
$crypt_block[$c] = '
$in = unpack("N*", $in);
$l = $in[1];
$r = $in[2];
$in = unpack("N*",
($shuffleip[ $r & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleip[($r >> 8) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleip[($r >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleip[($r >> 24) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleip[ $l & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleip[($l >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleip[($l >> 16) & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleip[($l >> 24) & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01")
);
' . /* Extract L0 and R0 */ '
$l = $in[1];
$r = $in[2];
';
$l = '$l';
$r = '$r';
// Perform DES or 3DES.
for ($ki = -1, $des_round = 0; $des_round < $des_rounds; ++$des_round) {
// Perform the 16 steps.
for ($i = 0; $i < 16; ++$i) {
// start of "the Feistel (F) function" - see the following URL:
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
// Merge key schedule.
$crypt_block[$c] .= '
$b1 = ((' . $r . ' >> 3) & 0x1FFFFFFF) ^ (' . $r . ' << 29) ^ ' . $k[$c][++$ki] . ';
$b2 = ((' . $r . ' >> 31) & 0x00000001) ^ (' . $r . ' << 1) ^ ' . $k[$c][++$ki] . ';' .
/* S-box indexing. */
$l . ' = $sbox1[($b1 >> 24) & 0x3F] ^ $sbox2[($b2 >> 24) & 0x3F] ^
$sbox3[($b1 >> 16) & 0x3F] ^ $sbox4[($b2 >> 16) & 0x3F] ^
$sbox5[($b1 >> 8) & 0x3F] ^ $sbox6[($b2 >> 8) & 0x3F] ^
$sbox7[ $b1 & 0x3F] ^ $sbox8[ $b2 & 0x3F] ^ ' . $l . ';
';
// end of "the Feistel (F) function"
// swap L & R
list($l, $r) = [$r, $l];
}
list($l, $r) = [$r, $l];
}
// Perform the inverse IP permutation.
$crypt_block[$c] .= '$in =
($shuffleinvip[($l >> 24) & 0xFF] & "\x80\x80\x80\x80\x80\x80\x80\x80") |
($shuffleinvip[($r >> 24) & 0xFF] & "\x40\x40\x40\x40\x40\x40\x40\x40") |
($shuffleinvip[($l >> 16) & 0xFF] & "\x20\x20\x20\x20\x20\x20\x20\x20") |
($shuffleinvip[($r >> 16) & 0xFF] & "\x10\x10\x10\x10\x10\x10\x10\x10") |
($shuffleinvip[($l >> 8) & 0xFF] & "\x08\x08\x08\x08\x08\x08\x08\x08") |
($shuffleinvip[($r >> 8) & 0xFF] & "\x04\x04\x04\x04\x04\x04\x04\x04") |
($shuffleinvip[ $l & 0xFF] & "\x02\x02\x02\x02\x02\x02\x02\x02") |
($shuffleinvip[ $r & 0xFF] & "\x01\x01\x01\x01\x01\x01\x01\x01");
';
}
// Creates the inline-crypt function
$this->inline_crypt = $this->createInlineCryptFunction(
[
'init_crypt' => $init_crypt,
'init_encrypt' => $init_encrypt,
'init_decrypt' => $init_decrypt,
'encrypt_block' => $crypt_block[self::ENCRYPT],
'decrypt_block' => $crypt_block[self::DECRYPT]
]
);
}
}
<?php
/**
* Pure-PHP (EC)DH implementation
*
* PHP version 5
*
* Here's an example of how to compute a shared secret with this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* $ourPrivate = \phpseclib3\Crypt\DH::createKey();
* $secret = DH::computeSecret($ourPrivate, $theirPublic);
*
* ?>
* </code>
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt;
use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\DH\Parameters;
use phpseclib3\Crypt\DH\PrivateKey;
use phpseclib3\Crypt\DH\PublicKey;
use phpseclib3\Exception\NoKeyLoadedException;
use phpseclib3\Exception\UnsupportedOperationException;
use phpseclib3\Math\BigInteger;
/**
* Pure-PHP (EC)DH implementation
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class DH extends AsymmetricKey
{
/**
* Algorithm Name
*
* @var string
*/
const ALGORITHM = 'DH';
/**
* DH prime
*
* @var \phpseclib3\Math\BigInteger
*/
protected $prime;
/**
* DH Base
*
* Prime divisor of p-1
*
* @var \phpseclib3\Math\BigInteger
*/
protected $base;
/**
* Public Key
*
* @var \phpseclib3\Math\BigInteger
*/
protected $publicKey;
/**
* Create DH parameters
*
* This method is a bit polymorphic. It can take any of the following:
* - two BigInteger's (prime and base)
* - an integer representing the size of the prime in bits (the base is assumed to be 2)
* - a string (eg. diffie-hellman-group14-sha1)
*
* @return Parameters
*/
public static function createParameters(...$args)
{
$params = new Parameters();
if (count($args) == 2 && $args[0] instanceof BigInteger && $args[1] instanceof BigInteger) {
//if (!$args[0]->isPrime()) {
// throw new \InvalidArgumentException('The first parameter should be a prime number');
//}
$params->prime = $args[0];
$params->base = $args[1];
return $params;
} elseif (count($args) == 1 && is_numeric($args[0])) {
$params->prime = BigInteger::randomPrime($args[0]);
$params->base = new BigInteger(2);
return $params;
} elseif (count($args) != 1 || !is_string($args[0])) {
throw new \InvalidArgumentException('Valid parameters are either: two BigInteger\'s (prime and base), a single integer (the length of the prime; base is assumed to be 2) or a string');
}
switch ($args[0]) {
// see http://tools.ietf.org/html/rfc2409#section-6.2 and
// http://tools.ietf.org/html/rfc2412, appendex E
case 'diffie-hellman-group1-sha1':
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
break;
// see http://tools.ietf.org/html/rfc3526#section-3
case 'diffie-hellman-group14-sha1': // 2048-bit MODP Group
case 'diffie-hellman-group14-sha256':
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
'98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
'9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
'3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
break;
// see https://tools.ietf.org/html/rfc3526#section-4
case 'diffie-hellman-group15-sha512': // 3072-bit MODP Group
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
'98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
'9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
'3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
'08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF';
break;
// see https://tools.ietf.org/html/rfc3526#section-5
case 'diffie-hellman-group16-sha512': // 4096-bit MODP Group
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
'98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
'9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
'3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
'08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' .
'88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' .
'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' .
'233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' .
'93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF';
break;
// see https://tools.ietf.org/html/rfc3526#section-6
case 'diffie-hellman-group17-sha512': // 6144-bit MODP Group
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
'98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
'9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
'3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
'08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' .
'88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' .
'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' .
'233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' .
'93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026' .
'C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AE' .
'B06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B' .
'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92EC' .
'F032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E' .
'59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA' .
'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76' .
'F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468' .
'043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF';
break;
// see https://tools.ietf.org/html/rfc3526#section-7
case 'diffie-hellman-group18-sha512': // 8192-bit MODP Group
$prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
'98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
'9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
'3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
'08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' .
'88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' .
'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' .
'233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' .
'93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026' .
'C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AE' .
'B06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B' .
'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92EC' .
'F032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E' .
'59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA' .
'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76' .
'F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468' .
'043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4' .
'38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED' .
'2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652D' .
'E3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B' .
'4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6' .
'6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851D' .
'F9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92' .
'4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA' .
'9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF';
break;
default:
throw new \InvalidArgumentException('Invalid named prime provided');
}
$params->prime = new BigInteger($prime, 16);
$params->base = new BigInteger(2);
return $params;
}
/**
* Create public / private key pair.
*
* The rationale for the second parameter is described in http://tools.ietf.org/html/rfc4419#section-6.2 :
*
* "To increase the speed of the key exchange, both client and server may
* reduce the size of their private exponents. It should be at least
* twice as long as the key material that is generated from the shared
* secret. For more details, see the paper by van Oorschot and Wiener
* [VAN-OORSCHOT]."
*
* $length is in bits
*
* @param Parameters $params
* @param int $length optional
* @return DH\PrivateKey
*/
public static function createKey(Parameters $params, $length = 0)
{
$one = new BigInteger(1);
if ($length) {
$max = $one->bitwise_leftShift($length);
$max = $max->subtract($one);
} else {
$max = $params->prime->subtract($one);
}
$key = new PrivateKey();
$key->prime = $params->prime;
$key->base = $params->base;
$key->privateKey = BigInteger::randomRange($one, $max);
$key->publicKey = $key->base->powMod($key->privateKey, $key->prime);
return $key;
}
/**
* Compute Shared Secret
*
* @param PrivateKey|EC $private
* @param PublicKey|BigInteger|string $public
* @return mixed
*/
public static function computeSecret($private, $public)
{
if ($private instanceof PrivateKey) { // DH\PrivateKey
switch (true) {
case $public instanceof PublicKey:
if (!$private->prime->equals($public->prime) || !$private->base->equals($public->base)) {
throw new \InvalidArgumentException('The public and private key do not share the same prime and / or base numbers');
}
return $public->publicKey->powMod($private->privateKey, $private->prime)->toBytes(true);
case is_string($public):
$public = new BigInteger($public, -256);
// fall-through
case $public instanceof BigInteger:
return $public->powMod($private->privateKey, $private->prime)->toBytes(true);
default:
throw new \InvalidArgumentException('$public needs to be an instance of DH\PublicKey, a BigInteger or a string');
}
}
if ($private instanceof EC\PrivateKey) {
switch (true) {
case $public instanceof EC\PublicKey:
$public = $public->getEncodedCoordinates();
// fall-through
case is_string($public):
$point = $private->multiply($public);
switch ($private->getCurve()) {
case 'Curve25519':
case 'Curve448':
$secret = $point;
break;
default:
// according to https://www.secg.org/sec1-v2.pdf#page=33 only X is returned
$secret = substr($point, 1, (strlen($point) - 1) >> 1);
}
/*
if (($secret[0] & "\x80") === "\x80") {
$secret = "\0$secret";
}
*/
return $secret;
default:
throw new \InvalidArgumentException('$public needs to be an instance of EC\PublicKey or a string (an encoded coordinate)');
}
}
}
/**
* Load the key
*
* @param string $key
* @param string $password optional
* @return AsymmetricKey
*/
public static function load($key, $password = false)
{
try {
return EC::load($key, $password);
} catch (NoKeyLoadedException $e) {
}
return parent::load($key, $password);
}
/**
* OnLoad Handler
*
* @return bool
*/
protected static function onLoad(array $components)
{
if (!isset($components['privateKey']) && !isset($components['publicKey'])) {
$new = new Parameters();
} else {
$new = isset($components['privateKey']) ?
new PrivateKey() :
new PublicKey();
}
$new->prime = $components['prime'];
$new->base = $components['base'];
if (isset($components['privateKey'])) {
$new->privateKey = $components['privateKey'];
}
if (isset($components['publicKey'])) {
$new->publicKey = $components['publicKey'];
}
return $new;
}
/**
* Determines which hashing function should be used
*
* @param string $hash
*/
public function withHash($hash)
{
throw new UnsupportedOperationException('DH does not use a hash algorithm');
}
/**
* Returns the hash algorithm currently being used
*
*/
public function getHash()
{
throw new UnsupportedOperationException('DH does not use a hash algorithm');
}
/**
* Returns the parameters
*
* A public / private key is only returned if the currently loaded "key" contains an x or y
* value.
*
* @see self::getPublicKey()
* @return mixed
*/
public function getParameters()
{
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
$key = $type::saveParameters($this->prime, $this->base);
return self::load($key, 'PKCS1');
}
}
<?php
/**
* "PKCS1" Formatted EC Key Handler
*
* PHP version 5
*
* Processes keys with the following headers:
*
* -----BEGIN DH PARAMETERS-----
*
* Technically, PKCS1 is for RSA keys, only, but we're using PKCS1 to describe
* DSA, whose format isn't really formally described anywhere, so might as well
* use it to describe this, too.
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DH\Formats\Keys;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;
/**
* "PKCS1" Formatted DH Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS1 extends Progenitor
{
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$key = parent::load($key, $password);
$decoded = ASN1::decodeBER($key);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER');
}
$components = ASN1::asn1map($decoded[0], Maps\DHParameter::MAP);
if (!is_array($components)) {
throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
}
return $components;
}
/**
* Convert EC parameters to the appropriate format
*
* @return string
*/
public static function saveParameters(BigInteger $prime, BigInteger $base, array $options = [])
{
$params = [
'prime' => $prime,
'base' => $base
];
$params = ASN1::encodeDER($params, Maps\DHParameter::MAP);
return "-----BEGIN DH PARAMETERS-----\r\n" .
chunk_split(base64_encode($params), 64) .
"-----END DH PARAMETERS-----\r\n";
}
}
<?php
/**
* PKCS#8 Formatted DH Key Handler
*
* PHP version 5
*
* Processes keys with the following headers:
*
* -----BEGIN ENCRYPTED PRIVATE KEY-----
* -----BEGIN PRIVATE KEY-----
* -----BEGIN PUBLIC KEY-----
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DH\Formats\Keys;
use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;
/**
* PKCS#8 Formatted DH Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS8 extends Progenitor
{
/**
* OID Name
*
* @var string
*/
const OID_NAME = 'dhKeyAgreement';
/**
* OID Value
*
* @var string
*/
const OID_VALUE = '1.2.840.113549.1.3.1';
/**
* Child OIDs loaded
*
* @var bool
*/
protected static $childOIDsLoaded = false;
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
if (!Strings::is_stringable($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
$isPublic = strpos($key, 'PUBLIC') !== false;
$key = parent::load($key, $password);
$type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';
switch (true) {
case !$isPublic && $type == 'publicKey':
throw new \UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key');
case $isPublic && $type == 'privateKey':
throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key');
}
$decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
if (empty($decoded)) {
throw new \RuntimeException('Unable to decode BER of parameters');
}
$components = ASN1::asn1map($decoded[0], Maps\DHParameter::MAP);
if (!is_array($components)) {
throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
}
$decoded = ASN1::decodeBER($key[$type]);
switch (true) {
case !isset($decoded):
case !isset($decoded[0]['content']):
case !$decoded[0]['content'] instanceof BigInteger:
throw new \RuntimeException('Unable to decode BER of parameters');
}
$components[$type] = $decoded[0]['content'];
return $components;
}
/**
* Convert a private key to the appropriate format.
*
* @param \phpseclib3\Math\BigInteger $prime
* @param \phpseclib3\Math\BigInteger $base
* @param \phpseclib3\Math\BigInteger $privateKey
* @param \phpseclib3\Math\BigInteger $publicKey
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $prime, BigInteger $base, BigInteger $privateKey, BigInteger $publicKey, $password = '', array $options = [])
{
$params = [
'prime' => $prime,
'base' => $base
];
$params = ASN1::encodeDER($params, Maps\DHParameter::MAP);
$params = new ASN1\Element($params);
$key = ASN1::encodeDER($privateKey, ['type' => ASN1::TYPE_INTEGER]);
return self::wrapPrivateKey($key, [], $params, $password, null, '', $options);
}
/**
* Convert a public key to the appropriate format
*
* @param \phpseclib3\Math\BigInteger $prime
* @param \phpseclib3\Math\BigInteger $base
* @param \phpseclib3\Math\BigInteger $publicKey
* @param array $options optional
* @return string
*/
public static function savePublicKey(BigInteger $prime, BigInteger $base, BigInteger $publicKey, array $options = [])
{
$params = [
'prime' => $prime,
'base' => $base
];
$params = ASN1::encodeDER($params, Maps\DHParameter::MAP);
$params = new ASN1\Element($params);
$key = ASN1::encodeDER($publicKey, ['type' => ASN1::TYPE_INTEGER]);
return self::wrapPublicKey($key, $params);
}
}
<?php
/**
* DH Parameters
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DH;
use phpseclib3\Crypt\DH;
/**
* DH Parameters
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class Parameters extends DH
{
/**
* Returns the parameters
*
* @param string $type
* @param array $options optional
* @return string
*/
public function toString($type = 'PKCS1', array $options = [])
{
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
return $type::saveParameters($this->prime, $this->base, $options);
}
}
<?php
/**
* DH Private Key
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DH;
use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\DH;
/**
* DH Private Key
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class PrivateKey extends DH
{
use Common\Traits\PasswordProtected;
/**
* Private Key
*
* @var \phpseclib3\Math\BigInteger
*/
protected $privateKey;
/**
* Public Key
*
* @var \phpseclib3\Math\BigInteger
*/
protected $publicKey;
/**
* Returns the public key
*
* @return DH\PublicKey
*/
public function getPublicKey()
{
$type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');
if (!isset($this->publicKey)) {
$this->publicKey = $this->base->powMod($this->privateKey, $this->prime);
}
$key = $type::savePublicKey($this->prime, $this->base, $this->publicKey);
return DH::loadFormat('PKCS8', $key);
}
/**
* Returns the private key
*
* @param string $type
* @param array $options optional
* @return string
*/
public function toString($type, array $options = [])
{
$type = self::validatePlugin('Keys', $type, 'savePrivateKey');
if (!isset($this->publicKey)) {
$this->publicKey = $this->base->powMod($this->privateKey, $this->prime);
}
return $type::savePrivateKey($this->prime, $this->base, $this->privateKey, $this->publicKey, $this->password, $options);
}
}
<?php
/**
* DH Public Key
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DH;
use phpseclib3\Crypt\Common;
use phpseclib3\Crypt\DH;
/**
* DH Public Key
*
* @author Jim Wigginton <terrafrost@php.net>
*/
class PublicKey extends DH
{
use Common\Traits\Fingerprint;
/**
* Returns the public key
*
* @param string $type
* @param array $options optional
* @return string
*/
public function toString($type, array $options = [])
{
$type = self::validatePlugin('Keys', $type, 'savePublicKey');
return $type::savePublicKey($this->prime, $this->base, $this->publicKey, $options);
}
/**
* Returns the public key as a BigInteger
*
* @return \phpseclib3\Math\BigInteger
*/
public function toBigInteger()
{
return $this->publicKey;
}
}
<?php
/**
* Pure-PHP FIPS 186-4 compliant implementation of DSA.
*
* PHP version 5
*
* Here's an example of how to create signatures and verify signatures with this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* $private = \phpseclib3\Crypt\DSA::createKey();
* $public = $private->getPublicKey();
*
* $plaintext = 'terrafrost';
*
* $signature = $private->sign($plaintext);
*
* echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified';
* ?>
* </code>
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt;
use phpseclib3\Crypt\Common\AsymmetricKey;
use phpseclib3\Crypt\DSA\Parameters;
use phpseclib3\Crypt\DSA\PrivateKey;
use phpseclib3\Crypt\DSA\PublicKey;
use phpseclib3\Exception\InsufficientSetupException;
use phpseclib3\Math\BigInteger;
/**
* Pure-PHP FIPS 186-4 compliant implementation of DSA.
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class DSA extends AsymmetricKey
{
/**
* Algorithm Name
*
* @var string
*/
const ALGORITHM = 'DSA';
/**
* DSA Prime P
*
* @var \phpseclib3\Math\BigInteger
*/
protected $p;
/**
* DSA Group Order q
*
* Prime divisor of p-1
*
* @var \phpseclib3\Math\BigInteger
*/
protected $q;
/**
* DSA Group Generator G
*
* @var \phpseclib3\Math\BigInteger
*/
protected $g;
/**
* DSA public key value y
*
* @var \phpseclib3\Math\BigInteger
*/
protected $y;
/**
* Signature Format
*
* @var string
*/
protected $sigFormat;
/**
* Signature Format (Short)
*
* @var string
*/
protected $shortFormat;
/**
* Create DSA parameters
*
* @param int $L
* @param int $N
* @return \phpseclib3\Crypt\DSA|bool
*/
public static function createParameters($L = 2048, $N = 224)
{
self::initialize_static_variables();
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
switch (true) {
case $N == 160:
/*
in FIPS 186-1 and 186-2 N was fixed at 160 whereas K had an upper bound of 1024.
RFC 4253 (SSH Transport Layer Protocol) references FIPS 186-2 and as such most
SSH DSA implementations only support keys with an N of 160.
puttygen let's you set the size of L (but not the size of N) and uses 2048 as the
default L value. that's not really compliant with any of the FIPS standards, however,
for the purposes of maintaining compatibility with puttygen, we'll support it
*/
//case ($L >= 512 || $L <= 1024) && (($L & 0x3F) == 0) && $N == 160:
// FIPS 186-3 changed this as follows:
//case $L == 1024 && $N == 160:
case $L == 2048 && $N == 224:
case $L == 2048 && $N == 256:
case $L == 3072 && $N == 256:
break;
default:
throw new \InvalidArgumentException('Invalid values for N and L');
}
$two = new BigInteger(2);
$q = BigInteger::randomPrime($N);
$divisor = $q->multiply($two);
do {
$x = BigInteger::random($L);
list(, $c) = $x->divide($divisor);
$p = $x->subtract($c->subtract(self::$one));
} while ($p->getLength() != $L || !$p->isPrime());
$p_1 = $p->subtract(self::$one);
list($e) = $p_1->divide($q);
// quoting http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#page=50 ,
// "h could be obtained from a random number generator or from a counter that
// changes after each use". PuTTY (sshdssg.c) starts h off at 1 and increments
// it on each loop. wikipedia says "commonly h = 2 is used" so we'll just do that
$h = clone $two;
while (true) {
$g = $h->powMod($e, $p);
if (!$g->equals(self::$one)) {
break;
}
$h = $h->add(self::$one);
}
$dsa = new Parameters();
$dsa->p = $p;
$dsa->q = $q;
$dsa->g = $g;
return $dsa;
}
/**
* Create public / private key pair.
*
* This method is a bit polymorphic. It can take a DSA/Parameters object, L / N as two distinct parameters or
* no parameters (at which point L and N will be generated with this method)
*
* Returns the private key, from which the publickey can be extracted
*
* @param int[] ...$args
* @return DSA\PrivateKey
*/
public static function createKey(...$args)
{
self::initialize_static_variables();
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if (count($args) == 2 && is_int($args[0]) && is_int($args[1])) {
$params = self::createParameters($args[0], $args[1]);
} elseif (count($args) == 1 && $args[0] instanceof Parameters) {
$params = $args[0];
} elseif (!count($args)) {
$params = self::createParameters();
} else {
throw new InsufficientSetupException('Valid parameters are either two integers (L and N), a single DSA object or no parameters at all.');
}
$private = new PrivateKey();
$private->p = $params->p;
$private->q = $params->q;
$private->g = $params->g;
$private->x = BigInteger::randomRange(self::$one, $private->q->subtract(self::$one));
$private->y = $private->g->powMod($private->x, $private->p);
//$public = clone $private;
//unset($public->x);
return $private
->withHash($params->hash->getHash())
->withSignatureFormat($params->shortFormat);
}
/**
* OnLoad Handler
*
* @return bool
*/
protected static function onLoad(array $components)
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if (!isset($components['x']) && !isset($components['y'])) {
$new = new Parameters();
} elseif (isset($components['x'])) {
$new = new PrivateKey();
$new->x = $components['x'];
} else {
$new = new PublicKey();
}
$new->p = $components['p'];
$new->q = $components['q'];
$new->g = $components['g'];
if (isset($components['y'])) {
$new->y = $components['y'];
}
return $new;
}
/**
* Constructor
*
* PublicKey and PrivateKey objects can only be created from abstract RSA class
*/
protected function __construct()
{
$this->sigFormat = self::validatePlugin('Signature', 'ASN1');
$this->shortFormat = 'ASN1';
parent::__construct();
}
/**
* Returns the key size
*
* More specifically, this L (the length of DSA Prime P) and N (the length of DSA Group Order q)
*
* @return array
*/
public function getLength()
{
return ['L' => $this->p->getLength(), 'N' => $this->q->getLength()];
}
/**
* Returns the current engine being used
*
* @see self::useInternalEngine()
* @see self::useBestEngine()
* @return string
*/
public function getEngine()
{
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
return self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods()) ?
'OpenSSL' : 'PHP';
}
/**
* Returns the parameters
*
* A public / private key is only returned if the currently loaded "key" contains an x or y
* value.
*
* @see self::getPublicKey()
* @return mixed
*/
public function getParameters()
{
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
$key = $type::saveParameters($this->p, $this->q, $this->g);
return DSA::load($key, 'PKCS1')
->withHash($this->hash->getHash())
->withSignatureFormat($this->shortFormat);
}
/**
* Determines the signature padding mode
*
* Valid values are: ASN1, SSH2, Raw
*
* @param string $format
*/
public function withSignatureFormat($format)
{
$new = clone $this;
$new->shortFormat = $format;
$new->sigFormat = self::validatePlugin('Signature', $format);
return $new;
}
/**
* Returns the signature format currently being used
*
*/
public function getSignatureFormat()
{
return $this->shortFormat;
}
}
<?php
/**
* OpenSSH Formatted DSA Key Handler
*
* PHP version 5
*
* Place in $HOME/.ssh/authorized_keys
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DSA\Formats\Keys;
use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\OpenSSH as Progenitor;
use phpseclib3\Math\BigInteger;
/**
* OpenSSH Formatted DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class OpenSSH extends Progenitor
{
/**
* Supported Key Types
*
* @var array
*/
protected static $types = ['ssh-dss'];
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$parsed = parent::load($key, $password);
if (isset($parsed['paddedKey'])) {
list($type) = Strings::unpackSSH2('s', $parsed['paddedKey']);
if ($type != $parsed['type']) {
throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])");
}
list($p, $q, $g, $y, $x, $comment) = Strings::unpackSSH2('i5s', $parsed['paddedKey']);
return compact('p', 'q', 'g', 'y', 'x', 'comment');
}
list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $parsed['publicKey']);
$comment = $parsed['comment'];
return compact('p', 'q', 'g', 'y', 'comment');
}
/**
* Convert a public key to the appropriate format
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @param array $options optional
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = [])
{
if ($q->getLength() != 160) {
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
}
// from <http://tools.ietf.org/html/rfc4253#page-15>:
// string "ssh-dss"
// mpint p
// mpint q
// mpint g
// mpint y
$DSAPublicKey = Strings::packSSH2('siiii', 'ssh-dss', $p, $q, $g, $y);
if (isset($options['binary']) ? $options['binary'] : self::$binary) {
return $DSAPublicKey;
}
$comment = isset($options['comment']) ? $options['comment'] : self::$comment;
$DSAPublicKey = 'ssh-dss ' . base64_encode($DSAPublicKey) . ' ' . $comment;
return $DSAPublicKey;
}
/**
* Convert a private key to the appropriate format.
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @param \phpseclib3\Math\BigInteger $x
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
{
$publicKey = self::savePublicKey($p, $q, $g, $y, ['binary' => true]);
$privateKey = Strings::packSSH2('si5', 'ssh-dss', $p, $q, $g, $y, $x);
return self::wrapPrivateKey($publicKey, $privateKey, $password, $options);
}
}
<?php
/**
* PKCS#1 Formatted DSA Key Handler
*
* PHP version 5
*
* Used by File/X509.php
*
* Processes keys with the following headers:
*
* -----BEGIN DSA PRIVATE KEY-----
* -----BEGIN DSA PUBLIC KEY-----
* -----BEGIN DSA PARAMETERS-----
*
* Analogous to ssh-keygen's pem format (as specified by -m)
*
* Also, technically, PKCS1 decribes RSA but I am not aware of a formal specification for DSA.
* The DSA private key format seems to have been adapted from the RSA private key format so
* we're just re-using that as the name.
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DSA\Formats\Keys;
use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;
/**
* PKCS#1 Formatted DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS1 extends Progenitor
{
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$key = parent::load($key, $password);
$decoded = ASN1::decodeBER($key);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER');
}
$key = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
if (is_array($key)) {
return $key;
}
$key = ASN1::asn1map($decoded[0], Maps\DSAPrivateKey::MAP);
if (is_array($key)) {
return $key;
}
$key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
if (is_array($key)) {
return $key;
}
throw new \RuntimeException('Unable to perform ASN1 mapping');
}
/**
* Convert DSA parameters to the appropriate format
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @return string
*/
public static function saveParameters(BigInteger $p, BigInteger $q, BigInteger $g)
{
$key = [
'p' => $p,
'q' => $q,
'g' => $g
];
$key = ASN1::encodeDER($key, Maps\DSAParams::MAP);
return "-----BEGIN DSA PARAMETERS-----\r\n" .
chunk_split(Strings::base64_encode($key), 64) .
"-----END DSA PARAMETERS-----\r\n";
}
/**
* Convert a private key to the appropriate format.
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @param \phpseclib3\Math\BigInteger $x
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
{
$key = [
'version' => 0,
'p' => $p,
'q' => $q,
'g' => $g,
'y' => $y,
'x' => $x
];
$key = ASN1::encodeDER($key, Maps\DSAPrivateKey::MAP);
return self::wrapPrivateKey($key, 'DSA', $password, $options);
}
/**
* Convert a public key to the appropriate format
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
{
$key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP);
return self::wrapPublicKey($key, 'DSA');
}
}
<?php
/**
* PKCS#8 Formatted DSA Key Handler
*
* PHP version 5
*
* Processes keys with the following headers:
*
* -----BEGIN ENCRYPTED PRIVATE KEY-----
* -----BEGIN PRIVATE KEY-----
* -----BEGIN PUBLIC KEY-----
*
* Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
* is specific to private keys it's basically creating a DER-encoded wrapper
* for keys. This just extends that same concept to public keys (much like ssh-keygen)
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DSA\Formats\Keys;
use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
use phpseclib3\File\ASN1;
use phpseclib3\File\ASN1\Maps;
use phpseclib3\Math\BigInteger;
/**
* PKCS#8 Formatted DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PKCS8 extends Progenitor
{
/**
* OID Name
*
* @var string
*/
const OID_NAME = 'id-dsa';
/**
* OID Value
*
* @var string
*/
const OID_VALUE = '1.2.840.10040.4.1';
/**
* Child OIDs loaded
*
* @var bool
*/
protected static $childOIDsLoaded = false;
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
if (!Strings::is_stringable($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
$isPublic = strpos($key, 'PUBLIC') !== false;
$key = parent::load($key, $password);
$type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';
switch (true) {
case !$isPublic && $type == 'publicKey':
throw new \UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key');
case $isPublic && $type == 'privateKey':
throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key');
}
$decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
if (!$decoded) {
throw new \RuntimeException('Unable to decode BER of parameters');
}
$components = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
if (!is_array($components)) {
throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
}
$decoded = ASN1::decodeBER($key[$type]);
if (empty($decoded)) {
throw new \RuntimeException('Unable to decode BER');
}
$var = $type == 'privateKey' ? 'x' : 'y';
$components[$var] = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
if (!$components[$var] instanceof BigInteger) {
throw new \RuntimeException('Unable to perform ASN1 mapping');
}
if (isset($key['meta'])) {
$components['meta'] = $key['meta'];
}
return $components;
}
/**
* Convert a private key to the appropriate format.
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @param \phpseclib3\Math\BigInteger $x
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
{
$params = [
'p' => $p,
'q' => $q,
'g' => $g
];
$params = ASN1::encodeDER($params, Maps\DSAParams::MAP);
$params = new ASN1\Element($params);
$key = ASN1::encodeDER($x, Maps\DSAPublicKey::MAP);
return self::wrapPrivateKey($key, [], $params, $password, null, '', $options);
}
/**
* Convert a public key to the appropriate format
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @param array $options optional
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = [])
{
$params = [
'p' => $p,
'q' => $q,
'g' => $g
];
$params = ASN1::encodeDER($params, Maps\DSAParams::MAP);
$params = new ASN1\Element($params);
$key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP);
return self::wrapPublicKey($key, $params);
}
}
<?php
/**
* PuTTY Formatted DSA Key Handler
*
* puttygen does not generate DSA keys with an N of anything other than 160, however,
* it can still load them and convert them. PuTTY will load them, too, but SSH servers
* won't accept them. Since PuTTY formatted keys are primarily used with SSH this makes
* keys with N > 160 kinda useless, hence this handlers not supporting such keys.
*
* PHP version 5
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DSA\Formats\Keys;
use phpseclib3\Common\Functions\Strings;
use phpseclib3\Crypt\Common\Formats\Keys\PuTTY as Progenitor;
use phpseclib3\Math\BigInteger;
/**
* PuTTY Formatted DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class PuTTY extends Progenitor
{
/**
* Public Handler
*
* @var string
*/
const PUBLIC_HANDLER = 'phpseclib3\Crypt\DSA\Formats\Keys\OpenSSH';
/**
* Algorithm Identifier
*
* @var array
*/
protected static $types = ['ssh-dss'];
/**
* Break a public or private key down into its constituent components
*
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$components = parent::load($key, $password);
if (!isset($components['private'])) {
return $components;
}
extract($components);
unset($components['public'], $components['private']);
list($p, $q, $g, $y) = Strings::unpackSSH2('iiii', $public);
list($x) = Strings::unpackSSH2('i', $private);
return compact('p', 'q', 'g', 'y', 'x', 'comment');
}
/**
* Convert a private key to the appropriate format.
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @param \phpseclib3\Math\BigInteger $x
* @param string $password optional
* @param array $options optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = false, array $options = [])
{
if ($q->getLength() != 160) {
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
}
$public = Strings::packSSH2('iiii', $p, $q, $g, $y);
$private = Strings::packSSH2('i', $x);
return self::wrapPrivateKey($public, $private, 'ssh-dss', $password, $options);
}
/**
* Convert a public key to the appropriate format
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
{
if ($q->getLength() != 160) {
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
}
return self::wrapPublicKey(Strings::packSSH2('iiii', $p, $q, $g, $y), 'ssh-dss');
}
}
<?php
/**
* Raw DSA Key Handler
*
* PHP version 5
*
* Reads and creates arrays as DSA keys
*
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2015 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib3\Crypt\DSA\Formats\Keys;
use phpseclib3\Math\BigInteger;
/**
* Raw DSA Key Handler
*
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class Raw
{
/**
* Break a public or private key down into its constituent components
*
* @param array $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
if (!is_array($key)) {
throw new \UnexpectedValueException('Key should be a array - not a ' . gettype($key));
}
switch (true) {
case !isset($key['p']) || !isset($key['q']) || !isset($key['g']):
case !$key['p'] instanceof BigInteger:
case !$key['q'] instanceof BigInteger:
case !$key['g'] instanceof BigInteger:
case !isset($key['x']) && !isset($key['y']):
case isset($key['x']) && !$key['x'] instanceof BigInteger:
case isset($key['y']) && !$key['y'] instanceof BigInteger:
throw new \UnexpectedValueException('Key appears to be malformed');
}
$options = ['p' => 1, 'q' => 1, 'g' => 1, 'x' => 1, 'y' => 1];
return array_intersect_key($key, $options);
}
/**
* Convert a private key to the appropriate format.
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @param \phpseclib3\Math\BigInteger $x
* @param string $password optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '')
{
return compact('p', 'q', 'g', 'y', 'x');
}
/**
* Convert a public key to the appropriate format
*
* @param \phpseclib3\Math\BigInteger $p
* @param \phpseclib3\Math\BigInteger $q
* @param \phpseclib3\Math\BigInteger $g
* @param \phpseclib3\Math\BigInteger $y
* @return string
*/
public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y)
{
return compact('p', 'q', 'g', 'y');
}
}