mirror of
https://github.com/danog/phpseclib.git
synced 2024-12-04 02:28:06 +01:00
undo merging of master to 2.0 branch
This commit is contained in:
parent
b4743df277
commit
a25ac1cd10
@ -1,223 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Miccrosoft BLOB Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* More info:
|
|
||||||
*
|
|
||||||
* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375601(v=vs.85).aspx
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* @category Crypt
|
|
||||||
* @package RSA
|
|
||||||
* @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 phpseclib\Crypt\RSA;
|
|
||||||
|
|
||||||
use phpseclib\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Microsoft BLOB Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* @package RSA
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
class MSBLOB
|
|
||||||
{
|
|
||||||
/**#@+
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Public/Private Key Pair
|
|
||||||
*/
|
|
||||||
const PRIVATEKEYBLOB = 0x7;
|
|
||||||
/**
|
|
||||||
* Public Key
|
|
||||||
*/
|
|
||||||
const PUBLICKEYBLOB = 0x6;
|
|
||||||
/**
|
|
||||||
* Public Key
|
|
||||||
*/
|
|
||||||
const PUBLICKEYBLOBEX = 0xA;
|
|
||||||
/**
|
|
||||||
* RSA public key exchange algorithm
|
|
||||||
*/
|
|
||||||
const CALG_RSA_KEYX = 0x0000A400;
|
|
||||||
/**
|
|
||||||
* RSA public key exchange algorithm
|
|
||||||
*/
|
|
||||||
const CALG_RSA_SIGN = 0x00002400;
|
|
||||||
/**
|
|
||||||
* Public Key
|
|
||||||
*/
|
|
||||||
const RSA1 = 0x31415352;
|
|
||||||
/**
|
|
||||||
* Private Key
|
|
||||||
*/
|
|
||||||
const RSA2 = 0x32415352;
|
|
||||||
/**#@-*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Break a public or private key down into its constituent components
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $key
|
|
||||||
* @param string $password optional
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static function load($key, $password = '')
|
|
||||||
{
|
|
||||||
if (!is_string($key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$key = base64_decode($key);
|
|
||||||
|
|
||||||
if (!is_string($key) || strlen($key) < 20) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PUBLICKEYSTRUC publickeystruc
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa387453(v=vs.85).aspx
|
|
||||||
extract(unpack('atype/aversion/vreserved/Valgo', self::_string_shift($key, 8)));
|
|
||||||
switch (ord($type)) {
|
|
||||||
case self::PUBLICKEYBLOB:
|
|
||||||
case self::PUBLICKEYBLOBEX:
|
|
||||||
$publickey = true;
|
|
||||||
break;
|
|
||||||
case self::PRIVATEKEYBLOB:
|
|
||||||
$publickey = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$components = array('isPublicKey' => $publickey);
|
|
||||||
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa375549(v=vs.85).aspx
|
|
||||||
switch ($algo) {
|
|
||||||
case self::CALG_RSA_KEYX:
|
|
||||||
case self::CALG_RSA_SIGN:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// RSAPUBKEY rsapubkey
|
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa387685(v=vs.85).aspx
|
|
||||||
// could do V for pubexp but that's unsigned 32-bit whereas some PHP installs only do signed 32-bit
|
|
||||||
extract(unpack('Vmagic/Vbitlen/a4pubexp', self::_string_shift($key, 12)));
|
|
||||||
switch ($magic) {
|
|
||||||
case self::RSA2:
|
|
||||||
$components['isPublicKey'] = false;
|
|
||||||
case self::RSA1:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$baseLength = $bitlen / 16;
|
|
||||||
if (strlen($key) != 2 * $baseLength && strlen($key) != 9 * $baseLength) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(strrev($pubexp), 256);
|
|
||||||
// BYTE modulus[rsapubkey.bitlen/8]
|
|
||||||
$components['modulus'] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 8)), 256);
|
|
||||||
|
|
||||||
if ($publickey) {
|
|
||||||
return $components;
|
|
||||||
}
|
|
||||||
|
|
||||||
$components['isPublicKey'] = false;
|
|
||||||
|
|
||||||
// BYTE prime1[rsapubkey.bitlen/16]
|
|
||||||
$components['primes'] = array(1 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
|
|
||||||
// BYTE prime2[rsapubkey.bitlen/16]
|
|
||||||
$components['primes'][] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256);
|
|
||||||
// BYTE exponent1[rsapubkey.bitlen/16]
|
|
||||||
$components['exponents'] = array(1 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
|
|
||||||
// BYTE exponent2[rsapubkey.bitlen/16]
|
|
||||||
$components['exponents'][] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256);
|
|
||||||
// BYTE coefficient[rsapubkey.bitlen/16]
|
|
||||||
$components['coefficients'] = array(2 => new BigInteger(strrev(self::_string_shift($key, $bitlen / 16)), 256));
|
|
||||||
if (isset($components['privateExponent'])) {
|
|
||||||
$components['publicExponent'] = $components['privateExponent'];
|
|
||||||
}
|
|
||||||
// BYTE privateExponent[rsapubkey.bitlen/8]
|
|
||||||
$components['privateExponent'] = new BigInteger(strrev(self::_string_shift($key, $bitlen / 8)), 256);
|
|
||||||
|
|
||||||
return $components;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a private key to the appropriate format.
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @param \phpseclib\Math\BigInteger $d
|
|
||||||
* @param array $primes
|
|
||||||
* @param array $exponents
|
|
||||||
* @param array $coefficients
|
|
||||||
* @param string $password optional
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
|
||||||
{
|
|
||||||
$n = strrev($n->toBytes());
|
|
||||||
$e = str_pad(strrev($e->toBytes()), 4, "\0");
|
|
||||||
$key = pack('aavV', chr(self::PRIVATEKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
|
|
||||||
$key.= pack('VVa*', self::RSA2, 8 * strlen($n), $e);
|
|
||||||
$key.= $n;
|
|
||||||
$key.= strrev($primes[1]->toBytes());
|
|
||||||
$key.= strrev($primes[2]->toBytes());
|
|
||||||
$key.= strrev($exponents[1]->toBytes());
|
|
||||||
$key.= strrev($exponents[2]->toBytes());
|
|
||||||
$key.= strrev($coefficients[1]->toBytes());
|
|
||||||
$key.= strrev($d->toBytes());
|
|
||||||
|
|
||||||
return base64_encode($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a public key to the appropriate format
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
|
||||||
{
|
|
||||||
$n = strrev($n->toBytes());
|
|
||||||
$e = str_pad(strrev($e->toBytes()), 4, "\0");
|
|
||||||
$key = pack('aavV', chr(self::PUBLICKEYBLOB), chr(2), 0, self::CALG_RSA_KEYX);
|
|
||||||
$key.= pack('VVa*', self::RSA1, 8 * strlen($n), $e);
|
|
||||||
$key.= $n;
|
|
||||||
|
|
||||||
return base64_encode($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* String Shift
|
|
||||||
*
|
|
||||||
* Inspired by array_shift
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @param int $index
|
|
||||||
* @return string
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
static function _string_shift(&$string, $index = 1)
|
|
||||||
{
|
|
||||||
$substr = substr($string, 0, $index);
|
|
||||||
$string = substr($string, $index);
|
|
||||||
return $substr;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,140 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* OpenSSH Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* Place in $HOME/.ssh/authorized_keys
|
|
||||||
*
|
|
||||||
* @category Crypt
|
|
||||||
* @package RSA
|
|
||||||
* @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 phpseclib\Crypt\RSA;
|
|
||||||
|
|
||||||
use phpseclib\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* OpenSSH Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* @package RSA
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
class OpenSSH
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Default comment
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
static $comment = 'phpseclib-generated-key';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default comment
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $comment
|
|
||||||
*/
|
|
||||||
static function setComment($comment)
|
|
||||||
{
|
|
||||||
self::$comment = str_replace(array("\r", "\n"), '', $comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Break a public or private key down into its constituent components
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $key
|
|
||||||
* @param string $password optional
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static function load($key, $password = '')
|
|
||||||
{
|
|
||||||
if (!is_string($key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parts = explode(' ', $key, 3);
|
|
||||||
|
|
||||||
$key = isset($parts[1]) ? base64_decode($parts[1]) : base64_decode($parts[0]);
|
|
||||||
if ($key === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$comment = isset($parts[2]) ? $parts[2] : false;
|
|
||||||
|
|
||||||
if (substr($key, 0, 11) != "\0\0\0\7ssh-rsa") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self::_string_shift($key, 11);
|
|
||||||
if (strlen($key) <= 4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
extract(unpack('Nlength', self::_string_shift($key, 4)));
|
|
||||||
if (strlen($key) <= $length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$publicExponent = new BigInteger(self::_string_shift($key, $length), -256);
|
|
||||||
if (strlen($key) <= 4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
extract(unpack('Nlength', self::_string_shift($key, 4)));
|
|
||||||
if (strlen($key) != $length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$modulus = new BigInteger(self::_string_shift($key, $length), -256);
|
|
||||||
|
|
||||||
return array(
|
|
||||||
'isPublicKey' => true,
|
|
||||||
'modulus' => $modulus,
|
|
||||||
'publicExponent' => $publicExponent,
|
|
||||||
'comment' => $comment
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a public key to the appropriate format
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function savePublicKey(BigInteger $n, BigInteger $e)
|
|
||||||
{
|
|
||||||
$publicExponent = $e->toBytes(true);
|
|
||||||
$modulus = $n->toBytes(true);
|
|
||||||
|
|
||||||
// from <http://tools.ietf.org/html/rfc4253#page-15>:
|
|
||||||
// string "ssh-rsa"
|
|
||||||
// mpint e
|
|
||||||
// mpint n
|
|
||||||
$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
|
|
||||||
$RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . self::$comment;
|
|
||||||
|
|
||||||
return $RSAPublicKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* String Shift
|
|
||||||
*
|
|
||||||
* Inspired by array_shift
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @param int $index
|
|
||||||
* @return string
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
static function _string_shift(&$string, $index = 1)
|
|
||||||
{
|
|
||||||
$substr = substr($string, 0, $index);
|
|
||||||
$string = substr($string, $index);
|
|
||||||
return $substr;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,485 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* PKCS Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* @category Crypt
|
|
||||||
* @package RSA
|
|
||||||
* @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 phpseclib\Crypt\RSA;
|
|
||||||
|
|
||||||
use phpseclib\Crypt\AES;
|
|
||||||
use phpseclib\Crypt\Base;
|
|
||||||
use phpseclib\Crypt\DES;
|
|
||||||
use phpseclib\Crypt\TripleDES;
|
|
||||||
use phpseclib\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PKCS Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* @package RSA
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
abstract class PKCS
|
|
||||||
{
|
|
||||||
/**#@+
|
|
||||||
* @access private
|
|
||||||
* @see \phpseclib\Crypt\RSA::createKey()
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* ASN1 Integer
|
|
||||||
*/
|
|
||||||
const ASN1_INTEGER = 2;
|
|
||||||
/**
|
|
||||||
* ASN1 Bit String
|
|
||||||
*/
|
|
||||||
const ASN1_BITSTRING = 3;
|
|
||||||
/**
|
|
||||||
* ASN1 Octet String
|
|
||||||
*/
|
|
||||||
const ASN1_OCTETSTRING = 4;
|
|
||||||
/**
|
|
||||||
* ASN1 Object Identifier
|
|
||||||
*/
|
|
||||||
const ASN1_OBJECT = 6;
|
|
||||||
/**
|
|
||||||
* ASN1 Sequence (with the constucted bit set)
|
|
||||||
*/
|
|
||||||
const ASN1_SEQUENCE = 48;
|
|
||||||
/**#@-*/
|
|
||||||
|
|
||||||
/**#@+
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Auto-detect the format
|
|
||||||
*/
|
|
||||||
const MODE_ANY = 0;
|
|
||||||
/**
|
|
||||||
* Require base64-encoded PEM's be supplied
|
|
||||||
*/
|
|
||||||
const MODE_PEM = 1;
|
|
||||||
/**
|
|
||||||
* Require raw DER's be supplied
|
|
||||||
*/
|
|
||||||
const MODE_DER = 2;
|
|
||||||
/**#@-*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is the key a base-64 encoded PEM, DER or should it be auto-detected?
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param int
|
|
||||||
*/
|
|
||||||
static $format = self::MODE_ANY;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the mode constant corresponding to the mode string
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $mode
|
|
||||||
* @return int
|
|
||||||
* @throws \UnexpectedValueException if the block cipher mode is unsupported
|
|
||||||
*/
|
|
||||||
static function getEncryptionMode($mode)
|
|
||||||
{
|
|
||||||
switch ($mode) {
|
|
||||||
case 'CBC':
|
|
||||||
return Base::MODE_CBC;
|
|
||||||
case 'ECB':
|
|
||||||
return Base::MODE_ECB;
|
|
||||||
case 'CFB':
|
|
||||||
return Base::MODE_CFB;
|
|
||||||
case 'OFB':
|
|
||||||
return Base::MODE_OFB;
|
|
||||||
case 'CTR':
|
|
||||||
return Base::MODE_CTR;
|
|
||||||
}
|
|
||||||
throw new \UnexpectedValueException('Unsupported block cipher mode of operation');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a cipher object corresponding to a string
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $algo
|
|
||||||
* @return string
|
|
||||||
* @throws \UnexpectedValueException if the encryption algorithm is unsupported
|
|
||||||
*/
|
|
||||||
static function getEncryptionObject($algo)
|
|
||||||
{
|
|
||||||
$modes = '(CBC|ECB|CFB|OFB|CTR)';
|
|
||||||
switch (true) {
|
|
||||||
case preg_match("#^AES-(128|192|256)-$modes$#", $algo, $matches):
|
|
||||||
$cipher = new AES(self::getEncryptionMode($matches[2]));
|
|
||||||
$cipher->setKeyLength($matches[1]);
|
|
||||||
return $cipher;
|
|
||||||
case preg_match("#^DES-EDE3-$modes$#", $algo, $matches):
|
|
||||||
return new TripleDES(self::getEncryptionMode($matches[1]));
|
|
||||||
case preg_match("#^DES-$modes$#", $algo, $matches):
|
|
||||||
return new DES(self::getEncryptionMode($matches[1]));
|
|
||||||
default:
|
|
||||||
throw new \UnexpectedValueException('Unsupported encryption algorithmn');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a symmetric key for PKCS#1 keys
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $password
|
|
||||||
* @param string $iv
|
|
||||||
* @param int $length
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function generateSymmetricKey($password, $iv, $length)
|
|
||||||
{
|
|
||||||
$symkey = '';
|
|
||||||
$iv = substr($iv, 0, 8);
|
|
||||||
while (strlen($symkey) < $length) {
|
|
||||||
$symkey.= pack('H*', md5($symkey . $password . $iv));
|
|
||||||
}
|
|
||||||
return substr($symkey, 0, $length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Break a public or private key down into its constituent components
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $key
|
|
||||||
* @param string $password optional
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static function load($key, $password = '')
|
|
||||||
{
|
|
||||||
if (!is_string($key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$components = array('isPublicKey' => strpos($key, 'PUBLIC') !== false);
|
|
||||||
|
|
||||||
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
|
|
||||||
"outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
|
|
||||||
protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
|
|
||||||
two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
|
|
||||||
|
|
||||||
http://tools.ietf.org/html/rfc1421#section-4.6.1.1
|
|
||||||
http://tools.ietf.org/html/rfc1421#section-4.6.1.3
|
|
||||||
|
|
||||||
DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
|
|
||||||
DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
|
|
||||||
function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
|
|
||||||
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
|
|
||||||
implementation are part of the standard, as well.
|
|
||||||
|
|
||||||
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
|
|
||||||
if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
|
|
||||||
$iv = pack('H*', trim($matches[2]));
|
|
||||||
// remove the Proc-Type / DEK-Info sections as they're no longer needed
|
|
||||||
$key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
|
|
||||||
$ciphertext = self::_extractBER($key);
|
|
||||||
if ($ciphertext === false) {
|
|
||||||
$ciphertext = $key;
|
|
||||||
}
|
|
||||||
$crypto = self::getEncryptionObject($matches[1]);
|
|
||||||
$crypto->setKey(self::generateSymmetricKey($password, $iv, $crypto->getKeyLength() >> 3));
|
|
||||||
$crypto->setIV($iv);
|
|
||||||
$key = $crypto->decrypt($ciphertext);
|
|
||||||
if ($key === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (self::$format != self::MODE_DER) {
|
|
||||||
$decoded = self::_extractBER($key);
|
|
||||||
if ($decoded !== false) {
|
|
||||||
$key = $decoded;
|
|
||||||
} elseif (self::$format == self::MODE_PEM) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (self::_decodeLength($key) != strlen($key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$tag = ord(self::_string_shift($key));
|
|
||||||
/* intended for keys for which OpenSSL's asn1parse returns the following:
|
|
||||||
|
|
||||||
0:d=0 hl=4 l= 631 cons: SEQUENCE
|
|
||||||
4:d=1 hl=2 l= 1 prim: INTEGER :00
|
|
||||||
7:d=1 hl=2 l= 13 cons: SEQUENCE
|
|
||||||
9:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
|
||||||
20:d=2 hl=2 l= 0 prim: NULL
|
|
||||||
22:d=1 hl=4 l= 609 prim: OCTET STRING
|
|
||||||
|
|
||||||
ie. PKCS8 keys */
|
|
||||||
|
|
||||||
if ($tag == self::ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
|
|
||||||
self::_string_shift($key, 3);
|
|
||||||
$tag = self::ASN1_SEQUENCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($tag == self::ASN1_SEQUENCE) {
|
|
||||||
$temp = self::_string_shift($key, self::_decodeLength($key));
|
|
||||||
if (ord(self::_string_shift($temp)) != self::ASN1_OBJECT) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$length = self::_decodeLength($temp);
|
|
||||||
switch (self::_string_shift($temp, $length)) {
|
|
||||||
case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01": // rsaEncryption
|
|
||||||
break;
|
|
||||||
case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03": // pbeWithMD5AndDES-CBC
|
|
||||||
/*
|
|
||||||
PBEParameter ::= SEQUENCE {
|
|
||||||
salt OCTET STRING (SIZE(8)),
|
|
||||||
iterationCount INTEGER }
|
|
||||||
*/
|
|
||||||
if (ord(self::_string_shift($temp)) != self::ASN1_SEQUENCE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (self::_decodeLength($temp) != strlen($temp)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self::_string_shift($temp); // assume it's an octet string
|
|
||||||
$salt = self::_string_shift($temp, self::_decodeLength($temp));
|
|
||||||
if (ord(self::_string_shift($temp)) != self::ASN1_INTEGER) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self::_decodeLength($temp);
|
|
||||||
list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
|
|
||||||
self::_string_shift($key); // assume it's an octet string
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
if (strlen($key) != $length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$crypto = new DES(DES::MODE_CBC);
|
|
||||||
$crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount);
|
|
||||||
$key = $crypto->decrypt($key);
|
|
||||||
if ($key === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return self::load($key);
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/* intended for keys for which OpenSSL's asn1parse returns the following:
|
|
||||||
|
|
||||||
0:d=0 hl=4 l= 290 cons: SEQUENCE
|
|
||||||
4:d=1 hl=2 l= 13 cons: SEQUENCE
|
|
||||||
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
|
||||||
17:d=2 hl=2 l= 0 prim: NULL
|
|
||||||
19:d=1 hl=4 l= 271 prim: BIT STRING */
|
|
||||||
$tag = ord(self::_string_shift($key)); // skip over the BIT STRING / OCTET STRING tag
|
|
||||||
self::_decodeLength($key); // skip over the BIT STRING / OCTET STRING length
|
|
||||||
// "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
|
|
||||||
// unused bits in the final subsequent octet. The number shall be in the range zero to seven."
|
|
||||||
// -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
|
|
||||||
if ($tag == self::ASN1_BITSTRING) {
|
|
||||||
self::_string_shift($key);
|
|
||||||
}
|
|
||||||
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (self::_decodeLength($key) != strlen($key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$tag = ord(self::_string_shift($key));
|
|
||||||
}
|
|
||||||
if ($tag != self::ASN1_INTEGER) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$temp = self::_string_shift($key, $length);
|
|
||||||
if (strlen($temp) != 1 || ord($temp) > 2) {
|
|
||||||
$components['modulus'] = new BigInteger($temp, 256);
|
|
||||||
self::_string_shift($key); // skip over self::ASN1_INTEGER
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
|
|
||||||
|
|
||||||
return $components;
|
|
||||||
}
|
|
||||||
if (ord(self::_string_shift($key)) != self::ASN1_INTEGER) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['modulus'] = new BigInteger(self::_string_shift($key, $length), 256);
|
|
||||||
self::_string_shift($key);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['publicExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
|
|
||||||
self::_string_shift($key);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['privateExponent'] = new BigInteger(self::_string_shift($key, $length), 256);
|
|
||||||
self::_string_shift($key);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['primes'] = array(1 => new BigInteger(self::_string_shift($key, $length), 256));
|
|
||||||
self::_string_shift($key);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['primes'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
|
||||||
self::_string_shift($key);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['exponents'] = array(1 => new BigInteger(self::_string_shift($key, $length), 256));
|
|
||||||
self::_string_shift($key);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['exponents'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
|
||||||
self::_string_shift($key);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['coefficients'] = array(2 => new BigInteger(self::_string_shift($key, $length), 256));
|
|
||||||
|
|
||||||
if (!empty($key)) {
|
|
||||||
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self::_decodeLength($key);
|
|
||||||
while (!empty($key)) {
|
|
||||||
if (ord(self::_string_shift($key)) != self::ASN1_SEQUENCE) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self::_decodeLength($key);
|
|
||||||
$key = substr($key, 1);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['primes'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
|
||||||
self::_string_shift($key);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['exponents'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
|
||||||
self::_string_shift($key);
|
|
||||||
$length = self::_decodeLength($key);
|
|
||||||
$components['coefficients'][] = new BigInteger(self::_string_shift($key, $length), 256);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $components;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require base64-encoded PEM's be supplied
|
|
||||||
*
|
|
||||||
* @see self::load()
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
static function requirePEM()
|
|
||||||
{
|
|
||||||
self::$format = self::MODE_PEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Require raw DER's be supplied
|
|
||||||
*
|
|
||||||
* @see self::load()
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
static function requireDER()
|
|
||||||
{
|
|
||||||
self::$format = self::MODE_DER;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accept any format and auto detect the format
|
|
||||||
*
|
|
||||||
* This is the default setting
|
|
||||||
*
|
|
||||||
* @see self::load()
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
static function requireAny()
|
|
||||||
{
|
|
||||||
self::$format = self::MODE_ANY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DER-decode the length
|
|
||||||
*
|
|
||||||
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
|
|
||||||
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param string $string
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
static function _decodeLength(&$string)
|
|
||||||
{
|
|
||||||
$length = ord(self::_string_shift($string));
|
|
||||||
if ($length & 0x80) { // definite length, long form
|
|
||||||
$length&= 0x7F;
|
|
||||||
$temp = self::_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
|
|
||||||
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 paragraph 8.1.3} for more information.
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param int $length
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static 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
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @param int $index
|
|
||||||
* @return string
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
static function _string_shift(&$string, $index = 1)
|
|
||||||
{
|
|
||||||
$substr = substr($string, 0, $index);
|
|
||||||
$string = substr($string, $index);
|
|
||||||
return $substr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract raw BER from Base64 encoding
|
|
||||||
*
|
|
||||||
* @access private
|
|
||||||
* @param string $str
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function _extractBER($str)
|
|
||||||
{
|
|
||||||
/* X.509 certs are assumed to be base64 encoded but sometimes they'll have additional things in them
|
|
||||||
* above and beyond the ceritificate.
|
|
||||||
* ie. some may have the following preceding the -----BEGIN CERTIFICATE----- line:
|
|
||||||
*
|
|
||||||
* Bag Attributes
|
|
||||||
* localKeyID: 01 00 00 00
|
|
||||||
* subject=/O=organization/OU=org unit/CN=common name
|
|
||||||
* issuer=/O=organization/CN=common name
|
|
||||||
*/
|
|
||||||
$temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
|
|
||||||
// remove the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- stuff
|
|
||||||
$temp = preg_replace('#-+[^-]+-+#', '', $temp);
|
|
||||||
// remove new lines
|
|
||||||
$temp = str_replace(array("\r", "\n", ' '), '', $temp);
|
|
||||||
$temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
|
|
||||||
return $temp != false ? $temp : $str;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,172 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* PKCS#1 Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* Used by File/X509.php
|
|
||||||
*
|
|
||||||
* Has the following header:
|
|
||||||
*
|
|
||||||
* -----BEGIN RSA PUBLIC KEY-----
|
|
||||||
*
|
|
||||||
* Analogous to ssh-keygen's pem format (as specified by -m)
|
|
||||||
*
|
|
||||||
* @category Crypt
|
|
||||||
* @package RSA
|
|
||||||
* @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 phpseclib\Crypt\RSA;
|
|
||||||
|
|
||||||
use phpseclib\Crypt\AES;
|
|
||||||
use phpseclib\Crypt\DES;
|
|
||||||
use phpseclib\Crypt\Random;
|
|
||||||
use phpseclib\Crypt\TripleDES;
|
|
||||||
use phpseclib\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PKCS#1 Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* @package RSA
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
class PKCS1 extends PKCS
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Default encryption algorithm
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
static $defaultEncryptionAlgorithm = 'DES-EDE3-CBC';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default encryption algorithm
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $algo
|
|
||||||
*/
|
|
||||||
static function setEncryptionAlgorithm($algo)
|
|
||||||
{
|
|
||||||
self::$defaultEncryptionAlgorithm = $algo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a private key to the appropriate format.
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @param \phpseclib\Math\BigInteger $d
|
|
||||||
* @param array $primes
|
|
||||||
* @param array $exponents
|
|
||||||
* @param array $coefficients
|
|
||||||
* @param string $password optional
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
|
||||||
{
|
|
||||||
$num_primes = count($primes);
|
|
||||||
$raw = array(
|
|
||||||
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
|
||||||
'modulus' => $n->toBytes(true),
|
|
||||||
'publicExponent' => $e->toBytes(true),
|
|
||||||
'privateExponent' => $d->toBytes(true),
|
|
||||||
'prime1' => $primes[1]->toBytes(true),
|
|
||||||
'prime2' => $primes[2]->toBytes(true),
|
|
||||||
'exponent1' => $exponents[1]->toBytes(true),
|
|
||||||
'exponent2' => $exponents[2]->toBytes(true),
|
|
||||||
'coefficient' => $coefficients[2]->toBytes(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
$components = array();
|
|
||||||
foreach ($raw as $name => $value) {
|
|
||||||
$components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($value)), $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
$RSAPrivateKey = implode('', $components);
|
|
||||||
|
|
||||||
if ($num_primes > 2) {
|
|
||||||
$OtherPrimeInfos = '';
|
|
||||||
for ($i = 3; $i <= $num_primes; $i++) {
|
|
||||||
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
|
|
||||||
//
|
|
||||||
// OtherPrimeInfo ::= SEQUENCE {
|
|
||||||
// prime INTEGER, -- ri
|
|
||||||
// exponent INTEGER, -- di
|
|
||||||
// coefficient INTEGER -- ti
|
|
||||||
// }
|
|
||||||
$OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
|
|
||||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
|
|
||||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
|
|
||||||
$OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
|
|
||||||
}
|
|
||||||
$RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
|
|
||||||
}
|
|
||||||
|
|
||||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
|
||||||
|
|
||||||
if (!empty($password) || is_string($password)) {
|
|
||||||
$cipher = self::getEncryptionObject(self::$defaultEncryptionAlgorithm);
|
|
||||||
$iv = Random::string($cipher->getBlockLength() >> 3);
|
|
||||||
$cipher->setKey(self::generateSymmetricKey($password, $iv, $cipher->getKeyLength() >> 3));
|
|
||||||
$cipher->setIV($iv);
|
|
||||||
$iv = strtoupper(bin2hex($iv));
|
|
||||||
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
|
||||||
"Proc-Type: 4,ENCRYPTED\r\n" .
|
|
||||||
"DEK-Info: " . self::$defaultEncryptionAlgorithm . ",$iv\r\n" .
|
|
||||||
"\r\n" .
|
|
||||||
chunk_split(base64_encode($cipher->encrypt($RSAPrivateKey)), 64) .
|
|
||||||
'-----END RSA PRIVATE KEY-----';
|
|
||||||
} else {
|
|
||||||
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
|
||||||
chunk_split(base64_encode($RSAPrivateKey), 64) .
|
|
||||||
'-----END RSA PRIVATE KEY-----';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $RSAPrivateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a public key to the appropriate format
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
|
||||||
{
|
|
||||||
$modulus = $n->toBytes(true);
|
|
||||||
$publicExponent = $e->toBytes(true);
|
|
||||||
|
|
||||||
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
|
|
||||||
// RSAPublicKey ::= SEQUENCE {
|
|
||||||
// modulus INTEGER, -- n
|
|
||||||
// publicExponent INTEGER -- e
|
|
||||||
// }
|
|
||||||
$components = array(
|
|
||||||
'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus),
|
|
||||||
'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)
|
|
||||||
);
|
|
||||||
|
|
||||||
$RSAPublicKey = pack(
|
|
||||||
'Ca*a*a*',
|
|
||||||
self::ASN1_SEQUENCE,
|
|
||||||
self::_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
|
||||||
$components['modulus'],
|
|
||||||
$components['publicExponent']
|
|
||||||
);
|
|
||||||
|
|
||||||
$RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
|
|
||||||
chunk_split(base64_encode($RSAPublicKey), 64) .
|
|
||||||
'-----END RSA PUBLIC KEY-----';
|
|
||||||
|
|
||||||
return $RSAPublicKey;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,208 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* PKCS#8 Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
|
|
||||||
*
|
|
||||||
* Has the following header:
|
|
||||||
*
|
|
||||||
* -----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)
|
|
||||||
*
|
|
||||||
* @category Crypt
|
|
||||||
* @package RSA
|
|
||||||
* @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 phpseclib\Crypt\RSA;
|
|
||||||
|
|
||||||
use phpseclib\Crypt\DES;
|
|
||||||
use phpseclib\Crypt\Random;
|
|
||||||
use phpseclib\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PKCS#8 Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* @package RSA
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
class PKCS8 extends PKCS
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Convert a private key to the appropriate format.
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @param \phpseclib\Math\BigInteger $d
|
|
||||||
* @param array $primes
|
|
||||||
* @param array $exponents
|
|
||||||
* @param array $coefficients
|
|
||||||
* @param string $password optional
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
|
||||||
{
|
|
||||||
$num_primes = count($primes);
|
|
||||||
$raw = array(
|
|
||||||
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
|
||||||
'modulus' => $n->toBytes(true),
|
|
||||||
'publicExponent' => $e->toBytes(true),
|
|
||||||
'privateExponent' => $d->toBytes(true),
|
|
||||||
'prime1' => $primes[1]->toBytes(true),
|
|
||||||
'prime2' => $primes[2]->toBytes(true),
|
|
||||||
'exponent1' => $exponents[1]->toBytes(true),
|
|
||||||
'exponent2' => $exponents[2]->toBytes(true),
|
|
||||||
'coefficient' => $coefficients[2]->toBytes(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
$components = array();
|
|
||||||
foreach ($raw as $name => $value) {
|
|
||||||
$components[$name] = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($value)), $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
$RSAPrivateKey = implode('', $components);
|
|
||||||
|
|
||||||
if ($num_primes > 2) {
|
|
||||||
$OtherPrimeInfos = '';
|
|
||||||
for ($i = 3; $i <= $num_primes; $i++) {
|
|
||||||
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
|
|
||||||
//
|
|
||||||
// OtherPrimeInfo ::= SEQUENCE {
|
|
||||||
// prime INTEGER, -- ri
|
|
||||||
// exponent INTEGER, -- di
|
|
||||||
// coefficient INTEGER -- ti
|
|
||||||
// }
|
|
||||||
$OtherPrimeInfo = pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
|
|
||||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
|
|
||||||
$OtherPrimeInfo.= pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
|
|
||||||
$OtherPrimeInfos.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
|
|
||||||
}
|
|
||||||
$RSAPrivateKey.= pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
|
|
||||||
}
|
|
||||||
|
|
||||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
|
||||||
|
|
||||||
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
|
|
||||||
$RSAPrivateKey = pack(
|
|
||||||
'Ca*a*Ca*a*',
|
|
||||||
self::ASN1_INTEGER,
|
|
||||||
"\01\00",
|
|
||||||
$rsaOID,
|
|
||||||
4,
|
|
||||||
self::_encodeLength(strlen($RSAPrivateKey)),
|
|
||||||
$RSAPrivateKey
|
|
||||||
);
|
|
||||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
|
||||||
if (!empty($password) || is_string($password)) {
|
|
||||||
$salt = Random::string(8);
|
|
||||||
$iterationCount = 2048;
|
|
||||||
|
|
||||||
$crypto = new DES(DES::MODE_CBC);
|
|
||||||
$crypto->setPassword($password, 'pbkdf1', 'md5', $salt, $iterationCount);
|
|
||||||
$RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
|
|
||||||
|
|
||||||
$parameters = pack(
|
|
||||||
'Ca*a*Ca*N',
|
|
||||||
self::ASN1_OCTETSTRING,
|
|
||||||
self::_encodeLength(strlen($salt)),
|
|
||||||
$salt,
|
|
||||||
self::ASN1_INTEGER,
|
|
||||||
self::_encodeLength(4),
|
|
||||||
$iterationCount
|
|
||||||
);
|
|
||||||
$pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
|
|
||||||
|
|
||||||
$encryptionAlgorithm = pack(
|
|
||||||
'Ca*a*Ca*a*',
|
|
||||||
self::ASN1_OBJECT,
|
|
||||||
self::_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
|
|
||||||
$pbeWithMD5AndDES_CBC,
|
|
||||||
self::ASN1_SEQUENCE,
|
|
||||||
self::_encodeLength(strlen($parameters)),
|
|
||||||
$parameters
|
|
||||||
);
|
|
||||||
|
|
||||||
$RSAPrivateKey = pack(
|
|
||||||
'Ca*a*Ca*a*',
|
|
||||||
self::ASN1_SEQUENCE,
|
|
||||||
self::_encodeLength(strlen($encryptionAlgorithm)),
|
|
||||||
$encryptionAlgorithm,
|
|
||||||
self::ASN1_OCTETSTRING,
|
|
||||||
self::_encodeLength(strlen($RSAPrivateKey)),
|
|
||||||
$RSAPrivateKey
|
|
||||||
);
|
|
||||||
|
|
||||||
$RSAPrivateKey = pack('Ca*a*', self::ASN1_SEQUENCE, self::_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
|
||||||
|
|
||||||
$RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
|
|
||||||
chunk_split(base64_encode($RSAPrivateKey), 64) .
|
|
||||||
'-----END ENCRYPTED PRIVATE KEY-----';
|
|
||||||
} else {
|
|
||||||
$RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
|
|
||||||
chunk_split(base64_encode($RSAPrivateKey), 64) .
|
|
||||||
'-----END PRIVATE KEY-----';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $RSAPrivateKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a public key to the appropriate format
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
|
||||||
{
|
|
||||||
$modulus = $n->toBytes(true);
|
|
||||||
$publicExponent = $e->toBytes(true);
|
|
||||||
|
|
||||||
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
|
|
||||||
// RSAPublicKey ::= SEQUENCE {
|
|
||||||
// modulus INTEGER, -- n
|
|
||||||
// publicExponent INTEGER -- e
|
|
||||||
// }
|
|
||||||
$components = array(
|
|
||||||
'modulus' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($modulus)), $modulus),
|
|
||||||
'publicExponent' => pack('Ca*a*', self::ASN1_INTEGER, self::_encodeLength(strlen($publicExponent)), $publicExponent)
|
|
||||||
);
|
|
||||||
|
|
||||||
$RSAPublicKey = pack(
|
|
||||||
'Ca*a*a*',
|
|
||||||
self::ASN1_SEQUENCE,
|
|
||||||
self::_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
|
||||||
$components['modulus'],
|
|
||||||
$components['publicExponent']
|
|
||||||
);
|
|
||||||
|
|
||||||
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
|
|
||||||
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
|
|
||||||
$RSAPublicKey = chr(0) . $RSAPublicKey;
|
|
||||||
$RSAPublicKey = chr(3) . self::_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
|
|
||||||
|
|
||||||
$RSAPublicKey = pack(
|
|
||||||
'Ca*a*',
|
|
||||||
self::ASN1_SEQUENCE,
|
|
||||||
self::_encodeLength(strlen($rsaOID . $RSAPublicKey)),
|
|
||||||
$rsaOID . $RSAPublicKey
|
|
||||||
);
|
|
||||||
|
|
||||||
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
|
|
||||||
chunk_split(base64_encode($RSAPublicKey), 64) .
|
|
||||||
'-----END PUBLIC KEY-----';
|
|
||||||
|
|
||||||
return $RSAPublicKey;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,311 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* PuTTY Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* @category Crypt
|
|
||||||
* @package RSA
|
|
||||||
* @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 phpseclib\Crypt\RSA;
|
|
||||||
|
|
||||||
use phpseclib\Crypt\AES;
|
|
||||||
use phpseclib\Crypt\Hash;
|
|
||||||
use phpseclib\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PuTTY Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* @package RSA
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
class PuTTY
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Default comment
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
static $comment = 'phpseclib-generated-key';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the default comment
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $comment
|
|
||||||
*/
|
|
||||||
static function setComment($comment)
|
|
||||||
{
|
|
||||||
self::$comment = str_replace(array("\r", "\n"), '', $comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a symmetric key for PuTTY keys
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $password
|
|
||||||
* @param string $iv
|
|
||||||
* @param int $length
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function generateSymmetricKey($password, $length)
|
|
||||||
{
|
|
||||||
$symkey = '';
|
|
||||||
$sequence = 0;
|
|
||||||
while (strlen($symkey) < $length) {
|
|
||||||
$temp = pack('Na*', $sequence++, $password);
|
|
||||||
$symkey.= pack('H*', sha1($temp));
|
|
||||||
}
|
|
||||||
return substr($symkey, 0, $length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Break a public or private key down into its constituent components
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $key
|
|
||||||
* @param string $password optional
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static function load($key, $password = '')
|
|
||||||
{
|
|
||||||
if (!is_string($key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static $one;
|
|
||||||
if (!isset($one)) {
|
|
||||||
$one = new BigInteger(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($key, 'BEGIN SSH2 PUBLIC KEY')) {
|
|
||||||
$data = preg_split('#[\r\n]+#', $key);
|
|
||||||
$data = array_splice($data, 2, -1);
|
|
||||||
$data = implode('', $data);
|
|
||||||
|
|
||||||
$components = OpenSSH::load($data);
|
|
||||||
if ($components === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!preg_match('#Comment: "(.+)"#', $key, $matches)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$components['comment'] = str_replace(array('\\\\', '\"'), array('\\', '"'), $matches[1]);
|
|
||||||
|
|
||||||
return $components;
|
|
||||||
}
|
|
||||||
|
|
||||||
$components = array('isPublicKey' => false);
|
|
||||||
$key = preg_split('#\r\n|\r|\n#', $key);
|
|
||||||
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
|
|
||||||
if ($type != 'ssh-rsa') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
|
|
||||||
$components['comment'] = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
|
|
||||||
|
|
||||||
$publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
|
|
||||||
$public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
|
|
||||||
$public = substr($public, 11);
|
|
||||||
extract(unpack('Nlength', self::_string_shift($public, 4)));
|
|
||||||
$components['publicExponent'] = new BigInteger(self::_string_shift($public, $length), -256);
|
|
||||||
extract(unpack('Nlength', self::_string_shift($public, 4)));
|
|
||||||
$components['modulus'] = new BigInteger(self::_string_shift($public, $length), -256);
|
|
||||||
|
|
||||||
$privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
|
|
||||||
$private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
|
|
||||||
|
|
||||||
switch ($encryption) {
|
|
||||||
case 'aes256-cbc':
|
|
||||||
$symkey = static::generateSymmetricKey($password, 32);
|
|
||||||
$crypto = new AES(AES::MODE_CBC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($encryption != 'none') {
|
|
||||||
$crypto->setKey($symkey);
|
|
||||||
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
|
|
||||||
$crypto->disablePadding();
|
|
||||||
$private = $crypto->decrypt($private);
|
|
||||||
if ($private === false) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extract(unpack('Nlength', self::_string_shift($private, 4)));
|
|
||||||
if (strlen($private) < $length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$components['privateExponent'] = new BigInteger(self::_string_shift($private, $length), -256);
|
|
||||||
extract(unpack('Nlength', self::_string_shift($private, 4)));
|
|
||||||
if (strlen($private) < $length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$components['primes'] = array(1 => new BigInteger(self::_string_shift($private, $length), -256));
|
|
||||||
extract(unpack('Nlength', self::_string_shift($private, 4)));
|
|
||||||
if (strlen($private) < $length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$components['primes'][] = new BigInteger(self::_string_shift($private, $length), -256);
|
|
||||||
|
|
||||||
$temp = $components['primes'][1]->subtract($one);
|
|
||||||
$components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
|
|
||||||
$temp = $components['primes'][2]->subtract($one);
|
|
||||||
$components['exponents'][] = $components['publicExponent']->modInverse($temp);
|
|
||||||
|
|
||||||
extract(unpack('Nlength', self::_string_shift($private, 4)));
|
|
||||||
if (strlen($private) < $length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$components['coefficients'] = array(2 => new BigInteger(self::_string_shift($private, $length), -256));
|
|
||||||
|
|
||||||
return $components;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* String Shift
|
|
||||||
*
|
|
||||||
* Inspired by array_shift
|
|
||||||
*
|
|
||||||
* @param string $string
|
|
||||||
* @param int $index
|
|
||||||
* @return string
|
|
||||||
* @access private
|
|
||||||
*/
|
|
||||||
static function _string_shift(&$string, $index = 1)
|
|
||||||
{
|
|
||||||
$substr = substr($string, 0, $index);
|
|
||||||
$string = substr($string, $index);
|
|
||||||
return $substr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a private key to the appropriate format.
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @param \phpseclib\Math\BigInteger $d
|
|
||||||
* @param array $primes
|
|
||||||
* @param array $exponents
|
|
||||||
* @param array $coefficients
|
|
||||||
* @param string $password optional
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
|
||||||
{
|
|
||||||
if (count($primes) != 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$raw = array(
|
|
||||||
'modulus' => $n->toBytes(true),
|
|
||||||
'publicExponent' => $e->toBytes(true),
|
|
||||||
'privateExponent' => $d->toBytes(true),
|
|
||||||
'prime1' => $primes[1]->toBytes(true),
|
|
||||||
'prime2' => $primes[2]->toBytes(true),
|
|
||||||
'exponent1' => $exponents[1]->toBytes(true),
|
|
||||||
'exponent2' => $exponents[2]->toBytes(true),
|
|
||||||
'coefficient' => $coefficients[2]->toBytes(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
$key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
|
|
||||||
$encryption = (!empty($password) || is_string($password)) ? 'aes256-cbc' : 'none';
|
|
||||||
$key.= $encryption;
|
|
||||||
$key.= "\r\nComment: " . self::$comment . "\r\n";
|
|
||||||
$public = pack(
|
|
||||||
'Na*Na*Na*',
|
|
||||||
strlen('ssh-rsa'),
|
|
||||||
'ssh-rsa',
|
|
||||||
strlen($raw['publicExponent']),
|
|
||||||
$raw['publicExponent'],
|
|
||||||
strlen($raw['modulus']),
|
|
||||||
$raw['modulus']
|
|
||||||
);
|
|
||||||
$source = pack(
|
|
||||||
'Na*Na*Na*Na*',
|
|
||||||
strlen('ssh-rsa'),
|
|
||||||
'ssh-rsa',
|
|
||||||
strlen($encryption),
|
|
||||||
$encryption,
|
|
||||||
strlen(self::$comment),
|
|
||||||
self::$comment,
|
|
||||||
strlen($public),
|
|
||||||
$public
|
|
||||||
);
|
|
||||||
$public = base64_encode($public);
|
|
||||||
$key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
|
|
||||||
$key.= chunk_split($public, 64);
|
|
||||||
$private = pack(
|
|
||||||
'Na*Na*Na*Na*',
|
|
||||||
strlen($raw['privateExponent']),
|
|
||||||
$raw['privateExponent'],
|
|
||||||
strlen($raw['prime1']),
|
|
||||||
$raw['prime1'],
|
|
||||||
strlen($raw['prime2']),
|
|
||||||
$raw['prime2'],
|
|
||||||
strlen($raw['coefficient']),
|
|
||||||
$raw['coefficient']
|
|
||||||
);
|
|
||||||
if (empty($password) && !is_string($password)) {
|
|
||||||
$source.= pack('Na*', strlen($private), $private);
|
|
||||||
$hashkey = 'putty-private-key-file-mac-key';
|
|
||||||
} else {
|
|
||||||
$private.= Random::string(16 - (strlen($private) & 15));
|
|
||||||
$source.= pack('Na*', strlen($private), $private);
|
|
||||||
$crypto = new AES();
|
|
||||||
|
|
||||||
$crypto->setKey(static::generateSymmetricKey($password, 32));
|
|
||||||
$crypto->setIV(str_repeat("\0", $crypto->getBlockLength() >> 3));
|
|
||||||
$crypto->disablePadding();
|
|
||||||
$private = $crypto->encrypt($private);
|
|
||||||
$hashkey = 'putty-private-key-file-mac-key' . $password;
|
|
||||||
}
|
|
||||||
|
|
||||||
$private = base64_encode($private);
|
|
||||||
$key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
|
|
||||||
$key.= chunk_split($private, 64);
|
|
||||||
$hash = new Hash('sha1');
|
|
||||||
$hash->setKey(pack('H*', sha1($hashkey)));
|
|
||||||
$key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a public key to the appropriate format
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
|
||||||
{
|
|
||||||
$n = $n->toBytes(true);
|
|
||||||
$e = $e->toBytes(true);
|
|
||||||
|
|
||||||
$key = pack(
|
|
||||||
'Na*Na*Na*',
|
|
||||||
strlen('ssh-rsa'),
|
|
||||||
'ssh-rsa',
|
|
||||||
strlen($e),
|
|
||||||
$e,
|
|
||||||
strlen($n),
|
|
||||||
$n
|
|
||||||
);
|
|
||||||
$key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" .
|
|
||||||
'Comment: "' . str_replace(array('\\', '"'), array('\\\\', '\"'), self::$comment) . "\"\r\n";
|
|
||||||
chunk_split(base64_encode($key), 64) .
|
|
||||||
'---- END SSH2 PUBLIC KEY ----';
|
|
||||||
|
|
||||||
return $key;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,103 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* Raw RSA Key Handler
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* An array containing two \phpseclib\Math\BigInteger objects.
|
|
||||||
*
|
|
||||||
* The exponent can be indexed with any of the following:
|
|
||||||
*
|
|
||||||
* 0, e, exponent, publicExponent
|
|
||||||
*
|
|
||||||
* The modulus can be indexed with any of the following:
|
|
||||||
*
|
|
||||||
* 1, n, modulo, modulus
|
|
||||||
*
|
|
||||||
* @category Crypt
|
|
||||||
* @package RSA
|
|
||||||
* @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 phpseclib\Crypt\RSA;
|
|
||||||
|
|
||||||
use phpseclib\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Raw RSA Key Handler
|
|
||||||
*
|
|
||||||
* @package RSA
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
class Raw
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Break a public or private key down into its constituent components
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $key
|
|
||||||
* @param string $password optional
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static function load($key, $password = '')
|
|
||||||
{
|
|
||||||
if (!is_array($key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (isset($key['isPublicKey']) && isset($key['modulus'])) {
|
|
||||||
if (isset($key['privateExponent']) || isset($key['publicExponent'])) {
|
|
||||||
if (!isset($key['primes'])) {
|
|
||||||
return $key;
|
|
||||||
}
|
|
||||||
if (isset($key['exponents']) && isset($key['coefficients']) && isset($key['publicExponent']) && isset($key['privateExponent'])) {
|
|
||||||
return $key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$components = array('isPublicKey' => true);
|
|
||||||
switch (true) {
|
|
||||||
case isset($key['e']):
|
|
||||||
$components['publicExponent'] = $key['e'];
|
|
||||||
break;
|
|
||||||
case isset($key['exponent']):
|
|
||||||
$components['publicExponent'] = $key['exponent'];
|
|
||||||
break;
|
|
||||||
case isset($key['publicExponent']):
|
|
||||||
$components['publicExponent'] = $key['publicExponent'];
|
|
||||||
break;
|
|
||||||
case isset($key[0]):
|
|
||||||
$components['publicExponent'] = $key[0];
|
|
||||||
}
|
|
||||||
switch (true) {
|
|
||||||
case isset($key['n']):
|
|
||||||
$components['modulus'] = $key['n'];
|
|
||||||
break;
|
|
||||||
case isset($key['modulo']):
|
|
||||||
$components['modulus'] = $key['modulo'];
|
|
||||||
break;
|
|
||||||
case isset($key['modulus']):
|
|
||||||
$components['modulus'] = $key['modulus'];
|
|
||||||
break;
|
|
||||||
case isset($key[1]):
|
|
||||||
$components['modulus'] = $key[1];
|
|
||||||
}
|
|
||||||
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a public key to the appropriate format
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
|
||||||
{
|
|
||||||
return array('e' => clone $e, 'n' => clone $n);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,146 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* XML Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* More info:
|
|
||||||
*
|
|
||||||
* http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
|
|
||||||
* http://en.wikipedia.org/wiki/XML_Signature
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* @category Crypt
|
|
||||||
* @package RSA
|
|
||||||
* @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 phpseclib\Crypt\RSA;
|
|
||||||
|
|
||||||
use phpseclib\Math\BigInteger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XML Formatted RSA Key Handler
|
|
||||||
*
|
|
||||||
* @package RSA
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
* @access public
|
|
||||||
*/
|
|
||||||
class XML
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Break a public or private key down into its constituent components
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param string $key
|
|
||||||
* @param string $password optional
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
static function load($key, $password = '')
|
|
||||||
{
|
|
||||||
if (!is_string($key)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$components = array(
|
|
||||||
'isPublicKey' => false,
|
|
||||||
'primes' => array(),
|
|
||||||
'exponents' => array(),
|
|
||||||
'coefficients' => array()
|
|
||||||
);
|
|
||||||
|
|
||||||
$use_errors = libxml_use_internal_errors(true);
|
|
||||||
|
|
||||||
$dom = new \DOMDocument();
|
|
||||||
if (!$dom->loadXML('<xml>' . $key . '</xml>')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
$xpath = new \DOMXPath($dom);
|
|
||||||
$keys = array('modulus', 'exponent', 'p', 'q', 'dp', 'dq', 'inverseq', 'd');
|
|
||||||
foreach ($keys as $key) {
|
|
||||||
// $dom->getElementsByTagName($key) is case-sensitive
|
|
||||||
$temp = $xpath->query("//*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$key']");
|
|
||||||
if (!$temp->length) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$value = new BigInteger(base64_decode($temp->item(0)->nodeValue), 256);
|
|
||||||
switch ($key) {
|
|
||||||
case 'modulus':
|
|
||||||
$components['modulus'] = $value;
|
|
||||||
break;
|
|
||||||
case 'exponent':
|
|
||||||
$components['publicExponent'] = $value;
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
$components['primes'][1] = $value;
|
|
||||||
break;
|
|
||||||
case 'q':
|
|
||||||
$components['primes'][2] = $value;
|
|
||||||
break;
|
|
||||||
case 'dp':
|
|
||||||
$components['exponents'][1] = $value;
|
|
||||||
break;
|
|
||||||
case 'dq':
|
|
||||||
$components['exponents'][2] = $value;
|
|
||||||
break;
|
|
||||||
case 'inverseq':
|
|
||||||
$components['coefficients'][2] = $value;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
$components['privateExponent'] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
libxml_use_internal_errors($use_errors);
|
|
||||||
|
|
||||||
return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a private key to the appropriate format.
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @param \phpseclib\Math\BigInteger $d
|
|
||||||
* @param array $primes
|
|
||||||
* @param array $exponents
|
|
||||||
* @param array $coefficients
|
|
||||||
* @param string $password optional
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, $primes, $exponents, $coefficients, $password = '')
|
|
||||||
{
|
|
||||||
if (count($primes) != 2) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return "<RSAKeyValue>\r\n" .
|
|
||||||
' <Modulus>' . base64_encode($n->toBytes()) . "</Modulus>\r\n" .
|
|
||||||
' <Exponent>' . base64_encode($e->toBytes()) . "</Exponent>\r\n" .
|
|
||||||
' <P>' . base64_encode($primes[1]->toBytes()) . "</P>\r\n" .
|
|
||||||
' <Q>' . base64_encode($primes[2]->toBytes()) . "</Q>\r\n" .
|
|
||||||
' <DP>' . base64_encode($exponents[1]->toBytes()) . "</DP>\r\n" .
|
|
||||||
' <DQ>' . base64_encode($exponents[2]->toBytes()) . "</DQ>\r\n" .
|
|
||||||
' <InverseQ>' . base64_encode($coefficients[2]->toBytes()) . "</InverseQ>\r\n" .
|
|
||||||
' <D>' . base64_encode($d->toBytes()) . "</D>\r\n" .
|
|
||||||
'</RSAKeyValue>';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a public key to the appropriate format
|
|
||||||
*
|
|
||||||
* @access public
|
|
||||||
* @param \phpseclib\Math\BigInteger $n
|
|
||||||
* @param \phpseclib\Math\BigInteger $e
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
static function savePublicKey(BigInteger $n, BigInteger $e)
|
|
||||||
{
|
|
||||||
return "<RSAKeyValue>\r\n" .
|
|
||||||
' <Modulus>' . base64_encode($n->toBytes()) . "</Modulus>\r\n" .
|
|
||||||
' <Exponent>' . base64_encode($e->toBytes()) . "</Exponent>\r\n" .
|
|
||||||
'</RSAKeyValue>';
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BadConfigurationException
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* @category Exception
|
|
||||||
* @package BadConfigurationException
|
|
||||||
* @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 phpseclib\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* BadConfigurationException
|
|
||||||
*
|
|
||||||
* @package BadConfigurationException
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
*/
|
|
||||||
class BadConfigurationException extends \RuntimeException
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FileNotFoundException
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* @category Exception
|
|
||||||
* @package FileNotFoundException
|
|
||||||
* @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 phpseclib\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FileNotFoundException
|
|
||||||
*
|
|
||||||
* @package FileNotFoundException
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
*/
|
|
||||||
class FileNotFoundException extends \RuntimeException
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NoSupportedAlgorithmsException
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* @category Exception
|
|
||||||
* @package NoSupportedAlgorithmsException
|
|
||||||
* @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 phpseclib\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* NoSupportedAlgorithmsException
|
|
||||||
*
|
|
||||||
* @package NoSupportedAlgorithmsException
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
*/
|
|
||||||
class NoSupportedAlgorithmsException extends \RuntimeException
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UnsupportedAlgorithmException
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* @category Exception
|
|
||||||
* @package UnsupportedAlgorithmException
|
|
||||||
* @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 phpseclib\Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UnsupportedAlgorithmException
|
|
||||||
*
|
|
||||||
* @package UnsupportedAlgorithmException
|
|
||||||
* @author Jim Wigginton <terrafrost@php.net>
|
|
||||||
*/
|
|
||||||
class UnsupportedAlgorithmException extends \RuntimeException
|
|
||||||
{
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user