2009-12-03 09:19:00 +01:00
< ? php
/**
* Pure - PHP PKCS #1 (v2.1) compliant implementation of RSA.
*
2015-04-02 12:57:52 +02:00
* PHP version 5
2009-12-03 09:19:00 +01:00
*
* Here ' s an example of how to encrypt and decrypt text with this library :
* < code >
* < ? php
2015-10-01 17:15:58 +02:00
* include 'vendor/autoload.php' ;
2009-12-03 09:19:00 +01:00
*
2016-01-07 14:00:26 +01:00
* extract ( \phpseclib\Crypt\RSA :: createKey ());
2009-12-03 09:19:00 +01:00
*
2015-10-01 17:15:58 +02:00
* $plaintext = 'terrafrost' ;
2009-12-03 09:19:00 +01:00
*
2015-10-01 17:15:58 +02:00
* $ciphertext = $publickey -> encrypt ( $plaintext );
2009-12-03 09:19:00 +01:00
*
2015-10-01 17:15:58 +02:00
* echo $privatekey -> decrypt ( $ciphertext );
2009-12-03 09:19:00 +01:00
* ?>
* </ code >
*
* Here ' s an example of how to create signatures and verify signatures with this library :
* < code >
* < ? php
2015-10-01 17:15:58 +02:00
* include 'vendor/autoload.php' ;
2009-12-03 09:19:00 +01:00
*
2015-10-01 17:15:58 +02:00
* extract ( \phpseclib\Crypt\RSA :: createKey ());
2009-12-03 09:19:00 +01:00
*
2015-10-01 17:15:58 +02:00
* $plaintext = 'terrafrost' ;
2009-12-03 09:19:00 +01:00
*
2015-10-01 22:57:31 +02:00
* $signature = $privatekey -> sign ( $plaintext );
2009-12-03 09:19:00 +01:00
*
2015-10-01 22:57:31 +02:00
* echo $publickey -> verify ( $plaintext , $signature ) ? 'verified' : 'unverified' ;
2009-12-03 09:19:00 +01:00
* ?>
* </ code >
*
2013-12-10 20:10:37 +01:00
* @ category Crypt
2014-12-17 01:16:54 +01:00
* @ package RSA
2013-12-10 20:10:37 +01:00
* @ author Jim Wigginton < terrafrost @ php . net >
2014-12-10 00:02:44 +01:00
* @ copyright 2009 Jim Wigginton
2013-12-10 20:10:37 +01:00
* @ license http :// www . opensource . org / licenses / mit - license . html MIT License
* @ link http :// phpseclib . sourceforge . net
2009-12-03 09:19:00 +01:00
*/
2014-12-17 01:16:54 +01:00
namespace phpseclib\Crypt ;
2014-06-02 20:09:47 +02:00
2015-12-24 17:58:06 +01:00
use phpseclib\File\ASN1 ;
2016-01-18 05:05:31 +01:00
use phpseclib\Math\BigInteger ;
2009-12-03 09:19:00 +01:00
/**
* Pure - PHP PKCS #1 compliant implementation of RSA.
*
2014-12-17 01:16:54 +01:00
* @ package RSA
2009-12-03 09:19:00 +01:00
* @ author Jim Wigginton < terrafrost @ php . net >
* @ access public
*/
2014-12-17 01:16:54 +01:00
class RSA
2013-12-03 19:34:41 +01:00
{
2014-12-09 19:46:30 +01:00
/** #@+
* @ access public
2015-10-12 21:10:26 +02:00
* @ see self :: encrypt ()
* @ see self :: decrypt ()
2014-12-09 19:46:30 +01:00
*/
/**
* Use { @ link http :// en . wikipedia . org / wiki / Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding }
* ( OAEP ) for encryption / decryption .
*
2015-12-24 17:58:06 +01:00
* Uses sha256 by default
2014-12-09 19:46:30 +01:00
*
2015-10-12 21:10:26 +02:00
* @ see self :: setHash ()
* @ see self :: setMGFHash ()
2014-12-09 19:46:30 +01:00
*/
2015-12-24 17:58:06 +01:00
const PADDING_OAEP = 1 ;
2014-12-09 19:46:30 +01:00
/**
* Use PKCS #1 padding.
*
2015-12-24 17:58:06 +01:00
* Although self :: PADDING_OAEP / self :: PADDING_PSS offers more security , including PKCS #1 padding is necessary for purposes of backwards
2014-12-09 19:46:30 +01:00
* compatibility with protocols ( like SSH - 1 ) written before OAEP ' s introduction .
2015-09-14 17:30:31 +02:00
*/
2015-12-24 17:58:06 +01:00
const PADDING_PKCS1 = 2 ;
2015-05-26 05:36:10 +02:00
/**
* Do not use any padding
*
* Although this method is not recommended it can none - the - less sometimes be useful if you ' re trying to decrypt some legacy
* stuff , if you 're trying to diagnose why an encrypted message isn' t decrypting , etc .
*/
2015-12-24 17:58:06 +01:00
const PADDING_NONE = 3 ;
/**
* Use PKCS #1 padding with PKCS1 v1.5 compatability
*
* A PKCS1 v2 . 1 encrypted message may not successfully decrypt with a PKCS1 v1 . 5 implementation ( such as OpenSSL ) .
*/
const PADDING_PKCS15_COMPAT = 6 ;
2014-12-09 19:46:30 +01:00
/**#@-*/
/** #@+
* @ access public
2015-10-12 21:10:26 +02:00
* @ see self :: sign ()
* @ see self :: verify ()
* @ see self :: setHash ()
2015-10-01 17:15:58 +02:00
*/
2014-12-09 19:46:30 +01:00
/**
* Use the Probabilistic Signature Scheme for signing
*
2015-12-24 17:58:06 +01:00
* Uses sha256 and 0 as the salt length
2014-12-09 19:46:30 +01:00
*
2015-10-12 21:10:26 +02:00
* @ see self :: setSaltLength ()
* @ see self :: setMGFHash ()
2015-12-24 17:58:06 +01:00
* @ see self :: setHash ()
2015-09-14 17:30:31 +02:00
*/
2015-12-24 17:58:06 +01:00
const PADDING_PSS = 4 ;
2014-12-09 19:46:30 +01:00
/**
2015-12-24 17:58:06 +01:00
* Use a relaxed version of PKCS #1 padding for signature verification
2015-09-14 17:30:31 +02:00
*/
2015-12-24 17:58:06 +01:00
const PADDING_RELAXED_PKCS1 = 5 ;
2014-12-09 19:46:30 +01:00
/**#@-*/
/** #@+
* @ access private
2015-10-16 17:01:18 +02:00
* @ see self :: createKey ()
2015-10-01 17:15:58 +02:00
*/
2014-12-09 19:46:30 +01:00
/**
* ASN1 Integer
2015-09-14 17:30:31 +02:00
*/
2014-12-09 19:46:30 +01:00
const ASN1_INTEGER = 2 ;
/**
* ASN1 Bit String
2015-09-14 17:30:31 +02:00
*/
2014-12-09 19:46:30 +01:00
const ASN1_BITSTRING = 3 ;
/**
* ASN1 Octet String
2015-09-14 17:30:31 +02:00
*/
2014-12-09 19:46:30 +01:00
const ASN1_OCTETSTRING = 4 ;
/**
* ASN1 Object Identifier
2015-09-14 17:30:31 +02:00
*/
2014-12-09 19:46:30 +01:00
const ASN1_OBJECT = 6 ;
/**
* ASN1 Sequence ( with the constucted bit set )
2015-09-14 17:30:31 +02:00
*/
2014-12-09 19:46:30 +01:00
const ASN1_SEQUENCE = 48 ;
/**#@-*/
/** #@+
* @ access private
2015-10-16 17:01:18 +02:00
* @ see self :: __construct ()
2015-10-01 17:15:58 +02:00
*/
2014-12-09 19:46:30 +01:00
/**
* To use the pure - PHP implementation
2015-09-14 17:30:31 +02:00
*/
2014-12-09 19:46:30 +01:00
const MODE_INTERNAL = 1 ;
/**
* To use the OpenSSL library
*
* ( if enabled ; otherwise , the internal implementation will be used )
2015-09-14 17:30:31 +02:00
*/
2014-12-09 19:46:30 +01:00
const MODE_OPENSSL = 2 ;
/**#@-*/
2009-12-03 09:19:00 +01:00
/**
* Precomputed Zero
*
2015-09-02 01:42:15 +02:00
* @ var array
2009-12-03 09:19:00 +01:00
* @ access private
*/
2015-10-01 17:15:58 +02:00
static $zero ;
2009-12-03 09:19:00 +01:00
/**
* Precomputed One
*
2015-09-02 01:42:15 +02:00
* @ var array
2009-12-03 09:19:00 +01:00
* @ access private
*/
2015-10-01 17:15:58 +02:00
static $one ;
2009-12-03 09:19:00 +01:00
/**
* Private Key Format
*
2015-10-01 17:15:58 +02:00
* @ var string
2009-12-03 09:19:00 +01:00
* @ access private
*/
2015-10-01 17:15:58 +02:00
var $privateKeyFormat = 'PKCS1' ;
2009-12-03 09:19:00 +01:00
/**
* Public Key Format
*
2015-10-01 17:15:58 +02:00
* @ var string
* @ access private
2009-12-03 09:19:00 +01:00
*/
2015-10-01 17:15:58 +02:00
var $publicKeyFormat = 'PKCS8' ;
2009-12-03 09:19:00 +01:00
/**
* Modulus ( ie . n )
*
2014-06-02 20:09:47 +02:00
* @ var \phpseclib\Math\BigInteger
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $modulus ;
/**
* Modulus length
*
2014-06-02 20:09:47 +02:00
* @ var \phpseclib\Math\BigInteger
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $k ;
/**
* Exponent ( ie . e or d )
*
2014-06-02 20:09:47 +02:00
* @ var \phpseclib\Math\BigInteger
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $exponent ;
/**
* Primes for Chinese Remainder Theorem ( ie . p and q )
*
2015-09-02 01:42:15 +02:00
* @ var array
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $primes ;
/**
* Exponents for Chinese Remainder Theorem ( ie . dP and dQ )
*
2015-09-02 01:42:15 +02:00
* @ var array
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $exponents ;
/**
* Coefficients for Chinese Remainder Theorem ( ie . qInv )
*
2015-09-02 01:42:15 +02:00
* @ var array
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $coefficients ;
/**
* Hash name
*
2015-09-02 01:42:15 +02:00
* @ var string
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $hashName ;
/**
* Hash function
*
2014-12-17 01:16:54 +01:00
* @ var \phpseclib\Crypt\Hash
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $hash ;
/**
* Length of hash function output
*
2015-09-02 01:42:15 +02:00
* @ var int
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $hLen ;
/**
* Length of salt
*
2015-09-02 01:42:15 +02:00
* @ var int
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $sLen ;
/**
* Hash function for the Mask Generation Function
*
2014-12-17 01:16:54 +01:00
* @ var \phpseclib\Crypt\Hash
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $mgfHash ;
2009-12-08 15:18:59 +01:00
/**
* Length of MGF hash function output
*
2015-09-02 01:42:15 +02:00
* @ var int
2009-12-08 15:18:59 +01:00
* @ access private
*/
var $mgfHLen ;
2009-12-03 09:19:00 +01:00
/**
* Public Exponent
*
2015-09-02 01:42:15 +02:00
* @ var mixed
2009-12-03 09:19:00 +01:00
* @ access private
*/
var $publicExponent = false ;
/**
* Password
*
2015-09-02 01:42:15 +02:00
* @ var string
2009-12-03 09:19:00 +01:00
* @ access private
*/
2012-08-23 15:59:49 +02:00
var $password = false ;
2009-12-03 09:19:00 +01:00
2015-10-22 17:57:05 +02:00
/**
* Loaded File Format
*
* @ var string
* @ access private
*/
var $format = false ;
2011-04-18 14:17:40 +02:00
/**
2015-10-01 17:15:58 +02:00
* OpenSSL configuration file name .
2011-04-18 14:17:40 +02:00
*
2015-10-01 17:15:58 +02:00
* Set to null to use system configuration file .
2011-04-18 14:17:40 +02:00
*
2015-10-11 19:22:07 +02:00
* @ see self :: createKey ()
2015-09-02 01:42:15 +02:00
* @ var mixed
2015-10-01 17:15:58 +02:00
* @ access public
2011-04-18 14:17:40 +02:00
*/
2015-10-01 17:15:58 +02:00
static $configFile ;
2011-04-18 14:17:40 +02:00
2012-12-10 12:07:49 +01:00
/**
2015-10-22 17:57:05 +02:00
* Supported file formats ( lower case )
2012-12-10 12:07:49 +01:00
*
2015-10-22 17:57:05 +02:00
* @ see self :: _initialize_static_variables ()
2015-10-01 17:15:58 +02:00
* @ var array
* @ access private
2012-12-10 12:07:49 +01:00
*/
2015-10-01 17:15:58 +02:00
static $fileFormats = false ;
2012-12-10 12:07:49 +01:00
2015-10-22 17:57:05 +02:00
/**
* Supported file formats ( original case )
*
* @ see self :: _initialize_static_variables ()
* @ var array
* @ access private
*/
static $origFileFormats = false ;
2013-05-06 01:38:34 +02:00
/**
2015-10-01 17:15:58 +02:00
* Initialize static variables
2013-05-06 01:38:34 +02:00
*
* @ access private
*/
2015-10-01 17:15:58 +02:00
static function _initialize_static_variables ()
{
if ( ! isset ( self :: $zero )) {
self :: $zero = new BigInteger ( 0 );
self :: $one = new BigInteger ( 1 );
self :: $configFile = __DIR__ . '/../openssl.cnf' ;
2015-10-05 06:11:38 +02:00
if ( self :: $fileFormats === false ) {
self :: $fileFormats = array ();
foreach ( glob ( __DIR__ . '/RSA/*.php' ) as $file ) {
$name = pathinfo ( $file , PATHINFO_FILENAME );
$type = 'phpseclib\Crypt\RSA\\' . $name ;
$meta = new \ReflectionClass ( $type );
if ( ! $meta -> isAbstract ()) {
self :: $fileFormats [ strtolower ( $name )] = $type ;
2015-10-22 17:57:05 +02:00
self :: $origFileFormats [] = $name ;
2015-10-05 06:11:38 +02:00
}
}
}
2015-10-01 17:15:58 +02:00
}
}
2013-05-06 01:38:34 +02:00
2009-12-03 09:19:00 +01:00
/**
* The constructor
*
* If you want to make use of the openssl extension , you ' ll need to set the mode manually , yourself . The reason
2014-12-17 01:16:54 +01:00
* \phpseclib\Crypt\RSA doesn 't do it is because OpenSSL doesn' t fail gracefully . openssl_pkey_new (), in particular , requires
2009-12-03 09:19:00 +01:00
* openssl . cnf be present somewhere and , unfortunately , the only real way to find out is too late .
*
2014-12-17 01:16:54 +01:00
* @ return \phpseclib\Crypt\RSA
2009-12-03 09:19:00 +01:00
* @ access public
*/
2014-06-16 17:06:34 +02:00
function __construct ()
2009-12-03 09:19:00 +01:00
{
2015-10-01 17:15:58 +02:00
self :: _initialize_static_variables ();
2015-12-24 17:58:06 +01:00
$this -> hash = new Hash ( 'sha256' );
2015-10-01 17:15:58 +02:00
$this -> hLen = $this -> hash -> getLength ();
2015-12-24 17:58:06 +01:00
$this -> hashName = 'sha256' ;
$this -> mgfHash = new Hash ( 'sha256' );
2015-10-01 17:15:58 +02:00
$this -> mgfHLen = $this -> mgfHash -> getLength ();
}
/**
* Create public / private key pair
*
* Returns an array with the following three elements :
* - 'privatekey' : The private key .
* - 'publickey' : The public key .
* - 'partialkey' : A partially computed key ( if the execution time exceeded $timeout ) .
* Will need to be passed back to \phpseclib\Crypt\RSA :: createKey () as the third parameter for further processing .
*
* @ access public
* @ param int $bits
* @ param int $timeout
* @ param array $p
*/
2016-01-08 20:58:06 +01:00
static function createKey ( $bits = 2048 , $timeout = false , $partial = array ())
2015-10-01 17:15:58 +02:00
{
self :: _initialize_static_variables ();
2012-12-10 12:07:49 +01:00
2015-07-15 03:52:31 +02:00
if ( ! defined ( 'CRYPT_RSA_MODE' )) {
2014-08-25 14:03:24 +02:00
switch ( true ) {
// Math/BigInteger's openssl requirements are a little less stringent than Crypt/RSA's. in particular,
// Math/BigInteger doesn't require an openssl.cfg file whereas Crypt/RSA does. so if Math/BigInteger
// can't use OpenSSL it can be pretty trivially assumed, then, that Crypt/RSA can't either.
case defined ( 'MATH_BIGINTEGER_OPENSSL_DISABLE' ) :
2014-12-09 19:46:30 +01:00
define ( 'CRYPT_RSA_MODE' , self :: MODE_INTERNAL );
2014-08-25 14:03:24 +02:00
break ;
2015-10-01 17:15:58 +02:00
case extension_loaded ( 'openssl' ) && file_exists ( self :: $configFile ) :
2013-09-10 18:07:56 +02:00
// some versions of XAMPP have mismatched versions of OpenSSL which causes it not to work
ob_start ();
2014-03-30 17:15:08 +02:00
@ phpinfo ();
2013-09-10 18:07:56 +02:00
$content = ob_get_contents ();
ob_end_clean ();
preg_match_all ( '#OpenSSL (Header|Library) Version(.*)#im' , $content , $matches );
$versions = array ();
if ( ! empty ( $matches [ 1 ])) {
2015-01-06 09:27:30 +01:00
for ( $i = 0 ; $i < count ( $matches [ 1 ]); $i ++ ) {
$fullVersion = trim ( str_replace ( '=>' , '' , strip_tags ( $matches [ 2 ][ $i ])));
// Remove letter part in OpenSSL version
if ( ! preg_match ( '/(\d+\.\d+\.\d+)/i' , $fullVersion , $m )) {
$versions [ $matches [ 1 ][ $i ]] = $fullVersion ;
} else {
$versions [ $matches [ 1 ][ $i ]] = $m [ 0 ];
}
}
2013-09-10 18:07:56 +02:00
}
2013-09-20 19:14:01 +02:00
// it doesn't appear that OpenSSL versions were reported upon until PHP 5.3+
2013-09-10 18:07:56 +02:00
switch ( true ) {
case ! isset ( $versions [ 'Header' ]) :
case ! isset ( $versions [ 'Library' ]) :
2013-09-20 19:14:01 +02:00
case $versions [ 'Header' ] == $versions [ 'Library' ] :
2014-12-09 19:46:30 +01:00
define ( 'CRYPT_RSA_MODE' , self :: MODE_OPENSSL );
2013-09-10 18:07:56 +02:00
break ;
default :
2014-12-09 19:46:30 +01:00
define ( 'CRYPT_RSA_MODE' , self :: MODE_INTERNAL );
2013-09-20 19:14:01 +02:00
define ( 'MATH_BIGINTEGER_OPENSSL_DISABLE' , true );
2013-09-10 18:07:56 +02:00
}
2012-07-01 19:07:42 +02:00
break ;
2014-08-25 14:58:38 +02:00
default :
2014-12-09 19:46:30 +01:00
define ( 'CRYPT_RSA_MODE' , self :: MODE_INTERNAL );
2009-12-03 09:19:00 +01:00
}
}
2012-07-01 19:07:42 +02:00
if ( ! defined ( 'CRYPT_RSA_EXPONENT' )) {
// http://en.wikipedia.org/wiki/65537_%28number%29
define ( 'CRYPT_RSA_EXPONENT' , '65537' );
}
// per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
// than 256 bits. as a consequence if the key you're trying to create is 1024 bits and you've set CRYPT_RSA_SMALLEST_PRIME
// to 384 bits then you're going to get a 384 bit prime and a 640 bit prime (384 + 1024 % 384). at least if
2014-12-09 19:46:30 +01:00
// CRYPT_RSA_MODE is set to self::MODE_INTERNAL. if CRYPT_RSA_MODE is set to self::MODE_OPENSSL then
2012-07-01 19:07:42 +02:00
// CRYPT_RSA_SMALLEST_PRIME is ignored (ie. multi-prime RSA support is more intended as a way to speed up RSA key
// generation when there's a chance neither gmp nor OpenSSL are installed)
if ( ! defined ( 'CRYPT_RSA_SMALLEST_PRIME' )) {
define ( 'CRYPT_RSA_SMALLEST_PRIME' , 4096 );
}
// OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
2015-07-17 13:36:18 +02:00
if ( CRYPT_RSA_MODE == self :: MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537 ) {
2012-12-10 12:07:49 +01:00
$config = array ();
2015-10-01 17:15:58 +02:00
if ( isset ( self :: $configFile )) {
$config [ 'config' ] = self :: $configFile ;
2012-12-10 12:07:49 +01:00
}
$rsa = openssl_pkey_new ( array ( 'private_key_bits' => $bits ) + $config );
2015-10-01 17:15:58 +02:00
openssl_pkey_export ( $rsa , $privatekeystr , null , $config );
$privatekey = new RSA ();
$privatekey -> load ( $privatekeystr );
2009-12-03 09:19:00 +01:00
2015-10-01 17:15:58 +02:00
$publickeyarr = openssl_pkey_get_details ( $rsa );
$publickey = new RSA ();
$publickey -> load ( $publickeyarr [ 'key' ]);
2009-12-03 09:19:00 +01:00
2012-07-01 19:07:42 +02:00
// clear the buffer of error strings stemming from a minimalistic openssl.cnf
2015-07-15 03:52:31 +02:00
while ( openssl_error_string () !== false ) {
}
2012-07-01 19:07:42 +02:00
2009-12-03 09:19:00 +01:00
return array (
'privatekey' => $privatekey ,
'publickey' => $publickey ,
'partialkey' => false
);
}
static $e ;
if ( ! isset ( $e )) {
2014-06-02 20:09:47 +02:00
$e = new BigInteger ( CRYPT_RSA_EXPONENT );
2009-12-03 09:19:00 +01:00
}
2015-10-01 17:15:58 +02:00
extract ( self :: _generateMinMax ( $bits ));
2009-12-03 09:19:00 +01:00
$absoluteMin = $min ;
2012-07-01 19:07:42 +02:00
$temp = $bits >> 1 ; // divide by two to see how many bits P and Q would be
2009-12-03 09:19:00 +01:00
if ( $temp > CRYPT_RSA_SMALLEST_PRIME ) {
$num_primes = floor ( $bits / CRYPT_RSA_SMALLEST_PRIME );
$temp = CRYPT_RSA_SMALLEST_PRIME ;
} else {
$num_primes = 2 ;
}
2015-10-01 17:15:58 +02:00
extract ( self :: _generateMinMax ( $temp + $bits % $temp ));
2009-12-03 09:19:00 +01:00
$finalMax = $max ;
2015-10-01 17:15:58 +02:00
extract ( self :: _generateMinMax ( $temp ));
2009-12-03 09:19:00 +01:00
2016-01-08 16:34:07 +01:00
$n = clone self :: $one ;
2010-01-21 01:52:11 +01:00
if ( ! empty ( $partial )) {
extract ( unserialize ( $partial ));
} else {
$exponents = $coefficients = $primes = array ();
$lcm = array (
2016-01-08 16:34:07 +01:00
'top' => clone self :: $one ,
2010-01-21 01:52:11 +01:00
'bottom' => false
);
}
2009-12-03 09:19:00 +01:00
$start = time ();
$i0 = count ( $primes ) + 1 ;
do {
for ( $i = $i0 ; $i <= $num_primes ; $i ++ ) {
if ( $timeout !== false ) {
$timeout -= time () - $start ;
$start = time ();
if ( $timeout <= 0 ) {
2011-02-06 01:04:07 +01:00
return array (
2009-12-03 09:19:00 +01:00
'privatekey' => '' ,
'publickey' => '' ,
2011-02-06 01:04:07 +01:00
'partialkey' => serialize ( array (
2010-01-21 01:52:11 +01:00
'primes' => $primes ,
'coefficients' => $coefficients ,
'lcm' => $lcm ,
'exponents' => $exponents
2011-02-06 01:04:07 +01:00
))
);
2009-12-03 09:19:00 +01:00
}
}
2010-03-01 18:28:19 +01:00
2009-12-03 09:19:00 +01:00
if ( $i == $num_primes ) {
list ( $min , $temp ) = $absoluteMin -> divide ( $n );
2015-10-01 17:15:58 +02:00
if ( ! $temp -> equals ( self :: $zero )) {
$min = $min -> add ( self :: $one ); // ie. ceil()
2009-12-03 09:19:00 +01:00
}
2015-12-27 13:13:57 +01:00
$primes [ $i ] = BigInteger :: randomPrime ( $min , $finalMax , $timeout );
2009-12-03 09:19:00 +01:00
} else {
2015-12-27 13:13:57 +01:00
$primes [ $i ] = BigInteger :: randomPrime ( $min , $max , $timeout );
2009-12-03 09:19:00 +01:00
}
if ( $primes [ $i ] === false ) { // if we've reached the timeout
2011-02-06 17:35:48 +01:00
if ( count ( $primes ) > 1 ) {
$partialkey = '' ;
} else {
array_pop ( $primes );
$partialkey = serialize ( array (
'primes' => $primes ,
2010-01-21 01:52:11 +01:00
'coefficients' => $coefficients ,
'lcm' => $lcm ,
'exponents' => $exponents
2011-02-06 17:35:48 +01:00
));
}
return array (
2015-10-01 17:15:58 +02:00
'privatekey' => false ,
'publickey' => false ,
2011-02-06 17:35:48 +01:00
'partialkey' => $partialkey
2009-12-03 09:19:00 +01:00
);
}
// the first coefficient is calculated differently from the rest
// ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
if ( $i > 2 ) {
$coefficients [ $i ] = $n -> modInverse ( $primes [ $i ]);
}
$n = $n -> multiply ( $primes [ $i ]);
2015-10-01 17:15:58 +02:00
$temp = $primes [ $i ] -> subtract ( self :: $one );
2009-12-03 09:19:00 +01:00
// textbook RSA implementations use Euler's totient function instead of the least common multiple.
// see http://en.wikipedia.org/wiki/Euler%27s_totient_function
$lcm [ 'top' ] = $lcm [ 'top' ] -> multiply ( $temp );
$lcm [ 'bottom' ] = $lcm [ 'bottom' ] === false ? $temp : $lcm [ 'bottom' ] -> gcd ( $temp );
$exponents [ $i ] = $e -> modInverse ( $temp );
}
2013-08-01 04:50:40 +02:00
list ( $temp ) = $lcm [ 'top' ] -> divide ( $lcm [ 'bottom' ]);
$gcd = $temp -> gcd ( $e );
2009-12-03 09:19:00 +01:00
$i0 = 1 ;
2015-10-01 17:15:58 +02:00
} while ( ! $gcd -> equals ( self :: $one ));
2009-12-03 09:19:00 +01:00
2013-08-01 04:50:40 +02:00
$d = $e -> modInverse ( $temp );
2009-12-03 09:19:00 +01:00
$coefficients [ 2 ] = $primes [ 2 ] -> modInverse ( $primes [ 1 ]);
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
// RSAPrivateKey ::= SEQUENCE {
// version Version,
// modulus INTEGER, -- n
// publicExponent INTEGER, -- e
// privateExponent INTEGER, -- d
// prime1 INTEGER, -- p
// prime2 INTEGER, -- q
// exponent1 INTEGER, -- d mod (p-1)
// exponent2 INTEGER, -- d mod (q-1)
// coefficient INTEGER, -- (inverse of q) mod p
// otherPrimeInfos OtherPrimeInfos OPTIONAL
// }
2015-10-01 17:15:58 +02:00
$privatekey = new RSA ();
$privatekey -> modulus = $n ;
$privatekey -> k = $bits >> 3 ;
$privatekey -> publicExponent = $e ;
$privatekey -> exponent = $d ;
$privatekey -> privateExponent = $e ;
$privatekey -> primes = $primes ;
$privatekey -> exponents = $exponents ;
$privatekey -> coefficients = $coefficients ;
$publickey = new RSA ();
$publickey -> modulus = $n ;
$publickey -> k = $bits >> 3 ;
$publickey -> exponent = $e ;
2009-12-03 09:19:00 +01:00
return array (
2015-10-01 17:15:58 +02:00
'privatekey' => $privatekey ,
'publickey' => $publickey ,
2009-12-03 09:19:00 +01:00
'partialkey' => false
);
}
/**
2015-10-05 06:11:38 +02:00
* Add a fileformat plugin
2009-12-03 09:19:00 +01:00
*
2015-10-05 06:11:38 +02:00
* The plugin needs to either already be loaded or be auto - loadable .
* Loading a plugin whose shortname overwrite an existing shortname will overwrite the old plugin .
*
2015-10-16 17:01:18 +02:00
* @ see self :: load ()
2015-10-05 06:11:38 +02:00
* @ param string $fullname
* @ access public
* @ return bool
2009-12-03 09:19:00 +01:00
*/
2015-10-05 06:11:38 +02:00
static function addFileFormat ( $fullname )
2009-12-03 09:19:00 +01:00
{
2015-10-05 06:11:38 +02:00
self :: _initialize_static_variables ();
if ( class_exists ( $fullname )) {
$meta = new \ReflectionClass ( $path );
2015-10-22 17:57:05 +02:00
$shortname = $meta -> getShortName ();
self :: $fileFormats [ strtolower ( $shortname )] = $fullname ;
self :: $origFileFormats [] = $shortname ;
2011-04-18 14:17:40 +02:00
}
}
2015-10-22 17:57:05 +02:00
/**
* Returns a list of supported formats .
*
* @ access public
* @ return array
*/
static function getSupportedFormats ()
{
self :: _initialize_static_variables ();
return self :: $origFileFormats ;
}
2009-12-03 09:19:00 +01:00
/**
* Loads a public or private key
*
2009-12-08 00:22:05 +01:00
* Returns true on success and false on failure ( ie . an incorrect password was provided or the key was malformed )
*
2009-12-03 09:19:00 +01:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $key
* @ param int $type optional
2009-12-03 09:19:00 +01:00
*/
2015-10-01 17:15:58 +02:00
function load ( $key , $type = false )
2009-12-03 09:19:00 +01:00
{
2014-12-24 22:05:56 +01:00
if ( $key instanceof RSA ) {
2013-10-18 20:24:06 +02:00
$this -> privateKeyFormat = $key -> privateKeyFormat ;
$this -> publicKeyFormat = $key -> publicKeyFormat ;
$this -> k = $key -> k ;
$this -> hLen = $key -> hLen ;
$this -> sLen = $key -> sLen ;
$this -> mgfHLen = $key -> mgfHLen ;
$this -> password = $key -> password ;
if ( is_object ( $key -> hash )) {
2014-12-17 01:16:54 +01:00
$this -> hash = new Hash ( $key -> hash -> getHash ());
2013-10-18 20:24:06 +02:00
}
if ( is_object ( $key -> mgfHash )) {
2014-12-17 01:16:54 +01:00
$this -> mgfHash = new Hash ( $key -> mgfHash -> getHash ());
2013-10-18 20:24:06 +02:00
}
if ( is_object ( $key -> modulus )) {
2016-01-08 16:34:07 +01:00
$this -> modulus = clone $key -> modulus ;
2013-10-18 20:24:06 +02:00
}
if ( is_object ( $key -> exponent )) {
2016-01-08 16:34:07 +01:00
$this -> exponent = clone $key -> exponent ;
2013-10-18 20:24:06 +02:00
}
if ( is_object ( $key -> publicExponent )) {
2016-01-08 16:34:07 +01:00
$this -> publicExponent = clone $key -> publicExponent ;
2013-10-18 20:24:06 +02:00
}
$this -> primes = array ();
$this -> exponents = array ();
$this -> coefficients = array ();
foreach ( $this -> primes as $prime ) {
2016-01-08 16:34:07 +01:00
$this -> primes [] = clone $prime ;
2013-10-18 20:24:06 +02:00
}
foreach ( $this -> exponents as $exponent ) {
2016-01-08 16:34:07 +01:00
$this -> exponents [] = clone $exponent ;
2013-10-18 20:24:06 +02:00
}
foreach ( $this -> coefficients as $coefficient ) {
2016-01-08 16:34:07 +01:00
$this -> coefficients [] = clone $coefficient ;
2013-10-18 20:24:06 +02:00
}
return true ;
}
2015-10-01 17:15:58 +02:00
$components = false ;
2011-04-18 14:17:40 +02:00
if ( $type === false ) {
2015-10-01 17:15:58 +02:00
foreach ( self :: $fileFormats as $format ) {
try {
$components = $format :: load ( $key , $this -> password );
} catch ( Exception $e ) {
$components = false ;
}
2011-04-18 14:17:40 +02:00
if ( $components !== false ) {
break ;
}
}
} else {
2015-10-22 17:57:05 +02:00
$format = strtolower ( $type );
if ( isset ( self :: $fileFormats [ $format ])) {
$format = self :: $fileFormats [ $format ];
2015-10-01 17:15:58 +02:00
try {
2015-10-22 17:57:05 +02:00
$components = $format :: load ( $key , $this -> password );
2015-10-01 17:15:58 +02:00
} catch ( Exception $e ) {
$components = false ;
}
}
2011-04-18 14:17:40 +02:00
}
2009-12-06 08:26:52 +01:00
if ( $components === false ) {
2015-10-22 17:57:05 +02:00
$this -> format = false ;
2009-12-06 08:26:52 +01:00
return false ;
}
2015-10-22 17:57:05 +02:00
$this -> format = $format ;
2009-12-03 09:19:00 +01:00
$this -> modulus = $components [ 'modulus' ];
$this -> k = strlen ( $this -> modulus -> toBytes ());
$this -> exponent = isset ( $components [ 'privateExponent' ]) ? $components [ 'privateExponent' ] : $components [ 'publicExponent' ];
if ( isset ( $components [ 'primes' ])) {
$this -> primes = $components [ 'primes' ];
$this -> exponents = $components [ 'exponents' ];
$this -> coefficients = $components [ 'coefficients' ];
$this -> publicExponent = $components [ 'publicExponent' ];
} else {
$this -> primes = array ();
$this -> exponents = array ();
$this -> coefficients = array ();
$this -> publicExponent = false ;
}
2009-12-08 00:22:05 +01:00
2015-10-01 17:15:58 +02:00
if ( $components [ 'isPublicKey' ]) {
$this -> setPublicKey ();
2014-04-17 17:30:32 +02:00
}
2009-12-08 00:22:05 +01:00
return true ;
2009-12-03 09:19:00 +01:00
}
2015-10-22 17:57:05 +02:00
/**
* Returns the format of the loaded key .
*
* If the key that was loaded wasn ' t in a valid or if the key was auto - generated
* with RSA :: createKey () then this will return false .
*
* @ see self :: load ()
* @ access public
* @ return mixed
*/
function getLoadedFormat ()
{
if ( $this -> format === false ) {
return false ;
}
$meta = new \ReflectionClass ( $this -> format );
return $meta -> getShortName ();
}
/**
2015-10-01 17:15:58 +02:00
* Returns the private key
*
* The private key is only returned if the currently loaded key contains the constituent prime numbers .
*
2015-10-16 17:01:18 +02:00
* @ see self :: getPublicKey ()
2015-10-01 17:15:58 +02:00
* @ access public
* @ param string $type optional
2015-10-16 17:01:18 +02:00
* @ return mixed
2015-10-01 17:15:58 +02:00
*/
function getPrivateKey ( $type = 'PKCS1' )
{
2015-10-05 06:11:38 +02:00
$type = strtolower ( $type );
if ( ! isset ( self :: $fileFormats [ $type ])) {
return false ;
2015-10-01 17:15:58 +02:00
}
2015-10-05 06:11:38 +02:00
$type = self :: $fileFormats [ $type ];
if ( ! method_exists ( $type , 'savePrivateKey' )) {
2015-10-01 17:15:58 +02:00
return false ;
}
if ( empty ( $this -> primes )) {
return false ;
}
$oldFormat = $this -> privateKeyFormat ;
$this -> privateKeyFormat = $type ;
$temp = $type :: savePrivateKey ( $this -> modulus , $this -> publicExponent , $this -> exponent , $this -> primes , $this -> exponents , $this -> coefficients , $this -> password );
$this -> privateKeyFormat = $oldFormat ;
return $temp ;
}
/**
* Returns the key size
*
* More specifically , this returns the size of the modulo in bits .
*
* @ access public
* @ return int
*/
function getSize ()
{
return ! isset ( $this -> modulus ) ? 0 : strlen ( $this -> modulus -> toBits ());
}
2009-12-03 09:19:00 +01:00
/**
* Sets the password
*
* Private keys can be encrypted with a password . To unset the password , pass in the empty string or false .
2012-08-23 15:59:49 +02:00
* Or rather , pass in $password such that empty ( $password ) && ! is_string ( $password ) is true .
2009-12-03 09:19:00 +01:00
*
2015-10-11 19:22:07 +02:00
* @ see self :: createKey ()
2015-10-16 17:01:18 +02:00
* @ see self :: load ()
2009-12-03 09:19:00 +01:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $password
2009-12-03 09:19:00 +01:00
*/
2012-08-23 15:59:49 +02:00
function setPassword ( $password = false )
2009-12-03 09:19:00 +01:00
{
$this -> password = $password ;
}
/**
* Defines the public key
*
* Some private key formats define the public exponent and some don 't. Those that don' t define it are problematic when
* used in certain contexts . For example , in SSH - 2 , RSA authentication works by sending the public key along with a
* message signed by the private key to the server . The SSH - 2 server looks the public key up in an index of public keys
* and if it 's present then proceeds to verify the signature. Problem is, if your private key doesn' t include the public
2014-04-17 17:30:32 +02:00
* exponent this won ' t work unless you manually add the public exponent . phpseclib tries to guess if the key being used
* is the public key but in the event that it guesses incorrectly you might still want to explicitly set the key as being
* public .
2009-12-03 09:19:00 +01:00
*
* Do note that when a new key is loaded the index will be cleared .
*
* Returns true on success , false on failure
*
2015-10-11 19:22:07 +02:00
* @ see self :: getPublicKey ()
2009-12-03 09:19:00 +01:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $key optional
* @ param int $type optional
* @ return bool
2009-12-03 09:19:00 +01:00
*/
2012-04-17 08:21:42 +02:00
function setPublicKey ( $key = false , $type = false )
2009-12-03 09:19:00 +01:00
{
2013-10-06 04:30:57 +02:00
// if a public key has already been loaded return false
2013-10-06 09:23:57 +02:00
if ( ! empty ( $this -> publicExponent )) {
2013-10-06 04:30:57 +02:00
return false ;
}
2012-04-17 08:21:42 +02:00
if ( $key === false && ! empty ( $this -> modulus )) {
$this -> publicExponent = $this -> exponent ;
return true ;
}
2015-10-01 17:15:58 +02:00
$components = false ;
2012-03-11 20:13:34 +01:00
if ( $type === false ) {
2015-10-01 17:15:58 +02:00
foreach ( self :: $fileFormats as $format ) {
if ( ! method_exists ( $format , 'savePublicKey' )) {
continue ;
}
try {
$components = $format :: load ( $key , $this -> password );
} catch ( Exception $e ) {
$components = false ;
}
2012-03-11 20:13:34 +01:00
if ( $components !== false ) {
break ;
}
}
} else {
2015-10-22 17:57:05 +02:00
$format = strtolower ( $type );
if ( isset ( self :: $fileFormats [ $format ])) {
$format = self :: $fileFormats [ $format ];
2015-10-01 17:15:58 +02:00
try {
2015-10-22 17:57:05 +02:00
$components = $format :: load ( $key , $this -> password );
2015-10-01 17:15:58 +02:00
} catch ( Exception $e ) {
$components = false ;
}
}
2012-03-11 20:13:34 +01:00
}
2010-07-11 04:33:13 +02:00
2012-04-17 08:21:42 +02:00
if ( $components === false ) {
2015-10-22 17:57:05 +02:00
$this -> format = false ;
2009-12-03 09:19:00 +01:00
return false ;
}
2010-06-19 14:01:21 +02:00
2015-10-22 17:57:05 +02:00
$this -> format = $format ;
2012-04-17 08:21:42 +02:00
if ( empty ( $this -> modulus ) || ! $this -> modulus -> equals ( $components [ 'modulus' ])) {
$this -> modulus = $components [ 'modulus' ];
$this -> exponent = $this -> publicExponent = $components [ 'publicExponent' ];
return true ;
}
2009-12-04 21:50:21 +01:00
$this -> publicExponent = $components [ 'publicExponent' ];
2010-06-19 14:01:21 +02:00
return true ;
2009-12-03 09:19:00 +01:00
}
2014-04-17 17:30:32 +02:00
/**
* Defines the private key
*
* If phpseclib guessed a private key was a public key and loaded it as such it might be desirable to force
* phpseclib to treat the key as a private key . This function will do that .
*
* Do note that when a new key is loaded the index will be cleared .
*
* Returns true on success , false on failure
*
2015-10-11 19:22:07 +02:00
* @ see self :: getPublicKey ()
2014-04-17 17:30:32 +02:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $key optional
* @ param int $type optional
* @ return bool
2014-04-17 17:30:32 +02:00
*/
function setPrivateKey ( $key = false , $type = false )
{
if ( $key === false && ! empty ( $this -> publicExponent )) {
unset ( $this -> publicExponent );
return true ;
}
2014-12-17 01:16:54 +01:00
$rsa = new RSA ();
2015-10-01 17:15:58 +02:00
if ( ! $rsa -> load ( $key , $type )) {
2014-04-17 17:30:32 +02:00
return false ;
}
unset ( $rsa -> publicExponent );
// don't overwrite the old key if the new key is invalid
2015-10-01 17:15:58 +02:00
$this -> load ( $rsa );
2014-04-17 17:30:32 +02:00
return true ;
}
2009-12-03 09:19:00 +01:00
/**
* Returns the public key
*
* The public key is only returned under two circumstances - if the private key had the public key embedded within it
* or if the public key was set via setPublicKey () . If the currently loaded key is supposed to be the public key this
* function won 't return it since this library, for the most part, doesn' t distinguish between public and private keys .
*
2015-10-16 17:01:18 +02:00
* @ see self :: getPrivateKey ()
2009-12-03 09:19:00 +01:00
* @ access public
2015-10-01 17:15:58 +02:00
* @ param string $type optional
2015-10-16 17:01:18 +02:00
* @ return mixed
2009-12-03 09:19:00 +01:00
*/
2015-10-01 17:15:58 +02:00
function getPublicKey ( $type = 'PKCS8' )
2009-12-03 09:19:00 +01:00
{
2015-10-05 06:11:38 +02:00
$type = strtolower ( $type );
if ( ! isset ( self :: $fileFormats [ $type ])) {
return false ;
2015-10-01 17:15:58 +02:00
}
2015-10-05 06:11:38 +02:00
$type = self :: $fileFormats [ $type ];
if ( ! method_exists ( $type , 'savePublicKey' )) {
2015-10-01 17:15:58 +02:00
return false ;
}
2009-12-06 08:26:52 +01:00
if ( empty ( $this -> modulus ) || empty ( $this -> publicExponent )) {
return false ;
}
2009-12-03 09:19:00 +01:00
$oldFormat = $this -> publicKeyFormat ;
$this -> publicKeyFormat = $type ;
2015-10-01 17:15:58 +02:00
$temp = $type :: savePublicKey ( $this -> modulus , $this -> publicExponent );
2009-12-03 09:19:00 +01:00
$this -> publicKeyFormat = $oldFormat ;
return $temp ;
}
2015-05-07 05:55:12 +02:00
/**
* 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 )
*
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $algorithm The hashing algorithm to be used . Valid options are 'md5' and 'sha256' . False is returned
2015-05-07 05:55:12 +02:00
* for invalid values .
2015-10-05 17:08:46 +02:00
* @ return mixed
2015-05-07 05:55:12 +02:00
*/
public function getPublicKeyFingerprint ( $algorithm = 'md5' )
{
if ( empty ( $this -> modulus ) || empty ( $this -> publicExponent )) {
return false ;
}
$modulus = $this -> modulus -> toBytes ( true );
$publicExponent = $this -> publicExponent -> toBytes ( true );
$RSAPublicKey = pack ( 'Na*Na*Na*' , strlen ( 'ssh-rsa' ), 'ssh-rsa' , strlen ( $publicExponent ), $publicExponent , strlen ( $modulus ), $modulus );
2015-07-15 03:52:31 +02:00
switch ( $algorithm ) {
2015-05-07 05:55:12 +02:00
case 'sha256' :
2015-05-05 08:51:17 +02:00
$hash = new Hash ( 'sha256' );
2015-05-07 05:55:12 +02:00
$base = base64_encode ( $hash -> hash ( $RSAPublicKey ));
return substr ( $base , 0 , strlen ( $base ) - 1 );
case 'md5' :
return substr ( chunk_split ( md5 ( $RSAPublicKey ), 2 , ':' ), 0 , - 1 );
default :
return false ;
}
}
2012-08-26 08:36:34 +02:00
/**
* Returns a minimalistic private key
*
* Returns the private key without the prime number constituants . Structurally identical to a public key that
* hasn ' t been set as the public key
*
2015-10-11 19:22:07 +02:00
* @ see self :: getPrivateKey ()
2012-08-26 08:36:34 +02:00
* @ access private
2015-10-01 17:15:58 +02:00
* @ param string $type optional
2015-10-16 17:31:43 +02:00
* @ return mixed
2012-08-26 08:36:34 +02:00
*/
2015-10-01 17:15:58 +02:00
function _getPrivatePublicKey ( $type = 'PKCS8' )
2012-08-26 08:36:34 +02:00
{
2015-10-05 06:11:38 +02:00
$type = strtolower ( $type );
if ( ! isset ( self :: $fileFormats [ $type ])) {
return false ;
2015-10-01 17:15:58 +02:00
}
2015-10-05 06:11:38 +02:00
$type = self :: $fileFormats [ $type ];
if ( ! method_exists ( $type , 'savePublicKey' )) {
2015-10-01 17:15:58 +02:00
return false ;
}
2012-08-26 08:36:34 +02:00
if ( empty ( $this -> modulus ) || empty ( $this -> exponent )) {
return false ;
}
$oldFormat = $this -> publicKeyFormat ;
2015-10-01 17:15:58 +02:00
$this -> publicKeyFormat = $type ;
$temp = $type :: savePublicKey ( $this -> modulus , $this -> exponent );
2012-08-26 08:36:34 +02:00
$this -> publicKeyFormat = $oldFormat ;
return $temp ;
}
2015-10-01 17:15:58 +02:00
2012-07-26 20:14:18 +02:00
/**
2015-10-16 16:36:49 +02:00
* __toString () magic method
2012-07-26 20:14:18 +02:00
*
* @ access public
2015-10-05 17:08:46 +02:00
* @ return string
2012-07-26 20:14:18 +02:00
*/
function __toString ()
{
$key = $this -> getPrivateKey ( $this -> privateKeyFormat );
2015-10-16 16:36:49 +02:00
if ( is_string ( $key )) {
2012-07-26 20:14:18 +02:00
return $key ;
}
2012-08-26 08:36:34 +02:00
$key = $this -> _getPrivatePublicKey ( $this -> publicKeyFormat );
2015-10-16 16:36:49 +02:00
return is_string ( $key ) ? $key : '' ;
2012-07-26 20:14:18 +02:00
}
2013-10-18 20:24:06 +02:00
/**
2015-10-16 16:36:49 +02:00
* __clone () magic method
2013-10-18 20:24:06 +02:00
*
* @ access public
2015-10-16 17:01:18 +02:00
* @ return \phpseclib\Crypt\RSA
2013-10-18 20:24:06 +02:00
*/
function __clone ()
{
2014-12-17 01:16:54 +01:00
$key = new RSA ();
2015-10-01 17:15:58 +02:00
$key -> load ( $this );
2013-10-18 20:24:06 +02:00
return $key ;
}
2009-12-03 09:19:00 +01:00
/**
* Generates the smallest and largest numbers requiring $bits bits
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param int $bits
* @ return array
2009-12-03 09:19:00 +01:00
*/
2015-10-01 17:15:58 +02:00
static function _generateMinMax ( $bits )
2009-12-03 09:19:00 +01:00
{
$bytes = $bits >> 3 ;
$min = str_repeat ( chr ( 0 ), $bytes );
$max = str_repeat ( chr ( 0xFF ), $bytes );
2009-12-31 07:11:07 +01:00
$msb = $bits & 7 ;
2009-12-03 09:19:00 +01:00
if ( $msb ) {
$min = chr ( 1 << ( $msb - 1 )) . $min ;
$max = chr (( 1 << $msb ) - 1 ) . $max ;
} else {
$min [ 0 ] = chr ( 0x80 );
}
return array (
2014-06-02 20:09:47 +02:00
'min' => new BigInteger ( $min , 256 ),
'max' => new BigInteger ( $max , 256 )
2009-12-03 09:19:00 +01:00
);
}
/**
* DER - decode the length
*
* DER supports lengths up to ( 2 ** 8 ) ** 127 , however , we ' ll only support lengths up to ( 2 ** 8 ) ** 4. See
2013-02-20 19:25:47 +01:00
* { @ link http :// itu . int / ITU - T / studygroups / com17 / languages / X . 690 - 0207. pdf #p=13 X.690 paragraph 8.1.3} for more information.
2009-12-03 09:19:00 +01:00
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $string
* @ return int
2009-12-03 09:19:00 +01:00
*/
function _decodeLength ( & $string )
{
$length = ord ( $this -> _string_shift ( $string ));
2015-07-15 03:52:31 +02:00
if ( $length & 0x80 ) { // definite length, long form
2009-12-03 09:19:00 +01:00
$length &= 0x7F ;
$temp = $this -> _string_shift ( $string , $length );
list (, $length ) = unpack ( 'N' , substr ( str_pad ( $temp , 4 , chr ( 0 ), STR_PAD_LEFT ), - 4 ));
}
return $length ;
}
/**
* DER - encode the length
*
* DER supports lengths up to ( 2 ** 8 ) ** 127 , however , we ' ll only support lengths up to ( 2 ** 8 ) ** 4. See
2013-02-20 19:25:47 +01:00
* { @ link http :// itu . int / ITU - T / studygroups / com17 / languages / X . 690 - 0207. pdf #p=13 X.690 paragraph 8.1.3} for more information.
2009-12-03 09:19:00 +01:00
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param int $length
* @ return string
2009-12-03 09:19:00 +01:00
*/
function _encodeLength ( $length )
{
if ( $length <= 0x7F ) {
return chr ( $length );
}
$temp = ltrim ( pack ( 'N' , $length ), chr ( 0 ));
return pack ( 'Ca*' , 0x80 | strlen ( $temp ), $temp );
}
/**
* String Shift
*
* Inspired by array_shift
*
2015-09-02 01:42:15 +02:00
* @ param string $string
* @ param int $index
* @ return string
2009-12-03 09:19:00 +01:00
* @ access private
*/
function _string_shift ( & $string , $index = 1 )
{
$substr = substr ( $string , 0 , $index );
$string = substr ( $string , $index );
return $substr ;
}
/**
* Determines the private key format
*
2015-10-11 19:22:07 +02:00
* @ see self :: createKey ()
2009-12-03 09:19:00 +01:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param int $format
2009-12-03 09:19:00 +01:00
*/
function setPrivateKeyFormat ( $format )
{
$this -> privateKeyFormat = $format ;
}
/**
* Determines the public key format
*
2015-10-11 19:22:07 +02:00
* @ see self :: createKey ()
2009-12-03 09:19:00 +01:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param int $format
2009-12-03 09:19:00 +01:00
*/
function setPublicKeyFormat ( $format )
{
$this -> publicKeyFormat = $format ;
}
/**
* Determines which hashing function should be used
*
2015-12-24 17:58:06 +01:00
* Used with signature production / verification and ( if the encryption mode is self :: PADDING_OAEP ) encryption and
2016-01-07 14:00:26 +01:00
* decryption . If $hash isn ' t supported , sha256 is used .
2009-12-03 09:19:00 +01:00
*
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $hash
2009-12-03 09:19:00 +01:00
*/
function setHash ( $hash )
{
2014-12-17 01:16:54 +01:00
// \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
2009-12-03 09:19:00 +01:00
switch ( $hash ) {
case 'md2' :
case 'md5' :
case 'sha1' :
case 'sha256' :
case 'sha384' :
case 'sha512' :
2014-12-17 01:16:54 +01:00
$this -> hash = new Hash ( $hash );
2009-12-03 09:19:00 +01:00
$this -> hashName = $hash ;
break ;
default :
2015-12-24 17:58:06 +01:00
$this -> hash = new Hash ( 'sha256' );
$this -> hashName = 'sha256' ;
2009-12-03 09:19:00 +01:00
}
2009-12-08 15:18:59 +01:00
$this -> hLen = $this -> hash -> getLength ();
2009-12-03 09:19:00 +01:00
}
/**
* Determines which hashing function should be used for the mask generation function
*
2015-12-24 17:58:06 +01:00
* The mask generation function is used by self :: PADDING_OAEP and self :: PADDING_PSS and although it ' s
2009-12-03 09:19:00 +01:00
* best if Hash and MGFHash are set to the same thing this is not a requirement .
*
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $hash
2009-12-03 09:19:00 +01:00
*/
function setMGFHash ( $hash )
{
2014-12-17 01:16:54 +01:00
// \phpseclib\Crypt\Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
2009-12-03 09:19:00 +01:00
switch ( $hash ) {
case 'md2' :
case 'md5' :
case 'sha1' :
case 'sha256' :
case 'sha384' :
case 'sha512' :
2014-12-17 01:16:54 +01:00
$this -> mgfHash = new Hash ( $hash );
2009-12-03 09:19:00 +01:00
break ;
default :
2016-01-07 14:00:26 +01:00
$this -> mgfHash = new Hash ( 'sha256' );
2009-12-03 09:19:00 +01:00
}
2009-12-08 15:18:59 +01:00
$this -> mgfHLen = $this -> mgfHash -> getLength ();
2009-12-03 09:19:00 +01:00
}
/**
* Determines the salt length
*
* To quote from { @ link http :// tools . ietf . org / html / rfc3447 #page-38 RFC3447#page-38}:
*
* Typical salt lengths in octets are hLen ( the length of the output
* of the hash function Hash ) and 0.
*
* @ access public
2015-09-02 01:42:15 +02:00
* @ param int $format
2009-12-03 09:19:00 +01:00
*/
function setSaltLength ( $sLen )
{
$this -> sLen = $sLen ;
}
/**
* Integer - to - Octet - String primitive
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-4.1 RFC3447#section-4.1}.
*
* @ access private
2016-01-07 14:00:26 +01:00
* @ param bool | \phpseclib\Math\BigInteger $x
2015-09-02 01:42:15 +02:00
* @ param int $xLen
2015-12-24 17:58:06 +01:00
* @ return bool | string
2009-12-03 09:19:00 +01:00
*/
function _i2osp ( $x , $xLen )
{
2016-01-07 14:00:26 +01:00
if ( $x === false ) {
return false ;
}
2009-12-03 09:19:00 +01:00
$x = $x -> toBytes ();
if ( strlen ( $x ) > $xLen ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
return str_pad ( $x , $xLen , chr ( 0 ), STR_PAD_LEFT );
}
/**
* Octet - String - to - Integer primitive
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-4.2 RFC3447#section-4.2}.
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $x
2014-06-02 20:09:47 +02:00
* @ return \phpseclib\Math\BigInteger
2009-12-03 09:19:00 +01:00
*/
function _os2ip ( $x )
{
2014-06-02 20:09:47 +02:00
return new BigInteger ( $x , 256 );
2009-12-03 09:19:00 +01:00
}
/**
* Exponentiate with or without Chinese Remainder Theorem
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-5.1.1 RFC3447#section-5.1.2}.
*
* @ access private
2014-06-02 20:09:47 +02:00
* @ param \phpseclib\Math\BigInteger $x
* @ return \phpseclib\Math\BigInteger
2009-12-03 09:19:00 +01:00
*/
function _exponentiate ( $x )
{
if ( empty ( $this -> primes ) || empty ( $this -> coefficients ) || empty ( $this -> exponents )) {
return $x -> modPow ( $this -> exponent , $this -> modulus );
}
$num_primes = count ( $this -> primes );
2010-02-28 06:28:38 +01:00
if ( defined ( 'CRYPT_RSA_DISABLE_BLINDING' )) {
$m_i = array (
1 => $x -> modPow ( $this -> exponents [ 1 ], $this -> primes [ 1 ]),
2 => $x -> modPow ( $this -> exponents [ 2 ], $this -> primes [ 2 ])
);
$h = $m_i [ 1 ] -> subtract ( $m_i [ 2 ]);
$h = $h -> multiply ( $this -> coefficients [ 2 ]);
list (, $h ) = $h -> divide ( $this -> primes [ 1 ]);
$m = $m_i [ 2 ] -> add ( $h -> multiply ( $this -> primes [ 2 ]));
$r = $this -> primes [ 1 ];
for ( $i = 3 ; $i <= $num_primes ; $i ++ ) {
$m_i = $x -> modPow ( $this -> exponents [ $i ], $this -> primes [ $i ]);
$r = $r -> multiply ( $this -> primes [ $i - 1 ]);
$h = $m_i -> subtract ( $m );
$h = $h -> multiply ( $this -> coefficients [ $i ]);
list (, $h ) = $h -> divide ( $this -> primes [ $i ]);
2009-12-03 09:19:00 +01:00
2010-02-28 06:28:38 +01:00
$m = $m -> add ( $r -> multiply ( $h ));
}
} else {
2010-03-01 18:28:19 +01:00
$smallest = $this -> primes [ 1 ];
for ( $i = 2 ; $i <= $num_primes ; $i ++ ) {
if ( $smallest -> compare ( $this -> primes [ $i ]) > 0 ) {
$smallest = $this -> primes [ $i ];
}
}
2015-12-27 13:13:57 +01:00
$r = BigInteger :: random ( self :: $one , $smallest -> subtract ( self :: $one ));
2010-03-01 18:28:19 +01:00
2010-02-28 06:28:38 +01:00
$m_i = array (
2010-03-01 18:28:19 +01:00
1 => $this -> _blind ( $x , $r , 1 ),
2 => $this -> _blind ( $x , $r , 2 )
2010-02-28 06:28:38 +01:00
);
$h = $m_i [ 1 ] -> subtract ( $m_i [ 2 ]);
$h = $h -> multiply ( $this -> coefficients [ 2 ]);
list (, $h ) = $h -> divide ( $this -> primes [ 1 ]);
$m = $m_i [ 2 ] -> add ( $h -> multiply ( $this -> primes [ 2 ]));
$r = $this -> primes [ 1 ];
for ( $i = 3 ; $i <= $num_primes ; $i ++ ) {
2010-03-01 18:28:19 +01:00
$m_i = $this -> _blind ( $x , $r , $i );
2009-12-03 09:19:00 +01:00
2010-02-28 06:28:38 +01:00
$r = $r -> multiply ( $this -> primes [ $i - 1 ]);
2009-12-03 09:19:00 +01:00
2010-02-28 06:28:38 +01:00
$h = $m_i -> subtract ( $m );
$h = $h -> multiply ( $this -> coefficients [ $i ]);
list (, $h ) = $h -> divide ( $this -> primes [ $i ]);
$m = $m -> add ( $r -> multiply ( $h ));
}
2009-12-03 09:19:00 +01:00
}
return $m ;
}
2010-02-28 06:28:38 +01:00
/**
* Performs RSA Blinding
*
* Protects against timing attacks by employing RSA Blinding .
* Returns $x -> modPow ( $this -> exponents [ $i ], $this -> primes [ $i ])
*
* @ access private
2014-06-02 20:09:47 +02:00
* @ param \phpseclib\Math\BigInteger $x
* @ param \phpseclib\Math\BigInteger $r
2015-09-02 01:42:15 +02:00
* @ param int $i
2014-06-02 20:09:47 +02:00
* @ return \phpseclib\Math\BigInteger
2010-02-28 06:28:38 +01:00
*/
2010-03-01 18:28:19 +01:00
function _blind ( $x , $r , $i )
2010-02-28 06:28:38 +01:00
{
$x = $x -> multiply ( $r -> modPow ( $this -> publicExponent , $this -> primes [ $i ]));
$x = $x -> modPow ( $this -> exponents [ $i ], $this -> primes [ $i ]);
$r = $r -> modInverse ( $this -> primes [ $i ]);
$x = $x -> multiply ( $r );
list (, $x ) = $x -> divide ( $this -> primes [ $i ]);
return $x ;
}
2012-05-06 01:57:30 +02:00
/**
* Performs blinded RSA equality testing
*
* Protects against a particular type of timing attack described .
*
2013-02-20 19:25:47 +01:00
* See { @ link http :// codahale . com / a - lesson - in - timing - attacks / A Lesson In Timing Attacks ( or , Don ' t use MessageDigest . isEquals )}
2012-05-06 01:57:30 +02:00
*
* Thanks for the heads up singpolyma !
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $x
* @ param string $y
* @ return bool
2012-05-06 01:57:30 +02:00
*/
function _equals ( $x , $y )
{
2012-06-05 12:52:00 +02:00
if ( strlen ( $x ) != strlen ( $y )) {
2012-05-06 01:57:30 +02:00
return false ;
}
$result = 0 ;
for ( $i = 0 ; $i < strlen ( $x ); $i ++ ) {
2012-09-29 21:32:27 +02:00
$result |= ord ( $x [ $i ]) ^ ord ( $y [ $i ]);
2012-05-06 01:57:30 +02:00
}
return $result == 0 ;
}
2009-12-03 09:19:00 +01:00
/**
* RSAEP
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-5.1.1 RFC3447#section-5.1.1}.
*
* @ access private
2014-06-02 20:09:47 +02:00
* @ param \phpseclib\Math\BigInteger $m
2015-12-24 17:58:06 +01:00
* @ return bool | \phpseclib\Math\BigInteger
2009-12-03 09:19:00 +01:00
*/
function _rsaep ( $m )
{
2015-10-01 17:15:58 +02:00
if ( $m -> compare ( self :: $zero ) < 0 || $m -> compare ( $this -> modulus ) > 0 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
return $this -> _exponentiate ( $m );
}
/**
* RSADP
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-5.1.2 RFC3447#section-5.1.2}.
*
* @ access private
2014-06-02 20:09:47 +02:00
* @ param \phpseclib\Math\BigInteger $c
2015-12-24 17:58:06 +01:00
* @ return bool | \phpseclib\Math\BigInteger
2009-12-03 09:19:00 +01:00
*/
function _rsadp ( $c )
{
2015-10-01 17:15:58 +02:00
if ( $c -> compare ( self :: $zero ) < 0 || $c -> compare ( $this -> modulus ) > 0 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
return $this -> _exponentiate ( $c );
}
/**
* RSASP1
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-5.2.1 RFC3447#section-5.2.1}.
*
* @ access private
2014-06-02 20:09:47 +02:00
* @ param \phpseclib\Math\BigInteger $m
2015-12-24 17:58:06 +01:00
* @ return bool | \phpseclib\Math\BigInteger
2009-12-03 09:19:00 +01:00
*/
function _rsasp1 ( $m )
{
2015-10-01 17:15:58 +02:00
if ( $m -> compare ( self :: $zero ) < 0 || $m -> compare ( $this -> modulus ) > 0 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
return $this -> _exponentiate ( $m );
}
/**
* RSAVP1
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-5.2.2 RFC3447#section-5.2.2}.
*
* @ access private
2014-06-02 20:09:47 +02:00
* @ param \phpseclib\Math\BigInteger $s
2015-12-24 17:58:06 +01:00
* @ return bool | \phpseclib\Math\BigInteger
2009-12-03 09:19:00 +01:00
*/
function _rsavp1 ( $s )
{
2015-10-01 17:15:58 +02:00
if ( $s -> compare ( self :: $zero ) < 0 || $s -> compare ( $this -> modulus ) > 0 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
return $this -> _exponentiate ( $s );
}
/**
* MGF1
*
2009-12-08 15:18:59 +01:00
* See { @ link http :// tools . ietf . org / html / rfc3447 #appendix-B.2.1 RFC3447#appendix-B.2.1}.
2009-12-03 09:19:00 +01:00
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $mgfSeed
* @ param int $mgfLen
* @ return string
2009-12-03 09:19:00 +01:00
*/
function _mgf1 ( $mgfSeed , $maskLen )
{
// if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
$t = '' ;
2009-12-08 15:18:59 +01:00
$count = ceil ( $maskLen / $this -> mgfHLen );
2009-12-03 09:19:00 +01:00
for ( $i = 0 ; $i < $count ; $i ++ ) {
$c = pack ( 'N' , $i );
$t .= $this -> mgfHash -> hash ( $mgfSeed . $c );
}
return substr ( $t , 0 , $maskLen );
}
/**
* RSAES - OAEP - ENCRYPT
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-7.1.1 RFC3447#section-7.1.1} and
* { http :// en . wikipedia . org / wiki / Optimal_Asymmetric_Encryption_Padding OAES } .
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
* @ param string $l
2015-10-01 17:15:58 +02:00
* @ throws \OutOfBoundsException if strlen ( $m ) > $this -> k - 2 * $this -> hLen - 2
2015-09-02 01:42:15 +02:00
* @ return string
2009-12-03 09:19:00 +01:00
*/
function _rsaes_oaep_encrypt ( $m , $l = '' )
{
$mLen = strlen ( $m );
// Length checking
// if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
// be output.
if ( $mLen > $this -> k - 2 * $this -> hLen - 2 ) {
2015-10-01 17:15:58 +02:00
throw new \OutOfBoundsException ( 'Message too long' );
2009-12-03 09:19:00 +01:00
}
// EME-OAEP encoding
$lHash = $this -> hash -> hash ( $l );
$ps = str_repeat ( chr ( 0 ), $this -> k - $mLen - 2 * $this -> hLen - 2 );
$db = $lHash . $ps . chr ( 1 ) . $m ;
2014-12-02 18:20:40 +01:00
$seed = Random :: string ( $this -> hLen );
2009-12-03 09:19:00 +01:00
$dbMask = $this -> _mgf1 ( $seed , $this -> k - $this -> hLen - 1 );
$maskedDB = $db ^ $dbMask ;
$seedMask = $this -> _mgf1 ( $maskedDB , $this -> hLen );
$maskedSeed = $seed ^ $seedMask ;
$em = chr ( 0 ) . $maskedSeed . $maskedDB ;
// RSA encryption
$m = $this -> _os2ip ( $em );
$c = $this -> _rsaep ( $m );
$c = $this -> _i2osp ( $c , $this -> k );
// Output the ciphertext C
return $c ;
}
/**
* RSAES - OAEP - DECRYPT
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
* messages aren ' t distinguishable from one another hinders debugging , but , to quote from RFC3447 #section-7.1.2:
2013-12-26 00:33:08 +01:00
*
2009-12-03 09:19:00 +01:00
* Note . Care must be taken to ensure that an opponent cannot
* distinguish the different error conditions in Step 3. g , whether by
* error message or timing , or , more generally , learn partial
* information about the encoded message EM . Otherwise an opponent may
* be able to obtain useful information about the decryption of the
* ciphertext C , leading to a chosen - ciphertext attack such as the one
* observed by Manger [ 36 ] .
*
* As for $l ... to quote from { @ link http :// tools . ietf . org / html / rfc3447 #page-17 RFC3447#page-17}:
*
* Both the encryption and the decryption operations of RSAES - OAEP take
* the value of a label L as input . In this version of PKCS #1, L is
* the empty string ; other uses of the label are outside the scope of
* this document .
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $c
* @ param string $l
2015-12-24 17:58:06 +01:00
* @ return bool | string
2009-12-03 09:19:00 +01:00
*/
function _rsaes_oaep_decrypt ( $c , $l = '' )
{
// Length checking
// if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
// be output.
if ( strlen ( $c ) != $this -> k || $this -> k < 2 * $this -> hLen + 2 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// RSA decryption
$c = $this -> _os2ip ( $c );
$m = $this -> _rsadp ( $c );
2016-01-07 14:00:26 +01:00
$em = $this -> _i2osp ( $m , $this -> k );
if ( $em === false ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// EME-OAEP decoding
$lHash = $this -> hash -> hash ( $l );
$y = ord ( $em [ 0 ]);
$maskedSeed = substr ( $em , 1 , $this -> hLen );
$maskedDB = substr ( $em , $this -> hLen + 1 );
$seedMask = $this -> _mgf1 ( $maskedDB , $this -> hLen );
$seed = $maskedSeed ^ $seedMask ;
$dbMask = $this -> _mgf1 ( $seed , $this -> k - $this -> hLen - 1 );
$db = $maskedDB ^ $dbMask ;
$lHash2 = substr ( $db , 0 , $this -> hLen );
$m = substr ( $db , $this -> hLen );
if ( $lHash != $lHash2 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
$m = ltrim ( $m , chr ( 0 ));
if ( ord ( $m [ 0 ]) != 1 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// Output the message M
return substr ( $m , 1 );
}
2015-05-26 05:30:38 +02:00
/**
* Raw Encryption / Decryption
*
* Doesn ' t use padding and is not recommended .
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
2016-01-07 14:00:26 +01:00
* @ return bool | string
2015-05-26 05:30:38 +02:00
*/
function _raw_encrypt ( $m )
{
$temp = $this -> _os2ip ( $m );
$temp = $this -> _rsaep ( $temp );
return $this -> _i2osp ( $temp , $this -> k );
}
2009-12-03 09:19:00 +01:00
/**
* RSAES - PKCS1 - V1_5 - ENCRYPT
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-7.2.1 RFC3447#section-7.2.1}.
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
2016-01-03 20:01:53 +01:00
* @ param bool $pkcs15_compat optional
2015-10-01 17:15:58 +02:00
* @ throws \OutOfBoundsException if strlen ( $m ) > $this -> k - 11
2016-01-07 14:00:26 +01:00
* @ return bool | string
2009-12-03 09:19:00 +01:00
*/
2015-12-24 17:58:06 +01:00
function _rsaes_pkcs1_v1_5_encrypt ( $m , $pkcs15_compat = false )
2009-12-03 09:19:00 +01:00
{
$mLen = strlen ( $m );
// Length checking
if ( $mLen > $this -> k - 11 ) {
2015-10-01 17:15:58 +02:00
throw new \OutOfBoundsException ( 'Message too long' );
2009-12-03 09:19:00 +01:00
}
// EME-PKCS1-v1_5 encoding
2013-03-23 20:13:24 +01:00
2012-12-16 09:20:16 +01:00
$psLen = $this -> k - $mLen - 3 ;
$ps = '' ;
while ( strlen ( $ps ) != $psLen ) {
2014-12-02 18:20:40 +01:00
$temp = Random :: string ( $psLen - strlen ( $ps ));
2012-12-16 09:20:16 +01:00
$temp = str_replace ( " \x00 " , '' , $temp );
$ps .= $temp ;
}
2013-03-23 20:13:24 +01:00
$type = 2 ;
// see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
2015-12-24 17:58:06 +01:00
if ( $pkcs15_compat && ( ! isset ( $this -> publicExponent ) || $this -> exponent !== $this -> publicExponent )) {
2013-03-23 20:13:24 +01:00
$type = 1 ;
// "The padding string PS shall consist of k-3-||D|| octets. ... for block type 01, they shall have value FF"
$ps = str_repeat ( " \xFF " , $psLen );
}
$em = chr ( 0 ) . chr ( $type ) . $ps . chr ( 0 ) . $m ;
2009-12-03 09:19:00 +01:00
// RSA encryption
$m = $this -> _os2ip ( $em );
$c = $this -> _rsaep ( $m );
$c = $this -> _i2osp ( $c , $this -> k );
// Output the ciphertext C
return $c ;
}
/**
* RSAES - PKCS1 - V1_5 - DECRYPT
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-7.2.2 RFC3447#section-7.2.2}.
*
2014-03-06 00:41:20 +01:00
* For compatibility purposes , this function departs slightly from the description given in RFC3447 .
2010-04-10 17:57:02 +02:00
* The reason being that RFC2313 #section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
* private key should have the second byte set to either 0 or 1 and that ciphertext ' s encrypted by the
* public key should have the second byte set to 2. In RFC3447 ( PKCS #1 v2.1), the second byte is supposed
2014-03-06 00:41:20 +01:00
* to be 2 regardless of which key is used . For compatibility purposes , we ' ll just check to make sure the
2010-04-10 17:57:02 +02:00
* second byte is 2 or less . If it is , we ' ll accept the decrypted string as valid .
*
2014-12-17 01:16:54 +01:00
* As a consequence of this , a private key encrypted ciphertext produced with \phpseclib\Crypt\RSA may not decrypt
2010-04-10 17:57:02 +02:00
* with a strictly PKCS #1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
* not private key encrypted ciphertext ' s .
*
2009-12-03 09:19:00 +01:00
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $c
2015-12-24 17:58:06 +01:00
* @ return bool | string
2009-12-03 09:19:00 +01:00
*/
function _rsaes_pkcs1_v1_5_decrypt ( $c )
{
// Length checking
if ( strlen ( $c ) != $this -> k ) { // or if k < 11
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// RSA decryption
$c = $this -> _os2ip ( $c );
$m = $this -> _rsadp ( $c );
2016-01-07 14:00:26 +01:00
$em = $this -> _i2osp ( $m , $this -> k );
if ( $em === false ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// EME-PKCS1-v1_5 decoding
2010-04-10 17:57:02 +02:00
if ( ord ( $em [ 0 ]) != 0 || ord ( $em [ 1 ]) > 2 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
$ps = substr ( $em , 2 , strpos ( $em , chr ( 0 ), 2 ) - 2 );
$m = substr ( $em , strlen ( $ps ) + 3 );
if ( strlen ( $ps ) < 8 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// Output M
return $m ;
}
/**
* EMSA - PSS - ENCODE
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-9.1.1 RFC3447#section-9.1.1}.
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
2015-10-01 17:15:58 +02:00
* @ throws \RuntimeException on encoding error
2015-09-02 01:42:15 +02:00
* @ param int $emBits
2009-12-03 09:19:00 +01:00
*/
function _emsa_pss_encode ( $m , $emBits )
{
// if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
// be output.
$emLen = ( $emBits + 1 ) >> 3 ; // ie. ceil($emBits / 8)
2015-08-11 14:27:56 +02:00
$sLen = $this -> sLen ? $this -> sLen : $this -> hLen ;
2009-12-03 09:19:00 +01:00
$mHash = $this -> hash -> hash ( $m );
if ( $emLen < $this -> hLen + $sLen + 2 ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
2014-12-02 18:20:40 +01:00
$salt = Random :: string ( $sLen );
2009-12-03 09:19:00 +01:00
$m2 = " \0 \0 \0 \0 \0 \0 \0 \0 " . $mHash . $salt ;
$h = $this -> hash -> hash ( $m2 );
$ps = str_repeat ( chr ( 0 ), $emLen - $sLen - $this -> hLen - 2 );
$db = $ps . chr ( 1 ) . $salt ;
$dbMask = $this -> _mgf1 ( $h , $emLen - $this -> hLen - 1 );
$maskedDB = $db ^ $dbMask ;
$maskedDB [ 0 ] = ~ chr ( 0xFF << ( $emBits & 7 )) & $maskedDB [ 0 ];
$em = $maskedDB . $h . chr ( 0xBC );
return $em ;
}
/**
* EMSA - PSS - VERIFY
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-9.1.2 RFC3447#section-9.1.2}.
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
* @ param string $em
* @ param int $emBits
* @ return string
2009-12-03 09:19:00 +01:00
*/
function _emsa_pss_verify ( $m , $em , $emBits )
{
// if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
// be output.
$emLen = ( $emBits + 1 ) >> 3 ; // ie. ceil($emBits / 8);
2015-08-11 14:27:56 +02:00
$sLen = $this -> sLen ? $this -> sLen : $this -> hLen ;
2009-12-03 09:19:00 +01:00
$mHash = $this -> hash -> hash ( $m );
if ( $emLen < $this -> hLen + $sLen + 2 ) {
return false ;
}
if ( $em [ strlen ( $em ) - 1 ] != chr ( 0xBC )) {
return false ;
}
2011-03-19 04:32:22 +01:00
$maskedDB = substr ( $em , 0 , - $this -> hLen - 1 );
$h = substr ( $em , - $this -> hLen - 1 , $this -> hLen );
2009-12-03 09:19:00 +01:00
$temp = chr ( 0xFF << ( $emBits & 7 ));
if (( ~ $maskedDB [ 0 ] & $temp ) != $temp ) {
return false ;
}
$dbMask = $this -> _mgf1 ( $h , $emLen - $this -> hLen - 1 );
$db = $maskedDB ^ $dbMask ;
$db [ 0 ] = ~ chr ( 0xFF << ( $emBits & 7 )) & $db [ 0 ];
$temp = $emLen - $this -> hLen - $sLen - 2 ;
if ( substr ( $db , 0 , $temp ) != str_repeat ( chr ( 0 ), $temp ) || ord ( $db [ $temp ]) != 1 ) {
return false ;
}
$salt = substr ( $db , $temp + 1 ); // should be $sLen long
$m2 = " \0 \0 \0 \0 \0 \0 \0 \0 " . $mHash . $salt ;
$h2 = $this -> hash -> hash ( $m2 );
2012-05-06 01:57:30 +02:00
return $this -> _equals ( $h , $h2 );
2009-12-03 09:19:00 +01:00
}
/**
* RSASSA - PSS - SIGN
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-8.1.1 RFC3447#section-8.1.1}.
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
2016-01-03 20:01:53 +01:00
* @ return bool | string
2009-12-03 09:19:00 +01:00
*/
function _rsassa_pss_sign ( $m )
{
// EMSA-PSS encoding
$em = $this -> _emsa_pss_encode ( $m , 8 * $this -> k - 1 );
// RSA signature
$m = $this -> _os2ip ( $em );
$s = $this -> _rsasp1 ( $m );
$s = $this -> _i2osp ( $s , $this -> k );
// Output the signature S
return $s ;
}
/**
* RSASSA - PSS - VERIFY
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-8.1.2 RFC3447#section-8.1.2}.
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
* @ param string $s
2016-01-07 14:00:26 +01:00
* @ return bool | string
2009-12-03 09:19:00 +01:00
*/
function _rsassa_pss_verify ( $m , $s )
{
// Length checking
if ( strlen ( $s ) != $this -> k ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// RSA verification
$modBits = 8 * $this -> k ;
$s2 = $this -> _os2ip ( $s );
$m2 = $this -> _rsavp1 ( $s2 );
$em = $this -> _i2osp ( $m2 , $modBits >> 3 );
if ( $em === false ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// EMSA-PSS verification
return $this -> _emsa_pss_verify ( $m , $em , $modBits - 1 );
}
/**
* EMSA - PKCS1 - V1_5 - ENCODE
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-9.2 RFC3447#section-9.2}.
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
* @ param int $emLen
2015-10-01 17:15:58 +02:00
* @ throws \LengthException if the intended encoded message length is too short
2015-09-02 01:42:15 +02:00
* @ return string
2009-12-03 09:19:00 +01:00
*/
function _emsa_pkcs1_v1_5_encode ( $m , $emLen )
{
$h = $this -> hash -> hash ( $m );
// see http://tools.ietf.org/html/rfc3447#page-43
switch ( $this -> hashName ) {
case 'md2' :
$t = pack ( 'H*' , '3020300c06082a864886f70d020205000410' );
break ;
case 'md5' :
$t = pack ( 'H*' , '3020300c06082a864886f70d020505000410' );
break ;
case 'sha1' :
$t = pack ( 'H*' , '3021300906052b0e03021a05000414' );
break ;
case 'sha256' :
$t = pack ( 'H*' , '3031300d060960864801650304020105000420' );
break ;
case 'sha384' :
$t = pack ( 'H*' , '3041300d060960864801650304020205000430' );
break ;
case 'sha512' :
$t = pack ( 'H*' , '3051300d060960864801650304020305000440' );
}
$t .= $h ;
$tLen = strlen ( $t );
if ( $emLen < $tLen + 11 ) {
2015-10-01 17:15:58 +02:00
throw new \LengthException ( 'Intended encoded message length too short' );
2009-12-03 09:19:00 +01:00
}
$ps = str_repeat ( chr ( 0xFF ), $emLen - $tLen - 3 );
$em = " \0 \1 $ps\0 $t " ;
return $em ;
}
/**
* RSASSA - PKCS1 - V1_5 - SIGN
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-8.2.1 RFC3447#section-8.2.1}.
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
2015-10-01 17:15:58 +02:00
* @ throws \LengthException if the RSA modulus is too short
2016-01-03 20:01:53 +01:00
* @ return bool | string
2009-12-03 09:19:00 +01:00
*/
function _rsassa_pkcs1_v1_5_sign ( $m )
{
// EMSA-PKCS1-v1_5 encoding
2015-12-24 17:58:06 +01:00
// If the encoding operation outputs "intended encoded message length too short," output "RSA modulus
// too short" and stop.
2016-01-03 20:01:53 +01:00
try {
$em = $this -> _emsa_pkcs1_v1_5_encode ( $m , $this -> k );
} catch ( \LengthException $e ) {
throw new \LengthException ( 'RSA modulus too short' );
2009-12-03 09:19:00 +01:00
}
// RSA signature
$m = $this -> _os2ip ( $em );
$s = $this -> _rsasp1 ( $m );
$s = $this -> _i2osp ( $s , $this -> k );
// Output the signature S
return $s ;
}
/**
* RSASSA - PKCS1 - V1_5 - VERIFY
*
* See { @ link http :// tools . ietf . org / html / rfc3447 #section-8.2.2 RFC3447#section-8.2.2}.
*
* @ access private
2015-09-02 01:42:15 +02:00
* @ param string $m
2016-01-03 20:01:53 +01:00
* @ param string $s
2015-10-01 17:15:58 +02:00
* @ throws \LengthException if the RSA modulus is too short
2016-01-03 20:01:53 +01:00
* @ return bool
2009-12-03 09:19:00 +01:00
*/
function _rsassa_pkcs1_v1_5_verify ( $m , $s )
{
// Length checking
if ( strlen ( $s ) != $this -> k ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// RSA verification
$s = $this -> _os2ip ( $s );
$m2 = $this -> _rsavp1 ( $s );
$em = $this -> _i2osp ( $m2 , $this -> k );
if ( $em === false ) {
2015-12-24 17:58:06 +01:00
return false ;
2009-12-03 09:19:00 +01:00
}
// EMSA-PKCS1-v1_5 encoding
2015-12-24 17:58:06 +01:00
// If the encoding operation outputs "intended encoded message length too short," output "RSA modulus
// too short" and stop.
try {
$em2 = $this -> _emsa_pkcs1_v1_5_encode ( $m , $this -> k );
} catch ( \LengthException $e ) {
2015-10-01 17:15:58 +02:00
throw new \LengthException ( 'RSA modulus too short' );
2009-12-03 09:19:00 +01:00
}
// Compare
2012-05-06 01:57:30 +02:00
return $this -> _equals ( $em , $em2 );
2009-12-03 09:19:00 +01:00
}
/**
2015-12-24 17:58:06 +01:00
* RSASSA - PKCS1 - V1_5 - VERIFY ( relaxed matching )
2009-12-03 09:19:00 +01:00
*
2015-12-24 17:58:06 +01:00
* Per { @ link http :// tools . ietf . org / html / rfc3447 #page-43 RFC3447#page-43} PKCS1 v1.5
* specified the use BER encoding rather than DER encoding that PKCS1 v2 . 0 specified .
* This means that under rare conditions you can have a perfectly valid v1 . 5 signature
* that fails to validate with _rsassa_pkcs1_v1_5_verify () . PKCS1 v2 . 1 also recommends
* that if you ' re going to validate these types of signatures you " should indicate
* whether the underlying BER encoding is a DER encoding and hence whether the signature
* is valid with respect to the specification given in [ PKCS1 v2 . 0 + ] " . so if you do
* $rsa -> getLastPadding () and get RSA :: PADDING_RELAXED_PKCS1 back instead of
* RSA :: PADDING_PKCS1 ... that means BER encoding was used .
2009-12-03 09:19:00 +01:00
*
2015-12-24 17:58:06 +01:00
* @ access private
* @ param string $m
2016-01-03 20:01:53 +01:00
* @ param string $s
* @ return bool
2009-12-03 09:19:00 +01:00
*/
2015-12-24 17:58:06 +01:00
function _rsassa_pkcs1_v1_5_relaxed_verify ( $m , $s )
2009-12-03 09:19:00 +01:00
{
2015-12-24 17:58:06 +01:00
// Length checking
2009-12-03 09:19:00 +01:00
2015-12-24 17:58:06 +01:00
if ( strlen ( $s ) != $this -> k ) {
return false ;
}
// RSA verification
$s = $this -> _os2ip ( $s );
$m2 = $this -> _rsavp1 ( $s );
if ( $m2 === false ) {
return false ;
}
$em = $this -> _i2osp ( $m2 , $this -> k );
if ( $em === false ) {
return false ;
}
if ( $this -> _string_shift ( $em , 2 ) != " \0 \1 " ) {
return false ;
}
$em = ltrim ( $em , " \xFF " );
if ( $this -> _string_shift ( $em ) != " \0 " ) {
return false ;
}
$asn1 = new ASN1 ();
$decoded = $asn1 -> decodeBER ( $em );
if ( ! is_array ( $decoded ) || empty ( $decoded [ 0 ]) || strlen ( $em ) > $decoded [ 0 ][ 'length' ]) {
return false ;
}
$AlgorithmIdentifier = array (
'type' => ASN1 :: TYPE_SEQUENCE ,
'children' => array (
'algorithm' => array ( 'type' => ASN1 :: TYPE_OBJECT_IDENTIFIER ),
'parameters' => array (
'type' => ASN1 :: TYPE_ANY ,
'optional' => true
)
)
);
$DigestInfo = array (
'type' => ASN1 :: TYPE_SEQUENCE ,
'children' => array (
'digestAlgorithm' => $AlgorithmIdentifier ,
'digest' => array ( 'type' => ASN1 :: TYPE_OCTET_STRING )
)
);
$oids = array (
'1.2.840.113549.2.2' => 'md2' ,
'1.2.840.113549.2.4' => 'md4' , // from PKCS1 v1.5
'1.2.840.113549.2.5' => 'md5' ,
'1.3.14.3.2.26' => 'sha1' ,
'2.16.840.1.101.3.4.2.1' => 'sha256' ,
'2.16.840.1.101.3.4.2.2' => 'sha384' ,
'2.16.840.1.101.3.4.2.3' => 'sha512' ,
// from PKCS1 v2.2
//'2.16.840.1.101.3.4.2.5' => 'sha512/224',
//'2.16.840.1.101.3.4.2.6' => 'sha512/256',
);
$asn1 -> loadOIDs ( $oids );
$decoded = $asn1 -> asn1map ( $decoded [ 0 ], $DigestInfo );
if ( ! isset ( $decoded ) || $decoded === false ) {
return false ;
}
if ( ! in_array ( $decoded [ 'digestAlgorithm' ][ 'algorithm' ], $oids )) {
return false ;
}
$hash = new Hash ( $decoded [ 'digestAlgorithm' ][ 'algorithm' ]);
$em = $hash -> hash ( $m );
$em2 = base64_decode ( $decoded [ 'digest' ]);
return $this -> _equals ( $em , $em2 );
2009-12-03 09:19:00 +01:00
}
/**
* Encryption
*
2015-12-24 17:58:06 +01:00
* Both self :: PADDING_OAEP and self :: PADDING_PKCS1 both place limits on how long $plaintext can be .
2009-12-03 09:19:00 +01:00
* If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext ' s will
* be concatenated together .
*
2015-10-11 19:22:07 +02:00
* @ see self :: decrypt ()
2009-12-03 09:19:00 +01:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $plaintext
2016-01-03 20:01:53 +01:00
* @ param int $padding optional
* @ return bool | string
2015-10-23 16:20:12 +02:00
* @ throws \LengthException if the RSA modulus is too short
2009-12-03 09:19:00 +01:00
*/
2015-12-24 17:58:06 +01:00
function encrypt ( $plaintext , $padding = self :: PADDING_OAEP )
2009-12-03 09:19:00 +01:00
{
2015-12-24 17:58:06 +01:00
switch ( $padding ) {
case self :: PADDING_NONE :
2015-05-26 05:30:38 +02:00
$plaintext = str_split ( $plaintext , $this -> k );
$ciphertext = '' ;
foreach ( $plaintext as $m ) {
2016-01-03 20:01:53 +01:00
$temp = $this -> _raw_encrypt ( $m );
if ( $temp === false ) {
return false ;
}
$ciphertext .= $temp ;
2015-05-26 05:30:38 +02:00
}
return $ciphertext ;
2015-12-24 17:58:06 +01:00
case self :: PADDING_PKCS15_COMPAT :
case self :: PADDING_PKCS1 :
2009-12-06 08:26:52 +01:00
$length = $this -> k - 11 ;
if ( $length <= 0 ) {
2015-10-23 16:20:12 +02:00
throw new \LengthException ( 'RSA modulus too short (' . $this -> k . ' bytes long; should be more than 11 bytes with PKCS1)' );
2009-12-06 08:26:52 +01:00
}
$plaintext = str_split ( $plaintext , $length );
2009-12-03 09:19:00 +01:00
$ciphertext = '' ;
foreach ( $plaintext as $m ) {
2016-01-03 20:01:53 +01:00
$temp = $this -> _rsaes_pkcs1_v1_5_encrypt ( $m , $padding == self :: PADDING_PKCS15_COMPAT );
if ( $temp === false ) {
return false ;
}
$ciphertext .= $temp ;
2009-12-03 09:19:00 +01:00
}
return $ciphertext ;
2015-12-24 17:58:06 +01:00
//case self::PADDING_OAEP:
2009-12-03 09:19:00 +01:00
default :
2009-12-06 08:26:52 +01:00
$length = $this -> k - 2 * $this -> hLen - 2 ;
if ( $length <= 0 ) {
2015-12-24 17:58:06 +01:00
throw new \LengthException ( 'RSA modulus too short (' . $this -> k . ' bytes long; should be more than ' . ( 2 * $this -> hLen + 2 ) . ' bytes with OAEP / ' . $this -> hashName . ')' );
2009-12-06 08:26:52 +01:00
}
$plaintext = str_split ( $plaintext , $length );
2009-12-03 09:19:00 +01:00
$ciphertext = '' ;
foreach ( $plaintext as $m ) {
2016-01-03 20:01:53 +01:00
$temp = $this -> _rsaes_oaep_encrypt ( $m );
if ( $temp === false ) {
return false ;
}
$ciphertext .= $temp ;
2009-12-03 09:19:00 +01:00
}
return $ciphertext ;
}
}
/**
* Decryption
*
2015-10-11 19:22:07 +02:00
* @ see self :: encrypt ()
2009-12-03 09:19:00 +01:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $plaintext
2016-01-03 20:01:53 +01:00
* @ param int $padding optional
2016-01-07 14:00:26 +01:00
* @ return bool | string
2009-12-03 09:19:00 +01:00
*/
2015-12-24 17:58:06 +01:00
function decrypt ( $ciphertext , $padding = self :: PADDING_OAEP )
2009-12-03 09:19:00 +01:00
{
2009-12-06 08:26:52 +01:00
if ( $this -> k <= 0 ) {
return false ;
}
$ciphertext = str_split ( $ciphertext , $this -> k );
2012-11-20 06:00:04 +01:00
$ciphertext [ count ( $ciphertext ) - 1 ] = str_pad ( $ciphertext [ count ( $ciphertext ) - 1 ], $this -> k , chr ( 0 ), STR_PAD_LEFT );
2009-12-06 08:26:52 +01:00
$plaintext = '' ;
2015-12-24 17:58:06 +01:00
switch ( $padding ) {
case self :: PADDING_NONE :
2015-05-26 05:30:38 +02:00
$decrypt = '_raw_encrypt' ;
break ;
2015-12-24 17:58:06 +01:00
case self :: PADDING_PKCS1 :
2009-12-06 08:26:52 +01:00
$decrypt = '_rsaes_pkcs1_v1_5_decrypt' ;
break ;
2015-12-24 17:58:06 +01:00
//case self::PADDING_OAEP:
2009-12-03 09:19:00 +01:00
default :
2009-12-06 08:26:52 +01:00
$decrypt = '_rsaes_oaep_decrypt' ;
2009-12-03 09:19:00 +01:00
}
2009-12-06 08:26:52 +01:00
foreach ( $ciphertext as $c ) {
$temp = $this -> $decrypt ( $c );
if ( $temp === false ) {
return false ;
}
$plaintext .= $temp ;
}
return $plaintext ;
2009-12-03 09:19:00 +01:00
}
/**
* Create a signature
*
2015-10-11 19:22:07 +02:00
* @ see self :: verify ()
2009-12-03 09:19:00 +01:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $message
2016-01-03 20:01:53 +01:00
* @ param int $padding optional
2015-09-02 01:42:15 +02:00
* @ return string
2009-12-03 09:19:00 +01:00
*/
2015-12-24 17:58:06 +01:00
function sign ( $message , $padding = self :: PADDING_PSS )
2009-12-03 09:19:00 +01:00
{
2009-12-06 08:26:52 +01:00
if ( empty ( $this -> modulus ) || empty ( $this -> exponent )) {
return false ;
}
2015-12-24 17:58:06 +01:00
switch ( $padding ) {
case self :: PADDING_PKCS1 :
case self :: PADDING_RELAXED_PKCS1 :
2009-12-03 09:19:00 +01:00
return $this -> _rsassa_pkcs1_v1_5_sign ( $message );
2015-12-24 17:58:06 +01:00
//case self::PADDING_PSS:
2009-12-03 09:19:00 +01:00
default :
return $this -> _rsassa_pss_sign ( $message );
}
}
/**
* Verifies a signature
*
2015-10-11 19:22:07 +02:00
* @ see self :: sign ()
2009-12-03 09:19:00 +01:00
* @ access public
2015-09-02 01:42:15 +02:00
* @ param string $message
* @ param string $signature
2016-01-03 20:01:53 +01:00
* @ param int $padding optional
2015-09-02 01:42:15 +02:00
* @ return bool
2009-12-03 09:19:00 +01:00
*/
2015-12-24 17:58:06 +01:00
function verify ( $message , $signature , $padding = self :: PADDING_PSS )
2009-12-03 09:19:00 +01:00
{
2009-12-06 08:26:52 +01:00
if ( empty ( $this -> modulus ) || empty ( $this -> exponent )) {
return false ;
}
2015-12-24 17:58:06 +01:00
switch ( $padding ) {
case self :: PADDING_RELAXED_PKCS1 :
return $this -> _rsassa_pkcs1_v1_5_relaxed_verify ( $message , $signature );
case self :: PADDING_PKCS1 :
2009-12-03 09:19:00 +01:00
return $this -> _rsassa_pkcs1_v1_5_verify ( $message , $signature );
2015-12-24 17:58:06 +01:00
//case self::PADDING_PSS:
2009-12-03 09:19:00 +01:00
default :
return $this -> _rsassa_pss_verify ( $message , $signature );
}
}
2015-10-16 17:31:43 +02:00
}