mirror of
https://github.com/phpseclib/phpseclib.git
synced 2025-02-03 20:38:29 +00:00
make RSA / DSA / ECDSA immutable and add support to SSH2 / X509
This commit is contained in:
parent
b09bc1883e
commit
cc32cd2e95
@ -15,11 +15,13 @@
|
||||
|
||||
namespace phpseclib\Crypt\Common;
|
||||
|
||||
use phpseclib\Exception\UnsupportedFormatException;
|
||||
use phpseclib\Exception\NoKeyLoadedException;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Crypt\Hash;
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use phpseclib\Exception\UnsupportedOperationException;
|
||||
use phpseclib\Exception\FileNotFoundException;
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\DSA;
|
||||
use phpseclib\Crypt\ECDSA;
|
||||
|
||||
/**
|
||||
* Base Class for all stream cipher classes
|
||||
@ -46,15 +48,36 @@ abstract class AsymmetricKey
|
||||
protected static $one;
|
||||
|
||||
/**
|
||||
* OpenSSL configuration file name.
|
||||
* Format of the loaded key
|
||||
*
|
||||
* Set to null to use system configuration file.
|
||||
*
|
||||
* @see self::createKey()
|
||||
* @var mixed
|
||||
* @access public
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected static $configFile;
|
||||
protected $format;
|
||||
|
||||
/**
|
||||
* Hash function
|
||||
*
|
||||
* @var \phpseclib\Crypt\Hash
|
||||
* @access private
|
||||
*/
|
||||
protected $hash;
|
||||
|
||||
/**
|
||||
* HMAC function
|
||||
*
|
||||
* @var \phpseclib\Crypt\Hash
|
||||
* @access private
|
||||
*/
|
||||
private $hmac;
|
||||
|
||||
/**
|
||||
* Enable Blinding?
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
protected static $enableBlinding = true;
|
||||
|
||||
/**
|
||||
* Supported plugins (lower case)
|
||||
@ -92,73 +115,6 @@ abstract class AsymmetricKey
|
||||
*/
|
||||
private static $signatureFileFormats = [];
|
||||
|
||||
/**
|
||||
* Password
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected $password = false;
|
||||
|
||||
/**
|
||||
* Loaded File Format
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected $format = false;
|
||||
|
||||
/**
|
||||
* Private Key Format
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected $privateKeyFormat = 'PKCS8';
|
||||
|
||||
/**
|
||||
* Public Key Format
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected $publicKeyFormat = 'PKCS8';
|
||||
|
||||
/**
|
||||
* Parameters Format
|
||||
*
|
||||
* No setParametersFormat method exists because PKCS1 is the only format that supports
|
||||
* parameters in both DSA and ECDSA (RSA doesn't have an analog)
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected $parametersFormat = 'PKCS1';
|
||||
|
||||
/**
|
||||
* Hash function
|
||||
*
|
||||
* @var \phpseclib\Crypt\Hash
|
||||
* @access private
|
||||
*/
|
||||
protected $hash;
|
||||
|
||||
/**
|
||||
* HMAC function
|
||||
*
|
||||
* @var \phpseclib\Crypt\Hash
|
||||
* @access private
|
||||
*/
|
||||
private $hmac;
|
||||
|
||||
/**
|
||||
* Hash manually set?
|
||||
*
|
||||
* @var bool
|
||||
* @access private
|
||||
*/
|
||||
protected $hashManuallySet = false;
|
||||
|
||||
/**
|
||||
* Available Engines
|
||||
*
|
||||
@ -169,10 +125,8 @@ abstract class AsymmetricKey
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function __construct()
|
||||
protected function __construct()
|
||||
{
|
||||
self::initialize_static_variables();
|
||||
|
||||
@ -180,51 +134,14 @@ abstract class AsymmetricKey
|
||||
$this->hmac = new Hash('sha256');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests engine validity
|
||||
*
|
||||
* @access public
|
||||
* @param int $val
|
||||
*/
|
||||
public static function useBestEngine()
|
||||
{
|
||||
static::$engines = [
|
||||
'PHP' => true,
|
||||
'OpenSSL' => extension_loaded('openssl') && file_exists(self::$configFile),
|
||||
// this test can be satisfied by either of the following:
|
||||
// http://php.net/manual/en/book.sodium.php
|
||||
// https://github.com/paragonie/sodium_compat
|
||||
'libsodium' => function_exists('sodium_crypto_sign_keypair')
|
||||
];
|
||||
|
||||
return static::$engines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag to use internal engine only (useful for unit testing)
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function useInternalEngine()
|
||||
{
|
||||
static::$engines = [
|
||||
'PHP' => true,
|
||||
'OpenSSL' => false,
|
||||
'libsodium' => false
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize static variables
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
protected static function initialize_static_variables()
|
||||
{
|
||||
if (!isset(self::$zero)) {
|
||||
self::$zero= new BigInteger(0);
|
||||
self::$one = new BigInteger(1);
|
||||
self::$configFile = __DIR__ . '/../../openssl.cnf';
|
||||
}
|
||||
|
||||
self::loadPlugins('Keys');
|
||||
@ -233,6 +150,70 @@ abstract class AsymmetricKey
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the key
|
||||
*
|
||||
* @param string $key
|
||||
* @param string $type
|
||||
* @param string $password
|
||||
* @return array|bool
|
||||
*/
|
||||
protected static function load($key, $type, $password)
|
||||
{
|
||||
self::initialize_static_variables();
|
||||
|
||||
$components = false;
|
||||
if ($type === false) {
|
||||
foreach (self::$plugins[static::ALGORITHM]['Keys'] as $format) {
|
||||
try {
|
||||
$components = $format::load($key, $password);
|
||||
} catch (\Exception $e) {
|
||||
$components = false;
|
||||
}
|
||||
if ($components !== false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$format = strtolower($type);
|
||||
if (isset(self::$plugins[static::ALGORITHM]['Keys'][$format])) {
|
||||
$format = self::$plugins[static::ALGORITHM]['Keys'][$format];
|
||||
$components = $format::load($key, $password);
|
||||
}
|
||||
}
|
||||
|
||||
if ($components === false) {
|
||||
throw new NoKeyLoadedException('Unable to read key');
|
||||
}
|
||||
|
||||
$components['format'] = $format;
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Plugin
|
||||
*
|
||||
* @access private
|
||||
* @param string $format
|
||||
* @param string $type
|
||||
* @param string $method optional
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function validatePlugin($format, $type, $method = NULL)
|
||||
{
|
||||
$type = strtolower($type);
|
||||
if (!isset(self::$plugins[static::ALGORITHM][$format][$type])) {
|
||||
throw new UnsupportedFormatException("$type is not a supported format");
|
||||
}
|
||||
$type = self::$plugins[static::ALGORITHM][$format][$type];
|
||||
if (isset($method) && !method_exists($type, $method)) {
|
||||
throw new UnsupportedFormatException("$type does not implement $method");
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Plugins
|
||||
*
|
||||
@ -259,118 +240,6 @@ abstract class AsymmetricKey
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Plugin
|
||||
*
|
||||
* @access private
|
||||
* @param string $format
|
||||
* @param string $type
|
||||
* @param string $method optional
|
||||
* @return mixed
|
||||
*/
|
||||
protected static function validatePlugin($format, $type, $method = NULL)
|
||||
{
|
||||
$type = strtolower($type);
|
||||
if (!isset(self::$plugins[static::ALGORITHM][$format][$type])) {
|
||||
return false;
|
||||
}
|
||||
$type = self::$plugins[static::ALGORITHM][$format][$type];
|
||||
if (isset($method) && !method_exists($type, $method)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the key
|
||||
*
|
||||
* @access private
|
||||
* @param string $key
|
||||
* @param string $type
|
||||
* @return array|bool
|
||||
*/
|
||||
protected function load($key, $type)
|
||||
{
|
||||
if ($key instanceof self) {
|
||||
$this->hmac = $key->hmac;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$components = false;
|
||||
if ($type === false) {
|
||||
foreach (self::$plugins[static::ALGORITHM]['Keys'] as $format) {
|
||||
try {
|
||||
$components = $format::load($key, $this->password);
|
||||
} catch (\Exception $e) {
|
||||
$components = false;
|
||||
}
|
||||
if ($components !== false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$format = strtolower($type);
|
||||
if (isset(self::$plugins[static::ALGORITHM]['Keys'][$format])) {
|
||||
$format = self::$plugins[static::ALGORITHM]['Keys'][$format];
|
||||
$components = $format::load($key, $this->password);
|
||||
}
|
||||
}
|
||||
|
||||
if ($components === false) {
|
||||
$this->format = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->format = $format;
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the public key
|
||||
*
|
||||
* @access private
|
||||
* @param string $key
|
||||
* @param string $type
|
||||
* @return array
|
||||
*/
|
||||
protected function setPublicKey($key, $type)
|
||||
{
|
||||
$components = false;
|
||||
if ($type === false) {
|
||||
foreach (self::$plugins[static::ALGORITHM]['Keys'] as $format) {
|
||||
if (!method_exists($format, 'savePublicKey')) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$components = $format::load($key, $this->password);
|
||||
} catch (\Exception $e) {
|
||||
$components = false;
|
||||
}
|
||||
if ($components !== false) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$format = strtolower($type);
|
||||
if (isset(self::$plugins[static::ALGORITHM]['Keys'][$format])) {
|
||||
$format = self::$plugins[static::ALGORITHM]['Keys'][$format];
|
||||
$components = $format::load($key, $this->password);
|
||||
}
|
||||
}
|
||||
|
||||
if ($components === false) {
|
||||
$this->format = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->format = $format;
|
||||
|
||||
return $components;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of supported formats.
|
||||
*
|
||||
@ -407,161 +276,6 @@ abstract class AsymmetricKey
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
|
||||
* for invalid values.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublicKeyFingerprint($algorithm = 'md5')
|
||||
{
|
||||
$type = self::validatePlugin('Keys', 'OpenSSH', 'getBinaryOutput');
|
||||
if ($type === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$status = $type::getBinaryOutput();
|
||||
$type::setBinaryOutput(true);
|
||||
|
||||
$key = $this->getPublicKey('OpenSSH');
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$type::setBinaryOutput($status);
|
||||
|
||||
switch ($algorithm) {
|
||||
case 'sha256':
|
||||
$hash = new Hash('sha256');
|
||||
$base = Base64::encode($hash->hash($key));
|
||||
return substr($base, 0, strlen($base) - 1);
|
||||
case 'md5':
|
||||
return substr(chunk_split(md5($key), 2, ':'), 0, -1);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* __toString() magic method
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
try {
|
||||
$key = $this->getPrivateKey($this->privateKeyFormat);
|
||||
if (is_string($key)) {
|
||||
return $key;
|
||||
}
|
||||
$key = $this->getPublicKey($this->publicKeyFormat);
|
||||
if (is_string($key)) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
if (!method_exists($this, 'getParameters')) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$key = $this->getParameters($this->parametersFormat);
|
||||
return is_string($key) ? $key : '';
|
||||
} catch (\Exception $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* __clone() magic method
|
||||
*
|
||||
* @access public
|
||||
* @return static
|
||||
*/
|
||||
public function __clone()
|
||||
{
|
||||
$key = new static();
|
||||
$key->load($this);
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the private key format
|
||||
*
|
||||
* @see self::__toString()
|
||||
* @access public
|
||||
* @param string $format
|
||||
*/
|
||||
public function setPrivateKeyFormat($format)
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $format);
|
||||
if ($type === false) {
|
||||
throw new FileNotFoundException('Plugin not found');
|
||||
}
|
||||
|
||||
$type = self::validatePlugin('Keys', $format, 'savePrivateKey');
|
||||
if ($type === false) {
|
||||
throw new UnsupportedOperationException('Plugin does not support private keys');
|
||||
}
|
||||
|
||||
$this->privateKeyFormat = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the public key format
|
||||
*
|
||||
* @see self::__toString()
|
||||
* @access public
|
||||
* @param string $format
|
||||
*/
|
||||
public function setPublicKeyFormat($format)
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $format);
|
||||
if ($type === false) {
|
||||
throw new FileNotFoundException('Plugin not found');
|
||||
}
|
||||
|
||||
$type = self::validatePlugin('Keys', $format, 'savePublicKey');
|
||||
if ($type === false) {
|
||||
throw new UnsupportedOperationException('Plugin does not support public keys');
|
||||
}
|
||||
|
||||
$this->publicKeyFormat = $format;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the key format
|
||||
*
|
||||
* Sets both the public key and private key formats to the specified format if those formats support
|
||||
* the key type
|
||||
*
|
||||
* @see self::__toString()
|
||||
* @access public
|
||||
* @param string $format
|
||||
*/
|
||||
public function setKeyFormat($format)
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $format);
|
||||
if ($type === false) {
|
||||
throw new FileNotFoundException('Plugin not found');
|
||||
}
|
||||
|
||||
try {
|
||||
$this->setPrivateKeyFormat($format);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
try {
|
||||
$this->setPublicKeyFormat($format);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the format of the loaded key.
|
||||
*
|
||||
@ -583,19 +297,47 @@ abstract class AsymmetricKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password
|
||||
* Tests engine validity
|
||||
*
|
||||
* Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
|
||||
* Or rather, pass in $password such that empty($password) && !is_string($password) is true.
|
||||
*
|
||||
* @see self::createKey()
|
||||
* @see self::load()
|
||||
* @access public
|
||||
* @param string|boolean $password
|
||||
* @param int $val
|
||||
*/
|
||||
public function setPassword($password = false)
|
||||
public static function useBestEngine()
|
||||
{
|
||||
$this->password = $password;
|
||||
static::$engines = [
|
||||
'PHP' => true,
|
||||
'OpenSSL' => extension_loaded('openssl'),
|
||||
// this test can be satisfied by either of the following:
|
||||
// http://php.net/manual/en/book.sodium.php
|
||||
// https://github.com/paragonie/sodium_compat
|
||||
'libsodium' => function_exists('sodium_crypto_sign_keypair')
|
||||
];
|
||||
|
||||
return static::$engines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag to use internal engine only (useful for unit testing)
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function useInternalEngine()
|
||||
{
|
||||
static::$engines = [
|
||||
'PHP' => true,
|
||||
'OpenSSL' => false,
|
||||
'libsodium' => false
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* __toString() magic method
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->toString('PKCS8');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -604,12 +346,14 @@ abstract class AsymmetricKey
|
||||
* @access public
|
||||
* @param string $hash
|
||||
*/
|
||||
public function setHash($hash)
|
||||
public function withHash($hash)
|
||||
{
|
||||
$this->hash = new Hash($hash);
|
||||
$this->hmac = new Hash($hash);
|
||||
$new = clone $this;
|
||||
|
||||
$this->hashManuallySet = true;
|
||||
$new->hash = new Hash($hash);
|
||||
$new->hmac = new Hash($hash);
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
|
65
phpseclib/Crypt/Common/Fingerprint.php
Normal file
65
phpseclib/Crypt/Common/Fingerprint.php
Normal file
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Fingerprint Trait for Public Keys
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Common
|
||||
* @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\Common;
|
||||
|
||||
use phpseclib\Crypt\Hash;
|
||||
|
||||
/**
|
||||
* Fingerprint Trait for Private Keys
|
||||
*
|
||||
* @package Common
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
trait Fingerprint
|
||||
{
|
||||
/**
|
||||
* Returns the public key's fingerprint
|
||||
*
|
||||
* The public key's fingerprint is returned, which is equivalent to running `ssh-keygen -lf rsa.pub`. If there is
|
||||
* no public key currently loaded, false is returned.
|
||||
* Example output (md5): "c1:b1:30:29:d7:b8:de:6c:97:77:10:d7:46:41:63:87" (as specified by RFC 4716)
|
||||
*
|
||||
* @access public
|
||||
* @param string $algorithm The hashing algorithm to be used. Valid options are 'md5' and 'sha256'. False is returned
|
||||
* for invalid values.
|
||||
* @return mixed
|
||||
*/
|
||||
public function getFingerprint($algorithm = 'md5')
|
||||
{
|
||||
$type = self::validatePlugin('Keys', 'OpenSSH', 'getBinaryOutput');
|
||||
if ($type === false) {
|
||||
return false;
|
||||
}
|
||||
$status = $type::getBinaryOutput();
|
||||
$type::setBinaryOutput(true);
|
||||
$key = $this->toString('OpenSSH');
|
||||
if ($key === false) {
|
||||
return false;
|
||||
}
|
||||
$type::setBinaryOutput($status);
|
||||
switch ($algorithm) {
|
||||
case 'sha256':
|
||||
$hash = new Hash('sha256');
|
||||
$base = base64_encode($hash->hash($key));
|
||||
return substr($base, 0, strlen($base) - 1);
|
||||
case 'md5':
|
||||
return substr(chunk_split(md5($key), 2, ':'), 0, -1);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -479,7 +479,7 @@ abstract class PKCS8 extends PKCS
|
||||
}
|
||||
if (isset($private['publicKey'])) {
|
||||
if ($private['publicKey'][0] != "\0") {
|
||||
throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($val));
|
||||
throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($private['publicKey'][0]));
|
||||
}
|
||||
$private['publicKey'] = substr($private['publicKey'], 1);
|
||||
}
|
||||
@ -494,7 +494,7 @@ abstract class PKCS8 extends PKCS
|
||||
|
||||
if (is_array($public)) {
|
||||
if ($public['publicKey'][0] != "\0") {
|
||||
throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($val));
|
||||
throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($public['publicKey'][0]));
|
||||
}
|
||||
if (is_array(static::OID_NAME)) {
|
||||
if (!in_array($public['publicKeyAlgorithm']['algorithm'], static::OID_NAME)) {
|
||||
|
51
phpseclib/Crypt/Common/PasswordProtected.php
Normal file
51
phpseclib/Crypt/Common/PasswordProtected.php
Normal file
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Password Protected Trait for Private Keys
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Common
|
||||
* @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\Common;
|
||||
|
||||
/**
|
||||
* Password Protected Trait for Private Keys
|
||||
*
|
||||
* @package Common
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
trait PasswordProtected
|
||||
{
|
||||
/**
|
||||
* Password
|
||||
*
|
||||
* @var string|bool
|
||||
*/
|
||||
private $password = false;
|
||||
|
||||
/**
|
||||
* Sets the password
|
||||
*
|
||||
* Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
|
||||
* Or rather, pass in $password such that empty($password) && !is_string($password) is true.
|
||||
*
|
||||
* @see self::createKey()
|
||||
* @see self::load()
|
||||
* @access public
|
||||
* @param string|boolean $password
|
||||
*/
|
||||
public function withPassword($password = false)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->password = $password;
|
||||
return $new;
|
||||
}
|
||||
}
|
30
phpseclib/Crypt/Common/PrivateKey.php
Normal file
30
phpseclib/Crypt/Common/PrivateKey.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PrivateKey interface
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Common
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2009 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\Common;
|
||||
|
||||
/**
|
||||
* PrivateKey interface
|
||||
*
|
||||
* @package Common
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
interface PrivateKey
|
||||
{
|
||||
public function sign($message);
|
||||
//public function decrypt($ciphertext);
|
||||
public function getPublicKey();
|
||||
public function toString($type);
|
||||
public function withPassword($string);
|
||||
}
|
29
phpseclib/Crypt/Common/PublicKey.php
Normal file
29
phpseclib/Crypt/Common/PublicKey.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PublicKey interface
|
||||
*
|
||||
* @category Crypt
|
||||
* @package Common
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2009 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt\Common;
|
||||
|
||||
/**
|
||||
* PublicKey interface
|
||||
*
|
||||
* @package Common
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
interface PublicKey
|
||||
{
|
||||
public function verify($message, $signature);
|
||||
//public function encrypt($plaintext);
|
||||
public function toString($type);
|
||||
public function getFingerprint($algorithm);
|
||||
}
|
@ -10,13 +10,14 @@
|
||||
* <?php
|
||||
* include 'vendor/autoload.php';
|
||||
*
|
||||
* extract(\phpseclib\Crypt\DSA::createKey());
|
||||
* $private = \phpseclib\Crypt\DSA::createKey();
|
||||
* $public = $private->getPublicKey();
|
||||
*
|
||||
* $plaintext = 'terrafrost';
|
||||
*
|
||||
* $signature = $privatekey->sign($plaintext, 'ASN1');
|
||||
* $signature = $private->sign($plaintext);
|
||||
*
|
||||
* echo $publickey->verify($plaintext, $signature) ? 'verified' : 'unverified';
|
||||
* echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified';
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
@ -30,14 +31,11 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use phpseclib\File\ASN1;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Crypt\Common\AsymmetricKey;
|
||||
use phpseclib\Math\PrimeField;
|
||||
use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature;
|
||||
use phpseclib\Exception\UnsupportedOperationException;
|
||||
use phpseclib\Exception\NoKeyLoadedException;
|
||||
use phpseclib\Crypt\DSA\PrivateKey;
|
||||
use phpseclib\Crypt\DSA\PublicKey;
|
||||
use phpseclib\Crypt\DSA\Parameters;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Exception\InsufficientSetupException;
|
||||
|
||||
/**
|
||||
@ -47,7 +45,7 @@ use phpseclib\Exception\InsufficientSetupException;
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class DSA extends AsymmetricKey
|
||||
abstract class DSA extends AsymmetricKey
|
||||
{
|
||||
/**
|
||||
* Algorithm Name
|
||||
@ -63,7 +61,7 @@ class DSA extends AsymmetricKey
|
||||
* @var \phpseclib\Math\BigInteger
|
||||
* @access private
|
||||
*/
|
||||
private $p;
|
||||
protected $p;
|
||||
|
||||
/**
|
||||
* DSA Group Order q
|
||||
@ -81,15 +79,7 @@ class DSA extends AsymmetricKey
|
||||
* @var \phpseclib\Math\BigInteger
|
||||
* @access private
|
||||
*/
|
||||
private $g;
|
||||
|
||||
/**
|
||||
* DSA secret exponent x
|
||||
*
|
||||
* @var \phpseclib\Math\BigInteger
|
||||
* @access private
|
||||
*/
|
||||
protected $x;
|
||||
protected $g;
|
||||
|
||||
/**
|
||||
* DSA public key value y
|
||||
@ -97,7 +87,23 @@ class DSA extends AsymmetricKey
|
||||
* @var \phpseclib\Math\BigInteger
|
||||
* @access private
|
||||
*/
|
||||
private $y;
|
||||
protected $y;
|
||||
|
||||
/**
|
||||
* Signature Format
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected $format;
|
||||
|
||||
/**
|
||||
* Signature Format (Short)
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected $shortFormat;
|
||||
|
||||
/**
|
||||
* Create DSA parameters
|
||||
@ -133,7 +139,7 @@ class DSA extends AsymmetricKey
|
||||
case $L == 3072 && $N == 256:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
throw new \InvalidArgumentException('Invalid values for N and L');
|
||||
}
|
||||
|
||||
$two = new BigInteger(2);
|
||||
@ -163,7 +169,7 @@ class DSA extends AsymmetricKey
|
||||
$h = $h->add(self::$one);
|
||||
}
|
||||
|
||||
$dsa = new DSA();
|
||||
$dsa = new Parameters;
|
||||
$dsa->p = $p;
|
||||
$dsa->q = $q;
|
||||
$dsa->g = $g;
|
||||
@ -174,17 +180,14 @@ class DSA extends AsymmetricKey
|
||||
/**
|
||||
* Create public / private key pair.
|
||||
*
|
||||
* This method is a bit polymorphic. It can take a DSA object (eg. pre-loaded with parameters),
|
||||
* L / N as two distinct parameters or no parameters (at which point L and N will be generated
|
||||
* with this method)
|
||||
* This method is a bit polymorphic. It can take a DSA/Parameters object, L / N as two distinct parameters or
|
||||
* no parameters (at which point L and N will be generated with this method)
|
||||
*
|
||||
* Returns an array with the following two elements:
|
||||
* - 'privatekey': The private key.
|
||||
* - 'publickey': The public key.
|
||||
* Returns the private key, from which the publickey can be extracted
|
||||
*
|
||||
* @param $args[]
|
||||
* @access public
|
||||
* @return array|DSA
|
||||
* @return DSA\PrivateKey
|
||||
*/
|
||||
public static function createKey(...$args)
|
||||
{
|
||||
@ -195,22 +198,29 @@ class DSA extends AsymmetricKey
|
||||
}
|
||||
|
||||
if (count($args) == 2 && is_int($args[0]) && is_int($args[1])) {
|
||||
$private = self::createParameters($args[0], $args[1]);
|
||||
} else if (count($args) == 1 && $args[0] instanceof DSA) {
|
||||
$private = clone $args[0];
|
||||
$params = self::createParameters($args[0], $args[1]);
|
||||
} else if (count($args) == 1 && $args[0] instanceof Parameters) {
|
||||
$params = $args[0];
|
||||
} else if (!count($args)) {
|
||||
$private = self::createParameters();
|
||||
$params = self::createParameters();
|
||||
} else {
|
||||
throw new InsufficientSetupException('Valid parameters are either two integers (L and N), a single DSA object or no parameters at all.');
|
||||
}
|
||||
|
||||
$private = new PrivateKey;
|
||||
$private->p = $params->p;
|
||||
$private->q = $params->q;
|
||||
$private->g = $params->g;
|
||||
|
||||
$private->x = BigInteger::randomRange(self::$one, $private->q->subtract(self::$one));
|
||||
$private->y = $private->g->powMod($private->x, $private->p);
|
||||
|
||||
$public = clone $private;
|
||||
unset($public->x);
|
||||
//$public = clone $private;
|
||||
//unset($public->x);
|
||||
|
||||
return ['privatekey' => $private, 'publickey' => $public];
|
||||
return $private
|
||||
->withHash($params->hash->getHash())
|
||||
->withSignatureFormat($params->shortFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -220,9 +230,10 @@ class DSA extends AsymmetricKey
|
||||
* @return bool
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param int|bool $type optional
|
||||
* @param string $type optional
|
||||
* @param string $password optional
|
||||
*/
|
||||
public function load($key, $type = false)
|
||||
public static function load($key, $type = false, $password = false)
|
||||
{
|
||||
self::initialize_static_variables();
|
||||
|
||||
@ -230,55 +241,38 @@ class DSA extends AsymmetricKey
|
||||
self::useBestEngine();
|
||||
}
|
||||
|
||||
if ($key instanceof DSA) {
|
||||
$this->privateKeyFormat = $key->privateKeyFormat;
|
||||
$this->publicKeyFormat = $key->publicKeyFormat;
|
||||
$this->format = $key->format;
|
||||
$this->p = $key->p;
|
||||
$this->q = $key->q;
|
||||
$this->g = $key->g;
|
||||
$this->x = $key->x;
|
||||
$this->y = $key->y;
|
||||
$this->parametersFormat = $key->parametersFormat;
|
||||
|
||||
return true;
|
||||
$components = parent::load($key, $type, $password);
|
||||
if (!isset($components['x']) && !isset($components['y'])) {
|
||||
$new = new Parameters;
|
||||
} else if (isset($components['x'])) {
|
||||
$new = new PrivateKey;
|
||||
$new->x = $components['x'];
|
||||
} else {
|
||||
$new = new PublicKey;
|
||||
}
|
||||
|
||||
$components = parent::load($key, $type);
|
||||
if ($components === false) {
|
||||
$this->format = null;
|
||||
$this->p = null;
|
||||
$this->q = null;
|
||||
$this->g = null;
|
||||
$this->x = null;
|
||||
$this->y = null;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($components['p'])) {
|
||||
switch (true) {
|
||||
case isset($this->p) && !$this->p->equals($components['p']):
|
||||
case isset($this->q) && !$this->q->equals($components['q']):
|
||||
case isset($this->g) && !$this->g->equals($components['g']):
|
||||
$this->x = $this->y = null;
|
||||
}
|
||||
|
||||
$this->p = $components['p'];
|
||||
$this->q = $components['q'];
|
||||
$this->g = $components['g'];
|
||||
}
|
||||
|
||||
$this->x = isset($components['x']) ? $components['x'] : null;
|
||||
$new->p = $components['p'];
|
||||
$new->q = $components['q'];
|
||||
$new->g = $components['g'];
|
||||
|
||||
if (isset($components['y'])) {
|
||||
$this->y = $components['y'];
|
||||
$new->y = $components['y'];
|
||||
}
|
||||
//} else if (isset($components['x'])) {
|
||||
// $this->y = $this->g->powMod($this->x, $this->p);
|
||||
//}
|
||||
|
||||
return true;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* PublicKey and PrivateKey objects can only be created from abstract RSA class
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
$this->format = self::validatePlugin('Signature', 'ASN1');
|
||||
$this->shortFormat = 'ASN1';
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -291,140 +285,7 @@ class DSA extends AsymmetricKey
|
||||
*/
|
||||
public function getLength()
|
||||
{
|
||||
return isset($this->p) ?
|
||||
['L' => $this->p->getLength(), 'N' => $this->q->getLength()] :
|
||||
['L' => 0, 'N' => 0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the private key
|
||||
*
|
||||
* PKCS1 DSA private keys contain x and y. PKCS8 DSA private keys just contain x
|
||||
* but y can be derived from x.
|
||||
*
|
||||
* @see self::getPublicKey()
|
||||
* @access public
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPrivateKey($type = 'PKCS8')
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'savePrivateKey');
|
||||
if ($type === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->x)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->y)) {
|
||||
$this->y = $this->g->powMod($this->x, $this->p);
|
||||
}
|
||||
|
||||
return $type::savePrivateKey($this->p, $this->q, $this->g, $this->y, $this->x, $this->password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the key a private key?
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isPrivateKey()
|
||||
{
|
||||
return isset($this->x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the key a public key?
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isPublicKey()
|
||||
{
|
||||
return isset($this->p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key
|
||||
*
|
||||
* If you do "openssl rsa -in private.rsa -pubout -outform PEM" you get a PKCS8 formatted key
|
||||
* that contains a publicKeyAlgorithm AlgorithmIdentifier and a publicKey BIT STRING.
|
||||
* An AlgorithmIdentifier contains an OID and a parameters field. With RSA public keys this
|
||||
* parameters field is NULL. With DSA PKCS8 public keys it is not - it contains the p, q and g
|
||||
* variables. The publicKey BIT STRING contains, simply, the y variable. This can be verified
|
||||
* by getting a DSA PKCS8 public key:
|
||||
*
|
||||
* "openssl dsa -in private.dsa -pubout -outform PEM"
|
||||
*
|
||||
* ie. just swap out rsa with dsa in the rsa command above.
|
||||
*
|
||||
* A PKCS1 public key corresponds to the publicKey portion of the PKCS8 key. In the case of RSA
|
||||
* the publicKey portion /is/ the key. In the case of DSA it is not. You cannot verify a signature
|
||||
* without the parameters and the PKCS1 DSA public key format does not include the parameters.
|
||||
*
|
||||
* @see self::getPrivateKey()
|
||||
* @access public
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublicKey($type = null)
|
||||
{
|
||||
$returnObj = false;
|
||||
if ($type === null) {
|
||||
$returnObj = true;
|
||||
$type = 'PKCS8';
|
||||
}
|
||||
|
||||
$type = self::validatePlugin('Keys', $type, 'savePublicKey');
|
||||
if ($type === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->y)) {
|
||||
if (!isset($this->x) || !isset($this->p)) {
|
||||
return false;
|
||||
}
|
||||
$this->y = $this->g->powMod($this->x, $this->p);
|
||||
}
|
||||
|
||||
$key = $type::savePublicKey($this->p, $this->q, $this->g, $this->y);
|
||||
if (!$returnObj) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
$public = clone $this;
|
||||
$public->load($key, 'PKCS8');
|
||||
|
||||
return $public;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters
|
||||
*
|
||||
* A public / private key is only returned if the currently loaded "key" contains an x or y
|
||||
* value.
|
||||
*
|
||||
* @see self::getPublicKey()
|
||||
* @see self::getPrivateKey()
|
||||
* @access public
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParameters($type = 'PKCS1')
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'saveParameters');
|
||||
if ($type === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->p) || !isset($this->q) || !isset($this->g)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $type::saveParameters($this->p, $this->q, $this->g);
|
||||
return ['L' => $this->p->getLength(), 'N' => $this->q->getLength()];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -442,145 +303,39 @@ class DSA extends AsymmetricKey
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a signature
|
||||
* Returns the parameters
|
||||
*
|
||||
* @see self::verify()
|
||||
* A public / private key is only returned if the currently loaded "key" contains an x or y
|
||||
* value.
|
||||
*
|
||||
* @see self::getPublicKey()
|
||||
* @access public
|
||||
* @param string $message
|
||||
* @param string $format optional
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function sign($message, $format = 'ASN1')
|
||||
public function getParameters()
|
||||
{
|
||||
$shortFormat = $format;
|
||||
$format = self::validatePlugin('Signature', $format);
|
||||
if ($format === false) {
|
||||
return false;
|
||||
}
|
||||
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
|
||||
|
||||
if (empty($this->x)) {
|
||||
if (empty($this->y)) {
|
||||
throw new NoKeyLoadedException('No key has been loaded');
|
||||
}
|
||||
throw new UnsupportedOperationException('A public key cannot be used to sign data');
|
||||
}
|
||||
|
||||
if (empty($this->p)) {
|
||||
throw new InsufficientSetupException('DSA Prime P is not set');
|
||||
}
|
||||
|
||||
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
|
||||
$signature = '';
|
||||
$result = openssl_sign($message, $signature, $this->getPrivateKey(), $this->hash->getHash());
|
||||
|
||||
if ($result) {
|
||||
if ($shortFormat == 'ASN1') {
|
||||
return $signature;
|
||||
}
|
||||
|
||||
extract(ASN1Signature::load($signature));
|
||||
|
||||
return $format::save($r, $s);
|
||||
}
|
||||
}
|
||||
|
||||
$h = $this->hash->hash($message);
|
||||
$h = $this->bits2int($h);
|
||||
|
||||
while (true) {
|
||||
$k = BigInteger::randomRange(self::$one, $this->q->subtract(self::$one));
|
||||
$r = $this->g->powMod($k, $this->p);
|
||||
list(, $r) = $r->divide($this->q);
|
||||
if ($r->equals(self::$zero)) {
|
||||
continue;
|
||||
}
|
||||
$kinv = $k->modInverse($this->q);
|
||||
$temp = $h->add($this->x->multiply($r));
|
||||
$temp = $kinv->multiply($temp);
|
||||
list(, $s) = $temp->divide($this->q);
|
||||
if (!$s->equals(self::$zero)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// the following is an RFC6979 compliant implementation of deterministic DSA
|
||||
// it's unused because it's mainly intended for use when a good CSPRNG isn't
|
||||
// available. if phpseclib's CSPRNG isn't good then even key generation is
|
||||
// suspect
|
||||
/*
|
||||
$h1 = $this->hash->hash($message);
|
||||
$k = $this->computek($h1);
|
||||
$r = $this->g->powMod($k, $this->p);
|
||||
list(, $r) = $r->divide($this->q);
|
||||
$kinv = $k->modInverse($this->q);
|
||||
$h1 = $this->bits2int($h1);
|
||||
$temp = $h1->add($this->x->multiply($r));
|
||||
$temp = $kinv->multiply($temp);
|
||||
list(, $s) = $temp->divide($this->q);
|
||||
*/
|
||||
|
||||
return $format::save($r, $s);
|
||||
$key = $type::saveParameters($this->p, $this->q, $this->g);
|
||||
return DSA::load($key, 'PKCS1')
|
||||
->withHash($this->hash->getHash())
|
||||
->withSignatureFormat($this->shortFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a signature
|
||||
* Determines the signature padding mode
|
||||
*
|
||||
* Valid values are: ASN1, SSH2, Raw
|
||||
*
|
||||
* @see self::verify()
|
||||
* @access public
|
||||
* @param string $message
|
||||
* @param string $signature
|
||||
* @param string $format optional
|
||||
* @return mixed
|
||||
* @param string $padding
|
||||
*/
|
||||
public function verify($message, $signature, $format = 'ASN1')
|
||||
public function withSignatureFormat($format)
|
||||
{
|
||||
$format = self::validatePlugin('Signature', $format);
|
||||
if ($format === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$params = $format::load($signature);
|
||||
if ($params === false || count($params) != 2) {
|
||||
return false;
|
||||
}
|
||||
extract($params);
|
||||
|
||||
if (empty($this->y)) {
|
||||
if (empty($this->x)) {
|
||||
throw new NoKeyLoadedException('No key has been loaded');
|
||||
}
|
||||
throw new UnsupportedOperationException('A private key cannot be used to sign data');
|
||||
}
|
||||
|
||||
if (empty($this->p)) {
|
||||
throw new InsufficientSetupException('DSA Prime P is not set');
|
||||
}
|
||||
|
||||
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
|
||||
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
|
||||
|
||||
$result = openssl_verify($message, $sig, $this->getPublicKey(), $this->hash->getHash());
|
||||
|
||||
if ($result != -1) {
|
||||
return (bool) $result;
|
||||
}
|
||||
}
|
||||
|
||||
$q_1 = $this->q->subtract(self::$one);
|
||||
if (!$r->between(self::$one, $q_1) || !$s->between(self::$one, $q_1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$w = $s->modInverse($this->q);
|
||||
$h = $this->hash->hash($message);
|
||||
$h = $this->bits2int($h);
|
||||
list(, $u1) = $h->multiply($w)->divide($this->q);
|
||||
list(, $u2) = $r->multiply($w)->divide($this->q);
|
||||
$v1 = $this->g->powMod($u1, $this->p);
|
||||
$v2 = $this->y->powMod($u2, $this->p);
|
||||
list(, $v) = $v1->multiply($v2)->divide($this->p);
|
||||
list(, $v) = $v->divide($this->q);
|
||||
|
||||
return $v->equals($r);
|
||||
$new = clone $this;
|
||||
$new->shortFormat = $format;
|
||||
$new->format = self::validatePlugin('Signature', $format);
|
||||
return $new;
|
||||
}
|
||||
}
|
39
phpseclib/Crypt/DSA/Parameters.php
Normal file
39
phpseclib/Crypt/DSA/Parameters.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* DSA Parameters
|
||||
*
|
||||
* @category Crypt
|
||||
* @package DSA
|
||||
* @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\DSA;
|
||||
|
||||
use phpseclib\Crypt\DSA;
|
||||
|
||||
/**
|
||||
* DSA Parameters
|
||||
*
|
||||
* @package DSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Parameters extends DSA
|
||||
{
|
||||
/**
|
||||
* Returns the public key
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function toString($type = 'PKCS1')
|
||||
{
|
||||
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
|
||||
|
||||
return $type::saveParameters($this->p, $this->q, $this->g);
|
||||
}
|
||||
}
|
159
phpseclib/Crypt/DSA/PrivateKey.php
Normal file
159
phpseclib/Crypt/DSA/PrivateKey.php
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* DSA Private Key
|
||||
*
|
||||
* @category Crypt
|
||||
* @package DSA
|
||||
* @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\DSA;
|
||||
|
||||
use phpseclib\Crypt\DSA;
|
||||
use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Crypt\Common;
|
||||
|
||||
/**
|
||||
* DSA Private Key
|
||||
*
|
||||
* @package DSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PrivateKey extends DSA implements Common\PrivateKey
|
||||
{
|
||||
use Common\PasswordProtected;
|
||||
|
||||
/**
|
||||
* DSA secret exponent x
|
||||
*
|
||||
* @var \phpseclib\Math\BigInteger
|
||||
* @access private
|
||||
*/
|
||||
protected $x;
|
||||
|
||||
/**
|
||||
* Returns the public key
|
||||
*
|
||||
* If you do "openssl rsa -in private.rsa -pubout -outform PEM" you get a PKCS8 formatted key
|
||||
* that contains a publicKeyAlgorithm AlgorithmIdentifier and a publicKey BIT STRING.
|
||||
* An AlgorithmIdentifier contains an OID and a parameters field. With RSA public keys this
|
||||
* parameters field is NULL. With DSA PKCS8 public keys it is not - it contains the p, q and g
|
||||
* variables. The publicKey BIT STRING contains, simply, the y variable. This can be verified
|
||||
* by getting a DSA PKCS8 public key:
|
||||
*
|
||||
* "openssl dsa -in private.dsa -pubout -outform PEM"
|
||||
*
|
||||
* ie. just swap out rsa with dsa in the rsa command above.
|
||||
*
|
||||
* A PKCS1 public key corresponds to the publicKey portion of the PKCS8 key. In the case of RSA
|
||||
* the publicKey portion /is/ the key. In the case of DSA it is not. You cannot verify a signature
|
||||
* without the parameters and the PKCS1 DSA public key format does not include the parameters.
|
||||
*
|
||||
* @see self::getPrivateKey()
|
||||
* @access public
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublicKey()
|
||||
{
|
||||
$type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');
|
||||
|
||||
if (!isset($this->y)) {
|
||||
$this->y = $this->g->powMod($this->x, $this->p);
|
||||
}
|
||||
|
||||
$key = $type::savePublicKey($this->p, $this->q, $this->g, $this->y);
|
||||
|
||||
return DSA::load($key, 'PKCS8')
|
||||
->withHash($this->hash->getHash())
|
||||
->withSignatureFormat($this->shortFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a signature
|
||||
*
|
||||
* @see self::verify()
|
||||
* @access public
|
||||
* @param string $message
|
||||
* @return mixed
|
||||
*/
|
||||
public function sign($message)
|
||||
{
|
||||
$format = $this->format;
|
||||
|
||||
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
|
||||
$signature = '';
|
||||
$result = openssl_sign($message, $signature, $this->toString('PKCS8'), $this->hash->getHash());
|
||||
|
||||
if ($result) {
|
||||
if ($this->shortFormat == 'ASN1') {
|
||||
return $signature;
|
||||
}
|
||||
|
||||
extract(ASN1Signature::load($signature));
|
||||
|
||||
return $format::save($r, $s);
|
||||
}
|
||||
}
|
||||
|
||||
$h = $this->hash->hash($message);
|
||||
$h = $this->bits2int($h);
|
||||
|
||||
while (true) {
|
||||
$k = BigInteger::randomRange(self::$one, $this->q->subtract(self::$one));
|
||||
$r = $this->g->powMod($k, $this->p);
|
||||
list(, $r) = $r->divide($this->q);
|
||||
if ($r->equals(self::$zero)) {
|
||||
continue;
|
||||
}
|
||||
$kinv = $k->modInverse($this->q);
|
||||
$temp = $h->add($this->x->multiply($r));
|
||||
$temp = $kinv->multiply($temp);
|
||||
list(, $s) = $temp->divide($this->q);
|
||||
if (!$s->equals(self::$zero)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// the following is an RFC6979 compliant implementation of deterministic DSA
|
||||
// it's unused because it's mainly intended for use when a good CSPRNG isn't
|
||||
// available. if phpseclib's CSPRNG isn't good then even key generation is
|
||||
// suspect
|
||||
/*
|
||||
$h1 = $this->hash->hash($message);
|
||||
$k = $this->computek($h1);
|
||||
$r = $this->g->powMod($k, $this->p);
|
||||
list(, $r) = $r->divide($this->q);
|
||||
$kinv = $k->modInverse($this->q);
|
||||
$h1 = $this->bits2int($h1);
|
||||
$temp = $h1->add($this->x->multiply($r));
|
||||
$temp = $kinv->multiply($temp);
|
||||
list(, $s) = $temp->divide($this->q);
|
||||
*/
|
||||
|
||||
return $format::save($r, $s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the private key
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function toString($type)
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'savePrivateKey');
|
||||
|
||||
if (!isset($this->y)) {
|
||||
$this->y = $this->g->powMod($this->x, $this->p);
|
||||
}
|
||||
|
||||
return $type::savePrivateKey($this->p, $this->q, $this->g, $this->y, $this->x, $this->password);
|
||||
}
|
||||
}
|
91
phpseclib/Crypt/DSA/PublicKey.php
Normal file
91
phpseclib/Crypt/DSA/PublicKey.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* DSA Public Key
|
||||
*
|
||||
* @category Crypt
|
||||
* @package DSA
|
||||
* @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\DSA;
|
||||
|
||||
use phpseclib\Crypt\DSA;
|
||||
use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature;
|
||||
use phpseclib\Crypt\Common;
|
||||
|
||||
/**
|
||||
* DSA Public Key
|
||||
*
|
||||
* @package DSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PublicKey extends DSA implements Common\PublicKey
|
||||
{
|
||||
use Common\Fingerprint;
|
||||
|
||||
/**
|
||||
* Verify a signature
|
||||
*
|
||||
* @see self::verify()
|
||||
* @access public
|
||||
* @param string $message
|
||||
* @param string $signature
|
||||
* @param string $format optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function verify($message, $signature)
|
||||
{
|
||||
$format = $this->format;
|
||||
|
||||
$params = $format::load($signature);
|
||||
if ($params === false || count($params) != 2) {
|
||||
return false;
|
||||
}
|
||||
extract($params);
|
||||
|
||||
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
|
||||
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
|
||||
|
||||
$result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash());
|
||||
|
||||
if ($result != -1) {
|
||||
return (bool) $result;
|
||||
}
|
||||
}
|
||||
|
||||
$q_1 = $this->q->subtract(self::$one);
|
||||
if (!$r->between(self::$one, $q_1) || !$s->between(self::$one, $q_1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$w = $s->modInverse($this->q);
|
||||
$h = $this->hash->hash($message);
|
||||
$h = $this->bits2int($h);
|
||||
list(, $u1) = $h->multiply($w)->divide($this->q);
|
||||
list(, $u2) = $r->multiply($w)->divide($this->q);
|
||||
$v1 = $this->g->powMod($u1, $this->p);
|
||||
$v2 = $this->y->powMod($u2, $this->p);
|
||||
list(, $v) = $v1->multiply($v2)->divide($this->p);
|
||||
list(, $v) = $v->divide($this->q);
|
||||
|
||||
return $v->equals($r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function toString($type)
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'savePublicKey');
|
||||
|
||||
return $type::savePublicKey($this->p, $this->q, $this->g, $this->y);
|
||||
}
|
||||
}
|
@ -10,13 +10,14 @@
|
||||
* <?php
|
||||
* include 'vendor/autoload.php';
|
||||
*
|
||||
* extract(\phpseclib\Crypt\ECDSA::createKey());
|
||||
* $private = \phpseclib\Crypt\ECDSA::createKey('secp256k1');
|
||||
* $public = $private->getPublicKey();
|
||||
*
|
||||
* $plaintext = 'terrafrost';
|
||||
*
|
||||
* $signature = $privatekey->sign($plaintext, 'ASN1');
|
||||
* $signature = $private->sign($plaintext);
|
||||
*
|
||||
* echo $publickey->verify($plaintext, $signature) ? 'verified' : 'unverified';
|
||||
* echo $public->verify($plaintext, $signature) ? 'verified' : 'unverified';
|
||||
* ?>
|
||||
* </code>
|
||||
*
|
||||
@ -30,21 +31,18 @@
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Crypt\Common\AsymmetricKey;
|
||||
use phpseclib\Exception\UnsupportedCurveException;
|
||||
use phpseclib\Exception\UnsupportedOperationException;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
use phpseclib\Exception\NoKeyLoadedException;
|
||||
use phpseclib\Exception\InsufficientSetupException;
|
||||
use phpseclib\File\ASN1;
|
||||
use phpseclib\File\ASN1\Maps\ECParameters;
|
||||
use phpseclib\Crypt\ECDSA\PrivateKey;
|
||||
use phpseclib\Crypt\ECDSA\PublicKey;
|
||||
use phpseclib\Crypt\ECDSA\Parameters;
|
||||
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
|
||||
use phpseclib\Crypt\ECDSA\Curves\Ed25519;
|
||||
use phpseclib\Crypt\ECDSA\Curves\Ed448;
|
||||
use phpseclib\Crypt\ECDSA\Keys\PKCS1;
|
||||
use phpseclib\Crypt\ECDSA\Keys\PKCS8;
|
||||
use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature;
|
||||
use phpseclib\File\ASN1\Maps\ECParameters;
|
||||
use phpseclib\File\ASN1;
|
||||
use phpseclib\Exception\UnsupportedCurveException;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
|
||||
/**
|
||||
* Pure-PHP implementation of ECDSA.
|
||||
@ -53,7 +51,7 @@ use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature;
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class ECDSA extends AsymmetricKey
|
||||
abstract class ECDSA extends AsymmetricKey
|
||||
{
|
||||
/**
|
||||
* Algorithm Name
|
||||
@ -63,30 +61,35 @@ class ECDSA extends AsymmetricKey
|
||||
*/
|
||||
const ALGORITHM = 'ECDSA';
|
||||
|
||||
/**
|
||||
* Private Key dA
|
||||
*
|
||||
* sign() converts this to a BigInteger so one might wonder why this is a FiniteFieldInteger instead of
|
||||
* a BigInteger. That's because a FiniteFieldInteger, when converted to a byte string, is null padded by
|
||||
* a certain amount whereas a BigInteger isn't.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
private $dA;
|
||||
|
||||
/**
|
||||
* Public Key QA
|
||||
*
|
||||
* @var object[]
|
||||
*/
|
||||
private $QA;
|
||||
protected $QA;
|
||||
|
||||
/**
|
||||
* Curve
|
||||
*
|
||||
* @var \phpseclib\Crypt\ECDSA\BaseCurves\Base
|
||||
*/
|
||||
private $curve;
|
||||
protected $curve;
|
||||
|
||||
/**
|
||||
* Signature Format
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected $format;
|
||||
|
||||
/**
|
||||
* Signature Format (Short)
|
||||
*
|
||||
* @var string
|
||||
* @access private
|
||||
*/
|
||||
protected $shortFormat;
|
||||
|
||||
/**
|
||||
* Curve Name
|
||||
@ -96,44 +99,18 @@ class ECDSA extends AsymmetricKey
|
||||
private $curveName;
|
||||
|
||||
/**
|
||||
* Curve Order
|
||||
* Context
|
||||
*
|
||||
* Used for deterministic ECDSA
|
||||
*
|
||||
* @var \phpseclib\Math\BigInteger
|
||||
* @var string
|
||||
*/
|
||||
protected $q;
|
||||
|
||||
/**
|
||||
* Alias for the private key
|
||||
*
|
||||
* Used for deterministic ECDSA. AsymmetricKey expects $x. I don't like x because
|
||||
* with x you have x * the base point yielding an (x, y)-coordinate that is the
|
||||
* public key. But the x is different depending on which side of the equal sign
|
||||
* you're on. It's less ambiguous if you do dA * base point = (x, y)-coordinate.
|
||||
*
|
||||
* @var \phpseclib\Math\BigInteger
|
||||
*/
|
||||
protected $x;
|
||||
|
||||
/**
|
||||
* Alias for the private key
|
||||
*
|
||||
* Used for deterministic ECDSA. AsymmetricKey expects $x. I don't like x because
|
||||
* with x you have x * the base point yielding an (x, y)-coordinate that is the
|
||||
* public key. But the x is different depending on which side of the equal sign
|
||||
* you're on. It's less ambiguous if you do dA * base point = (x, y)-coordinate.
|
||||
*
|
||||
* @var \phpseclib\Math\BigInteger
|
||||
*/
|
||||
private $context;
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* Create public / private key pair.
|
||||
*
|
||||
* @access public
|
||||
* @param string $curve
|
||||
* @return \phpseclib\Crypt\ECDSA[]
|
||||
* @return \phpseclib\Crypt\ECDSA\PrivateKey
|
||||
*/
|
||||
public static function createKey($curve)
|
||||
{
|
||||
@ -143,51 +120,62 @@ class ECDSA extends AsymmetricKey
|
||||
self::useBestEngine();
|
||||
}
|
||||
|
||||
if (self::$engines['libsodium'] && $curve == 'Ed25519' && function_exists('sodium_crypto_sign_keypair')) {
|
||||
$curve = strtolower($curve);
|
||||
if (self::$engines['libsodium'] && $curve == 'ed25519' && function_exists('sodium_crypto_sign_keypair')) {
|
||||
$kp = sodium_crypto_sign_keypair();
|
||||
|
||||
$privatekey = new static();
|
||||
$privatekey->load(sodium_crypto_sign_secretkey($kp));
|
||||
$privatekey = ECDSA::load(sodium_crypto_sign_secretkey($kp), 'libsodium');
|
||||
//$publickey = ECDSA::load(sodium_crypto_sign_publickey($kp), 'libsodium');
|
||||
|
||||
$publickey = new static();
|
||||
$publickey->load(sodium_crypto_sign_publickey($kp));
|
||||
$privatekey->curveName = 'Ed25519';
|
||||
//$publickey->curveName = $curve;
|
||||
|
||||
$publickey->curveName = $privatekey->curveName = $curve;
|
||||
|
||||
return compact('privatekey', 'publickey');
|
||||
return $privatekey;
|
||||
}
|
||||
|
||||
$privatekey = new static();
|
||||
$privatekey = new PrivateKey;
|
||||
|
||||
$curveName = $curve;
|
||||
$curve = '\phpseclib\Crypt\ECDSA\Curves\\' . $curve;
|
||||
if (!class_exists($curve)) {
|
||||
throw new UnsupportedCurveException('Named Curve of ' . $curve . ' is not supported');
|
||||
throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported');
|
||||
}
|
||||
|
||||
$reflect = new \ReflectionClass($curve);
|
||||
$curveName = $reflect->isFinal() ?
|
||||
$reflect->getParentClass()->getShortName() :
|
||||
$reflect->getShortName();
|
||||
|
||||
$curve = new $curve();
|
||||
$privatekey->dA = $dA = $curve->createRandomMultiplier();
|
||||
$privatekey->QA = $curve->multiplyPoint($curve->getBasePoint(), $dA);
|
||||
$privatekey->curve = $curve;
|
||||
|
||||
$publickey = clone $privatekey;
|
||||
unset($publickey->dA);
|
||||
unset($publickey->x);
|
||||
//$publickey = clone $privatekey;
|
||||
//unset($publickey->dA);
|
||||
//unset($publickey->x);
|
||||
|
||||
$publickey->curveName = $privatekey->curveName = $curveName;
|
||||
$privatekey->curveName = $curveName;
|
||||
//$publickey->curveName = $curveName;
|
||||
|
||||
return compact('privatekey', 'publickey');
|
||||
if ($privatekey->curve instanceof TwistedEdwardsCurve) {
|
||||
return $privatekey->withHash($curve::HASH);
|
||||
}
|
||||
|
||||
return $privatekey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a public or private key
|
||||
*
|
||||
* Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
|
||||
*
|
||||
* @return bool
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param int $type optional
|
||||
* @param string $type optional
|
||||
* @param string $password optional
|
||||
*/
|
||||
public function load($key, $type = false)
|
||||
public static function load($key, $type = false, $password = false)
|
||||
{
|
||||
self::initialize_static_variables();
|
||||
|
||||
@ -195,54 +183,42 @@ class ECDSA extends AsymmetricKey
|
||||
self::useBestEngine();
|
||||
}
|
||||
|
||||
if ($key instanceof ECDSA) {
|
||||
$this->privateKeyFormat = $key->privateKeyFormat;
|
||||
$this->publicKeyFormat = $key->publicKeyFormat;
|
||||
$this->format = $key->format;
|
||||
$this->dA = isset($key->dA) ? $key->dA : null;
|
||||
$this->QA = $key->QA;
|
||||
$this->curve = $key->curve;
|
||||
$this->parametersFormat = $key->parametersFormat;
|
||||
$this->hash = $key->hash;
|
||||
$components = parent::load($key, $type, $password);
|
||||
|
||||
parent::load($key, false);
|
||||
|
||||
return true;
|
||||
if (!isset($components['dA']) && !isset($components['QA'])) {
|
||||
$new = new Parameters;
|
||||
$new->curve = $components['curve'];
|
||||
return $new;
|
||||
}
|
||||
|
||||
$components = parent::load($key, $type);
|
||||
if ($components === false) {
|
||||
$this->clearKey();
|
||||
return false;
|
||||
$new = isset($components['dA']) ?
|
||||
new PrivateKey :
|
||||
new PublicKey;
|
||||
$new->curve = $components['curve'];
|
||||
$new->QA = $components['QA'];
|
||||
|
||||
if (isset($components['dA'])) {
|
||||
$new->dA = $components['dA'];
|
||||
}
|
||||
|
||||
if ($components['curve'] instanceof Ed25519 && $this->hashManuallySet && $this->hash->getHash() != 'sha512') {
|
||||
$this->clearKey();
|
||||
throw new UnsupportedAlgorithmException('Ed25519 only supports sha512 as a hash');
|
||||
}
|
||||
if ($components['curve'] instanceof Ed448 && $this->hashManuallySet && $this->hash->getHash() != 'shake256-912') {
|
||||
$this->clearKey();
|
||||
throw new UnsupportedAlgorithmException('Ed448 only supports shake256 with a length of 114 bytes');
|
||||
if ($new->curve instanceof TwistedEdwardsCurve) {
|
||||
return $new->withHash($components['curve']::HASH);
|
||||
}
|
||||
|
||||
$this->curve = $components['curve'];
|
||||
$this->QA = $components['QA'];
|
||||
$this->dA = isset($components['dA']) ? $components['dA'] : null;
|
||||
|
||||
return true;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a key
|
||||
* Constructor
|
||||
*
|
||||
* @access private
|
||||
* PublicKey and PrivateKey objects can only be created from abstract RSA class
|
||||
*/
|
||||
private function clearKey()
|
||||
protected function __construct()
|
||||
{
|
||||
$this->format = null;
|
||||
$this->dA = null;
|
||||
$this->QA = null;
|
||||
$this->curve = null;
|
||||
$this->format = self::validatePlugin('Signature', 'ASN1');
|
||||
$this->shortFormat = 'ASN1';
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,117 +282,9 @@ class ECDSA extends AsymmetricKey
|
||||
*/
|
||||
public function getLength()
|
||||
{
|
||||
if (!isset($this->QA)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $this->curve->getLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the key a private key?
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isPrivateKey()
|
||||
{
|
||||
return isset($this->dA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the key a public key?
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isPublicKey()
|
||||
{
|
||||
return isset($this->QA);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the private key
|
||||
*
|
||||
* @see self::getPublicKey()
|
||||
* @access public
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPrivateKey($type = 'PKCS8')
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'savePrivateKey');
|
||||
if ($type === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->dA)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $type::savePrivateKey($this->dA, $this->curve, $this->QA, $this->password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key
|
||||
*
|
||||
* @see self::getPrivateKey()
|
||||
* @access public
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublicKey($type = null)
|
||||
{
|
||||
$returnObj = false;
|
||||
if ($type === null) {
|
||||
$returnObj = true;
|
||||
$type = 'PKCS8';
|
||||
}
|
||||
$type = self::validatePlugin('Keys', $type, 'savePublicKey');
|
||||
if ($type === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->QA)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$key = $type::savePublicKey($this->curve, $this->QA);
|
||||
if ($returnObj) {
|
||||
$public = clone $this;
|
||||
$public->load($key, 'PKCS8');
|
||||
|
||||
return $public;
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters
|
||||
*
|
||||
* A public / private key is only returned if the currently loaded "key" contains an x or y
|
||||
* value.
|
||||
*
|
||||
* @see self::getPublicKey()
|
||||
* @see self::getPrivateKey()
|
||||
* @access public
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParameters($type = 'PKCS1')
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'saveParameters');
|
||||
if ($type === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($this->curve) || $this->curve instanceof TwistedEdwardsCurve) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $type::saveParameters($this->curve);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current engine being used
|
||||
*
|
||||
@ -427,10 +295,6 @@ class ECDSA extends AsymmetricKey
|
||||
*/
|
||||
public function getEngine()
|
||||
{
|
||||
if (!isset($this->curve)) {
|
||||
throw new InsufficientSetupException('getEngine should not be called until after a key has been loaded');
|
||||
}
|
||||
|
||||
if ($this->curve instanceof TwistedEdwardsCurve) {
|
||||
return $this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context) ?
|
||||
'libsodium' : 'PHP';
|
||||
@ -440,6 +304,41 @@ class ECDSA extends AsymmetricKey
|
||||
'OpenSSL' : 'PHP';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parameters
|
||||
*
|
||||
* @see self::getPublicKey()
|
||||
* @access public
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function getParameters($type = 'PKCS1')
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'saveParameters');
|
||||
|
||||
$key = $type::saveParameters($this->curve);
|
||||
|
||||
return ECDSA::load($key, 'PKCS1')
|
||||
->withHash($this->hash->getHash())
|
||||
->withSignatureFormat($this->shortFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the signature padding mode
|
||||
*
|
||||
* Valid values are: ASN1, SSH2, Raw
|
||||
*
|
||||
* @access public
|
||||
* @param string $padding
|
||||
*/
|
||||
public function withSignatureFormat($format)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->shortFormat = $format;
|
||||
$new->format = self::validatePlugin('Signature', $format);
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the context
|
||||
*
|
||||
@ -450,11 +349,16 @@ class ECDSA extends AsymmetricKey
|
||||
* @access public
|
||||
* @param string $context optional
|
||||
*/
|
||||
public function setContext($context = null)
|
||||
public function withContext($context = null)
|
||||
{
|
||||
if (!$this->curve instanceof TwistedEdwardsCurve) {
|
||||
throw new UnsupportedCurveException('Only Ed25519 and Ed448 support contexts');
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
if (!isset($context)) {
|
||||
$this->context = null;
|
||||
return;
|
||||
$new->context = null;
|
||||
return $new;
|
||||
}
|
||||
if (!is_string($context)) {
|
||||
throw new \InvalidArgumentException('setContext expects a string');
|
||||
@ -462,7 +366,8 @@ class ECDSA extends AsymmetricKey
|
||||
if (strlen($context) > 255) {
|
||||
throw new \LengthException('The context is supposed to be, at most, 255 bytes long');
|
||||
}
|
||||
$this->context = $context;
|
||||
$new->context = $context;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -471,7 +376,7 @@ class ECDSA extends AsymmetricKey
|
||||
* @access public
|
||||
* @param string $hash
|
||||
*/
|
||||
public function setHash($hash)
|
||||
public function withHash($hash)
|
||||
{
|
||||
if ($this->curve instanceof Ed25519 && $hash != 'sha512') {
|
||||
throw new UnsupportedAlgorithmException('Ed25519 only supports sha512 as a hash');
|
||||
@ -480,279 +385,6 @@ class ECDSA extends AsymmetricKey
|
||||
throw new UnsupportedAlgorithmException('Ed448 only supports shake256 with a length of 114 bytes');
|
||||
}
|
||||
|
||||
parent::setHash($hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a signature
|
||||
*
|
||||
* @see self::verify()
|
||||
* @access public
|
||||
* @param string $message
|
||||
* @param string $format optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function sign($message, $format = 'ASN1')
|
||||
{
|
||||
if (!isset($this->dA)) {
|
||||
if (!isset($this->QA)) {
|
||||
throw new NoKeyLoadedException('No key has been loaded');
|
||||
}
|
||||
throw new UnsupportedOperationException('A public key cannot be used to sign data');
|
||||
}
|
||||
|
||||
$dA = $this->dA->toBigInteger();
|
||||
|
||||
$order = $this->curve->getOrder();
|
||||
|
||||
if ($this->curve instanceof TwistedEdwardsCurve) {
|
||||
if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) {
|
||||
return sodium_crypto_sign_detached($message, $this->getPrivateKey('libsodium'));
|
||||
}
|
||||
|
||||
// contexts (Ed25519ctx) are supported but prehashing (Ed25519ph) is not.
|
||||
// quoting https://tools.ietf.org/html/rfc8032#section-8.5 ,
|
||||
// "The Ed25519ph and Ed448ph variants ... SHOULD NOT be used"
|
||||
$A = $this->curve->encodePoint($this->QA);
|
||||
$curve = $this->curve;
|
||||
$hash = new Hash($curve::HASH);
|
||||
|
||||
$secret = substr($hash->hash($this->dA->secret), $curve::SIZE);
|
||||
|
||||
if ($curve instanceof Ed25519) {
|
||||
$dom = !isset($this->context) ? '' :
|
||||
'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context;
|
||||
} else {
|
||||
$context = isset($this->context) ? $this->context : '';
|
||||
$dom = 'SigEd448' . "\0" . chr(strlen($context)) . $context;
|
||||
}
|
||||
// SHA-512(dom2(F, C) || prefix || PH(M))
|
||||
$r = $hash->hash($dom . $secret . $message);
|
||||
$r = strrev($r);
|
||||
$r = new BigInteger($r, 256);
|
||||
list(, $r) = $r->divide($order);
|
||||
$R = $curve->multiplyPoint($curve->getBasePoint(), $curve->convertInteger($r));
|
||||
$R = $curve->encodePoint($R);
|
||||
$k = $hash->hash($dom . $R . $A . $message);
|
||||
$k = strrev($k);
|
||||
$k = new BigInteger($k, 256);
|
||||
list(, $k) = $k->divide($order);
|
||||
$S = $k->multiply($dA)->add($r);
|
||||
list(, $S) = $S->divide($order);
|
||||
$S = str_pad(strrev($S->toBytes()), $curve::SIZE, "\0");
|
||||
return $R . $S;
|
||||
}
|
||||
|
||||
$shortFormat = $format;
|
||||
$format = self::validatePlugin('Signature', $format);
|
||||
if ($format === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
|
||||
$namedCurves = PKCS8::isUsingNamedCurves();
|
||||
|
||||
// use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve;
|
||||
// doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even
|
||||
// has curve-specific optimizations
|
||||
PKCS8::useSpecifiedCurve();
|
||||
|
||||
$signature = '';
|
||||
// altho PHP's OpenSSL bindings only supported ECDSA key creation in PHP 7.1 they've long
|
||||
// supported signing / verification
|
||||
$result = openssl_sign($message, $signature, $this->getPrivateKey(), $this->hash->getHash());
|
||||
|
||||
if ($namedCurves) {
|
||||
PKCS8::useNamedCurve();
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
if ($shortFormat == 'ASN1') {
|
||||
return $signature;
|
||||
}
|
||||
|
||||
extract(ASN1Signature::load($signature));
|
||||
|
||||
return $shortFormat == 'SSH2' ? $format::save($r, $s, $this->getCurve()) : $format::save($r, $s);
|
||||
}
|
||||
}
|
||||
|
||||
$e = $this->hash->hash($message);
|
||||
$e = new BigInteger($e, 256);
|
||||
|
||||
$Ln = $this->hash->getLength() - $order->getLength();
|
||||
$z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e;
|
||||
|
||||
while (true) {
|
||||
$k = BigInteger::randomRange(self::$one, $order->subtract(self::$one));
|
||||
list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $this->curve->convertInteger($k));
|
||||
$x = $x->toBigInteger();
|
||||
list(, $r) = $x->divide($order);
|
||||
if ($r->equals(self::$zero)) {
|
||||
continue;
|
||||
}
|
||||
$kinv = $k->modInverse($order);
|
||||
$temp = $z->add($dA->multiply($r));
|
||||
$temp = $kinv->multiply($temp);
|
||||
list(, $s) = $temp->divide($order);
|
||||
if (!$s->equals(self::$zero)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// the following is an RFC6979 compliant implementation of deterministic ECDSA
|
||||
// it's unused because it's mainly intended for use when a good CSPRNG isn't
|
||||
// available. if phpseclib's CSPRNG isn't good then even key generation is
|
||||
// suspect
|
||||
/*
|
||||
// if this were actually being used it'd probably be better if this lived in load() and createKey()
|
||||
$this->q = $this->curve->getOrder();
|
||||
$dA = $this->dA->toBigInteger();
|
||||
$this->x = $dA;
|
||||
|
||||
$h1 = $this->hash->hash($message);
|
||||
$k = $this->computek($h1);
|
||||
list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $this->curve->convertInteger($k));
|
||||
$x = $x->toBigInteger();
|
||||
list(, $r) = $x->divide($this->q);
|
||||
$kinv = $k->modInverse($this->q);
|
||||
$h1 = $this->bits2int($h1);
|
||||
$temp = $h1->add($dA->multiply($r));
|
||||
$temp = $kinv->multiply($temp);
|
||||
list(, $s) = $temp->divide($this->q);
|
||||
*/
|
||||
|
||||
return $shortFormat == 'SSH2' ? $format::save($r, $s, $this->getCurve()) : $format::save($r, $s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a signature
|
||||
*
|
||||
* @see self::verify()
|
||||
* @access public
|
||||
* @param string $message
|
||||
* @param string $format optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function verify($message, $signature, $format = 'ASN1')
|
||||
{
|
||||
if (!isset($this->QA)) {
|
||||
if (!isset($this->dA)) {
|
||||
throw new NoKeyLoadedException('No key has been loaded');
|
||||
}
|
||||
throw new UnsupportedOperationException('A private key cannot be used to verify data');
|
||||
}
|
||||
|
||||
$order = $this->curve->getOrder();
|
||||
|
||||
if ($this->curve instanceof TwistedEdwardsCurve) {
|
||||
if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) {
|
||||
return sodium_crypto_sign_verify_detached($signature, $message, $this->getPublicKey('libsodium'));
|
||||
}
|
||||
|
||||
$curve = $this->curve;
|
||||
if (strlen($signature) != 2 * $curve::SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$R = substr($signature, 0, $curve::SIZE);
|
||||
$S = substr($signature, $curve::SIZE);
|
||||
|
||||
try {
|
||||
$R = PKCS1::extractPoint($R, $curve);
|
||||
$R = $this->curve->convertToInternal($R);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$S = strrev($S);
|
||||
$S = new BigInteger($S, 256);
|
||||
|
||||
if ($S->compare($order) >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$A = $curve->encodePoint($this->QA);
|
||||
|
||||
if ($curve instanceof Ed25519) {
|
||||
$dom2 = !isset($this->context) ? '' :
|
||||
'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context;
|
||||
} else {
|
||||
$context = isset($this->context) ? $this->context : '';
|
||||
$dom2 = 'SigEd448' . "\0" . chr(strlen($context)) . $context;
|
||||
}
|
||||
|
||||
$hash = new Hash($curve::HASH);
|
||||
$k = $hash->hash($dom2 . substr($signature, 0, $curve::SIZE) . $A . $message);
|
||||
$k = strrev($k);
|
||||
$k = new BigInteger($k, 256);
|
||||
list(, $k) = $k->divide($order);
|
||||
|
||||
$qa = $curve->convertToInternal($this->QA);
|
||||
|
||||
$lhs = $curve->multiplyPoint($curve->getBasePoint(), $curve->convertInteger($S));
|
||||
$rhs = $curve->multiplyPoint($qa, $curve->convertInteger($k));
|
||||
$rhs = $curve->addPoint($rhs, $R);
|
||||
$rhs = $curve->convertToAffine($rhs);
|
||||
|
||||
return $lhs[0]->equals($rhs[0]) && $lhs[1]->equals($rhs[1]);
|
||||
}
|
||||
|
||||
$format = self::validatePlugin('Signature', $format);
|
||||
if ($format === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$params = $format::load($signature);
|
||||
if ($params === false || count($params) != 2) {
|
||||
return false;
|
||||
}
|
||||
extract($params);
|
||||
|
||||
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
|
||||
$namedCurves = PKCS8::isUsingNamedCurves();
|
||||
|
||||
PKCS8::useSpecifiedCurve();
|
||||
|
||||
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
|
||||
|
||||
$result = openssl_verify($message, $sig, $this->getPublicKey(), $this->hash->getHash());
|
||||
|
||||
if ($namedCurves) {
|
||||
PKCS8::useNamedCurve();
|
||||
}
|
||||
|
||||
if ($result != -1) {
|
||||
return (bool) $result;
|
||||
}
|
||||
}
|
||||
|
||||
$n_1 = $order->subtract(self::$one);
|
||||
if (!$r->between(self::$one, $n_1) || !$s->between(self::$one, $n_1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$e = $this->hash->hash($message);
|
||||
$e = new BigInteger($e, 256);
|
||||
|
||||
$Ln = $this->hash->getLength() - $order->getLength();
|
||||
$z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e;
|
||||
|
||||
$w = $s->modInverse($order);
|
||||
list(, $u1) = $z->multiply($w)->divide($order);
|
||||
list(, $u2) = $r->multiply($w)->divide($order);
|
||||
|
||||
$u1 = $this->curve->convertInteger($u1);
|
||||
$u2 = $this->curve->convertInteger($u2);
|
||||
|
||||
list($x1, $y1) = $this->curve->multiplyAddPoints(
|
||||
[$this->curve->getBasePoint(), $this->QA],
|
||||
[$u1, $u2]
|
||||
);
|
||||
|
||||
$x1 = $x1->toBigInteger();
|
||||
list(, $x1) = $x1->divide($order);
|
||||
|
||||
return $x1->equals($r);
|
||||
return parent::withHash($hash);
|
||||
}
|
||||
}
|
39
phpseclib/Crypt/ECDSA/Parameters.php
Normal file
39
phpseclib/Crypt/ECDSA/Parameters.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ECDSA Parameters
|
||||
*
|
||||
* @category Crypt
|
||||
* @package ECDSA
|
||||
* @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\ECDSA;
|
||||
|
||||
use phpseclib\Crypt\ECDSA;
|
||||
|
||||
/**
|
||||
* ECDSA Parameters
|
||||
*
|
||||
* @package ECDSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class Parameters extends ECDSA
|
||||
{
|
||||
/**
|
||||
* Returns the public key
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function toString($type = 'PKCS1')
|
||||
{
|
||||
$type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters');
|
||||
|
||||
return $type::saveParameters($this->curve);
|
||||
}
|
||||
}
|
214
phpseclib/Crypt/ECDSA/PrivateKey.php
Normal file
214
phpseclib/Crypt/ECDSA/PrivateKey.php
Normal file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ECDSA Private Key
|
||||
*
|
||||
* @category Crypt
|
||||
* @package ECDSA
|
||||
* @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\ECDSA;
|
||||
|
||||
use phpseclib\Crypt\ECDSA;
|
||||
use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Crypt\ECDSA\Curves\Ed25519;
|
||||
use phpseclib\Crypt\ECDSA\Keys\PKCS8;
|
||||
use phpseclib\Crypt\Common;
|
||||
|
||||
/**
|
||||
* ECDSA Private Key
|
||||
*
|
||||
* @package ECDSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PrivateKey extends ECDSA implements Common\PrivateKey
|
||||
{
|
||||
use Common\PasswordProtected;
|
||||
|
||||
/**
|
||||
* Private Key dA
|
||||
*
|
||||
* sign() converts this to a BigInteger so one might wonder why this is a FiniteFieldInteger instead of
|
||||
* a BigInteger. That's because a FiniteFieldInteger, when converted to a byte string, is null padded by
|
||||
* a certain amount whereas a BigInteger isn't.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $dA;
|
||||
|
||||
/**
|
||||
* Create a signature
|
||||
*
|
||||
* @see self::verify()
|
||||
* @access public
|
||||
* @param string $message
|
||||
* @return mixed
|
||||
*/
|
||||
public function sign($message)
|
||||
{
|
||||
$dA = $this->dA->toBigInteger();
|
||||
|
||||
$order = $this->curve->getOrder();
|
||||
|
||||
if ($this->curve instanceof TwistedEdwardsCurve) {
|
||||
if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) {
|
||||
return sodium_crypto_sign_detached($message, $this->toString('libsodium'));
|
||||
}
|
||||
|
||||
// contexts (Ed25519ctx) are supported but prehashing (Ed25519ph) is not.
|
||||
// quoting https://tools.ietf.org/html/rfc8032#section-8.5 ,
|
||||
// "The Ed25519ph and Ed448ph variants ... SHOULD NOT be used"
|
||||
$A = $this->curve->encodePoint($this->QA);
|
||||
$curve = $this->curve;
|
||||
$hash = new Hash($curve::HASH);
|
||||
|
||||
$secret = substr($hash->hash($this->dA->secret), $curve::SIZE);
|
||||
|
||||
if ($curve instanceof Ed25519) {
|
||||
$dom = !isset($this->context) ? '' :
|
||||
'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context;
|
||||
} else {
|
||||
$context = isset($this->context) ? $this->context : '';
|
||||
$dom = 'SigEd448' . "\0" . chr(strlen($context)) . $context;
|
||||
}
|
||||
// SHA-512(dom2(F, C) || prefix || PH(M))
|
||||
$r = $hash->hash($dom . $secret . $message);
|
||||
$r = strrev($r);
|
||||
$r = new BigInteger($r, 256);
|
||||
list(, $r) = $r->divide($order);
|
||||
$R = $curve->multiplyPoint($curve->getBasePoint(), $curve->convertInteger($r));
|
||||
$R = $curve->encodePoint($R);
|
||||
$k = $hash->hash($dom . $R . $A . $message);
|
||||
$k = strrev($k);
|
||||
$k = new BigInteger($k, 256);
|
||||
list(, $k) = $k->divide($order);
|
||||
$S = $k->multiply($dA)->add($r);
|
||||
list(, $S) = $S->divide($order);
|
||||
$S = str_pad(strrev($S->toBytes()), $curve::SIZE, "\0");
|
||||
return $R . $S;
|
||||
}
|
||||
|
||||
$shortFormat = $this->shortFormat;
|
||||
$format = $this->format;
|
||||
if ($format === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
|
||||
$namedCurves = PKCS8::isUsingNamedCurves();
|
||||
|
||||
// use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve;
|
||||
// doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even
|
||||
// has curve-specific optimizations
|
||||
PKCS8::useSpecifiedCurve();
|
||||
|
||||
$signature = '';
|
||||
// altho PHP's OpenSSL bindings only supported ECDSA key creation in PHP 7.1 they've long
|
||||
// supported signing / verification
|
||||
$result = openssl_sign($message, $signature, $this->toString('PKCS8'), $this->hash->getHash());
|
||||
|
||||
if ($namedCurves) {
|
||||
PKCS8::useNamedCurve();
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
if ($shortFormat == 'ASN1') {
|
||||
return $signature;
|
||||
}
|
||||
|
||||
extract(ASN1Signature::load($signature));
|
||||
|
||||
return $shortFormat == 'SSH2' ? $format::save($r, $s, $this->getCurve()) : $format::save($r, $s);
|
||||
}
|
||||
}
|
||||
|
||||
$e = $this->hash->hash($message);
|
||||
$e = new BigInteger($e, 256);
|
||||
|
||||
$Ln = $this->hash->getLength() - $order->getLength();
|
||||
$z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e;
|
||||
|
||||
while (true) {
|
||||
$k = BigInteger::randomRange(self::$one, $order->subtract(self::$one));
|
||||
list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $this->curve->convertInteger($k));
|
||||
$x = $x->toBigInteger();
|
||||
list(, $r) = $x->divide($order);
|
||||
if ($r->equals(self::$zero)) {
|
||||
continue;
|
||||
}
|
||||
$kinv = $k->modInverse($order);
|
||||
$temp = $z->add($dA->multiply($r));
|
||||
$temp = $kinv->multiply($temp);
|
||||
list(, $s) = $temp->divide($order);
|
||||
if (!$s->equals(self::$zero)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// the following is an RFC6979 compliant implementation of deterministic ECDSA
|
||||
// it's unused because it's mainly intended for use when a good CSPRNG isn't
|
||||
// available. if phpseclib's CSPRNG isn't good then even key generation is
|
||||
// suspect
|
||||
/*
|
||||
// if this were actually being used it'd probably be better if this lived in load() and createKey()
|
||||
$this->q = $this->curve->getOrder();
|
||||
$dA = $this->dA->toBigInteger();
|
||||
$this->x = $dA;
|
||||
|
||||
$h1 = $this->hash->hash($message);
|
||||
$k = $this->computek($h1);
|
||||
list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $this->curve->convertInteger($k));
|
||||
$x = $x->toBigInteger();
|
||||
list(, $r) = $x->divide($this->q);
|
||||
$kinv = $k->modInverse($this->q);
|
||||
$h1 = $this->bits2int($h1);
|
||||
$temp = $h1->add($dA->multiply($r));
|
||||
$temp = $kinv->multiply($temp);
|
||||
list(, $s) = $temp->divide($this->q);
|
||||
*/
|
||||
|
||||
return $shortFormat == 'SSH2' ? $format::save($r, $s, $this->getCurve()) : $format::save($r, $s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the private key
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function toString($type)
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'savePrivateKey');
|
||||
|
||||
return $type::savePrivateKey($this->dA, $this->curve, $this->QA, $this->password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key
|
||||
*
|
||||
* @see self::getPrivateKey()
|
||||
* @access public
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublicKey()
|
||||
{
|
||||
$type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');
|
||||
|
||||
$key = $type::savePublicKey($this->curve, $this->QA);
|
||||
$key = ECDSA::load($key, 'PKCS8')
|
||||
->withHash($this->hash->getHash())
|
||||
->withSignatureFormat($this->shortFormat);
|
||||
if ($this->curve instanceof TwistedEdwardsCurve) {
|
||||
$key = $key->withContext($this->context);
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
}
|
170
phpseclib/Crypt/ECDSA/PublicKey.php
Normal file
170
phpseclib/Crypt/ECDSA/PublicKey.php
Normal file
@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ECDSA Public Key
|
||||
*
|
||||
* @category Crypt
|
||||
* @package ECDSA
|
||||
* @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\ECDSA;
|
||||
|
||||
use phpseclib\Crypt\ECDSA;
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature;
|
||||
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
|
||||
use phpseclib\Crypt\ECDSA\Curves\Ed25519;
|
||||
use phpseclib\Crypt\ECDSA\Keys\PKCS1;
|
||||
use phpseclib\Crypt\ECDSA\Keys\PKCS8;
|
||||
use phpseclib\Crypt\Common;
|
||||
|
||||
/**
|
||||
* ECDSA Public Key
|
||||
*
|
||||
* @package ECDSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PublicKey extends ECDSA implements Common\PublicKey
|
||||
{
|
||||
use Common\Fingerprint;
|
||||
|
||||
/**
|
||||
* Verify a signature
|
||||
*
|
||||
* @see self::verify()
|
||||
* @access public
|
||||
* @param string $message
|
||||
* @param string $signature
|
||||
* @return mixed
|
||||
*/
|
||||
public function verify($message, $signature)
|
||||
{
|
||||
$order = $this->curve->getOrder();
|
||||
|
||||
if ($this->curve instanceof TwistedEdwardsCurve) {
|
||||
if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) {
|
||||
return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium'));
|
||||
}
|
||||
|
||||
$curve = $this->curve;
|
||||
if (strlen($signature) != 2 * $curve::SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$R = substr($signature, 0, $curve::SIZE);
|
||||
$S = substr($signature, $curve::SIZE);
|
||||
|
||||
try {
|
||||
$R = PKCS1::extractPoint($R, $curve);
|
||||
$R = $this->curve->convertToInternal($R);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$S = strrev($S);
|
||||
$S = new BigInteger($S, 256);
|
||||
|
||||
if ($S->compare($order) >= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$A = $curve->encodePoint($this->QA);
|
||||
|
||||
if ($curve instanceof Ed25519) {
|
||||
$dom2 = !isset($this->context) ? '' :
|
||||
'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context;
|
||||
} else {
|
||||
$context = isset($this->context) ? $this->context : '';
|
||||
$dom2 = 'SigEd448' . "\0" . chr(strlen($context)) . $context;
|
||||
}
|
||||
|
||||
$hash = new Hash($curve::HASH);
|
||||
$k = $hash->hash($dom2 . substr($signature, 0, $curve::SIZE) . $A . $message);
|
||||
$k = strrev($k);
|
||||
$k = new BigInteger($k, 256);
|
||||
list(, $k) = $k->divide($order);
|
||||
|
||||
$qa = $curve->convertToInternal($this->QA);
|
||||
|
||||
$lhs = $curve->multiplyPoint($curve->getBasePoint(), $curve->convertInteger($S));
|
||||
$rhs = $curve->multiplyPoint($qa, $curve->convertInteger($k));
|
||||
$rhs = $curve->addPoint($rhs, $R);
|
||||
$rhs = $curve->convertToAffine($rhs);
|
||||
|
||||
return $lhs[0]->equals($rhs[0]) && $lhs[1]->equals($rhs[1]);
|
||||
}
|
||||
|
||||
$format = $this->format;
|
||||
|
||||
$params = $format::load($signature);
|
||||
if ($params === false || count($params) != 2) {
|
||||
return false;
|
||||
}
|
||||
extract($params);
|
||||
|
||||
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
|
||||
$namedCurves = PKCS8::isUsingNamedCurves();
|
||||
|
||||
PKCS8::useSpecifiedCurve();
|
||||
|
||||
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
|
||||
|
||||
$result = openssl_verify($message, $sig, $this->toString('PKCS8'), $this->hash->getHash());
|
||||
|
||||
if ($namedCurves) {
|
||||
PKCS8::useNamedCurve();
|
||||
}
|
||||
|
||||
if ($result != -1) {
|
||||
return (bool) $result;
|
||||
}
|
||||
}
|
||||
|
||||
$n_1 = $order->subtract(self::$one);
|
||||
if (!$r->between(self::$one, $n_1) || !$s->between(self::$one, $n_1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$e = $this->hash->hash($message);
|
||||
$e = new BigInteger($e, 256);
|
||||
|
||||
$Ln = $this->hash->getLength() - $order->getLength();
|
||||
$z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e;
|
||||
|
||||
$w = $s->modInverse($order);
|
||||
list(, $u1) = $z->multiply($w)->divide($order);
|
||||
list(, $u2) = $r->multiply($w)->divide($order);
|
||||
|
||||
$u1 = $this->curve->convertInteger($u1);
|
||||
$u2 = $this->curve->convertInteger($u2);
|
||||
|
||||
list($x1, $y1) = $this->curve->multiplyAddPoints(
|
||||
[$this->curve->getBasePoint(), $this->QA],
|
||||
[$u1, $u2]
|
||||
);
|
||||
|
||||
$x1 = $x1->toBigInteger();
|
||||
list(, $x1) = $x1->divide($order);
|
||||
|
||||
return $x1->equals($r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function toString($type)
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'savePublicKey');
|
||||
|
||||
return $type::savePublicKey($this->curve, $this->QA);
|
||||
}
|
||||
}
|
74
phpseclib/Crypt/PublicKeyLoader.php
Normal file
74
phpseclib/Crypt/PublicKeyLoader.php
Normal file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* PublicKeyLoader
|
||||
*
|
||||
* Returns a PublicKey or PrivateKey object.
|
||||
*
|
||||
* @category Crypt
|
||||
* @package PublicKeyLoader
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @copyright 2009 Jim Wigginton
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @link http://phpseclib.sourceforge.net
|
||||
*/
|
||||
|
||||
namespace phpseclib\Crypt;
|
||||
|
||||
use phpseclib\Exception\NoKeyLoadedException;
|
||||
use phpseclib\Crypt\Common\PrivateKey;
|
||||
use phpseclib\File\X509;
|
||||
|
||||
/**
|
||||
* PublicKeyLoader
|
||||
*
|
||||
* @package Common
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
abstract class PublicKeyLoader
|
||||
{
|
||||
/**
|
||||
* Loads a public or private key
|
||||
*
|
||||
* @return AsymmetricKey
|
||||
* @access public
|
||||
* @param string $key
|
||||
* @param string $password optional
|
||||
*/
|
||||
public static function load($key, $password = false)
|
||||
{
|
||||
try {
|
||||
$new = ECDSA::load($key, false, $password);
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
if (!isset($new)) {
|
||||
try {
|
||||
$new = RSA::load($key, false, $password);
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
if (!isset($new)) {
|
||||
try {
|
||||
$new = DSA::load($key, false, $password);
|
||||
} catch (\Exception $e) {}
|
||||
}
|
||||
|
||||
if (isset($new)) {
|
||||
return $new instanceof PrivateKey ?
|
||||
$new->withPassword($password) :
|
||||
$new;
|
||||
}
|
||||
|
||||
try {
|
||||
$x509 = new X509();
|
||||
$x509->loadX509($key);
|
||||
$key = $x509->getPublicKey();
|
||||
if ($key) {
|
||||
return $key;
|
||||
}
|
||||
} catch (\Exception $e) {}
|
||||
|
||||
throw new NoKeyLoadedException('Unable to read key');
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -102,7 +102,16 @@ abstract class XML
|
||||
|
||||
libxml_use_internal_errors($use_errors);
|
||||
|
||||
foreach ($components as $key => $value) {
|
||||
if (is_array($value) && !count($value)) {
|
||||
unset($components[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($components['modulus']) && isset($components['publicExponent'])) {
|
||||
if (count($components) == 3) {
|
||||
$components['isPublicKey'] = true;
|
||||
}
|
||||
return $components;
|
||||
}
|
||||
|
||||
|
561
phpseclib/Crypt/RSA/PrivateKey.php
Normal file
561
phpseclib/Crypt/RSA/PrivateKey.php
Normal file
@ -0,0 +1,561 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* RSA Private Key
|
||||
*
|
||||
* @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\RSA;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\File\ASN1;
|
||||
use phpseclib\Common\Functions\Strings;
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Exceptions\NoKeyLoadedException;
|
||||
use phpseclib\Exception\UnsupportedFormatException;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Crypt\Common;
|
||||
|
||||
/**
|
||||
* Raw RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PrivateKey extends RSA implements Common\PrivateKey
|
||||
{
|
||||
use Common\PasswordProtected;
|
||||
|
||||
/**
|
||||
* Primes for Chinese Remainder Theorem (ie. p and q)
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
protected $primes;
|
||||
|
||||
/**
|
||||
* Exponents for Chinese Remainder Theorem (ie. dP and dQ)
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
protected $exponents;
|
||||
|
||||
/**
|
||||
* Coefficients for Chinese Remainder Theorem (ie. qInv)
|
||||
*
|
||||
* @var array
|
||||
* @access private
|
||||
*/
|
||||
protected $coefficients;
|
||||
|
||||
/**
|
||||
* Public Exponent
|
||||
*
|
||||
* @var mixed
|
||||
* @access private
|
||||
*/
|
||||
protected $publicExponent = false;
|
||||
|
||||
/**
|
||||
* RSADP
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
|
||||
*
|
||||
* @access private
|
||||
* @param \phpseclib\Math\BigInteger $c
|
||||
* @return bool|\phpseclib\Math\BigInteger
|
||||
*/
|
||||
private function rsadp($c)
|
||||
{
|
||||
if ($c->compare(self::$zero) < 0 || $c->compare($this->modulus) > 0) {
|
||||
return false;
|
||||
}
|
||||
return $this->exponentiate($c);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSASP1
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
|
||||
*
|
||||
* @access private
|
||||
* @param \phpseclib\Math\BigInteger $m
|
||||
* @return bool|\phpseclib\Math\BigInteger
|
||||
*/
|
||||
private function rsasp1($m)
|
||||
{
|
||||
if ($m->compare(self::$zero) < 0 || $m->compare($this->modulus) > 0) {
|
||||
return false;
|
||||
}
|
||||
return $this->exponentiate($m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exponentiate
|
||||
*
|
||||
* @param \phpseclib\Math\BigInteger $x
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
*/
|
||||
protected function exponentiate(BigInteger $x)
|
||||
{
|
||||
switch (true) {
|
||||
case empty($this->primes):
|
||||
case $this->primes[1]->equals(self::$zero):
|
||||
case empty($this->coefficients):
|
||||
case $this->coefficients[2]->equals(self::$zero):
|
||||
case empty($this->exponents):
|
||||
case $this->exponents[1]->equals(self::$zero):
|
||||
return $x->modPow($this->exponent, $this->modulus);
|
||||
}
|
||||
|
||||
$num_primes = count($this->primes);
|
||||
|
||||
if (!static::$enableBlinding) {
|
||||
$m_i = [
|
||||
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]);
|
||||
|
||||
$m = $m->add($r->multiply($h));
|
||||
}
|
||||
} else {
|
||||
$smallest = $this->primes[1];
|
||||
for ($i = 2; $i <= $num_primes; $i++) {
|
||||
if ($smallest->compare($this->primes[$i]) > 0) {
|
||||
$smallest = $this->primes[$i];
|
||||
}
|
||||
}
|
||||
|
||||
$r = BigInteger::randomRange(self::$one, $smallest->subtract(self::$one));
|
||||
|
||||
$m_i = [
|
||||
1 => $this->blind($x, $r, 1),
|
||||
2 => $this->blind($x, $r, 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 = $this->blind($x, $r, $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]);
|
||||
|
||||
$m = $m->add($r->multiply($h));
|
||||
}
|
||||
}
|
||||
|
||||
return $m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs RSA Blinding
|
||||
*
|
||||
* Protects against timing attacks by employing RSA Blinding.
|
||||
* Returns $x->modPow($this->exponents[$i], $this->primes[$i])
|
||||
*
|
||||
* @access private
|
||||
* @param \phpseclib\Math\BigInteger $x
|
||||
* @param \phpseclib\Math\BigInteger $r
|
||||
* @param int $i
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
*/
|
||||
private function blind($x, $r, $i)
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* EMSA-PSS-ENCODE
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
|
||||
*
|
||||
* @return string
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @throws \RuntimeException on encoding error
|
||||
* @param int $emBits
|
||||
*/
|
||||
private 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)
|
||||
$sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
|
||||
|
||||
$mHash = $this->hash->hash($m);
|
||||
if ($emLen < $this->hLen + $sLen + 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$salt = Random::string($sLen);
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* RSASSA-PSS-SIGN
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @return bool|string
|
||||
*/
|
||||
private 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-PKCS1-V1_5-SIGN
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @throws \LengthException if the RSA modulus is too short
|
||||
* @return bool|string
|
||||
*/
|
||||
private function rsassa_pkcs1_v1_5_sign($m)
|
||||
{
|
||||
// EMSA-PKCS1-v1_5 encoding
|
||||
|
||||
// If the encoding operation outputs "intended encoded message length too short," output "RSA modulus
|
||||
// too short" and stop.
|
||||
try {
|
||||
$em = $this->emsa_pkcs1_v1_5_encode($m, $this->k);
|
||||
} catch (\LengthException $e) {
|
||||
throw new \LengthException('RSA modulus too short');
|
||||
}
|
||||
|
||||
// RSA signature
|
||||
|
||||
$m = $this->os2ip($em);
|
||||
$s = $this->rsasp1($m);
|
||||
$s = $this->i2osp($s, $this->k);
|
||||
|
||||
// Output the signature S
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a signature
|
||||
*
|
||||
* @see self::verify()
|
||||
* @access public
|
||||
* @param string $message
|
||||
* @return string
|
||||
*/
|
||||
public function sign($message)
|
||||
{
|
||||
switch ($this->signaturePadding) {
|
||||
case self::SIGNATURE_PKCS1:
|
||||
case self::SIGNATURE_RELAXED_PKCS1:
|
||||
return $this->rsassa_pkcs1_v1_5_sign($message);
|
||||
//case self::SIGNATURE_PSS:
|
||||
default:
|
||||
return $this->rsassa_pss_sign($message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RSAES-PKCS1-V1_5-DECRYPT
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
|
||||
*
|
||||
* For compatibility purposes, this function departs slightly from the description given in RFC3447.
|
||||
* 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
|
||||
* to be 2 regardless of which key is used. For compatibility purposes, we'll just check to make sure the
|
||||
* second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
|
||||
*
|
||||
* As a consequence of this, a private key encrypted ciphertext produced with \phpseclib\Crypt\RSA may not decrypt
|
||||
* with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
|
||||
* not private key encrypted ciphertext's.
|
||||
*
|
||||
* @access private
|
||||
* @param string $c
|
||||
* @return bool|string
|
||||
*/
|
||||
private function rsaes_pkcs1_v1_5_decrypt($c)
|
||||
{
|
||||
// Length checking
|
||||
|
||||
if (strlen($c) != $this->k) { // or if k < 11
|
||||
return false;
|
||||
}
|
||||
|
||||
// RSA decryption
|
||||
|
||||
$c = $this->os2ip($c);
|
||||
$m = $this->rsadp($c);
|
||||
$em = $this->i2osp($m, $this->k);
|
||||
if ($em === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// EME-PKCS1-v1_5 decoding
|
||||
|
||||
if (ord($em[0]) != 0 || ord($em[1]) > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
|
||||
$m = substr($em, strlen($ps) + 3);
|
||||
|
||||
if (strlen($ps) < 8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Output M
|
||||
|
||||
return $m;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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:
|
||||
*
|
||||
* 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].
|
||||
*
|
||||
* @access private
|
||||
* @param string $c
|
||||
* @return bool|string
|
||||
*/
|
||||
private function rsaes_oaep_decrypt($c)
|
||||
{
|
||||
// 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) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// RSA decryption
|
||||
|
||||
$c = $this->os2ip($c);
|
||||
$m = $this->rsadp($c);
|
||||
$em = $this->i2osp($m, $this->k);
|
||||
if ($em === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// EME-OAEP decoding
|
||||
|
||||
$lHash = $this->hash->hash($this->label);
|
||||
$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);
|
||||
$hashesMatch = hash_equals($lHash, $lHash2);
|
||||
$leadingZeros = 1;
|
||||
$patternMatch = 0;
|
||||
$offset = 0;
|
||||
for ($i = 0; $i < strlen($m); $i++) {
|
||||
$patternMatch|= $leadingZeros & ($m[$i] === "\1");
|
||||
$leadingZeros&= $m[$i] === "\0";
|
||||
$offset+= $patternMatch ? 0 : 1;
|
||||
}
|
||||
|
||||
// we do & instead of && to avoid https://en.wikipedia.org/wiki/Short-circuit_evaluation
|
||||
// to protect against timing attacks
|
||||
if (!$hashesMatch & !$patternMatch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Output the message M
|
||||
|
||||
return substr($m, $offset + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw Encryption / Decryption
|
||||
*
|
||||
* Doesn't use padding and is not recommended.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @return bool|string
|
||||
* @throws \LengthException if strlen($m) > $this->k
|
||||
*/
|
||||
private function raw_encrypt($m)
|
||||
{
|
||||
if (strlen($m) > $this->k) {
|
||||
throw new \LengthException('Message too long');
|
||||
}
|
||||
|
||||
$temp = $this->os2ip($m);
|
||||
$temp = $this->rsadp($temp);
|
||||
return $this->i2osp($temp, $this->k);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decryption
|
||||
*
|
||||
* @see self::encrypt()
|
||||
* @access public
|
||||
* @param string $ciphertext
|
||||
* @param int $padding optional
|
||||
* @return bool|string
|
||||
*/
|
||||
public function decrypt($ciphertext)
|
||||
{
|
||||
switch ($this->encryptionPadding) {
|
||||
case self::ENCRYPTION_NONE:
|
||||
return $this->raw_encrypt($ciphertext);
|
||||
case self::ENCRYPTION_PKCS1:
|
||||
return $this->rsaes_pkcs1_v1_5_decrypt($ciphertext);
|
||||
//case self::ENCRYPTION_OAEP:
|
||||
default:
|
||||
return $this->rsaes_oaep_decrypt($ciphertext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key
|
||||
*
|
||||
* @access public
|
||||
* @param string $type optional
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPublicKey()
|
||||
{
|
||||
$type = self::validatePlugin('Keys', 'PKCS8', 'savePublicKey');
|
||||
if (empty($this->modulus) || empty($this->publicExponent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$key = $type::savePublicKey($this->modulus, $this->publicExponent);
|
||||
return RSA::load($key, 'PKCS8')
|
||||
->withHash($this->hash->getHash())
|
||||
->withMGFHash($this->mgfHash->getHash())
|
||||
->withSaltLength($this->sLen)
|
||||
->withLabel($this->label)
|
||||
->withPadding($this->signaturePadding | $this->encryptionPadding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the private key
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function toString($type)
|
||||
{
|
||||
$type = self::validatePlugin(
|
||||
'Keys',
|
||||
$type,
|
||||
empty($this->primes) ? 'savePublicKey' : 'savePrivateKey'
|
||||
);
|
||||
|
||||
if (empty($this->primes)) {
|
||||
return $type::savePublicKey($this->modulus, $this->exponent);
|
||||
}
|
||||
|
||||
return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password);
|
||||
|
||||
/*
|
||||
$key = $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients, $this->password);
|
||||
if ($key !== false || count($this->primes) == 2) {
|
||||
return $key;
|
||||
}
|
||||
|
||||
$nSize = $this->getSize() >> 1;
|
||||
|
||||
$primes = [1 => clone self::$one, clone self::$one];
|
||||
$i = 1;
|
||||
foreach ($this->primes as $prime) {
|
||||
$primes[$i] = $primes[$i]->multiply($prime);
|
||||
if ($primes[$i]->getLength() >= $nSize) {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
$exponents = [];
|
||||
$coefficients = [2 => $primes[2]->modInverse($primes[1])];
|
||||
|
||||
foreach ($primes as $i => $prime) {
|
||||
$temp = $prime->subtract(self::$one);
|
||||
$exponents[$i] = $this->modulus->modInverse($temp);
|
||||
}
|
||||
|
||||
return $type::savePrivateKey($this->modulus, $this->publicExponent, $this->exponent, $primes, $exponents, $coefficients, $this->password);
|
||||
*/
|
||||
}
|
||||
}
|
496
phpseclib/Crypt/RSA/PublicKey.php
Normal file
496
phpseclib/Crypt/RSA/PublicKey.php
Normal file
@ -0,0 +1,496 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* RSA Public Key
|
||||
*
|
||||
* @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\RSA;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\File\ASN1;
|
||||
use phpseclib\Common\Functions\Strings;
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Exceptions\NoKeyLoadedException;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Crypt\Common;
|
||||
use phpseclib\File\ASN1\Maps\DigestInfo;
|
||||
|
||||
/**
|
||||
* Raw RSA Key Handler
|
||||
*
|
||||
* @package RSA
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access public
|
||||
*/
|
||||
class PublicKey extends RSA implements Common\PublicKey
|
||||
{
|
||||
use Common\Fingerprint;
|
||||
|
||||
/**
|
||||
* Exponentiate
|
||||
*
|
||||
* @param \phpseclib\Math\BigInteger $x
|
||||
* @return \phpseclib\Math\BigInteger
|
||||
*/
|
||||
private function exponentiate(BigInteger $x)
|
||||
{
|
||||
return $x->modPow($this->exponent, $this->modulus);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSAVP1
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
|
||||
*
|
||||
* @access private
|
||||
* @param \phpseclib\Math\BigInteger $s
|
||||
* @return bool|\phpseclib\Math\BigInteger
|
||||
*/
|
||||
private function rsavp1($s)
|
||||
{
|
||||
if ($s->compare(self::$zero) < 0 || $s->compare($this->modulus) > 0) {
|
||||
return false;
|
||||
}
|
||||
return $this->exponentiate($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
|
||||
* @param string $m
|
||||
* @param string $s
|
||||
* @throws \LengthException if the RSA modulus is too short
|
||||
* @return bool
|
||||
*/
|
||||
private function rsassa_pkcs1_v1_5_verify($m, $s)
|
||||
{
|
||||
// Length checking
|
||||
|
||||
if (strlen($s) != $this->k) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// RSA verification
|
||||
|
||||
$s = $this->os2ip($s);
|
||||
$m2 = $this->rsavp1($s);
|
||||
$em = $this->i2osp($m2, $this->k);
|
||||
if ($em === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// EMSA-PKCS1-v1_5 encoding
|
||||
|
||||
// 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) {
|
||||
throw new \LengthException('RSA modulus too short');
|
||||
}
|
||||
|
||||
// Compare
|
||||
return hash_equals($em, $em2);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSASSA-PKCS1-V1_5-VERIFY (relaxed matching)
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @param string $s
|
||||
* @return bool
|
||||
*/
|
||||
private function rsassa_pkcs1_v1_5_relaxed_verify($m, $s)
|
||||
{
|
||||
// Length checking
|
||||
|
||||
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 (Strings::shift($em, 2) != "\0\1") {
|
||||
return false;
|
||||
}
|
||||
|
||||
$em = ltrim($em, "\xFF");
|
||||
if (Strings::shift($em) != "\0") {
|
||||
return false;
|
||||
}
|
||||
|
||||
$decoded = ASN1::decodeBER($em);
|
||||
if (!is_array($decoded) || empty($decoded[0]) || strlen($em) > $decoded[0]['length']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static $oids;
|
||||
if (!isset($oids)) {
|
||||
$oids = [
|
||||
'md2' => '1.2.840.113549.2.2',
|
||||
'md4' => '1.2.840.113549.2.4', // from PKCS1 v1.5
|
||||
'md5' => '1.2.840.113549.2.5',
|
||||
'id-sha1' => '1.3.14.3.2.26',
|
||||
'id-sha256' => '2.16.840.1.101.3.4.2.1',
|
||||
'id-sha384' => '2.16.840.1.101.3.4.2.2',
|
||||
'id-sha512' => '2.16.840.1.101.3.4.2.3',
|
||||
// from PKCS1 v2.2
|
||||
'id-sha224' => '2.16.840.1.101.3.4.2.4',
|
||||
'id-sha512/224' => '2.16.840.1.101.3.4.2.5',
|
||||
'id-sha512/256' => '2.16.840.1.101.3.4.2.6',
|
||||
];
|
||||
ASN1::loadOIDs($oids);
|
||||
}
|
||||
|
||||
$decoded = ASN1::asn1map($decoded[0], DigestInfo::MAP);
|
||||
if (!isset($decoded) || $decoded === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($oids[$decoded['digestAlgorithm']['algorithm']])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hash = $decoded['digestAlgorithm']['algorithm'];
|
||||
$hash = substr($hash, 0, 3) == 'id-' ?
|
||||
substr($hash, 3) :
|
||||
$hash;
|
||||
$hash = new Hash($hash);
|
||||
$em = $hash->hash($m);
|
||||
$em2 = $decoded['digest'];
|
||||
|
||||
return hash_equals($em, $em2);
|
||||
}
|
||||
|
||||
/**
|
||||
* EMSA-PSS-VERIFY
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @param string $em
|
||||
* @param int $emBits
|
||||
* @return string
|
||||
*/
|
||||
private 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);
|
||||
$sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
|
||||
|
||||
$mHash = $this->hash->hash($m);
|
||||
if ($emLen < $this->hLen + $sLen + 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($em[strlen($em) - 1] != chr(0xBC)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$maskedDB = substr($em, 0, -$this->hLen - 1);
|
||||
$h = substr($em, -$this->hLen - 1, $this->hLen);
|
||||
$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);
|
||||
return hash_equals($h, $h2);
|
||||
}
|
||||
|
||||
/**
|
||||
* RSASSA-PSS-VERIFY
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @param string $s
|
||||
* @return bool|string
|
||||
*/
|
||||
private function rsassa_pss_verify($m, $s)
|
||||
{
|
||||
// Length checking
|
||||
|
||||
if (strlen($s) != $this->k) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// RSA verification
|
||||
|
||||
$modBits = 8 * $this->k;
|
||||
|
||||
$s2 = $this->os2ip($s);
|
||||
$m2 = $this->rsavp1($s2);
|
||||
$em = $this->i2osp($m2, $modBits >> 3);
|
||||
if ($em === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// EMSA-PSS verification
|
||||
|
||||
return $this->emsa_pss_verify($m, $em, $modBits - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies a signature
|
||||
*
|
||||
* @see self::sign()
|
||||
* @param string $message
|
||||
* @param string $signature
|
||||
* @return bool
|
||||
*/
|
||||
public function verify($message, $signature)
|
||||
{
|
||||
switch ($this->signaturePadding) {
|
||||
case self::SIGNATURE_RELAXED_PKCS1:
|
||||
return $this->rsassa_pkcs1_v1_5_relaxed_verify($message, $signature);
|
||||
case self::SIGNATURE_PKCS1:
|
||||
return $this->rsassa_pkcs1_v1_5_verify($message, $signature);
|
||||
//case self::SIGNATURE_PSS:
|
||||
default:
|
||||
return $this->rsassa_pss_verify($message, $signature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RSAES-PKCS1-V1_5-ENCRYPT
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @param bool $pkcs15_compat optional
|
||||
* @throws \LengthException if strlen($m) > $this->k - 11
|
||||
* @return bool|string
|
||||
*/
|
||||
private function rsaes_pkcs1_v1_5_encrypt($m, $pkcs15_compat = false)
|
||||
{
|
||||
$mLen = strlen($m);
|
||||
|
||||
// Length checking
|
||||
|
||||
if ($mLen > $this->k - 11) {
|
||||
throw new \LengthException('Message too long');
|
||||
}
|
||||
|
||||
// EME-PKCS1-v1_5 encoding
|
||||
|
||||
$psLen = $this->k - $mLen - 3;
|
||||
$ps = '';
|
||||
while (strlen($ps) != $psLen) {
|
||||
$temp = Random::string($psLen - strlen($ps));
|
||||
$temp = str_replace("\x00", '', $temp);
|
||||
$ps.= $temp;
|
||||
}
|
||||
$type = 2;
|
||||
// see the comments of _rsaes_pkcs1_v1_5_decrypt() to understand why this is being done
|
||||
if ($pkcs15_compat && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
|
||||
$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;
|
||||
|
||||
// RSA encryption
|
||||
$m = $this->os2ip($em);
|
||||
$c = $this->rsaep($m);
|
||||
$c = $this->i2osp($c, $this->k);
|
||||
|
||||
// Output the ciphertext C
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @param string $m
|
||||
* @throws \LengthException if strlen($m) > $this->k - 2 * $this->hLen - 2
|
||||
* @return string
|
||||
*/
|
||||
private function rsaes_oaep_encrypt($m)
|
||||
{
|
||||
$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) {
|
||||
throw new \LengthException('Message too long');
|
||||
}
|
||||
|
||||
// EME-OAEP encoding
|
||||
|
||||
$lHash = $this->hash->hash($this->label);
|
||||
$ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
|
||||
$db = $lHash . $ps . chr(1) . $m;
|
||||
$seed = Random::string($this->hLen);
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* RSAEP
|
||||
*
|
||||
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
|
||||
*
|
||||
* @access private
|
||||
* @param \phpseclib\Math\BigInteger $m
|
||||
* @return bool|\phpseclib\Math\BigInteger
|
||||
*/
|
||||
private function rsaep($m)
|
||||
{
|
||||
if ($m->compare(self::$zero) < 0 || $m->compare($this->modulus) > 0) {
|
||||
return false;
|
||||
}
|
||||
return $this->exponentiate($m);
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw Encryption / Decryption
|
||||
*
|
||||
* Doesn't use padding and is not recommended.
|
||||
*
|
||||
* @access private
|
||||
* @param string $m
|
||||
* @return bool|string
|
||||
* @throws \LengthException if strlen($m) > $this->k
|
||||
*/
|
||||
private function raw_encrypt($m)
|
||||
{
|
||||
if (strlen($m) > $this->k) {
|
||||
throw new \LengthException('Message too long');
|
||||
}
|
||||
|
||||
$temp = $this->os2ip($m);
|
||||
$temp = $this->rsaep($temp);
|
||||
return $this->i2osp($temp, $this->k);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encryption
|
||||
*
|
||||
* Both self::PADDING_OAEP and self::PADDING_PKCS1 both place limits on how long $plaintext can be.
|
||||
* If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
|
||||
* be concatenated together.
|
||||
*
|
||||
* @see self::decrypt()
|
||||
* @access public
|
||||
* @param string $plaintext
|
||||
* @return bool|string
|
||||
* @throws \LengthException if the RSA modulus is too short
|
||||
*/
|
||||
public function encrypt($plaintext)
|
||||
{
|
||||
switch ($this->encryptionPadding) {
|
||||
case self::ENCRYPTION_NONE:
|
||||
return $this->raw_encrypt($plaintext);
|
||||
case self::ENCRYPTION_PKCS15_COMPAT:
|
||||
case self::ENCRYPTION_PKCS1:
|
||||
return $this->rsaes_pkcs1_v1_5_encrypt($plaintext, $padding == self::ENCRYPTION_PKCS15_COMPAT);
|
||||
//case self::ENCRYPTION_OAEP:
|
||||
default:
|
||||
return $this->rsaes_oaep_encrypt($plaintext);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param string $type
|
||||
* @return mixed
|
||||
*/
|
||||
public function toString($type)
|
||||
{
|
||||
$type = self::validatePlugin('Keys', $type, 'savePublicKey');
|
||||
|
||||
return $type::savePublicKey($this->modulus, $this->publicExponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a public key to a private key
|
||||
*
|
||||
* @return RSA
|
||||
*/
|
||||
public function asPrivateKey()
|
||||
{
|
||||
$new = new PrivateKey;
|
||||
$new->exponent = $this->exponent;
|
||||
$new->modulus = $this->modulus;
|
||||
$new->k = $this->k;
|
||||
$new->format = $this->format;
|
||||
return $new
|
||||
->withHash($this->hash->getHash())
|
||||
->withMGFHash($this->mgfHash->getHash())
|
||||
->withSaltLength($this->sLen)
|
||||
->withLabel($this->label)
|
||||
->withPadding($this->signaturePadding | $this->encryptionPadding);
|
||||
}
|
||||
}
|
26
phpseclib/Exception/UnsupportedFormatException.php
Normal file
26
phpseclib/Exception/UnsupportedFormatException.php
Normal file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* UnsupportedFormatException
|
||||
*
|
||||
* PHP version 5
|
||||
*
|
||||
* @category Exception
|
||||
* @package UnsupportedFormatException
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* UnsupportedFormatException
|
||||
*
|
||||
* @package UnsupportedFormatException
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
*/
|
||||
class UnsupportedFormatException extends \RuntimeException
|
||||
{
|
||||
}
|
@ -31,6 +31,10 @@ use ParagonIE\ConstantTime\Hex;
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\DSA;
|
||||
use phpseclib\Crypt\ECDSA;
|
||||
use phpseclib\Crypt\Common\PublicKey;
|
||||
use phpseclib\Crypt\Common\PrivateKey;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
use phpseclib\File\ASN1\Element;
|
||||
use phpseclib\Math\BigInteger;
|
||||
@ -273,18 +277,18 @@ class X509
|
||||
if (!self::$oidsLoaded) {
|
||||
// OIDs from RFC5280 and those RFCs mentioned in RFC5280#section-4.1.1.2
|
||||
ASN1::loadOIDs([
|
||||
'id-pkix' => '1.3.6.1.5.5.7',
|
||||
'id-pe' => '1.3.6.1.5.5.7.1',
|
||||
'id-qt' => '1.3.6.1.5.5.7.2',
|
||||
'id-kp' => '1.3.6.1.5.5.7.3',
|
||||
'id-ad' => '1.3.6.1.5.5.7.48',
|
||||
//'id-pkix' => '1.3.6.1.5.5.7',
|
||||
//'id-pe' => '1.3.6.1.5.5.7.1',
|
||||
//'id-qt' => '1.3.6.1.5.5.7.2',
|
||||
//'id-kp' => '1.3.6.1.5.5.7.3',
|
||||
//'id-ad' => '1.3.6.1.5.5.7.48',
|
||||
'id-qt-cps' => '1.3.6.1.5.5.7.2.1',
|
||||
'id-qt-unotice' => '1.3.6.1.5.5.7.2.2',
|
||||
'id-ad-ocsp' =>'1.3.6.1.5.5.7.48.1',
|
||||
'id-ad-caIssuers' => '1.3.6.1.5.5.7.48.2',
|
||||
'id-ad-timeStamping' => '1.3.6.1.5.5.7.48.3',
|
||||
'id-ad-caRepository' => '1.3.6.1.5.5.7.48.5',
|
||||
'id-at' => '2.5.4',
|
||||
//'id-at' => '2.5.4',
|
||||
'id-at-name' => '2.5.4.41',
|
||||
'id-at-surname' => '2.5.4.4',
|
||||
'id-at-givenName' => '2.5.4.42',
|
||||
@ -307,18 +311,19 @@ class X509
|
||||
'id-at-role' => '2.5.4.72',
|
||||
'id-at-postalAddress' => '2.5.4.16',
|
||||
|
||||
'id-domainComponent' => '0.9.2342.19200300.100.1.25',
|
||||
'pkcs-9' => '1.2.840.113549.1.9',
|
||||
//'id-domainComponent' => '0.9.2342.19200300.100.1.25',
|
||||
//'pkcs-9' => '1.2.840.113549.1.9',
|
||||
'pkcs-9-at-emailAddress' => '1.2.840.113549.1.9.1',
|
||||
'id-ce' => '2.5.29',
|
||||
//'id-ce' => '2.5.29',
|
||||
'id-ce-authorityKeyIdentifier' => '2.5.29.35',
|
||||
'id-ce-subjectKeyIdentifier' => '2.5.29.14',
|
||||
'id-ce-keyUsage' => '2.5.29.15',
|
||||
'id-ce-privateKeyUsagePeriod' => '2.5.29.16',
|
||||
'id-ce-certificatePolicies' => '2.5.29.32',
|
||||
'anyPolicy' => '2.5.29.32.0',
|
||||
//'anyPolicy' => '2.5.29.32.0',
|
||||
|
||||
'id-ce-policyMappings' => '2.5.29.33',
|
||||
|
||||
'id-ce-subjectAltName' => '2.5.29.17',
|
||||
'id-ce-issuerAltName' => '2.5.29.18',
|
||||
'id-ce-subjectDirectoryAttributes' => '2.5.29.9',
|
||||
@ -327,7 +332,7 @@ class X509
|
||||
'id-ce-policyConstraints' => '2.5.29.36',
|
||||
'id-ce-cRLDistributionPoints' => '2.5.29.31',
|
||||
'id-ce-extKeyUsage' => '2.5.29.37',
|
||||
'anyExtendedKeyUsage' => '2.5.29.37.0',
|
||||
//'anyExtendedKeyUsage' => '2.5.29.37.0',
|
||||
'id-kp-serverAuth' => '1.3.6.1.5.5.7.3.1',
|
||||
'id-kp-clientAuth' => '1.3.6.1.5.5.7.3.2',
|
||||
'id-kp-codeSigning' => '1.3.6.1.5.5.7.3.3',
|
||||
@ -344,82 +349,47 @@ class X509
|
||||
'id-ce-cRLReasons' => '2.5.29.21',
|
||||
'id-ce-certificateIssuer' => '2.5.29.29',
|
||||
'id-ce-holdInstructionCode' => '2.5.29.23',
|
||||
'holdInstruction' => '1.2.840.10040.2',
|
||||
//'holdInstruction' => '1.2.840.10040.2',
|
||||
'id-holdinstruction-none' => '1.2.840.10040.2.1',
|
||||
'id-holdinstruction-callissuer' => '1.2.840.10040.2.2',
|
||||
'id-holdinstruction-reject' => '1.2.840.10040.2.3',
|
||||
'id-ce-invalidityDate' => '2.5.29.24',
|
||||
|
||||
'md2' => '1.2.840.113549.2.2',
|
||||
'md5' => '1.2.840.113549.2.5',
|
||||
'id-sha1' => '1.3.14.3.2.26',
|
||||
'id-dsa' => '1.2.840.10040.4.1',
|
||||
'id-dsa-with-sha1' => '1.2.840.10040.4.3',
|
||||
'pkcs-1' => '1.2.840.113549.1.1',
|
||||
'rsaEncryption' => '1.2.840.113549.1.1.1',
|
||||
'md2WithRSAEncryption' => '1.2.840.113549.1.1.2',
|
||||
'md5WithRSAEncryption' => '1.2.840.113549.1.1.4',
|
||||
'sha1WithRSAEncryption' => '1.2.840.113549.1.1.5',
|
||||
'dhpublicnumber' => '1.2.840.10046.2.1',
|
||||
'id-keyExchangeAlgorithm' => '2.16.840.1.101.2.1.1.22',
|
||||
'ansi-X9-62' => '1.2.840.10045',
|
||||
'id-ecSigType' => '1.2.840.10045.4',
|
||||
'ecdsa-with-SHA1' => '1.2.840.10045.4.1',
|
||||
'id-fieldType' => '1.2.840.10045.1',
|
||||
'prime-field' => '1.2.840.10045.1.1',
|
||||
'characteristic-two-field' => '1.2.840.10045.1.2',
|
||||
'id-characteristic-two-basis' => '1.2.840.10045.1.2.3',
|
||||
'gnBasis' => '1.2.840.10045.1.2.3.1',
|
||||
'tpBasis' => '1.2.840.10045.1.2.3.2',
|
||||
'ppBasis' => '1.2.840.10045.1.2.3.3',
|
||||
'id-publicKeyType' => '1.2.840.10045.2',
|
||||
'id-ecPublicKey' => '1.2.840.10045.2.1',
|
||||
'ellipticCurve' => '1.2.840.10045.3',
|
||||
'c-TwoCurve' => '1.2.840.10045.3.0',
|
||||
'c2pnb163v1' => '1.2.840.10045.3.0.1',
|
||||
'c2pnb163v2' => '1.2.840.10045.3.0.2',
|
||||
'c2pnb163v3' => '1.2.840.10045.3.0.3',
|
||||
'c2pnb176w1' => '1.2.840.10045.3.0.4',
|
||||
'c2pnb191v1' => '1.2.840.10045.3.0.5',
|
||||
'c2pnb191v2' => '1.2.840.10045.3.0.6',
|
||||
'c2pnb191v3' => '1.2.840.10045.3.0.7',
|
||||
'c2pnb191v4' => '1.2.840.10045.3.0.8',
|
||||
'c2pnb191v5' => '1.2.840.10045.3.0.9',
|
||||
'c2pnb208w1' => '1.2.840.10045.3.0.10',
|
||||
'c2pnb239v1' => '1.2.840.10045.3.0.11',
|
||||
'c2pnb239v2' => '1.2.840.10045.3.0.12',
|
||||
'c2pnb239v3' => '1.2.840.10045.3.0.13',
|
||||
'c2pnb239v4' => '1.2.840.10045.3.0.14',
|
||||
'c2pnb239v5' => '1.2.840.10045.3.0.15',
|
||||
'c2pnb272w1' => '1.2.840.10045.3.0.16',
|
||||
'c2pnb304w1' => '1.2.840.10045.3.0.17',
|
||||
'c2pnb359v1' => '1.2.840.10045.3.0.18',
|
||||
'c2pnb368w1' => '1.2.840.10045.3.0.19',
|
||||
'c2pnb431r1' => '1.2.840.10045.3.0.20',
|
||||
'primeCurve' => '1.2.840.10045.3.1',
|
||||
'prime192v1' => '1.2.840.10045.3.1.1',
|
||||
'prime192v2' => '1.2.840.10045.3.1.2',
|
||||
'prime192v3' => '1.2.840.10045.3.1.3',
|
||||
'prime239v1' => '1.2.840.10045.3.1.4',
|
||||
'prime239v2' => '1.2.840.10045.3.1.5',
|
||||
'prime239v3' => '1.2.840.10045.3.1.6',
|
||||
'prime256v1' => '1.2.840.10045.3.1.7',
|
||||
'id-RSAES-OAEP' => '1.2.840.113549.1.1.7',
|
||||
'id-pSpecified' => '1.2.840.113549.1.1.9',
|
||||
'id-RSASSA-PSS' => '1.2.840.113549.1.1.10',
|
||||
'id-mgf1' => '1.2.840.113549.1.1.8',
|
||||
'sha224WithRSAEncryption' => '1.2.840.113549.1.1.14',
|
||||
'sha256WithRSAEncryption' => '1.2.840.113549.1.1.11',
|
||||
'sha384WithRSAEncryption' => '1.2.840.113549.1.1.12',
|
||||
'sha512WithRSAEncryption' => '1.2.840.113549.1.1.13',
|
||||
'id-sha224' => '2.16.840.1.101.3.4.2.4',
|
||||
'id-sha256' => '2.16.840.1.101.3.4.2.1',
|
||||
'id-sha384' => '2.16.840.1.101.3.4.2.2',
|
||||
'id-sha512' => '2.16.840.1.101.3.4.2.3',
|
||||
'id-GostR3411-94-with-GostR3410-94' => '1.2.643.2.2.4',
|
||||
'id-GostR3411-94-with-GostR3410-2001' => '1.2.643.2.2.3',
|
||||
'id-GostR3410-2001' => '1.2.643.2.2.20',
|
||||
'id-GostR3410-94' => '1.2.643.2.2.19',
|
||||
|
||||
'id-ecPublicKey' => '1.2.840.10045.2.1',
|
||||
'ecdsa-with-SHA1' => '1.2.840.10045.4.1',
|
||||
// from https://tools.ietf.org/html/rfc5758#section-3.2
|
||||
'ecdsa-with-SHA224' => '1.2.840.10045.4.3.1',
|
||||
'ecdsa-with-SHA256' => '1.2.840.10045.4.3.2',
|
||||
'ecdsa-with-SHA384' => '1.2.840.10045.4.3.3',
|
||||
'ecdsa-with-SHA512' => '1.2.840.10045.4.3.4',
|
||||
|
||||
'id-dsa' => '1.2.840.10040.4.1',
|
||||
'id-dsa-with-sha1' => '1.2.840.10040.4.3',
|
||||
// from https://tools.ietf.org/html/rfc5758#section-3.1
|
||||
'id-dsa-with-sha224' => '2.16.840.1.101.3.4.3.1',
|
||||
'id-dsa-with-sha256' => '2.16.840.1.101.3.4.3.2',
|
||||
|
||||
// from https://tools.ietf.org/html/rfc8410:
|
||||
'id-Ed25519' => '1.3.101.112',
|
||||
'id-Ed448' => '1.3.101.113',
|
||||
|
||||
//'id-sha224' => '2.16.840.1.101.3.4.2.4',
|
||||
//'id-sha256' => '2.16.840.1.101.3.4.2.1',
|
||||
//'id-sha384' => '2.16.840.1.101.3.4.2.2',
|
||||
//'id-sha512' => '2.16.840.1.101.3.4.2.3',
|
||||
//'id-GostR3411-94-with-GostR3410-94' => '1.2.643.2.2.4',
|
||||
//'id-GostR3411-94-with-GostR3410-2001' => '1.2.643.2.2.3',
|
||||
//'id-GostR3410-2001' => '1.2.643.2.2.20',
|
||||
//'id-GostR3410-94' => '1.2.643.2.2.19',
|
||||
// Netscape Object Identifiers from "Netscape Certificate Extensions"
|
||||
'netscape' => '2.16.840.1.113730',
|
||||
'netscape-cert-extension' => '2.16.840.1.113730.1',
|
||||
@ -499,8 +469,12 @@ class X509
|
||||
$this->mapInDNs($x509, 'tbsCertificate/issuer/rdnSequence');
|
||||
$this->mapInDNs($x509, 'tbsCertificate/subject/rdnSequence');
|
||||
|
||||
$key = &$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'];
|
||||
$key = $this->reformatKey($x509['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $key);
|
||||
$key = $x509['tbsCertificate']['subjectPublicKeyInfo'];
|
||||
$key = ASN1::encodeDER($key, Maps\SubjectPublicKeyInfo::MAP);
|
||||
$x509['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'] =
|
||||
"-----BEGIN PUBLIC KEY-----\r\n" .
|
||||
chunk_split(base64_encode($key), 64) .
|
||||
"-----END PUBLIC KEY-----";
|
||||
|
||||
$this->currentCert = $x509;
|
||||
$this->dn = $x509['tbsCertificate']['subject'];
|
||||
@ -531,21 +505,14 @@ class X509
|
||||
case is_object($cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']):
|
||||
break;
|
||||
default:
|
||||
switch ($algorithm) {
|
||||
case 'rsaEncryption':
|
||||
$cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']
|
||||
= "\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']));
|
||||
/* "[For RSA keys] the parameters field MUST have ASN.1 type NULL for this algorithm identifier."
|
||||
-- https://tools.ietf.org/html/rfc3279#section-2.3.1
|
||||
$cert['tbsCertificate']['subjectPublicKeyInfo'] = new Element(
|
||||
base64_decode(preg_replace('#-.+-|[\r\n]#', '', $cert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey']))
|
||||
);
|
||||
}
|
||||
|
||||
given that and the fact that RSA keys appear to be the only key type for which the parameters field can be blank,
|
||||
it seems like perhaps the ASN.1 description ought not say the parameters field is OPTIONAL, but whatever.
|
||||
*/
|
||||
$cert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['parameters'] = null;
|
||||
// https://tools.ietf.org/html/rfc3279#section-2.2.1
|
||||
$cert['signatureAlgorithm']['parameters'] = null;
|
||||
$cert['tbsCertificate']['signature']['parameters'] = null;
|
||||
}
|
||||
if ($algorithm == 'rsaEncryption') {
|
||||
$cert['signatureAlgorithm']['parameters'] = null;
|
||||
$cert['tbsCertificate']['signature']['parameters'] = null;
|
||||
}
|
||||
|
||||
$filters = [];
|
||||
@ -1389,9 +1356,7 @@ class X509
|
||||
{
|
||||
switch ($publicKeyAlgorithm) {
|
||||
case 'rsaEncryption':
|
||||
$rsa = new RSA();
|
||||
$rsa->load($publicKey);
|
||||
|
||||
$key = RSA::load($publicKey, 'PKCS8');
|
||||
switch ($signatureAlgorithm) {
|
||||
case 'md2WithRSAEncryption':
|
||||
case 'md5WithRSAEncryption':
|
||||
@ -1400,10 +1365,41 @@ class X509
|
||||
case 'sha256WithRSAEncryption':
|
||||
case 'sha384WithRSAEncryption':
|
||||
case 'sha512WithRSAEncryption':
|
||||
$rsa->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
|
||||
if (!@$rsa->verify($signatureSubject, $signature, RSA::PADDING_PKCS1)) {
|
||||
return false;
|
||||
}
|
||||
$key = $key
|
||||
->withHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm))
|
||||
->withPadding(RSA::SIGNATURE_PKCS1);
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
|
||||
}
|
||||
break;
|
||||
case 'id-Ed25519':
|
||||
case 'id-Ed448':
|
||||
$key = ECDSA::load($publicKey, 'PKCS8');
|
||||
break;
|
||||
case 'id-ecPublicKey':
|
||||
$key = ECDSA::load($publicKey, 'PKCS8');
|
||||
switch ($signatureAlgorithm) {
|
||||
case 'ecdsa-with-SHA1':
|
||||
case 'ecdsa-with-SHA224':
|
||||
case 'ecdsa-with-SHA256':
|
||||
case 'ecdsa-with-SHA384':
|
||||
case 'ecdsa-with-SHA512':
|
||||
$key = $key
|
||||
->withHash(preg_replace('#^ecdsa-with-#', '', strtolower($signatureAlgorithm)));
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
|
||||
}
|
||||
break;
|
||||
case 'id-dsa':
|
||||
$key = DSA::load($publicKey, 'PKCS8');
|
||||
switch ($signatureAlgorithm) {
|
||||
case 'id-dsa-with-sha1':
|
||||
case 'id-dsa-with-sha224':
|
||||
case 'id-dsa-with-sha256':
|
||||
$key = $key
|
||||
->withHash(preg_replace('#^id-dsa-with-#', '', strtolower($signatureAlgorithm)));
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
|
||||
@ -1413,7 +1409,7 @@ class X509
|
||||
throw new UnsupportedAlgorithmException('Public key algorithm unsupported');
|
||||
}
|
||||
|
||||
return true;
|
||||
return $key->verify($signatureSubject, $signature);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1451,32 +1447,6 @@ class X509
|
||||
self::$disable_url_fetch = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reformat public keys
|
||||
*
|
||||
* Reformats a public key to a format supported by phpseclib (if applicable)
|
||||
*
|
||||
* @param string $algorithm
|
||||
* @param string $key
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
private function reformatKey($algorithm, $key)
|
||||
{
|
||||
switch ($algorithm) {
|
||||
case 'rsaEncryption':
|
||||
return
|
||||
"-----BEGIN RSA PUBLIC KEY-----\r\n" .
|
||||
// subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits
|
||||
// in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox
|
||||
// uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do.
|
||||
chunk_split(Base64::encode(substr($key, 1)), 64) .
|
||||
'-----END RSA PUBLIC KEY-----';
|
||||
default:
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an IP address
|
||||
*
|
||||
@ -2053,9 +2023,8 @@ class X509
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function setPublicKey($key)
|
||||
public function setPublicKey(PublicKey $key)
|
||||
{
|
||||
$key->setPublicKey();
|
||||
$this->publicKey = $key;
|
||||
}
|
||||
|
||||
@ -2067,7 +2036,7 @@ class X509
|
||||
* @param object $key
|
||||
* @access public
|
||||
*/
|
||||
public function setPrivateKey($key)
|
||||
public function setPrivateKey(PrivateKey $key)
|
||||
{
|
||||
$this->privateKey = $key;
|
||||
}
|
||||
@ -2115,15 +2084,16 @@ class X509
|
||||
|
||||
switch ($keyinfo['algorithm']['algorithm']) {
|
||||
case 'rsaEncryption':
|
||||
$publicKey = new RSA();
|
||||
$publicKey->load($key);
|
||||
$publicKey->setPublicKey();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
return RSA::load($key, 'PKCS8');
|
||||
case 'id-ecPublicKey':
|
||||
case 'id-Ed25519':
|
||||
case 'id-Ed448':
|
||||
return ECDSA::load($key, 'PKCS8');
|
||||
case 'id-dsa':
|
||||
return DSA::load($key, 'PKCS8');
|
||||
}
|
||||
|
||||
return $publicKey;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2185,19 +2155,15 @@ class X509
|
||||
|
||||
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
|
||||
|
||||
$algorithm = &$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'];
|
||||
$key = &$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'];
|
||||
$key = $this->reformatKey($algorithm, $key);
|
||||
$key = $csr['certificationRequestInfo']['subjectPKInfo'];
|
||||
$key = ASN1::encodeDER($key, Maps\SubjectPublicKeyInfo::MAP);
|
||||
$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'] =
|
||||
"-----BEGIN PUBLIC KEY-----\r\n" .
|
||||
chunk_split(base64_encode($key), 64) .
|
||||
"-----END PUBLIC KEY-----";
|
||||
|
||||
switch ($algorithm) {
|
||||
case 'rsaEncryption':
|
||||
$this->publicKey = new RSA();
|
||||
$this->publicKey->load($key);
|
||||
$this->publicKey->setPublicKey();
|
||||
break;
|
||||
default:
|
||||
$this->publicKey = null;
|
||||
}
|
||||
$this->publicKey = null;
|
||||
$this->publicKey = $this->getPublicKey();
|
||||
|
||||
$this->currentKeyIdentifier = null;
|
||||
$this->currentCert = $csr;
|
||||
@ -2224,14 +2190,9 @@ class X509
|
||||
case is_object($csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']):
|
||||
break;
|
||||
default:
|
||||
switch ($algorithm) {
|
||||
case 'rsaEncryption':
|
||||
$csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']
|
||||
= "\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']));
|
||||
$csr['certificationRequestInfo']['subjectPKInfo']['algorithm']['parameters'] = null;
|
||||
$csr['signatureAlgorithm']['parameters'] = null;
|
||||
$csr['certificationRequestInfo']['signature']['parameters'] = null;
|
||||
}
|
||||
$csr['certificationRequestInfo']['subjectPKInfo'] = new Element(
|
||||
base64_decode(preg_replace('#-.+-|[\r\n]#', '', $csr['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey']))
|
||||
);
|
||||
}
|
||||
|
||||
$filters = [];
|
||||
@ -2305,18 +2266,15 @@ class X509
|
||||
|
||||
$this->signatureSubject = substr($orig, $decoded[0]['content'][0]['start'], $decoded[0]['content'][0]['length']);
|
||||
|
||||
$algorithm = &$spkac['publicKeyAndChallenge']['spki']['algorithm']['algorithm'];
|
||||
$key = &$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'];
|
||||
$key = $this->reformatKey($algorithm, $key);
|
||||
$key = $spkac['publicKeyAndChallenge']['spki'];
|
||||
$key = ASN1::encodeDER($key, Maps\SubjectPublicKeyInfo::MAP);
|
||||
$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey'] =
|
||||
"-----BEGIN PUBLIC KEY-----\r\n" .
|
||||
chunk_split(base64_encode($key), 64) .
|
||||
"-----END PUBLIC KEY-----";
|
||||
|
||||
switch ($algorithm) {
|
||||
case 'rsaEncryption':
|
||||
$this->publicKey = new RSA();
|
||||
$this->publicKey->load($key);
|
||||
break;
|
||||
default:
|
||||
$this->publicKey = null;
|
||||
}
|
||||
$this->publicKey = null;
|
||||
$this->publicKey = $this->getPublicKey();
|
||||
|
||||
$this->currentKeyIdentifier = null;
|
||||
$this->currentCert = $spkac;
|
||||
@ -2344,11 +2302,9 @@ class X509
|
||||
case is_object($spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']):
|
||||
break;
|
||||
default:
|
||||
switch ($algorithm) {
|
||||
case 'rsaEncryption':
|
||||
$spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']
|
||||
= "\0" . Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']));
|
||||
}
|
||||
$spkac['publicKeyAndChallenge']['spki'] = new Element(
|
||||
base64_decode(preg_replace('#-.+-|[\r\n]#', '', $spkac['publicKeyAndChallenge']['spki']['subjectPublicKey']))
|
||||
);
|
||||
}
|
||||
|
||||
$spkac = ASN1::encodeDER($spkac, Maps\SignedPublicKeyAndChallenge::MAP);
|
||||
@ -2535,7 +2491,7 @@ class X509
|
||||
}
|
||||
|
||||
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
|
||||
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
|
||||
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
|
||||
|
||||
if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
|
||||
$this->currentCert = $subject->currentCert;
|
||||
@ -2713,17 +2669,12 @@ class X509
|
||||
}
|
||||
|
||||
$origPublicKey = $this->publicKey;
|
||||
$class = get_class($this->privateKey);
|
||||
$this->publicKey = new $class();
|
||||
$this->publicKey->load($this->privateKey->getPublicKey());
|
||||
$this->publicKey->setPublicKey();
|
||||
if (!($publicKey = $this->formatSubjectPublicKey())) {
|
||||
return false;
|
||||
}
|
||||
$this->publicKey = $this->privateKey->getPublicKey();
|
||||
$publicKey = $this->formatSubjectPublicKey();
|
||||
$this->publicKey = $origPublicKey;
|
||||
|
||||
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
|
||||
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
|
||||
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
|
||||
|
||||
if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['certificationRequestInfo'])) {
|
||||
$this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
|
||||
@ -2772,18 +2723,12 @@ class X509
|
||||
}
|
||||
|
||||
$origPublicKey = $this->publicKey;
|
||||
$class = get_class($this->privateKey);
|
||||
$this->publicKey = new $class();
|
||||
$this->publicKey->load($this->privateKey->getPublicKey());
|
||||
$this->publicKey->setPublicKey();
|
||||
$this->publicKey = $this->privateKey->getPublicKey();
|
||||
$publicKey = $this->formatSubjectPublicKey();
|
||||
if (!$publicKey) {
|
||||
return false;
|
||||
}
|
||||
$this->publicKey = $origPublicKey;
|
||||
|
||||
$currentCert = isset($this->currentCert) ? $this->currentCert : null;
|
||||
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject: null;
|
||||
$signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
|
||||
|
||||
// re-signing a SPKAC seems silly but since everything else supports re-signing why not?
|
||||
if (isset($this->currentCert) && is_array($this->currentCert) && isset($this->currentCert['publicKeyAndChallenge'])) {
|
||||
@ -2966,7 +2911,7 @@ class X509
|
||||
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
|
||||
* @return mixed
|
||||
*/
|
||||
private function signHelper($key, $signatureAlgorithm)
|
||||
private function signHelper(PrivateKey $key, $signatureAlgorithm)
|
||||
{
|
||||
if ($key instanceof RSA) {
|
||||
switch ($signatureAlgorithm) {
|
||||
@ -2977,9 +2922,52 @@ class X509
|
||||
case 'sha256WithRSAEncryption':
|
||||
case 'sha384WithRSAEncryption':
|
||||
case 'sha512WithRSAEncryption':
|
||||
$key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm));
|
||||
$key = $key
|
||||
->withHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm))
|
||||
->withPadding(RSA::SIGNATURE_PKCS1);
|
||||
$this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject);
|
||||
return $this->currentCert;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
|
||||
}
|
||||
}
|
||||
|
||||
$this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject, RSA::PADDING_PKCS1);
|
||||
if ($key instanceof DSA) {
|
||||
switch ($signatureAlgorithm) {
|
||||
case 'id-dsa-with-sha1':
|
||||
case 'id-dsa-with-sha224':
|
||||
case 'id-dsa-with-sha256':
|
||||
$key = $key
|
||||
->withHash(preg_replace('#^id-dsa-with-#', '', strtolower($signatureAlgorithm)));
|
||||
$this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject);
|
||||
return $this->currentCert;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
|
||||
}
|
||||
}
|
||||
|
||||
if ($key instanceof ECDSA) {
|
||||
switch ($signatureAlgorithm) {
|
||||
case 'id-Ed25519':
|
||||
if ($key->getCurve() !== 'Ed25519') {
|
||||
throw new UnsupportedAlgorithmException('Loaded ECDSA does not use the Ed25519 key and yet that is the signature algorithm that has been chosen');
|
||||
}
|
||||
$this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject);
|
||||
return $this->currentCert;
|
||||
case 'id-Ed448':
|
||||
if ($key->getCurve() !== 'Ed448') {
|
||||
throw new UnsupportedAlgorithmException('Loaded ECDSA does not use the Ed448 key and yet that is the signature algorithm that has been chosen');
|
||||
}
|
||||
$this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject);
|
||||
return $this->currentCert;
|
||||
case 'ecdsa-with-SHA1':
|
||||
case 'ecdsa-with-SHA224':
|
||||
case 'ecdsa-with-SHA256':
|
||||
case 'ecdsa-with-SHA384':
|
||||
case 'ecdsa-with-SHA512':
|
||||
$key = $key
|
||||
->withHash(preg_replace('#^ecdsa-with-#', '', strtolower($signatureAlgorithm)));
|
||||
$this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject);
|
||||
return $this->currentCert;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('Signature algorithm unsupported');
|
||||
@ -3669,17 +3657,14 @@ class X509
|
||||
*/
|
||||
private function formatSubjectPublicKey()
|
||||
{
|
||||
if ($this->publicKey instanceof RSA) {
|
||||
// the following two return statements do the same thing. i dunno.. i just prefer the later for some reason.
|
||||
// the former is a good example of how to do fuzzing on the public key
|
||||
//return new Element(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey()));
|
||||
return [
|
||||
'algorithm' => ['algorithm' => 'rsaEncryption'],
|
||||
'subjectPublicKey' => $this->publicKey->getPublicKey('PKCS1')
|
||||
];
|
||||
}
|
||||
$publicKey = base64_decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey));
|
||||
|
||||
return false;
|
||||
$decoded = ASN1::decodeBER($publicKey);
|
||||
$mapped = ASN1::asn1map($decoded[0], Maps\SubjectPublicKeyInfo::MAP);
|
||||
|
||||
$mapped['subjectPublicKey'] = (string) $this->publicKey;
|
||||
|
||||
return $mapped;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,6 +16,7 @@
|
||||
namespace phpseclib\Math\BigInteger\Engines;
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\RSA\Keys\PKCS8;
|
||||
use phpseclib\Math\BigInteger;
|
||||
|
||||
/**
|
||||
@ -51,11 +52,11 @@ abstract class OpenSSL
|
||||
throw new \OutOfRangeException('Only modulo between 31 and 16384 bits are accepted');
|
||||
}
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load([
|
||||
'e' => new BigInteger($e),
|
||||
'n' => new BigInteger($n)
|
||||
]);
|
||||
$key = PKCS8::savePublicKey(
|
||||
new BigInteger($n),
|
||||
new BigInteger($e)
|
||||
);
|
||||
$rsa = RSA::load($key);
|
||||
//$rsa->setPublicKeyFormat('PKCS1');
|
||||
|
||||
$plaintext = str_pad($x->toBytes(), strlen($n->toBytes(true)) - 1, "\0", STR_PAD_LEFT);
|
||||
|
@ -24,7 +24,7 @@
|
||||
* <?php
|
||||
* include 'vendor/autoload.php';
|
||||
*
|
||||
* $key = new \phpseclib\Crypt\RSA();
|
||||
* \phpseclib\Crypt\PublicKeyLoader::load('...');
|
||||
* //$key->setPassword('whatever');
|
||||
* $key->load(file_get_contents('privatekey'));
|
||||
*
|
||||
@ -49,12 +49,12 @@
|
||||
|
||||
namespace phpseclib\Net;
|
||||
|
||||
use ParagonIE\ConstantTime\Base64;
|
||||
use phpseclib\Crypt\Blowfish;
|
||||
use phpseclib\Crypt\Hash;
|
||||
use phpseclib\Crypt\Random;
|
||||
use phpseclib\Crypt\RC4;
|
||||
use phpseclib\Crypt\Rijndael;
|
||||
use phpseclib\Crypt\Common\PrivateKey;
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\DSA;
|
||||
use phpseclib\Crypt\ECDSA;
|
||||
@ -66,6 +66,7 @@ use phpseclib\System\SSH\Agent;
|
||||
use phpseclib\System\SSH\Agent\Identity as AgentIdentity;
|
||||
use phpseclib\Exception\NoSupportedAlgorithmsException;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
use phpseclib\Exception\UnsupportedCurveException;
|
||||
use phpseclib\Common\Functions\Strings;
|
||||
|
||||
/**
|
||||
@ -2112,9 +2113,11 @@ class SSH2
|
||||
return !is_string($password) && !is_array($password) ? false : $this->keyboard_interactive_process($password);
|
||||
}
|
||||
|
||||
if ($password instanceof RSA) {
|
||||
if ($password instanceof PrivateKey) {
|
||||
return $this->privatekey_login($username, $password);
|
||||
} elseif ($password instanceof Agent) {
|
||||
}
|
||||
|
||||
if ($password instanceof Agent) {
|
||||
return $this->ssh_agent_login($username, $password);
|
||||
}
|
||||
|
||||
@ -2126,6 +2129,10 @@ class SSH2
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_string($password)) {
|
||||
throw new \UnexpectedValueException('$password needs to either be an instance of \phpseclib\Crypt\Common\PrivateKey, \System\SSH\Agent, an array or a string');
|
||||
}
|
||||
|
||||
if (!isset($password)) {
|
||||
$packet = Strings::packSSH2(
|
||||
'Cs3',
|
||||
@ -2361,7 +2368,7 @@ class SSH2
|
||||
* @return bool
|
||||
* @access private
|
||||
*/
|
||||
private function ssh_agent_login($username, $agent)
|
||||
private function ssh_agent_login($username, Agent $agent)
|
||||
{
|
||||
$this->agent = $agent;
|
||||
$keys = $agent->requestIdentities();
|
||||
@ -2378,42 +2385,69 @@ class SSH2
|
||||
* Login with an RSA private key
|
||||
*
|
||||
* @param string $username
|
||||
* @param \phpseclib\Crypt\RSA $password
|
||||
* @param \phpseclib\Crypt\Common\PrivateKey $privatekey
|
||||
* @return bool
|
||||
* @throws \RuntimeException on connection error
|
||||
* @access private
|
||||
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
|
||||
* by sending dummy SSH_MSG_IGNORE messages.
|
||||
*/
|
||||
private function privatekey_login($username, $privatekey)
|
||||
private function privatekey_login($username, PrivateKey $privatekey)
|
||||
{
|
||||
// see http://tools.ietf.org/html/rfc4253#page-15
|
||||
$publickey = $privatekey->getPublicKey('Raw');
|
||||
if ($publickey === false) {
|
||||
return false;
|
||||
$publickey = $privatekey->getPublicKey();
|
||||
|
||||
if ($publickey instanceof RSA) {
|
||||
$privatekey = $privatekey->withPadding(RSA::SIGNATURE_PKCS1);
|
||||
switch ($this->signature_format) {
|
||||
case 'rsa-sha2-512':
|
||||
$hash = 'sha512';
|
||||
$signatureType = 'rsa-sha2-512';
|
||||
break;
|
||||
case 'rsa-sha2-256':
|
||||
$hash = 'sha256';
|
||||
$signatureType = 'rsa-sha2-256';
|
||||
break;
|
||||
//case 'ssh-rsa':
|
||||
default:
|
||||
$hash = 'sha1';
|
||||
$signatureType = 'ssh-rsa';
|
||||
}
|
||||
} else if ($publickey instanceof ECDSA) {
|
||||
$privatekey = $privatekey->withSignatureFormat('SSH2');
|
||||
$curveName = $privatekey->getCurve();
|
||||
switch ($curveName) {
|
||||
case 'Ed25519':
|
||||
$hash = 'sha512';
|
||||
$signatureType = 'ssh-ed25519';
|
||||
break;
|
||||
case 'secp256r1': // nistp256
|
||||
$hash = 'sha256';
|
||||
$signatureType = 'ecdsa-sha2-nistp256';
|
||||
break;
|
||||
case 'secp384r1': // nistp384
|
||||
$hash = 'sha384';
|
||||
$signatureType = 'ecdsa-sha2-nistp384';
|
||||
break;
|
||||
case 'secp521r1': // nistp521
|
||||
$hash = 'sha512';
|
||||
$signatureType = 'ecdsa-sha2-nistp521';
|
||||
break;
|
||||
default:
|
||||
if (is_array($curveName)) {
|
||||
throw new UnsupportedCurveException('Specified Curves are not supported by SSH2');
|
||||
}
|
||||
throw new UnsupportedCurveException('Named Curve of ' . $curveName . ' is not supported by phpseclib\'s SSH2 implementation');
|
||||
}
|
||||
} else if ($publickey instanceof DSA) {
|
||||
$privatekey = $privatekey->withSignatureFormat('SSH2');
|
||||
$hash = 'sha1';
|
||||
$signatureType = 'ssh-dss';
|
||||
} else {
|
||||
throw new UnsupportedAlgorithmException('Please use either an RSA key, an ECDSA one or a DSA key');
|
||||
}
|
||||
|
||||
$publickey = Strings::packSSH2(
|
||||
'sii',
|
||||
'ssh-rsa',
|
||||
$publickey['e'],
|
||||
$publickey['n']
|
||||
);
|
||||
|
||||
switch ($this->signature_format) {
|
||||
case 'rsa-sha2-512':
|
||||
$hash = 'sha512';
|
||||
$signatureType = 'rsa-sha2-512';
|
||||
break;
|
||||
case 'rsa-sha2-256':
|
||||
$hash = 'sha256';
|
||||
$signatureType = 'rsa-sha2-256';
|
||||
break;
|
||||
//case 'ssh-rsa':
|
||||
default:
|
||||
$hash = 'sha1';
|
||||
$signatureType = 'ssh-rsa';
|
||||
}
|
||||
$publickeyStr = $publickey->toString('OpenSSH');
|
||||
$publickeyStr = base64_decode(preg_replace('#(^.*? )|( .*?)$#', '', $publickeyStr));
|
||||
|
||||
$part1 = Strings::packSSH2(
|
||||
'Csss',
|
||||
@ -2422,7 +2456,7 @@ class SSH2
|
||||
'ssh-connection',
|
||||
'publickey'
|
||||
);
|
||||
$part2 = Strings::packSSH2('ss', $signatureType, $publickey);
|
||||
$part2 = Strings::packSSH2('ss', $signatureType, $publickeyStr);
|
||||
|
||||
$packet = $part1 . chr(0) . $part2;
|
||||
$this->send_binary_packet($packet);
|
||||
@ -2438,7 +2472,6 @@ class SSH2
|
||||
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
||||
list($message) = Strings::unpackSSH2('s', $response);
|
||||
$this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $message;
|
||||
|
||||
return false;
|
||||
case NET_SSH2_MSG_USERAUTH_PK_OK:
|
||||
// we'll just take it on faith that the public key blob and the public key algorithm name are as
|
||||
@ -2453,9 +2486,11 @@ class SSH2
|
||||
}
|
||||
|
||||
$packet = $part1 . chr(1) . $part2;
|
||||
$privatekey->setHash($hash);
|
||||
$signature = $privatekey->sign(Strings::packSSH2('s', $this->session_id) . $packet, RSA::PADDING_PKCS1);
|
||||
$signature = Strings::packSSH2('ss', $signatureType, $signature);
|
||||
$privatekey = $privatekey->withHash($hash);
|
||||
$signature = $privatekey->sign(Strings::packSSH2('s', $this->session_id) . $packet);
|
||||
if ($publickey instanceof RSA) {
|
||||
$signature = Strings::packSSH2('ss', $signatureType, $signature);
|
||||
}
|
||||
$packet.= Strings::packSSH2('s', $signature);
|
||||
|
||||
$this->send_binary_packet($packet);
|
||||
@ -4258,6 +4293,8 @@ class SSH2
|
||||
return [
|
||||
'ssh-ed25519', // https://tools.ietf.org/html/draft-ietf-curdle-ssh-ed25519-02
|
||||
'ecdsa-sha2-nistp256', // RFC 5656
|
||||
'ecdsa-sha2-nistp384', // RFC 5656
|
||||
'ecdsa-sha2-nistp521', // RFC 5656
|
||||
'rsa-sha2-256', // RFC 8332
|
||||
'rsa-sha2-512', // RFC 8332
|
||||
'ssh-rsa', // RECOMMENDED sign Raw RSA Key
|
||||
@ -4553,7 +4590,7 @@ class SSH2
|
||||
|
||||
if ($this->signature_validated) {
|
||||
return $this->bitmap ?
|
||||
$this->signature_format . ' ' . Base64::encode($this->server_public_host_key) :
|
||||
$this->signature_format . ' ' . $server_public_host_key :
|
||||
false;
|
||||
}
|
||||
|
||||
@ -4562,27 +4599,30 @@ class SSH2
|
||||
switch ($this->signature_format) {
|
||||
case 'ssh-ed25519':
|
||||
case 'ecdsa-sha2-nistp256':
|
||||
$ec = new ECDSA();
|
||||
$ec->load($server_public_host_key, 'OpenSSH');
|
||||
case 'ecdsa-sha2-nistp384':
|
||||
case 'ecdsa-sha2-nistp521':
|
||||
$key = ECDSA::load($server_public_host_key, 'OpenSSH')
|
||||
->withSignatureFormat('SSH2');
|
||||
switch ($this->signature_format) {
|
||||
case 'ssh-ed25519':
|
||||
//$ec->setHash('sha512');
|
||||
Strings::shift($signature, 4 + strlen('ssh-ed25519') + 4);
|
||||
$hash = 'sha512';
|
||||
break;
|
||||
case 'ecdsa-sha2-nistp256':
|
||||
$ec->setHash('sha256');
|
||||
$hash = 'sha256';
|
||||
break;
|
||||
case 'ecdsa-sha2-nistp384':
|
||||
$hash = 'sha384';
|
||||
break;
|
||||
case 'ecdsa-sha2-nistp521':
|
||||
$hash = 'sha512';
|
||||
}
|
||||
if (!$ec->verify($this->exchange_hash, $signature, 'SSH2')) {
|
||||
return $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
};
|
||||
$key = $key->withHash($hash);
|
||||
break;
|
||||
case 'ssh-dss':
|
||||
$dsa = new DSA();
|
||||
$dsa->load($server_public_host_key, 'OpenSSH');
|
||||
$dsa->setHash('sha1');
|
||||
if (!$dsa->verify($this->exchange_hash, $signature, 'SSH2')) {
|
||||
return $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
};
|
||||
$key = DSA::load($server_public_host_key, 'OpenSSH')
|
||||
->withSignatureFormat('SSH2')
|
||||
->withHash('sha1');
|
||||
break;
|
||||
case 'ssh-rsa':
|
||||
case 'rsa-sha2-256':
|
||||
@ -4594,8 +4634,8 @@ class SSH2
|
||||
$temp = unpack('Nlength', Strings::shift($signature, 4));
|
||||
$signature = Strings::shift($signature, $temp['length']);
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($server_public_host_key, 'OpenSSH');
|
||||
$key = RSA::load($server_public_host_key, 'OpenSSH')
|
||||
->withPadding(RSA::SIGNATURE_PKCS1);
|
||||
switch ($this->signature_format) {
|
||||
case 'rsa-sha2-512':
|
||||
$hash = 'sha512';
|
||||
@ -4607,17 +4647,18 @@ class SSH2
|
||||
default:
|
||||
$hash = 'sha1';
|
||||
}
|
||||
$rsa->setHash($hash);
|
||||
if (!$rsa->verify($this->exchange_hash, $signature, RSA::PADDING_PKCS1)) {
|
||||
return $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
}
|
||||
$key = $key->withHash($hash);
|
||||
break;
|
||||
default:
|
||||
$this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
throw new NoSupportedAlgorithmsException('Unsupported signature format');
|
||||
}
|
||||
|
||||
return $this->signature_format . ' ' . Base64::encode($this->server_public_host_key);
|
||||
if (!$key->verify($this->exchange_hash, $signature)) {
|
||||
return $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
||||
};
|
||||
|
||||
return $this->signature_format . ' ' . $server_public_host_key;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -38,6 +38,7 @@ use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Exception\BadConfigurationException;
|
||||
use phpseclib\System\SSH\Agent\Identity;
|
||||
use phpseclib\Common\Functions\Strings;
|
||||
use phpseclib\Crypt\PublicKeyLoader;
|
||||
|
||||
/**
|
||||
* Pure-PHP ssh-agent client identity factory
|
||||
@ -198,9 +199,8 @@ class Agent
|
||||
$temp = $key_blob;
|
||||
list($key_type) = Strings::unpackSSH2('s', $temp);
|
||||
switch ($key_type) {
|
||||
case 'ssh-rsa':
|
||||
$key = new RSA();
|
||||
$key->load($key_str);
|
||||
case 'ssh-rsa':
|
||||
$key = PublicKeyLoader::load(base64_encode($key_blob));
|
||||
break;
|
||||
case 'ssh-dss':
|
||||
// not currently supported
|
||||
|
@ -20,6 +20,8 @@ use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Exception\UnsupportedAlgorithmException;
|
||||
use phpseclib\System\SSH\Agent;
|
||||
use phpseclib\Common\Functions\Strings;
|
||||
use phpseclib\Crypt\Common\PrivateKey;
|
||||
|
||||
|
||||
/**
|
||||
* Pure-PHP ssh-agent client identity object
|
||||
@ -34,7 +36,7 @@ use phpseclib\Common\Functions\Strings;
|
||||
* @author Jim Wigginton <terrafrost@php.net>
|
||||
* @access internal
|
||||
*/
|
||||
class Identity
|
||||
class Identity implements PrivateKey
|
||||
{
|
||||
/**@+
|
||||
* Signature Flags
|
||||
@ -107,7 +109,6 @@ class Identity
|
||||
public function setPublicKey($key)
|
||||
{
|
||||
$this->key = $key;
|
||||
$this->key->setPublicKey();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -135,32 +136,48 @@ class Identity
|
||||
*/
|
||||
public function getPublicKey($type = 'PKCS8')
|
||||
{
|
||||
return $this->key->getPublicKey($type);
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hash
|
||||
*
|
||||
* ssh-agent only supports signatures with sha1 hashes but to maintain BC with RSA.php this function exists
|
||||
*
|
||||
* @param string $hash optional
|
||||
* @param string $hash
|
||||
* @access public
|
||||
*/
|
||||
public function setHash($hash)
|
||||
public function withHash($hash)
|
||||
{
|
||||
$this->flags = 0;
|
||||
$new = clone $this;
|
||||
$new->flags = 0;
|
||||
switch ($hash) {
|
||||
case 'sha1':
|
||||
break;
|
||||
case 'sha256':
|
||||
$this->flags = self::SSH_AGENT_RSA2_256;
|
||||
$new->flags = self::SSH_AGENT_RSA2_256;
|
||||
break;
|
||||
case 'sha512':
|
||||
$this->flags = self::SSH_AGENT_RSA2_512;
|
||||
$new->flags = self::SSH_AGENT_RSA2_512;
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedAlgorithmException('The only supported hashes for RSA are sha1, sha256 and sha512');
|
||||
}
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the padding
|
||||
*
|
||||
* Only PKCS1 padding is supported
|
||||
*
|
||||
* @param string $padding
|
||||
* @access public
|
||||
*/
|
||||
public function withPadding($padding = RSA::SIGNATURE_PKCS1)
|
||||
{
|
||||
if ($padding != RSA::SIGNATURE_PKCS1 && $padding != RSA::SIGNATURE_RELAXED_PKCS1) {
|
||||
throw new UnsupportedAlgorithmException('ssh-agent can only create PKCS1 signatures');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,12 +192,8 @@ class Identity
|
||||
* @throws \phpseclib\Exception\UnsupportedAlgorithmException if the algorithm is unsupported
|
||||
* @access public
|
||||
*/
|
||||
public function sign($message, $padding = RSA::PADDING_PKCS1)
|
||||
public function sign($message)
|
||||
{
|
||||
if ($padding != RSA::PADDING_PKCS1 && $padding != RSA::PADDING_RELAXED_PKCS1) {
|
||||
throw new UnsupportedAlgorithmException('ssh-agent can only create PKCS1 signatures');
|
||||
}
|
||||
|
||||
// the last parameter (currently 0) is for flags and ssh-agent only defines one flag (for ssh-dss): SSH_AGENT_OLD_SIGNATURE
|
||||
$packet = Strings::packSSH2(
|
||||
'CssN',
|
||||
@ -206,4 +219,26 @@ class Identity
|
||||
|
||||
return $signature_blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the private key
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public function toString($type)
|
||||
{
|
||||
throw new \RuntimeException('ssh-agent does not provide a mechanism to get the private key');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the password
|
||||
*
|
||||
* @access public
|
||||
* @param string|boolean $password
|
||||
*/
|
||||
public function withPassword($password = false)
|
||||
{
|
||||
throw new \RuntimeException('ssh-agent does not provide a mechanism to get the private key');
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,9 @@
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\DSA;
|
||||
use phpseclib\Crypt\DSA\Parameters;
|
||||
use phpseclib\Crypt\DSA\PublicKey;
|
||||
use phpseclib\Crypt\DSA\PrivateKey;
|
||||
|
||||
/**
|
||||
* @requires PHP 7.0
|
||||
@ -16,14 +19,17 @@ class Unit_Crypt_DSA_CreateKeyTest extends PhpseclibTestCase
|
||||
public function testCreateParameters()
|
||||
{
|
||||
$dsa = DSA::createParameters();
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\DSA', $dsa);
|
||||
$this->assertInstanceOf(Parameters::class, $dsa);
|
||||
$this->assertRegexp('#BEGIN DSA PARAMETERS#', "$dsa");
|
||||
|
||||
$dsa = DSA::createParameters(100, 100);
|
||||
$this->assertFalse($dsa);
|
||||
try {
|
||||
$dsa = DSA::createParameters(100, 100);
|
||||
} catch (Exception $e) {
|
||||
$this->assertInstanceOf(Exception::class, $e);
|
||||
}
|
||||
|
||||
$dsa = DSA::createParameters(512, 160);
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\DSA', $dsa);
|
||||
$this->assertInstanceOf(Parameters::class, $dsa);
|
||||
$this->assertRegexp('#BEGIN DSA PARAMETERS#', "$dsa");
|
||||
|
||||
return $dsa;
|
||||
@ -34,17 +40,17 @@ class Unit_Crypt_DSA_CreateKeyTest extends PhpseclibTestCase
|
||||
*/
|
||||
public function testCreateKey($params)
|
||||
{
|
||||
extract(DSA::createKey());
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\DSA', $privatekey);
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\DSA', $publickey);
|
||||
$privatekey = DSA::createKey();
|
||||
$this->assertInstanceOf(PrivateKey::class, $privatekey);
|
||||
$this->assertInstanceOf(PublicKey::class, $privatekey->getPublicKey());
|
||||
|
||||
extract(DSA::createKey($params));
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\DSA', $privatekey);
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\DSA', $publickey);
|
||||
$privatekey = DSA::createKey($params);
|
||||
$this->assertInstanceOf(PrivateKey::class, $privatekey);
|
||||
$this->assertInstanceOf(PublicKey::class, $privatekey->getPublicKey());
|
||||
|
||||
extract(DSA::createKey(512, 160));
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\DSA', $privatekey);
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\DSA', $publickey);
|
||||
$privatekey = DSA::createKey(512, 160);
|
||||
$this->assertInstanceOf(PrivateKey::class, $privatekey);
|
||||
$this->assertInstanceOf(PublicKey::class, $privatekey->getPublicKey());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,10 @@
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\DSA;
|
||||
use phpseclib\Crypt\PublicKeyLoader;
|
||||
use phpseclib\Crypt\DSA\PrivateKey;
|
||||
use phpseclib\Crypt\DSA\PublicKey;
|
||||
use phpseclib\Crypt\DSA\Parameters;
|
||||
use phpseclib\Crypt\DSA\Keys\PKCS1;
|
||||
use phpseclib\Crypt\DSA\Keys\PKCS8;
|
||||
use phpseclib\Crypt\DSA\Keys\PuTTY;
|
||||
@ -13,18 +16,17 @@ use phpseclib\Math\BigInteger;
|
||||
|
||||
class Unit_Crypt_DSA_LoadKeyTest extends PhpseclibTestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \phpseclib\Exception\NoKeyLoadedException
|
||||
*/
|
||||
public function testBadKey()
|
||||
{
|
||||
$dsa = new DSA();
|
||||
|
||||
$key = 'zzzzzzzzzzzzzz';
|
||||
|
||||
$this->assertFalse($dsa->load($key));
|
||||
PublicKeyLoader::load($key);
|
||||
}
|
||||
|
||||
public function testPuTTYKey()
|
||||
{
|
||||
$dsa = new DSA();
|
||||
|
||||
$key = 'PuTTY-User-Key-File-2: ssh-dss
|
||||
Encryption: none
|
||||
Comment: dsa-key-20161223
|
||||
@ -52,23 +54,19 @@ AAAAFFMy7BG9rPXwzqZzIY/lqsHEILNf
|
||||
Private-MAC: 62b92ddd8b341b9414d640c24ba6ae929a78e039
|
||||
';
|
||||
|
||||
$dsa->setPrivateKeyFormat('PuTTY');
|
||||
$dsa->setPublicKeyFormat('PuTTY');
|
||||
$dsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertTrue($dsa->load($key));
|
||||
$this->assertInstanceOf(PrivateKey::class, $dsa);
|
||||
$this->assertInternalType('string', "$dsa");
|
||||
$this->assertSame("$dsa", $dsa->getPrivateKey('PuTTY'));
|
||||
$this->assertInternalType('string', $dsa->getPublicKey('PuTTY'));
|
||||
$this->assertInternalType('string', $dsa->getParameters());
|
||||
$this->assertInternalType('string', $dsa->getPublicKey()->toString('PuTTY'));
|
||||
$this->assertInternalType('string', $dsa->getParameters()->toString('PuTTY'));
|
||||
|
||||
$dsa->setPassword('password');
|
||||
$dsa = $dsa->withPassword('password');
|
||||
$this->assertGreaterThan(0, strlen("$dsa"));
|
||||
}
|
||||
|
||||
public function testPKCS1Key()
|
||||
{
|
||||
$dsa = new DSA();
|
||||
|
||||
$key = '-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIDPQIBAAKCAQEAiwfUDxLuCgQSd5boP/MleHXPKllGUqXDu81onvJeL2+pSQqd
|
||||
NJcr2VHj+djLhJVNxUCljSwRTZFIOuJ0tPLjRl4w8Csf6zFHuUJJnYC42r2xDG7p
|
||||
@ -90,20 +88,16 @@ yVFGWdP2B4Gyj85IXCm3r+JNVoV5tVX9IUBTXnUor7YfWNncwWn56Lc+RQIUUzLs
|
||||
Eb2s9fDOpnMhj+WqwcQgs18=
|
||||
-----END DSA PRIVATE KEY-----';
|
||||
|
||||
$dsa->setPrivateKeyFormat('PKCS1');
|
||||
$dsa->setPublicKeyFormat('PKCS1');
|
||||
$dsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertTrue($dsa->load($key));
|
||||
$this->assertInstanceOf(PrivateKey::class, $dsa);
|
||||
$this->assertInternalType('string', "$dsa");
|
||||
$this->assertSame("$dsa", $dsa->getPrivateKey('PKCS1'));
|
||||
$this->assertInternalType('string', $dsa->getPublicKey('PKCS1'));
|
||||
$this->assertInternalType('string', $dsa->getParameters());
|
||||
$this->assertInternalType('string', $dsa->getPublicKey()->toString('PKCS1'));
|
||||
$this->assertInternalType('string', (string) $dsa->getParameters());
|
||||
}
|
||||
|
||||
public function testParameters()
|
||||
{
|
||||
$dsa = new DSA();
|
||||
|
||||
$key = '-----BEGIN DSA PARAMETERS-----
|
||||
MIIBHgKBgQDandMycPZNOEwDXpIDSdFODWOQVO5tlnt38wK0X33TJh4wQdqOSiVF
|
||||
I+g+X8reP43ag3TEHu5bstrk6Znm7y1htTTvXQVTEwp6X3YHXbJG4Faul3g08Vud
|
||||
@ -114,16 +108,15 @@ L1cwyXx0KMaaampd34MzOIHbC44SHY+cE3aVVUsnmt6Ur1nQaVYVszl+AO6m8bPm
|
||||
4Vg=
|
||||
-----END DSA PARAMETERS-----';
|
||||
$key = str_replace(["\n", "\r"], '', $key);
|
||||
$dsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertTrue($dsa->load($key));
|
||||
$this->assertInstanceOf(Parameters::class, $dsa);
|
||||
$this->assertSame($key, str_replace(["\n", "\r"], '', "$dsa"));
|
||||
$this->assertSame($key, str_replace(["\n", "\r"], '', $dsa->getParameters()));
|
||||
$this->assertSame($key, str_replace(["\n", "\r"], '', (string) $dsa->getParameters()));
|
||||
}
|
||||
|
||||
public function testPKCS8Public()
|
||||
{
|
||||
$dsa = new DSA();
|
||||
|
||||
$key = '-----BEGIN PUBLIC KEY-----
|
||||
MIIBtjCCASsGByqGSM44BAEwggEeAoGBANqd0zJw9k04TANekgNJ0U4NY5BU7m2W
|
||||
e3fzArRffdMmHjBB2o5KJUUj6D5fyt4/jdqDdMQe7luy2uTpmebvLWG1NO9dBVMT
|
||||
@ -137,14 +130,14 @@ ZpmyOpXM/0opRMIRdmqVW4ardBFNokmlqngwcbaptfRnk9W2cQtx0lmKy6X/vnis
|
||||
3AElwP86TYgBhw==
|
||||
-----END PUBLIC KEY-----';
|
||||
|
||||
$this->assertTrue($dsa->load($key));
|
||||
$dsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertInstanceOf(PublicKey::class, $dsa);
|
||||
$this->assertInternalType('string', "$dsa");
|
||||
}
|
||||
|
||||
public function testPKCS8Private()
|
||||
{
|
||||
$dsa = new DSA();
|
||||
|
||||
$key = '-----BEGIN PRIVATE KEY-----
|
||||
MIIBSgIBADCCASsGByqGSM44BAEwggEeAoGBANqd0zJw9k04TANekgNJ0U4NY5BU
|
||||
7m2We3fzArRffdMmHjBB2o5KJUUj6D5fyt4/jdqDdMQe7luy2uTpmebvLWG1NO9d
|
||||
@ -155,20 +148,19 @@ rgPJisERm7NDMd6J9o7qUG8NI18vVzDJfHQoxppqal3fgzM4gdsLjhIdj5wTdpVV
|
||||
Syea3pSvWdBpVhWzOX4A7qbxs+bhWAQWAhQiF7sFfCtZ7oOgCb2aJ9ySC9sTug==
|
||||
-----END PRIVATE KEY-----';
|
||||
|
||||
$this->assertTrue($dsa->load($key));
|
||||
$dsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertInstanceOf(PrivateKey::class, $dsa);
|
||||
$this->assertInternalType('string', "$dsa");
|
||||
$this->assertSame("$dsa", $dsa->getPrivateKey());
|
||||
$this->assertInstanceOf(DSA::class, $dsa->getPublicKey());
|
||||
$this->assertInternalType('string', $dsa->getParameters());
|
||||
$this->assertInstanceOf(PublicKey::class, $dsa->getPublicKey());
|
||||
$this->assertInstanceOf(Parameters::class, $dsa->getParameters());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \UnexpectedValueException
|
||||
* @expectedException \phpseclib\Exception\NoKeyLoadedException
|
||||
*/
|
||||
public function testPuTTYBadMAC()
|
||||
{
|
||||
$dsa = new DSA();
|
||||
|
||||
$key = 'PuTTY-User-Key-File-2: ssh-dss
|
||||
Encryption: none
|
||||
Comment: dsa-key-20161223
|
||||
@ -196,14 +188,11 @@ AAAAFFMy7BG9rPXwzqZzIY/lqsHEILNf
|
||||
Private-MAC: aaaaaadd8b341b9414d640c24ba6ae929a78e039
|
||||
';
|
||||
|
||||
$this->assertFalse($dsa->load($key));
|
||||
$dsa->load($key, 'PuTTY');
|
||||
PublicKeyLoader::load($key);
|
||||
}
|
||||
|
||||
public function testXML()
|
||||
{
|
||||
$dsa = new DSA();
|
||||
|
||||
$key = '-----BEGIN PUBLIC KEY-----
|
||||
MIIBtjCCASsGByqGSM44BAEwggEeAoGBANqd0zJw9k04TANekgNJ0U4NY5BU7m2W
|
||||
e3fzArRffdMmHjBB2o5KJUUj6D5fyt4/jdqDdMQe7luy2uTpmebvLWG1NO9dBVMT
|
||||
@ -217,13 +206,12 @@ ZpmyOpXM/0opRMIRdmqVW4ardBFNokmlqngwcbaptfRnk9W2cQtx0lmKy6X/vnis
|
||||
3AElwP86TYgBhw==
|
||||
-----END PUBLIC KEY-----';
|
||||
|
||||
$dsa->load($key);
|
||||
$xml = $dsa->getPublicKey('XML');
|
||||
$dsa = PublicKeyLoader::load($key);
|
||||
$xml = $dsa->toString('XML');
|
||||
$this->assertContains('DSAKeyValue', $xml);
|
||||
|
||||
$dsa = new DSA();
|
||||
$dsa->load($xml);
|
||||
$pkcs8 = $dsa->getPublicKey('PKCS8');
|
||||
$dsa = PublicKeyLoader::load($xml);
|
||||
$pkcs8 = $dsa->toString('PKCS8');
|
||||
|
||||
$this->assertSame(
|
||||
strtolower(preg_replace('#\s#', '', $pkcs8)),
|
||||
|
@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\DSA;
|
||||
use phpseclib\Crypt\PublicKeyLoader;
|
||||
|
||||
class Unit_Crypt_DSA_SignatureTest extends PhpseclibTestCase
|
||||
{
|
||||
@ -14,9 +15,7 @@ class Unit_Crypt_DSA_SignatureTest extends PhpseclibTestCase
|
||||
{
|
||||
$message = 'hello, world!';
|
||||
|
||||
$dsa = new DSA();
|
||||
|
||||
$dsa->load('-----BEGIN DSA PRIVATE KEY-----
|
||||
$dsa = PublicKeyLoader::load('-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIBvAIBAAKBgQDsGAHAM16bsPlwl7jaec4QMynYa0YLiLiOZC4mvH4UW/tRJxTz
|
||||
aV7eH1EtnP9D9J78x/07wKYs8zJEWCXmuq0UluQfjA47+pb68b/ucQTNeZHboNN9
|
||||
5oEi+8BCSK0y8G3uf3Y89qHvqa9Si6rP374MinEMrbVFm+UpsGflFcd83wIVALtJ
|
||||
@ -27,10 +26,11 @@ CCBGBQJRAoGBALnHTAZlpoLJZuSBVtnMuRM3cSX43IkE9w9FveDV1jX5mmfK7yBV
|
||||
pQFV8eVJfk91ERQ4Dn6ePLUv2dRIt4a0S0qHqadgzyoFyqkmmUi1kNLyixtRqh+m
|
||||
2gXx0t63HEpZDbEPppdpnlppZquVQh7TyrKSXW9MTzUkQjFI9UY7kZeKAhQXiJgI
|
||||
kBniZHdFBAZBTE14YJUBkw==
|
||||
-----END DSA PRIVATE KEY-----');
|
||||
$signature = $dsa->sign($message, 'ASN1');
|
||||
-----END DSA PRIVATE KEY-----')
|
||||
->withSignatureFormat('ASN1');
|
||||
$signature = $dsa->sign($message);
|
||||
|
||||
$dsa->load('-----BEGIN PUBLIC KEY-----
|
||||
$dsa = PublicKeyLoader::load('-----BEGIN PUBLIC KEY-----
|
||||
MIIBuDCCASwGByqGSM44BAEwggEfAoGBAOwYAcAzXpuw+XCXuNp5zhAzKdhrRguI
|
||||
uI5kLia8fhRb+1EnFPNpXt4fUS2c/0P0nvzH/TvApizzMkRYJea6rRSW5B+MDjv6
|
||||
lvrxv+5xBM15kdug033mgSL7wEJIrTLwbe5/djz2oe+pr1KLqs/fvgyKcQyttUWb
|
||||
@ -41,37 +41,36 @@ jhGOrO+kJcZBxUSxINgIIEYFAlEDgYUAAoGBALnHTAZlpoLJZuSBVtnMuRM3cSX4
|
||||
3IkE9w9FveDV1jX5mmfK7yBVpQFV8eVJfk91ERQ4Dn6ePLUv2dRIt4a0S0qHqadg
|
||||
zyoFyqkmmUi1kNLyixtRqh+m2gXx0t63HEpZDbEPppdpnlppZquVQh7TyrKSXW9M
|
||||
TzUkQjFI9UY7kZeK
|
||||
-----END PUBLIC KEY-----');
|
||||
-----END PUBLIC KEY-----')
|
||||
->withSignatureFormat('ASN1');
|
||||
|
||||
$this->assertTrue($dsa->verify($message, $signature, 'ASN1'));
|
||||
$this->assertFalse($dsa->verify('foozbar', $signature, 'ASN1'));
|
||||
$this->assertTrue($dsa->verify($message, $signature));
|
||||
$this->assertFalse($dsa->verify('foozbar', $signature));
|
||||
|
||||
// openssl dgst -dss1 -sign dsa_priv.pem foo.txt > sigfile.bin
|
||||
$signature = '302c021456d7e7da10d1538a6cd45dcb2b0ce15c28bac03402147e973a4de1e92e8a87ed5218c797952a3f854df5';
|
||||
$signature = pack('H*', $signature);
|
||||
|
||||
$dsa->setHash('sha1');
|
||||
$dsa = $dsa->withHash('sha1');
|
||||
|
||||
$this->assertTrue($dsa->verify("foobar\n", $signature, 'ASN1'));
|
||||
$this->assertFalse($dsa->verify('foozbar', $signature, 'ASN1'));
|
||||
$this->assertTrue($dsa->verify("foobar\n", $signature));
|
||||
$this->assertFalse($dsa->verify('foozbar', $signature));
|
||||
|
||||
// openssl dgst -sha256 -sign dsa_priv.pem foo.txt > sigfile.bin
|
||||
$signature = '302e021500b131ec2682c4c0be13e6558ba3d64929ebc0ac420215009946300a03561cef50c0a51d0cd0a2c835e798fc';
|
||||
$signature = pack('H*', $signature);
|
||||
|
||||
$dsa->setHash('sha256');
|
||||
$dsa = $dsa->withHash('sha256');
|
||||
|
||||
$this->assertTrue($dsa->verify('abcdefghijklmnopqrstuvwxyz', $signature, 'ASN1'));
|
||||
$this->assertFalse($dsa->verify('zzzz', $signature, 'ASN1'));
|
||||
$this->assertTrue($dsa->verify('abcdefghijklmnopqrstuvwxyz', $signature));
|
||||
$this->assertFalse($dsa->verify('zzzz', $signature));
|
||||
}
|
||||
|
||||
public function testRandomSignature()
|
||||
{
|
||||
$message = 'hello, world!';
|
||||
|
||||
$dsa = new DSA();
|
||||
|
||||
$dsa->load('-----BEGIN DSA PRIVATE KEY-----
|
||||
$dsa = PublicKeyLoader::load('-----BEGIN DSA PRIVATE KEY-----
|
||||
MIIBvAIBAAKBgQDsGAHAM16bsPlwl7jaec4QMynYa0YLiLiOZC4mvH4UW/tRJxTz
|
||||
aV7eH1EtnP9D9J78x/07wKYs8zJEWCXmuq0UluQfjA47+pb68b/ucQTNeZHboNN9
|
||||
5oEi+8BCSK0y8G3uf3Y89qHvqa9Si6rP374MinEMrbVFm+UpsGflFcd83wIVALtJ
|
||||
@ -82,9 +81,11 @@ CCBGBQJRAoGBALnHTAZlpoLJZuSBVtnMuRM3cSX43IkE9w9FveDV1jX5mmfK7yBV
|
||||
pQFV8eVJfk91ERQ4Dn6ePLUv2dRIt4a0S0qHqadgzyoFyqkmmUi1kNLyixtRqh+m
|
||||
2gXx0t63HEpZDbEPppdpnlppZquVQh7TyrKSXW9MTzUkQjFI9UY7kZeKAhQXiJgI
|
||||
kBniZHdFBAZBTE14YJUBkw==
|
||||
-----END DSA PRIVATE KEY-----');
|
||||
$signature1 = $dsa->sign($message, 'ASN1');
|
||||
$signature2 = $dsa->sign($message, 'ASN1');
|
||||
-----END DSA PRIVATE KEY-----')
|
||||
->withSignatureFormat('ASN1');
|
||||
$public = $dsa->getPublicKey();
|
||||
$signature1 = $dsa->sign($message);
|
||||
$signature2 = $dsa->sign($message);
|
||||
|
||||
// phpseclib's DSA implementation uses a CSPRNG to generate the k parameter.
|
||||
// used correctly this should result in different signatures every time.
|
||||
@ -93,31 +94,31 @@ kBniZHdFBAZBTE14YJUBkw==
|
||||
// unit test would need to be updated
|
||||
$this->assertNotEquals($signature1, $signature2);
|
||||
|
||||
$this->assertTrue($dsa->verify($message, $signature1, 'ASN1'));
|
||||
$this->assertTrue($dsa->verify($message, $signature2, 'ASN1'));
|
||||
$this->assertTrue($public->verify($message, $signature1));
|
||||
$this->assertTrue($public->verify($message, $signature2));
|
||||
|
||||
$signature = $dsa->sign($message, 'SSH2');
|
||||
$dsa = $dsa->withSignatureFormat('SSH2');
|
||||
$public = $public->withSignatureFormat('SSH2');
|
||||
|
||||
$pubKey = $dsa->getPublicKey();
|
||||
$signature = $dsa->sign($message);
|
||||
|
||||
$dsa = new DSA();
|
||||
$dsa->load($pubKey);
|
||||
$this->assertTrue($dsa->verify($message, $signature, 'SSH2'));
|
||||
$this->assertTrue($public->verify($message, $signature));
|
||||
}
|
||||
|
||||
public function testSSHSignature()
|
||||
{
|
||||
$dsa = new DSA();
|
||||
$dsa->setHash('sha1');
|
||||
$dsa->load('AAAAB3NzaC1kc3MAAACBAPyzZzm4oqmY12lxmHwNcfYDNyXr38M1lU6xy9I792U1YSKgX27nUW9eXdJ8Mrn63Le5rrBRfg2Niycx' .
|
||||
$dsa = PublicKeyLoader::load('AAAAB3NzaC1kc3MAAACBAPyzZzm4oqmY12lxmHwNcfYDNyXr38M1lU6xy9I792U1YSKgX27nUW9eXdJ8Mrn63Le5rrBRfg2Niycx' .
|
||||
'JF2IwDpwCi7YpIv79uwT3RtA0chQDS4vx8qi8BWBzy7PZC9hmqY62+mgfj8ooga1sr+JpMh+8r4j3KjPM+wE37khkgkvAAAAFQDn' .
|
||||
'19pBng6TajI/vdg7GPnxsitCqQAAAIEA6Pl1Z/TVdkc+HpfkAvcg2Q+yNtnVq7+26RCbRDO3b9Ocr+tZA9u23qnO3KDYeygzaLnI' .
|
||||
'gpErp61Bj70iIUldhXy2LFGZFEC9XiKmt/tQxSDKiBbj3bS3wKfHrAlElgjhqxiRh+GixgSsmCj96eJFXcsxPjQU81HR+WJ0ALV1' .
|
||||
'UnMAAACABRdNuqqe1Y68es8TIflV71P0J7Ci2BbbqAXRwYYKc9/7DrygwaN2UIbMXyOLuojeZgQPPoM9nkzd6QZo8M9apawVKKwD' .
|
||||
'GAUj2of+F9WVRxhE0ohTQBzD/3HqT80pQsX+rYcxuSx1cCtdMp4oLrrfKO2J4EiWUkaoSB7SdCaj+vU=');
|
||||
$dsa = $dsa
|
||||
->withHash('sha1')
|
||||
->withSignatureFormat('SSH2');
|
||||
$message = pack('H*', '8bfc69a222c12ddf6bc6bf33c9cadc106af04feb');
|
||||
$signature = pack('H*', '000000077373682d64737300000028a7a2e55dc43e5e6145aa94daa0552ea479d1139d6d6ba50650b489e24e976593e73f76557813d6bc');
|
||||
|
||||
$this->assertTrue($dsa->verify($message, $signature, 'SSH2'));
|
||||
$this->assertTrue($dsa->verify($message, $signature));
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use phpseclib\Crypt\ECDSA;
|
||||
use phpseclib\File\ASN1;
|
||||
use phpseclib\Crypt\ECDSA\Curves\Ed448;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Crypt\PublicKeyLoader;
|
||||
|
||||
class Ed448PublicKey
|
||||
{
|
||||
@ -167,7 +168,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$plaintext = 'zzz';
|
||||
|
||||
ECDSA::useInternalEngine();
|
||||
extract(ECDSA::createKey($name));
|
||||
$privatekey = ECDSA::createKey($name);
|
||||
$publickey = $privatekey->getPublicKey();
|
||||
$sig = $privatekey->sign($plaintext);
|
||||
|
||||
ECDSA::useBestEngine();
|
||||
@ -189,7 +191,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$plaintext = 'zzz';
|
||||
|
||||
ECDSA::useBestEngine();
|
||||
extract(ECDSA::createKey($name));
|
||||
$privatekey = ECDSA::createKey($name);
|
||||
$publickey = $privatekey->getPublicKey();
|
||||
$sig = $privatekey->sign($plaintext);
|
||||
|
||||
ECDSA::useInternalEngine();
|
||||
@ -207,11 +210,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '6c82a562cb808d10d632be89c8513ebf6c929f34ddfa8c9f63c9960ef6e348a3528c8a3fcc2f044e39a3fc5b94492f8f032e7549a20098f95b');
|
||||
$public = pack('H*', '5fd7449b59b461fd2ce787ec616ad46a1da1342485a70e1f8a0ea75d80e96778edf124769b46c7061bd6783df1e50f6cd1fa1abeafe8256180');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$expected = '533a37f6bbe457251f023c0d88f976ae2dfb504a843e34d2074fd823d41a591f2b233f034f628281f2fd7a22ddd47d7828c59bd0a21bfd3980' .
|
||||
'ff0d2028d4b18a9df63e006c5d1c2d345b925d8dc00b4104852db99ac5c7cdda8530a113a0f4dbb61149f05a7363268c71d95808ff2e652600';
|
||||
@ -221,19 +221,16 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', 'c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e');
|
||||
$public = pack('H*', '43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$expected = '26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f4352541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd77980' .
|
||||
'5e0dbcc0aae1cbcee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0ff3348ab21aa4adafd1d234441cf807c03a00';
|
||||
$this->assertSame($expected, bin2hex($sig = $privateKey->sign("\x03")));
|
||||
$this->assertTrue($publicKey->verify("\x03", $sig));
|
||||
|
||||
$publicKey->setContext(pack('H*', '666f6f'));
|
||||
$privateKey->setContext(pack('H*', '666f6f'));
|
||||
$publicKey = $publicKey->withContext(pack('H*', '666f6f'));
|
||||
$privateKey = $privateKey->withContext(pack('H*', '666f6f'));
|
||||
|
||||
$expected = 'd4f8f6131770dd46f40867d6fd5d5055de43541f8c5e35abbcd001b32a89f7d2151f7647f11d8ca2ae279fb842d607217fce6e042f6815ea00' .
|
||||
'0c85741de5c8da1144a6a1aba7f96de42505d7a7298524fda538fccbbb754f578c1cad10d54d0d5428407e85dcbc98a49155c13764e66c3c00';
|
||||
@ -243,11 +240,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '258cdd4ada32ed9c9ff54e63756ae582fb8fab2ac721f2c8e676a72768513d939f63dddb55609133f29adf86ec9929dccb52c1c5fd2ff7e21b');
|
||||
$public = pack('H*', '3ba16da0c6f2cc1f30187740756f5e798d6bc5fc015d7c63cc9510ee3fd44adc24d8e968b6e46e6f94d19b945361726bd75e149ef09817f580');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$message = pack('H*', '64a65f3cdedcdd66811e2915');
|
||||
|
||||
@ -259,11 +253,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '7ef4e84544236752fbb56b8f31a23a10e42814f5f55ca037cdcc11c64c9a3b2949c1bb60700314611732a6c2fea98eebc0266a11a93970100e');
|
||||
$public = pack('H*', 'b3da079b0aa493a5772029f0467baebee5a8112d9d3a22532361da294f7bb3815c5dc59e176b4d9f381ca0938e13c6c07b174be65dfa578e80');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$message = pack('H*', '64a65f3cdedcdd66811e2915e7');
|
||||
|
||||
@ -275,11 +266,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', 'd65df341ad13e008567688baedda8e9dcdc17dc024974ea5b4227b6530e339bff21f99e68ca6968f3cca6dfe0fb9f4fab4fa135d5542ea3f01');
|
||||
$public = pack('H*', 'df9705f58edbab802c7f8363cfe5560ab1c6132c20a9f1dd163483a26f8ac53a39d6808bf4a1dfbd261b099bb03b3fb50906cb28bd8a081f00');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$message = 'bd0f6a3747cd561bdddf4640a332461a4a30a12a434cd0bf40d766d9c6d458e5512204a30c17d1f50b5079631f64eb3112182da3005835461113718d1a5ef944';
|
||||
$message = pack('H*', $message);
|
||||
@ -292,11 +280,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '2ec5fe3c17045abdb136a5e6a913e32ab75ae68b53d2fc149b77e504132d37569b7e766ba74a19bd6162343a21c8590aa9cebca9014c636df5');
|
||||
$public = pack('H*', '79756f014dcfe2079f5dd9e718be4171e2ef2486a08f25186f6bff43a9936b9bfe12402b08ae65798a3d81e22e9ec80e7690862ef3d4ed3a00');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$message = '15777532b0bdd0d1389f636c5f6b9ba734c90af572877e2d272dd078aa1e567cfa80e12928bb542330e8409f3174504107ecd5efac61ae7504dabe2a602ede89e5cca6257a7c77e27a702b3ae39fc769fc54f2395ae6a1178cab4738e543072fc1c177fe71e92e25bf03e4ecb72f47b64d0465aaea4c7fad372536c8ba516a60' .
|
||||
'39c3c2a39f0e4d832be432dfa9a706a6e5c7e19f397964ca4258002f7c0541b590316dbc5622b6b2a6fe7a4abffd96105eca76ea7b98816af0748c10df048ce012d901015a51f189f3888145c03650aa23ce894c3bd889e030d565071c59f409a9981b51878fd6fc110624dcbcde0bf7a69ccce38fabdf86f3bef6044819de11';
|
||||
@ -310,11 +295,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '872d093780f5d3730df7c212664b37b8a0f24f56810daa8382cd4fa3f77634ec44dc54f1c2ed9bea86fafb7632d8be199ea165f5ad55dd9ce8');
|
||||
$public = pack('H*', 'a81b2e8a70a5ac94ffdbcc9badfc3feb0801f258578bb114ad44ece1ec0e799da08effb81c5d685c0c56f64eecaef8cdf11cc38737838cf400');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$message = '6ddf802e1aae4986935f7f981ba3f0351d6273c0a0c22c9c0e8339168e675412a3debfaf435ed651558007db4384b650fcc07e3b586a27a4f7a00ac8a6fec2cd86ae4bf1570c41e6a40c931db27b2faa15a8cedd52cff7362c4e6e23daec0fbc3a79b6806e316efcc7b68119bf46bc76a26067a53f296dafdbdc11c77f7777e9' .
|
||||
'72660cf4b6a9b369a6665f02e0cc9b6edfad136b4fabe723d2813db3136cfde9b6d044322fee2947952e031b73ab5c603349b307bdc27bc6cb8b8bbd7bd323219b8033a581b59eadebb09b3c4f3d2277d4f0343624acc817804728b25ab797172b4c5c21a22f9c7839d64300232eb66e53f31c723fa37fe387c7d3e50bdf9813' .
|
||||
@ -342,12 +324,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60');
|
||||
$public = pack('H*', 'd75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
// libsodium format
|
||||
$privateKey->load($private . $public);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private . $public); // libsodium format
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$expected = 'e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e06522490155' .
|
||||
'5fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b';
|
||||
@ -357,11 +335,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb');
|
||||
$public = pack('H*', '3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private . $public);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private . $public);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$expected = '92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da' .
|
||||
'085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c00';
|
||||
@ -371,11 +346,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', 'c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7');
|
||||
$public = pack('H*', 'fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private . $public);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private . $public); // libsodium format
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$expected = '6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac' .
|
||||
'18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40a';
|
||||
@ -385,11 +357,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', 'f5e5767cf153319517630f226876b86c8160cc583bc013744c6bf255f5cc0ee5');
|
||||
$public = pack('H*', '278117fc144c72340f67d0f2316e8386ceffbf2b2428c9c51fef7c597f1d426e');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private . $public);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private . $public); // libsodium format
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$message = '08b8b2b733424243760fe426a4b54908632110a66c2f6591eabd3345e3e4eb98' .
|
||||
'fa6e264bf09efe12ee50f8f54e9f77b1e355f6c50544e23fb1433ddf73be84d8' .
|
||||
@ -433,11 +402,8 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42');
|
||||
$public = pack('H*', 'ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private . $public);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
$privateKey = PublicKeyLoader::load($private . $public);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$message = 'ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a' .
|
||||
'2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f';
|
||||
@ -451,14 +417,11 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6');
|
||||
$public = pack('H*', 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private . $public);
|
||||
$privateKey = PublicKeyLoader::load($private . $public);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
|
||||
$privateKey->setContext("\x62\x61\x72");
|
||||
$publicKey->setContext("\x62\x61\x72");
|
||||
$privateKey = $privateKey->withContext("\x62\x61\x72");
|
||||
$publicKey = $publicKey->withContext("\x62\x61\x72");
|
||||
|
||||
$message = 'f726936d19c800494e3fdaff20b276a8';
|
||||
$message = pack('H*', $message);
|
||||
@ -471,14 +434,11 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', '0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6');
|
||||
$public = pack('H*', 'dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private . $public);
|
||||
$privateKey = PublicKeyLoader::load($private . $public);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
|
||||
$privateKey->setContext("\x66\x6f\x6f");
|
||||
$publicKey->setContext("\x66\x6f\x6f");
|
||||
$privateKey = $privateKey->withContext("\x66\x6f\x6f");
|
||||
$publicKey = $publicKey->withContext("\x66\x6f\x6f");
|
||||
|
||||
$message = '508e9e6882b979fea900f62adceaca35';
|
||||
$message = pack('H*', $message);
|
||||
@ -491,14 +451,11 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
$private = pack('H*', 'ab9c2853ce297ddab85c993b3ae14bcad39b2c682beabc27d6d4eb20711d6560');
|
||||
$public = pack('H*', '0f1d1274943b91415889152e893d80e93275a1fc0b65fd71b4b0dda10ad7d772');
|
||||
|
||||
$privateKey = new ECDSA();
|
||||
$privateKey->load($private . $public);
|
||||
$privateKey = PublicKeyLoader::load($private . $public);
|
||||
$publicKey = PublicKeyLoader::load($public);
|
||||
|
||||
$publicKey = new ECDSA();
|
||||
$publicKey->load($public);
|
||||
|
||||
$privateKey->setContext("\x66\x6f\x6f");
|
||||
$publicKey->setContext("\x66\x6f\x6f");
|
||||
$privateKey = $privateKey->withContext("\x66\x6f\x6f");
|
||||
$publicKey = $publicKey->withContext("\x66\x6f\x6f");
|
||||
|
||||
$message = 'f726936d19c800494e3fdaff20b276a8';
|
||||
$message = pack('H*', $message);
|
||||
@ -512,8 +469,7 @@ class Unit_Crypt_ECDSA_CurveTest extends PhpseclibTestCase
|
||||
public function testRandomSignature()
|
||||
{
|
||||
$message = 'hello, world!';
|
||||
$private = new ECDSA();
|
||||
$private->load('PuTTY-User-Key-File-2: ecdsa-sha2-nistp256
|
||||
$private = PublicKeyLoader::load('PuTTY-User-Key-File-2: ecdsa-sha2-nistp256
|
||||
Encryption: none
|
||||
Comment: ecdsa-key-20181105
|
||||
Public-Lines: 3
|
||||
|
@ -11,28 +11,27 @@ use phpseclib\Crypt\ECDSA\Keys\PKCS8;
|
||||
use phpseclib\Crypt\ECDSA\Keys\PuTTY;
|
||||
use phpseclib\Crypt\ECDSA\Keys\OpenSSH;
|
||||
use phpseclib\Crypt\ECDSA\Keys\XML;
|
||||
use phpseclib\Crypt\PublicKeyLoader;
|
||||
|
||||
class Unit_Crypt_ECDSA_LoadKeyTest extends PhpseclibTestCase
|
||||
{
|
||||
// openssl ecparam -name secp256k1 -genkey -noout -out secp256k1.pem
|
||||
public function testPKCS1PrivateKey()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = '-----BEGIN EC PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load($expected = '-----BEGIN EC PRIVATE KEY-----
|
||||
MHQCAQEEIEzUawcXqUsQhaEQ51JLeOIY0ddzlO2nNgwDk32ETqwkoAcGBSuBBAAK
|
||||
oUQDQgAEFuVcVb9iCUhg2cknHPE+BouHGhQ39ORjMaMI3T4RfRxr6dj5HAXdEqVZ
|
||||
1W94KMe30ndmTndcJ8BPeT1Dd15FdQ==
|
||||
-----END EC PRIVATE KEY-----');
|
||||
$this->assertSame('secp256k1', $key->getCurve());
|
||||
//PKCS1::useNamedCurve();
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS1'));
|
||||
$this->assertSame($expected, $key->toString('PKCS1'));
|
||||
}
|
||||
|
||||
// openssl ecparam -name secp256k1 -genkey -noout -out secp256k1.pem -param_enc explicit
|
||||
public function testPKCS1PrivateKeySpecifiedCurve()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN EC PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load('-----BEGIN EC PRIVATE KEY-----
|
||||
MIIBEwIBAQQgFr6TF5meGfgCXDqVxoSEltGI+T94G42PPbA6/ibq+ouggaUwgaIC
|
||||
AQEwLAYHKoZIzj0BAQIhAP////////////////////////////////////7///wv
|
||||
MAYEAQAEAQcEQQR5vmZ++dy7rFWgYpXOhwsHApv82y3OKNlZ8oFbFvgXmEg62ncm
|
||||
@ -61,29 +60,27 @@ AAAAAAAAAAAAAAAAAAAAAAAAAAAABwRBBHm+Zn753LusVaBilc6HCwcCm/zbLc4o
|
||||
E5w=
|
||||
-----END EC PRIVATE KEY-----';
|
||||
PKCS1::useSpecifiedCurve();
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS1'));
|
||||
$this->assertSame($expected, $key->toString('PKCS1'));
|
||||
}
|
||||
|
||||
// openssl ecparam -name secp256k1 -genkey -noout -out secp256k1.pem
|
||||
// openssl pkcs8 -topk8 -nocrypt -in secp256k1.pem -out secp256k1-2.pem
|
||||
public function testPKCS8PrivateKey()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = '-----BEGIN PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load($expected = '-----BEGIN PRIVATE KEY-----
|
||||
MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgAYCXwnhqMT6fCIKIkQ0w
|
||||
cac7QqHrn4TCQMF9a+im74WhRANCAATwCjyGuP8xQbvVjznqazL36oeAnD32I+X2
|
||||
+wscW3OmyTDpk41HaWYPh+j+BoufsSkCwf8dBRGEQbCieZbbZogy
|
||||
-----END PRIVATE KEY-----');
|
||||
$this->assertSame('secp256k1', $key->getCurve());
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS8'));
|
||||
$this->assertSame($expected, $key->toString('PKCS8'));
|
||||
}
|
||||
|
||||
// openssl ecparam -name secp256k1 -genkey -noout -out secp256k1.pem -param_enc explicit
|
||||
// openssl pkcs8 -topk8 -nocrypt -in secp256k1.pem -out secp256k1-2.pem
|
||||
public function testPKCS8PrivateKeySpecifiedCurve()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load('-----BEGIN PRIVATE KEY-----
|
||||
MIIBIwIBADCBrgYHKoZIzj0CATCBogIBATAsBgcqhkjOPQEBAiEA////////////
|
||||
/////////////////////////v///C8wBgQBAAQBBwRBBHm+Zn753LusVaBilc6H
|
||||
CwcCm/zbLc4o2VnygVsW+BeYSDradyajxGVdpPv8DhEIqP0XtEimhVQZnEfQj/sQ
|
||||
@ -107,28 +104,26 @@ AASdfrr5QLNRbdP9+QsYgh9mMmblsgzABXzkukOibaEjjjUlHH79bhaq0a5b4H8s
|
||||
AFLpken6rN6lOEIeyNLdD097
|
||||
-----END PRIVATE KEY-----';
|
||||
PKCS8::useSpecifiedCurve();
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS8'));
|
||||
$this->assertSame($expected, $key->toString('PKCS8'));
|
||||
}
|
||||
|
||||
// openssl ecparam -name sect113r1 -genkey -noout -out sect113r1.pem
|
||||
public function testBinaryPKCS1PrivateKey()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = '-----BEGIN EC PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load($expected = '-----BEGIN EC PRIVATE KEY-----
|
||||
MEECAQEEDwBZdP4eSzKk/uQa6jdtfKAHBgUrgQQABKEiAyAABAHqCoNb++mK5qvE
|
||||
c4rCzQEuI19czqvXpEPcAWSXew==
|
||||
-----END EC PRIVATE KEY-----');
|
||||
$this->assertSame('sect113r1', $key->getCurve());
|
||||
|
||||
PKCS1::useNamedCurve();
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS1'));
|
||||
$this->assertSame($expected, $key->toString('PKCS1'));
|
||||
}
|
||||
|
||||
// openssl ecparam -name sect113r1 -genkey -noout -out sect113r1.pem -param_enc explicit
|
||||
public function testBinaryPKCS1PrivateKeySpecifiedCurve()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN EC PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load('-----BEGIN EC PRIVATE KEY-----
|
||||
MIHNAgEBBA8AuSc4BeeyYTq9rbSDuL2ggZIwgY8CAQEwHAYHKoZIzj0BAjARAgFx
|
||||
BgkqhkjOPQECAwICAQkwNwQOMIglDKbnx/5knOhYIPcEDui+5NPiJgdEGIvg6ccj
|
||||
AxUAEOcjqxTWluZ2h1YVF1b+v4/LSakEHwQAnXNhbzX0qxQH1zViwQ8ApSgwJ3lY
|
||||
@ -149,7 +144,7 @@ BACdc2FvNfSrFAfXNWLBDwClKDAneVjuhNExXtMYhgIPAQAAAAAAAADZzOyKOeVv
|
||||
oSIDIAAEAULtznTLu7D6K4d4wK1bAKko0FRxV6IeZ7rT0O/+
|
||||
-----END EC PRIVATE KEY-----';
|
||||
PKCS1::useSpecifiedCurve();
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS1'));
|
||||
$this->assertSame($expected, $key->toString('PKCS1'));
|
||||
}
|
||||
|
||||
// openssl ecparam -name sect113r1 -genkey -noout -out sect113r1.pem
|
||||
@ -157,23 +152,21 @@ oSIDIAAEAULtznTLu7D6K4d4wK1bAKko0FRxV6IeZ7rT0O/+
|
||||
// sect113r1's reduction polynomial is a trinomial
|
||||
public function testBinaryPKCS8PrivateKey()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = '-----BEGIN PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load($expected = '-----BEGIN PRIVATE KEY-----
|
||||
MFECAQAwEAYHKoZIzj0CAQYFK4EEAAQEOjA4AgEBBA8A5OuqAY8HYoFOaz9mE6mh
|
||||
IgMgAAQASF3rOTPXvH0QdRBvsrMBdLMf27yd8AWABrZTxvI=
|
||||
-----END PRIVATE KEY-----');
|
||||
$this->assertSame('sect113r1', $key->getCurve());
|
||||
|
||||
PKCS8::useNamedCurve();
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS8'));
|
||||
$this->assertSame($expected, $key->toString('PKCS8'));
|
||||
}
|
||||
|
||||
// openssl ecparam -name sect113r1 -genkey -noout -out sect113r1.pem -param_enc explicit
|
||||
// openssl pkcs8 -topk8 -nocrypt -in sect113r1.pem -out sect113r1-2.pem
|
||||
public function testBinaryPKCS8PrivateKeySpecifiedCurve()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load('-----BEGIN PRIVATE KEY-----
|
||||
MIHdAgEAMIGbBgcqhkjOPQIBMIGPAgEBMBwGByqGSM49AQIwEQIBcQYJKoZIzj0B
|
||||
AgMCAgEJMDcEDjCIJQym58f+ZJzoWCD3BA7ovuTT4iYHRBiL4OnHIwMVABDnI6sU
|
||||
1pbmdodWFRdW/r+Py0mpBB8EAJ1zYW819KsUB9c1YsEPAKUoMCd5WO6E0TFe0xiG
|
||||
@ -193,15 +186,14 @@ BA8AXtfDMRsRTx8snPbWHquhIgMgAAQA9xdWGJ6vV23+vkdq0C8BLJVg5E3amMyf
|
||||
/5keGa4=
|
||||
-----END PRIVATE KEY-----';
|
||||
PKCS8::useSpecifiedCurve();
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS8'));
|
||||
$this->assertSame($expected, $key->toString('PKCS8'));
|
||||
}
|
||||
|
||||
// openssl ecparam -name sect131r1 -genkey -noout -out sect131r1.pem -param_enc explicit
|
||||
// sect131r1's reduction polynomial is a pentanomial
|
||||
public function testBinaryPentanomialPKCS1PrivateKey()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN EC PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load('-----BEGIN EC PRIVATE KEY-----
|
||||
MIHoAgEBBBECPEK9NCISWf2riBsORoTM+6CBpzCBpAIBATAlBgcqhkjOPQECMBoC
|
||||
AgCDBgkqhkjOPQECAwMwCQIBAgIBAwIBCDA9BBEHoRsJp2tWIURBj/P/jCVwuAQR
|
||||
AhfAVhCIS2O5xscpFnj500EDFQBNaW5naHVhUXWYW9OtutohtDqX4gQjBACBuvkf
|
||||
@ -221,14 +213,13 @@ SxtO+eFQAhEEAAAAAAAAAAIxI5U6lGS1TaEmAyQABARCKJRo6OZZ7GKjWoKmDzmh
|
||||
BjoJZJZQztmlj7Qep/sf1l8=
|
||||
-----END EC PRIVATE KEY-----';
|
||||
PKCS1::useSpecifiedCurve();
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS1'));
|
||||
$this->assertSame($expected, $key->toString('PKCS1'));
|
||||
}
|
||||
|
||||
// from https://tools.ietf.org/html/draft-ietf-curdle-pkix-07#section-10.1
|
||||
public function testEd25519PublicKey()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN PUBLIC KEY-----
|
||||
$key = PublicKeyLoader::load('-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=
|
||||
-----END PUBLIC KEY-----');
|
||||
$this->assertSame('Ed25519', $key->getCurve());
|
||||
@ -240,23 +231,21 @@ MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=
|
||||
$expected = '-----BEGIN PUBLIC KEY-----
|
||||
MCwwBwYDK2VwBQADIQAZv0QJaYTN/oVBusFn3DuWyFCGqjC2tssMXDitcDFm4Q==
|
||||
-----END PUBLIC KEY-----';
|
||||
$this->assertSame($expected, $key->getPublicKey('PKCS8'));
|
||||
$this->assertSame($expected, $key->toString('PKCS8'));
|
||||
}
|
||||
|
||||
// from https://tools.ietf.org/html/draft-ietf-curdle-pkix-07#section-10.3
|
||||
public function testEd25519PrivateKey()
|
||||
{
|
||||
// without public key (public key should be derived)
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load('-----BEGIN PRIVATE KEY-----
|
||||
MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC
|
||||
-----END PRIVATE KEY-----');
|
||||
$this->assertSame('Ed25519', $key->getCurve());
|
||||
$this->assertSame('Ed25519', $key->getPublicKey()->getCurve());
|
||||
|
||||
// with public key
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load('-----BEGIN PRIVATE KEY-----
|
||||
MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC
|
||||
oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB
|
||||
Z9w7lshQhqowtrbLDFw4rXAxZuE=
|
||||
@ -271,13 +260,12 @@ Z9w7lshQhqowtrbLDFw4rXAxZuE=
|
||||
MFICAQEwBwYDK2VwBQAEIgQg1O5y2/kTWErVttjx92n4rTr+fCjL8dT74Jeoj0R1
|
||||
WEKBIBm/RAlphM3+hUG6wWfcO5bIUIaqMLa2ywxcOK1wMWbh
|
||||
-----END PRIVATE KEY-----';
|
||||
$this->assertSame($expected, $key->getPrivateKey('PKCS8'));
|
||||
$this->assertSame($expected, $key->toString('PKCS8'));
|
||||
}
|
||||
|
||||
public function testPuTTYnistp256()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = 'PuTTY-User-Key-File-2: ecdsa-sha2-nistp256
|
||||
$key = PublicKeyLoader::load($expected = 'PuTTY-User-Key-File-2: ecdsa-sha2-nistp256
|
||||
Encryption: none
|
||||
Comment: ecdsa-key-20181105
|
||||
Public-Lines: 3
|
||||
@ -291,20 +279,18 @@ Private-MAC: b85ca0eb7c612df5d18af85128821bd53faaa3ef
|
||||
$this->assertSame('nistp256', $key->getCurve());
|
||||
|
||||
PuTTY::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->getPrivateKey('PuTTY'));
|
||||
$this->assertSame($expected, $key->toString('PuTTY'));
|
||||
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJEXCsWA8s18m25MJlVE1urbXPYFi4q8oMbb2H0kE2f5WPxizsKXRmb1J68paXQizryL9fC4FTqICJ1+UnaPfk0= ecdsa-key-20181105');
|
||||
$key = PublicKeyLoader::load($expected = 'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJEXCsWA8s18m25MJlVE1urbXPYFi4q8oMbb2H0kE2f5WPxizsKXRmb1J68paXQizryL9fC4FTqICJ1+UnaPfk0= ecdsa-key-20181105');
|
||||
$this->assertSame('nistp256', $key->getCurve());
|
||||
|
||||
OpenSSH::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->getPublicKey('OpenSSH'));
|
||||
$this->assertSame($expected, $key->toString('OpenSSH'));
|
||||
}
|
||||
|
||||
public function testPuTTYnistp384()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = 'PuTTY-User-Key-File-2: ecdsa-sha2-nistp384
|
||||
$key = PublicKeyLoader::load($expected = 'PuTTY-User-Key-File-2: ecdsa-sha2-nistp384
|
||||
Encryption: none
|
||||
Comment: ecdsa-key-20181105
|
||||
Public-Lines: 3
|
||||
@ -319,21 +305,19 @@ Private-MAC: 97a990a3d5f6b8f268d4be9c4ab9ebfd8fa79849
|
||||
$this->assertSame('nistp384', $key->getCurve());
|
||||
|
||||
PuTTY::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->getPrivateKey('PuTTY'));
|
||||
$this->assertSame($expected, $key->toString('PuTTY'));
|
||||
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = 'ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBOI53wHG3CdcAJZq5PXWZAEAxxsNVFQlQgOX9toWEOgqQF5LbK2nWLKRvaHMzocUXaTYZDccSS0ATZFPT3j1Er1LU9cu4PHpyS07v262jdzkxIvKCPcAeISuV80MC7rHog== ecdsa-key-20181105');
|
||||
$key = PublicKeyLoader::load($expected = 'ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBOI53wHG3CdcAJZq5PXWZAEAxxsNVFQlQgOX9toWEOgqQF5LbK2nWLKRvaHMzocUXaTYZDccSS0ATZFPT3j1Er1LU9cu4PHpyS07v262jdzkxIvKCPcAeISuV80MC7rHog== ecdsa-key-20181105');
|
||||
$this->assertSame('nistp384', $key->getCurve());
|
||||
|
||||
OpenSSH::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->getPublicKey('OpenSSH'));
|
||||
$this->assertSame($expected, $key->toString('OpenSSH'));
|
||||
|
||||
}
|
||||
|
||||
public function testPuTTYnistp521()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = 'PuTTY-User-Key-File-2: ecdsa-sha2-nistp521
|
||||
$key = PublicKeyLoader::load($expected = 'PuTTY-User-Key-File-2: ecdsa-sha2-nistp521
|
||||
Encryption: none
|
||||
Comment: ecdsa-key-20181105
|
||||
Public-Lines: 4
|
||||
@ -349,20 +333,18 @@ Private-MAC: 6d49ce289b85549a43d74422dd8bb3ba8798c72c
|
||||
$this->assertSame('nistp521', $key->getCurve());
|
||||
|
||||
PuTTY::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->getPrivateKey('PuTTY'));
|
||||
$this->assertSame($expected, $key->toString('PuTTY'));
|
||||
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = 'ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAF1Eg0MjaJwooFj6HCNh4RWbvmQRY+sdczJyBdT3EaTc/6IUcCfW7w7rAeRp2CDdE9RlAVD8IuLqW7DJH06Xeov8wBO5G6jUqXu0rlHsOSiC6VcCxBJuWVNB1IorHnS7PX0f6HdLlIEme73P77drqpn5YY0XLtP6hFrF7H5XfCxpNyaJA== ecdsa-key-20181105');
|
||||
$key = PublicKeyLoader::load($expected = 'ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAF1Eg0MjaJwooFj6HCNh4RWbvmQRY+sdczJyBdT3EaTc/6IUcCfW7w7rAeRp2CDdE9RlAVD8IuLqW7DJH06Xeov8wBO5G6jUqXu0rlHsOSiC6VcCxBJuWVNB1IorHnS7PX0f6HdLlIEme73P77drqpn5YY0XLtP6hFrF7H5XfCxpNyaJA== ecdsa-key-20181105');
|
||||
$this->assertSame('nistp521', $key->getCurve());
|
||||
|
||||
OpenSSH::setComment('ecdsa-key-20181105');
|
||||
$this->assertSame($expected, $key->getPublicKey('OpenSSH'));
|
||||
$this->assertSame($expected, $key->toString('OpenSSH'));
|
||||
}
|
||||
|
||||
public function testPuTTYed25519()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = 'PuTTY-User-Key-File-2: ssh-ed25519
|
||||
$key = PublicKeyLoader::load($expected = 'PuTTY-User-Key-File-2: ssh-ed25519
|
||||
Encryption: none
|
||||
Comment: ed25519-key-20181105
|
||||
Public-Lines: 2
|
||||
@ -375,14 +357,13 @@ Private-MAC: 8a06821a1c8b8b40fc40f876e543c4ea3fb81bb9
|
||||
$this->assertSame('Ed25519', $key->getCurve());
|
||||
|
||||
PuTTY::setComment('ed25519-key-20181105');
|
||||
$this->assertSame($expected, $key->getPrivateKey('PuTTY'));
|
||||
$this->assertSame($expected, $key->toString('PuTTY'));
|
||||
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC6I6RyYAqtBcWXws9EDqGbhFtc5rKG4NMn/G7temQtu ed25519-key-20181105');
|
||||
$key = PublicKeyLoader::load($expected = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC6I6RyYAqtBcWXws9EDqGbhFtc5rKG4NMn/G7temQtu ed25519-key-20181105');
|
||||
$this->assertSame('Ed25519', $key->getCurve());
|
||||
|
||||
OpenSSH::setComment('ed25519-key-20181105');
|
||||
$this->assertSame($expected, $key->getPublicKey('OpenSSH'));
|
||||
$this->assertSame($expected, $key->toString('OpenSSH'));
|
||||
}
|
||||
|
||||
public function testlibsodium()
|
||||
@ -393,22 +374,19 @@ Private-MAC: 8a06821a1c8b8b40fc40f876e543c4ea3fb81bb9
|
||||
|
||||
$kp = sodium_crypto_sign_keypair();
|
||||
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = sodium_crypto_sign_secretkey($kp));
|
||||
$key = PublicKeyLoader::load($expected = sodium_crypto_sign_secretkey($kp));
|
||||
$this->assertSame('Ed25519', $key->getCurve());
|
||||
$this->assertSame($expected, $key->getPrivateKey('libsodium'));
|
||||
$this->assertSame($expected, $key->toString('libsodium'));
|
||||
|
||||
$key = new ECDSA;
|
||||
$key->load($expected = sodium_crypto_sign_publickey($kp));
|
||||
$key = PublicKeyLoader::load($expected = sodium_crypto_sign_publickey($kp));
|
||||
$this->assertSame('Ed25519', $key->getCurve());
|
||||
$this->assertSame($expected, $key->getPublicKey('libsodium'));
|
||||
$this->assertSame($expected, $key->toString('libsodium'));
|
||||
}
|
||||
|
||||
// ssh-keygen -t ed25519
|
||||
public function testOpenSSHPrivateKey()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
$key = PublicKeyLoader::load('-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
|
||||
QyNTUxOQAAACCpm7dS1/WDTW+uuhp2+aFLPKaJle6+oJqDGLXhlQAX4AAAAJg8TmN5PE5j
|
||||
eQAAAAtzc2gtZWQyNTUxOQAAACCpm7dS1/WDTW+uuhp2+aFLPKaJle6+oJqDGLXhlQAX4A
|
||||
@ -424,16 +402,14 @@ pomV7r6gmoMYteGVABfgAAAAD3ZhZ3JhbnRAdmFncmFudAECAwQFBg==
|
||||
// support encrypted keys
|
||||
// none-the-less, because of the randomized component we can't easily
|
||||
// see if the key string is equal to another known string
|
||||
$key2 = new ECDSA;
|
||||
$key2->load($key->getPrivateKey('OpenSSH'));
|
||||
$key2 = PublicKeyLoader::load($key->toString('OpenSSH'));
|
||||
$this->assertSame('Ed25519', $key2->getCurve());
|
||||
}
|
||||
|
||||
// from https://www.w3.org/TR/xmldsig-core/#sec-RFC4050Compat
|
||||
public function testXMLKey()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load($orig = '<ECDSAKeyValue xmlns="http://www.w3.org/2001/04/xmldsig-more#">
|
||||
$key = PublicKeyLoader::load($orig = '<ECDSAKeyValue xmlns="http://www.w3.org/2001/04/xmldsig-more#">
|
||||
<DomainParameters>
|
||||
<NamedCurve URN="urn:oid:1.2.840.10045.3.1.7" />
|
||||
</DomainParameters>
|
||||
@ -453,22 +429,12 @@ pomV7r6gmoMYteGVABfgAAAAD3ZhZ3JhbnRAdmFncmFudAECAwQFBg==
|
||||
|
||||
//$dom = new DOMDocument();
|
||||
//$dom->preserveWhiteSpace = false;
|
||||
$dom->loadXML($key->getPublicKey('XML'));
|
||||
$dom->loadXML($key->toString('XML'));
|
||||
$actual = $dom->C14N();
|
||||
|
||||
$this->assertSame($expected, $actual);
|
||||
}
|
||||
|
||||
public function testToPublicKey()
|
||||
{
|
||||
$key = new ECDSA;
|
||||
$key->load('-----BEGIN PRIVATE KEY-----
|
||||
MFICAQEwBwYDK2VwBQAEIgQgS5tTLrcNRaml4g5CgGeMvptuXuSrcrFbl+zVSxHD
|
||||
H76BIDXmiVv2hLjr5MhZENlKIuz0ak1hUO8MdZ2vgY/nGcUV
|
||||
-----END PRIVATE KEY-----');
|
||||
$this->assertInternalType('string', (string) $key->getPublicKey());
|
||||
}
|
||||
|
||||
public static function assertSame($expected, $actual, $message = '')
|
||||
{
|
||||
$expected = str_replace("\r\n", "\n", $expected);
|
||||
|
@ -8,14 +8,17 @@
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\RSA\Keys\PKCS1;
|
||||
use phpseclib\Crypt\RSA\PrivateKey;
|
||||
use phpseclib\Crypt\RSA\PublicKey;
|
||||
|
||||
class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
|
||||
{
|
||||
public function testCreateKey()
|
||||
{
|
||||
extract(RSA::createKey(768));
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $privatekey);
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $publickey);
|
||||
$privatekey = RSA::createKey(768);
|
||||
$publickey = $privatekey->getPublicKey();
|
||||
$this->assertInstanceOf(PrivateKey::class, $privatekey);
|
||||
$this->assertInstanceOf(PublicKey::class, $publickey);
|
||||
$this->assertNotEmpty("$privatekey");
|
||||
$this->assertNotEmpty("$publickey");
|
||||
$this->assertSame($privatekey->getLength(), 768);
|
||||
@ -40,15 +43,15 @@ class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
|
||||
{
|
||||
RSA::useInternalEngine();
|
||||
RSA::setSmallestPrime(256);
|
||||
extract(RSA::createKey(1024));
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $privatekey);
|
||||
$this->assertInstanceOf('\phpseclib\Crypt\RSA', $publickey);
|
||||
$privatekey->setPrivateKeyFormat('PKCS1');
|
||||
$this->assertNotEmpty("$privatekey");
|
||||
$this->assertNotEmpty("$publickey");
|
||||
$privatekey = RSA::createKey(1024);
|
||||
$publickey = $privatekey->getPublicKey();
|
||||
$this->assertInstanceOf(PrivateKey::class, $privatekey);
|
||||
$this->assertInstanceOf(PublicKey::class, $publickey);
|
||||
$this->assertNotEmpty($privatekey->toString('PKCS1'));
|
||||
$this->assertNotEmpty($publickey->toString('PKCS1'));
|
||||
$this->assertSame($privatekey->getLength(), 1024);
|
||||
$this->assertSame($publickey->getLength(), 1024);
|
||||
$r = PKCS1::load("$privatekey");
|
||||
$r = PKCS1::load($privatekey->toString('PKCS1'));
|
||||
$this->assertCount(4, $r['primes']);
|
||||
// the last prime number could be slightly over. eg. 99 * 99 == 9801 but 10 * 10 = 100. the more numbers you're
|
||||
// multiplying the less certain you are to have each of them multiply to an n-bit number
|
||||
@ -56,10 +59,9 @@ class Unit_Crypt_RSA_CreateKeyTest extends PhpseclibTestCase
|
||||
$this->assertSame($prime->getLength(), 256);
|
||||
}
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($privatekey->getPrivateKey());
|
||||
$rsa = RSA::load($privatekey->toString('PKCS1'));
|
||||
$signature = $rsa->sign('zzz');
|
||||
$rsa->load($rsa->getPublicKey());
|
||||
$rsa = RSA::load($rsa->getPublicKey()->toString('PKCS1'));
|
||||
$this->assertTrue($rsa->verify('zzz', $signature));
|
||||
|
||||
RSA::useBestEngine();
|
||||
|
@ -6,6 +6,9 @@
|
||||
*/
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\PublicKeyLoader;
|
||||
use phpseclib\Crypt\RSA\PrivateKey;
|
||||
use phpseclib\Crypt\RSA\PublicKey;
|
||||
use phpseclib\Crypt\RSA\Keys\PKCS1;
|
||||
use phpseclib\Crypt\RSA\Keys\PKCS8;
|
||||
use phpseclib\Crypt\RSA\Keys\PuTTY;
|
||||
@ -20,19 +23,17 @@ class Unit_Crypt_RSA_LoadKeyTest extends PhpseclibTestCase
|
||||
OpenSSH::setComment('phpseclib-generated-key');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \phpseclib\Exception\NoKeyLoadedException
|
||||
*/
|
||||
public function testBadKey()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = 'zzzzzzzzzzzzzz';
|
||||
|
||||
$this->assertFalse($rsa->load($key));
|
||||
PublicKeyLoader::load($key);
|
||||
}
|
||||
|
||||
public function testPKCS1Key()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
||||
@ -47,14 +48,14 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
$this->assertInternalType('string', "$rsa");
|
||||
}
|
||||
|
||||
public function testPKCS1SpacesKey()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
||||
@ -70,14 +71,14 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$key = str_replace(["\r", "\n", "\r\n"], ' ', $key);
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
$this->assertInternalType('string', "$rsa");
|
||||
}
|
||||
|
||||
public function testPKCS1NoHeaderKey()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = 'MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
||||
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
|
||||
@ -90,14 +91,14 @@ X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
|
||||
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
$this->assertInternalType('string', "$rsa");
|
||||
}
|
||||
|
||||
public function testPKCS1NoWhitespaceNoHeaderKey()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = 'MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp' .
|
||||
'wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5' .
|
||||
'1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh' .
|
||||
@ -110,14 +111,14 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
'U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ' .
|
||||
'37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
$this->assertInternalType('string', "$rsa");
|
||||
}
|
||||
|
||||
public function testRawPKCS1Key()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = 'MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp' .
|
||||
'wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5' .
|
||||
'1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh' .
|
||||
@ -131,15 +132,14 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
'37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=';
|
||||
$key = base64_decode($key);
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
$this->assertInternalType('string', "$rsa");
|
||||
}
|
||||
|
||||
public function testLoadPKCS8PrivateKey()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->setPassword('password');
|
||||
|
||||
$key = '-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||
MIIE6TAbBgkqhkiG9w0BBQMwDgQIcWWgZeQYPTcCAggABIIEyLoa5b3ktcPmy4VB
|
||||
hHkpHzVSEsKJPmQTUaQvUwIp6+hYZeuOk78EPehrYJ/QezwJRdyBoD51oOxqWCE2
|
||||
@ -170,14 +170,14 @@ GF/qoZyC1mbqdtyyeWgHtVbJVUORmpbNnXOII9duEqBUNDiO9VSZNn/8h/VsYeAB
|
||||
xryZaRDVmtMuf/OZBQ==
|
||||
-----END ENCRYPTED PRIVATE KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInternalType('string', $rsa->getPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key, 'password');
|
||||
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
$this->assertInternalType('string', "$rsa");
|
||||
}
|
||||
|
||||
public function testSavePKCS8PrivateKey()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
||||
@ -191,20 +191,19 @@ X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
|
||||
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$rsa->setPassword('password');
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$rsa = PublicKeyLoader::load($key, 'password');
|
||||
|
||||
$key = $rsa->getPrivateKey('PKCS8');
|
||||
$this->assertInternalType('string', $key);
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$key = (string) $rsa->withPassword('password');
|
||||
$rsa = PublicKeyLoader::load($key, 'password');
|
||||
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
}
|
||||
|
||||
public function testPubKey1()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '-----BEGIN RSA PUBLIC KEY-----
|
||||
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
|
||||
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
|
||||
@ -214,15 +213,12 @@ gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
|
||||
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
|
||||
-----END RSA PUBLIC KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInstanceOf(RSA::class, $rsa->getPublicKey());
|
||||
$this->assertFalse($rsa->getPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$this->assertInstanceOf(PublicKey::class, $rsa);
|
||||
}
|
||||
|
||||
public function testPubKey2()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA61BjmfXGEvWmegnBGSuS
|
||||
+rU9soUg2FnODva32D1AqhwdziwHINFaD1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBS
|
||||
@ -233,29 +229,23 @@ lmCpGSynXNcpZ/06+vofGi/2MlpQZNhHAo8eayMp6FcvNucIpUndo1X8dKMv3Y26
|
||||
ZQIDAQAB
|
||||
-----END PUBLIC KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInstanceOf(RSA::class, $rsa->getPublicKey());
|
||||
$this->assertFalse($rsa->getPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$this->assertInstanceOf(PublicKey::class, $rsa);
|
||||
}
|
||||
|
||||
public function testSSHPubKey()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4e' .
|
||||
'CZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMS' .
|
||||
'GkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZw== ' .
|
||||
'phpseclib-generated-key';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInstanceOf(RSA::class, $rsa->getPublicKey());
|
||||
$this->assertFalse($rsa->getPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$this->assertInstanceOf(PublicKey::class, $rsa);
|
||||
}
|
||||
|
||||
public function testSSHPubKeyFingerprint()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD9K+ebJRMN10kGanhi6kDz6EYFqZttZWZh0'.
|
||||
'YoEbIbbere9N2Yvfc7oIoCTHYowhXND9WSJaIs1E4bx0085CZnofWaqf4NbZTzAh18iZup08ec'.
|
||||
'COB5gJVS1efpgVSviDF2L7jxMsBVoOBfqsmA8m0RwDDVezyWvw4y+STSuVzu2jI8EfwN7ZFGC6'.
|
||||
@ -263,15 +253,14 @@ ZQIDAQAB
|
||||
'b6wYtY/q/WtUFr3nK+x0lgOtokhnJfRR/6fnmC1CztPnIT4BWK81VGKWONAxuhMyQ5XChyu6S9'.
|
||||
'mWG5tUlUI/5';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertSame($rsa->getPublicKeyFingerprint('md5'), 'bd:2c:2f:31:b9:ef:b8:f8:ad:fc:40:a6:94:4f:28:82');
|
||||
$this->assertSame($rsa->getPublicKeyFingerprint('sha256'), 'N9sV2uSNZEe8TITODku0pRI27l+Zk0IY0TrRTw3ozwM');
|
||||
$rsa = PublicKeyLoader::load($key, 'password');
|
||||
$this->assertInstanceOf(PublicKey::class, $rsa);
|
||||
$this->assertSame($rsa->getFingerprint('md5'), 'bd:2c:2f:31:b9:ef:b8:f8:ad:fc:40:a6:94:4f:28:82');
|
||||
$this->assertSame($rsa->getFingerprint('sha256'), 'N9sV2uSNZEe8TITODku0pRI27l+Zk0IY0TrRTw3ozwM');
|
||||
}
|
||||
|
||||
public function testSetPrivate()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '-----BEGIN RSA PUBLIC KEY-----
|
||||
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
|
||||
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
|
||||
@ -281,29 +270,28 @@ gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
|
||||
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
|
||||
-----END RSA PUBLIC KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertTrue($rsa->setPrivateKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$this->assertInstanceOf(PublicKey::class, $rsa);
|
||||
$rsa = $rsa->asPrivateKey();
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
$this->assertFalse($rsa->getPublicKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* make phpseclib generated XML keys be unsigned. this may need to be reverted
|
||||
* if it is later learned that XML keys are, in fact, supposed to be signed
|
||||
*
|
||||
* @group github468
|
||||
*/
|
||||
public function testUnsignedXML()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '<RSAKeyValue>
|
||||
<Modulus>v5OxcEgxPUfa701NpxnScCmlRkbwSGBiTWobHkIWZEB+AlRTHaVoZg/D8l6YzR7VdQidG6gF+nuUMjY75dBXgY/XcyVq0Hccf1jTfgARuNuq4GGG3hnCJVi2QsOgcf9R7TeXn+p1RKIhjQoWCiEQeEBTotNbJhcabNcPGSEJw+s=</Modulus>
|
||||
<Exponent>AQAB</Exponent>
|
||||
</RSAKeyValue>';
|
||||
|
||||
$rsa->load($key);
|
||||
$rsa->setPublicKey();
|
||||
$newkey = $rsa->getPublicKey('XML');
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$newkey = $rsa->toString('XML');
|
||||
|
||||
$this->assertSame(strtolower(preg_replace('#\s#', '', $key)), strtolower(preg_replace('#\s#', '', $newkey)));
|
||||
}
|
||||
@ -313,8 +301,6 @@ Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
|
||||
*/
|
||||
public function testSignedPKCS1()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/k7FwSDE9R9rvTU2nGdJwKaVG
|
||||
RvBIYGJNahseQhZkQH4CVFMdpWhmD8PyXpjNHtV1CJ0bqAX6e5QyNjvl0FeBj9dz
|
||||
@ -322,9 +308,8 @@ JWrQdxx/WNN+ABG426rgYYbeGcIlWLZCw6Bx/1HtN5ef6nVEoiGNChYKIRB4QFOi
|
||||
01smFxps1w8ZIQnD6wIDAQAB
|
||||
-----END PUBLIC KEY-----';
|
||||
|
||||
$rsa->load($key);
|
||||
$rsa->setPublicKey();
|
||||
$newkey = $rsa->getPublicKey();
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$newkey = "$rsa";
|
||||
|
||||
$this->assertSame(preg_replace('#\s#', '', $key), preg_replace('#\s#', '', $newkey));
|
||||
}
|
||||
@ -334,8 +319,6 @@ JWrQdxx/WNN+ABG426rgYYbeGcIlWLZCw6Bx/1HtN5ef6nVEoiGNChYKIRB4QFOi
|
||||
*/
|
||||
public function testPKCS8Only()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '-----BEGIN PRIVATE KEY-----
|
||||
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKB0yPMAbUHKqJxP
|
||||
5sjG9AOrQSAYNDc34NsnZ1tsi7fZ9lHlBaKZ6gjm2U9q+/qCKv2BuGINxWo2CMJp
|
||||
@ -353,15 +336,13 @@ qMnD/pkHR/NFcYSYShUJS0cHyryVl7/eCclsQlZTRdnVTtKF9xPGTQC8fK0G7BDN
|
||||
Z2sKniRCcDT1ZP4=
|
||||
-----END PRIVATE KEY-----';
|
||||
|
||||
$result = $rsa->load($key, 'PKCS8');
|
||||
$rsa = RSA::load($key, false, 'PKCS8');
|
||||
|
||||
$this->assertTrue($result);
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
}
|
||||
|
||||
public function testPKCS1EncryptionChange()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = 'PuTTY-User-Key-File-2: ssh-rsa
|
||||
Encryption: none
|
||||
Comment: phpseclib-generated-key
|
||||
@ -382,44 +363,23 @@ Gpb88h5NBYZzWXGZ37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ
|
||||
Private-MAC: 03e2cb74e1d67652fbad063d2ed0478f31bdf256
|
||||
';
|
||||
$key = preg_replace('#(?<!\r)\n#', "\r\n", $key);
|
||||
$this->assertTrue($rsa->load($key));
|
||||
|
||||
$rsa->setPrivateKeyFormat('PKCS1');
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
|
||||
PKCS1::setEncryptionAlgorithm('AES-256-CBC');
|
||||
$rsa->setPassword('demo');
|
||||
|
||||
$encryptedKey = (string) $rsa;
|
||||
$encryptedKey = $rsa->withPassword('demo')->toString('PKCS1');
|
||||
|
||||
$this->assertRegExp('#AES-256-CBC#', $encryptedKey);
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->setPassword('demo');
|
||||
$this->assertTrue($rsa->load($encryptedKey));
|
||||
$rsa->setPassword();
|
||||
$rsa->setPrivateKeyFormat('PuTTY');
|
||||
$key2 = (string) $rsa;
|
||||
$rsa = PublicKeyLoader::load($key, 'demo');
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
|
||||
OpenSSH::setComment('ecdsa-key-20181105');
|
||||
$key2 = $rsa->withPassword()->toString('PuTTY');
|
||||
|
||||
$this->assertSame($key, $key2);
|
||||
}
|
||||
|
||||
public function testRawKey()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = [
|
||||
'e' => new BigInteger('10001', 16),
|
||||
'n' => new BigInteger('aa18aba43b50deef38598faf87d2ab634e4571c130a9bca7b878267414faab8b471bd8965f5c9fc3' .
|
||||
'818485eaf529c26246f3055064a8de19c8c338be5496cbaeb059dc0b358143b44a35449eb2641131' .
|
||||
'21a455bd7fde3fac919e94b56fb9bb4f651cdb23ead439d6cd523eb08191e75b35fd13a7419b3090' .
|
||||
'f24787bd4f4e1967', 16)
|
||||
];
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$rsa->setPublicKeyFormat('raw');
|
||||
$this->assertEmpty("$rsa");
|
||||
}
|
||||
|
||||
public function testRawComment()
|
||||
{
|
||||
$key = 'PuTTY-User-Key-File-2: ssh-rsa
|
||||
@ -440,13 +400,10 @@ fM8VzC3ukvzzRh0pujUVTr/yQdmciASVFnZlt4xQy+ZEOVUAOfwjd//AFfXTvk6x
|
||||
EOpSeghXSs7IilJu8I6/sB1w5dakdeBSFkIynrlFXkO0uUw+QJJWjxY8SypzgIuP
|
||||
DzduF6XsQrCyo6dnIpGQCQ==
|
||||
Private-MAC: 35134b7434bf828b21404099861d455e660e8740';
|
||||
|
||||
$raw = PuTTY::load($key, 'password');
|
||||
$this->assertArrayHasKey('comment', $raw);
|
||||
$this->assertEquals($raw['comment'], 'phpseclib-generated-key');
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($raw);
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
}
|
||||
|
||||
public function testPrivateMSBlob()
|
||||
@ -465,16 +422,13 @@ Private-MAC: 35134b7434bf828b21404099861d455e660e8740';
|
||||
|
||||
$plaintext = 'zzz';
|
||||
|
||||
$privKey = new RSA();
|
||||
$privKey->load($key);
|
||||
|
||||
$privKey = PublicKeyLoader::load($key);
|
||||
$this->assertInstanceOf(PrivateKey::class, $privKey);
|
||||
$this->assertSame($privKey->getLoadedFormat(), 'MSBLOB');
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$privKey"));
|
||||
|
||||
$pubKey = new RSA();
|
||||
$pubKey->load($privKey->getPublicKey('msblob'));
|
||||
|
||||
$pubKey = PublicKeyLoader::load($privKey->getPublicKey()->toString('msblob'));
|
||||
$this->assertInstanceOf(PublicKey::class, $pubKey);
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$pubKey"));
|
||||
|
||||
$ciphertext = $pubKey->encrypt($plaintext);
|
||||
@ -486,9 +440,8 @@ Private-MAC: 35134b7434bf828b21404099861d455e660e8740';
|
||||
{
|
||||
$key = 'AAAAB3NzaC1yc2EAAAABIwAAAIEA/NcGSQFZ0ZgN1EbDusV6LLwLnQjs05ljKcVVP7Z6aKIJUyhUDHE30uJa5XfwPPBsZ3L3Q7S0yycVcuuHjdauugmpn9xx+gyoYs7UiV5G5rvxNcA/Tc+MofGhAMiTmNicorNAs5mv6fRoVbkpIONRXPz6WK0kjx/X04EV42Vm9Qk=';
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($key);
|
||||
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$this->assertInstanceOf(PublicKey::class, $rsa);
|
||||
$this->assertSame($rsa->getLoadedFormat(), 'OpenSSH');
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
@ -504,48 +457,13 @@ C/EwUYl8b0fAwEsEF3myb+ryzgA9ihY08Zs9NZdmt1Maa+I7lQcLX9F/65YdcAch
|
||||
ILaEujU=
|
||||
---- END SSH2 PUBLIC KEY ----';
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($key);
|
||||
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$this->assertInstanceOf(PublicKey::class, $rsa);
|
||||
$this->assertSame($rsa->getLoadedFormat(), 'PuTTY');
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, strlen("$rsa"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group github960
|
||||
*/
|
||||
public function testSetLoad()
|
||||
{
|
||||
$key = 'PuTTY-User-Key-File-2: ssh-rsa
|
||||
Encryption: aes256-cbc
|
||||
Comment: phpseclib-generated-key
|
||||
Public-Lines: 4
|
||||
AAAAB3NzaC1yc2EAAAADAQABAAAAgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4
|
||||
eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RK
|
||||
NUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0Tp0GbMJDy
|
||||
R4e9T04ZZw==
|
||||
Private-Lines: 8
|
||||
llx04QMegql0/nE5RvcJSrGrodxt6ytuv/JX2caeZBUyQwQc2WBNYagLHyHPM9jI
|
||||
9OUWz59FLhjFXZMDNMoUXxVmjwQpOAaVPYNxxFM9AF6/NXFji64K7huD9n4A+kLn
|
||||
sHwMLWPR5a/tZA0r05DZNz9ULA3mQu7Hz4EQ8ifu3uTPJuTmL51x6RmudYKysb20
|
||||
fM8VzC3ukvzzRh0pujUVTr/yQdmciASVFnZlt4xQy+ZEOVUAOfwjd//AFfXTvk6x
|
||||
7A45rNlU/uicHwLgoY1APvRHCFxw7F+uVW5L4mSX7NNzqBKkZ+1qpQTAfQvIfEIb
|
||||
444+CXsgIyOpqt6VxJH2u6elAtE1wau3YaFR8Alm8m97rFYzRi3oDP5NZYkTCWSV
|
||||
EOpSeghXSs7IilJu8I6/sB1w5dakdeBSFkIynrlFXkO0uUw+QJJWjxY8SypzgIuP
|
||||
DzduF6XsQrCyo6dnIpGQCQ==
|
||||
Private-MAC: 35134b7434bf828b21404099861d455e660e8740';
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->setPrivateKey($key);
|
||||
$rsa->load($key);
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($key);
|
||||
$rsa->setPrivateKey();
|
||||
$rsa->load($rsa);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group github980
|
||||
*/
|
||||
@ -558,19 +476,17 @@ NNj0BDlf38hOtkhDzz/hkYb+EBYLLvldhgsD0OvRNy8yhz7EjaUqLCB0juIN4QIB
|
||||
AAIBAAIBAAIBAAIBAA==
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load($key);
|
||||
$rsa->setHash('md5');
|
||||
$rsa->setMGFHash('md5');
|
||||
$rsa = PublicKeyLoader::load($key)
|
||||
->withHash('md5')
|
||||
->withMGFHash('md5')
|
||||
->withPadding(RSA::SIGNATURE_PKCS1);
|
||||
|
||||
$rsa->sign('zzzz', RSA::PADDING_PKCS1);
|
||||
$rsa->sign('zzzz');
|
||||
}
|
||||
|
||||
public function pkcs8tester($key, $pass)
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->setPassword($pass);
|
||||
$rsa->load($key);
|
||||
$rsa = PublicKeyLoader::load($key, $pass);
|
||||
$r = PKCS8::load($key, $pass);
|
||||
PKCS8::setEncryptionAlgorithm($r['meta']['algorithm']);
|
||||
if (isset($r['meta']['cipher'])) {
|
||||
@ -590,15 +506,13 @@ AAIBAAIBAAIBAAIBAA==
|
||||
$this->assertSame($r['meta']['prf'], $r2['meta']['prf']);
|
||||
}
|
||||
|
||||
$rsa2 = new RSA();
|
||||
$rsa2->setPassword($pass);
|
||||
$rsa2->load($newkey);
|
||||
$rsa2 = PublicKeyLoader::load($newkey, $pass);
|
||||
|
||||
// comparing $key to $newkey won't work since phpseclib randomly generates IV's and salt's
|
||||
// so we'll strip the encryption
|
||||
|
||||
$rsa->setPassword();
|
||||
$rsa2->setPassword();
|
||||
$rsa = $rsa->withPassword();
|
||||
$rsa2 = $rsa2->withPassword();
|
||||
$this->assertSame("$rsa", "$rsa2");
|
||||
}
|
||||
|
||||
@ -930,29 +844,8 @@ OFLPBrLe4Hw=
|
||||
$this->pkcs8tester($key, $pass);
|
||||
}
|
||||
|
||||
public function testGoodBad()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '-----BEGIN RSA PUBLIC KEY-----
|
||||
MIIBCgKCAQEA61BjmfXGEvWmegnBGSuS+rU9soUg2FnODva32D1AqhwdziwHINFa
|
||||
D1MVlcrYG6XRKfkcxnaXGfFDWHLEvNBSEVCgJjtHAGZIm5GL/KA86KDp/CwDFMSw
|
||||
luowcXwDwoyinmeOY9eKyh6aY72xJh7noLBBq1N0bWi1e2i+83txOCg4yV2oVXhB
|
||||
o8pYEJ8LT3el6Smxol3C1oFMVdwPgc0vTl25XucMcG/ALE/KNY6pqC2AQ6R2ERlV
|
||||
gPiUWOPatVkt7+Bs3h5Ramxh7XjBOXeulmCpGSynXNcpZ/06+vofGi/2MlpQZNhH
|
||||
Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
|
||||
-----END RSA PUBLIC KEY-----';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInstanceOf(RSA::class, $rsa->getPublicKey());
|
||||
$this->assertFalse($rsa->load('zzz'));
|
||||
$this->assertFalse($rsa->getPublicKey());
|
||||
}
|
||||
|
||||
public function testXMLDeclaration()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
|
||||
$key = '<?xml version="1.0" encoding="utf-8"?>
|
||||
<RSAKeyValue>
|
||||
<Modulus>AKoYq6Q7UN7vOFmPr4fSq2NORXHBMKm8p7h4JnQU+quLRxvYll9cn8OBhIXq9SnCYkbzBVBkqN4ZyMM4vlSWy66wWdwLNYFDtEo1RJ6yZBExIaRVvX/eP6yRnpS1b7m7T2Uc2yPq1DnWzVI+sIGR51s1/ROnQZswkPJHh71PThln</Modulus>
|
||||
@ -965,7 +858,8 @@ Ao8eayMp6FcvNucIpUndo1X8dKMv3Y26ZQIDAQAB
|
||||
<D>Fijko56+qGyN8M0RVyaRAXz++xTqHBLh3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxE=</D>
|
||||
</RSAKeyValue>';
|
||||
|
||||
$this->assertTrue($rsa->load($key));
|
||||
$this->assertInstanceOf(RSA::class, $rsa->getPublicKey());
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
$this->assertInstanceOf(PrivateKey::class, $rsa);
|
||||
$this->assertInstanceOf(PublicKey::class, $rsa->getPublicKey());
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@
|
||||
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Math\BigInteger;
|
||||
use phpseclib\Crypt\PublicKeyLoader;
|
||||
use phpseclib\Crypt\RSA\Keys\PKCS8;
|
||||
|
||||
class Unit_Crypt_RSA_ModeTest extends PhpseclibTestCase
|
||||
{
|
||||
@ -14,8 +16,6 @@ class Unit_Crypt_RSA_ModeTest extends PhpseclibTestCase
|
||||
{
|
||||
$plaintext = 'a';
|
||||
|
||||
$rsa = new RSA();
|
||||
|
||||
$privatekey = '-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
||||
@ -29,19 +29,21 @@ X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
|
||||
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$rsa->load($privatekey);
|
||||
$rsa->load($rsa->getPublicKey());
|
||||
$rsa = PublicKeyLoader::load($privatekey);
|
||||
$rsa = $rsa->getPublicKey()
|
||||
->withPadding(RSA::ENCRYPTION_NONE);
|
||||
|
||||
$expected = '105b92f59a87a8ad4da52c128b8c99491790ef5a54770119e0819060032fb9e772ed6772828329567f3d7e9472154c1530f8156ba7fd732f52ca1c06' .
|
||||
'5a3f5ed8a96c442e4662e0464c97f133aed31262170201993085a589565d67cc9e727e0d087e3b225c8965203b271e38a499c92fc0d6502297eca712' .
|
||||
'4d04bd467f6f1e7c';
|
||||
$expected = pack('H*', $expected);
|
||||
$result = $rsa->encrypt($plaintext, RSA::PADDING_NONE);
|
||||
$result = $rsa->encrypt($plaintext);
|
||||
|
||||
$this->assertEquals($result, $expected);
|
||||
|
||||
$rsa->load($privatekey);
|
||||
$this->assertEquals(trim($rsa->decrypt($result, RSA::PADDING_NONE), "\0"), $plaintext);
|
||||
$rsa = PublicKeyLoader::load($privatekey)
|
||||
->withPadding(RSA::ENCRYPTION_NONE);
|
||||
$this->assertEquals(trim($rsa->decrypt($result), "\0"), $plaintext);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,15 +51,14 @@ U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
*/
|
||||
public function testPSSSigs()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->setHash('sha1');
|
||||
$rsa->setMGFHash('sha1');
|
||||
$rsa->load('-----BEGIN PUBLIC KEY-----
|
||||
$rsa = PublicKeyLoader::load('-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqGKukO1De7zhZj6+H0qtjTkVx
|
||||
wTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUpwmJG8wVQZKjeGcjDOL5UlsuusFnc
|
||||
CzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ51s1SPrCBkedbNf0T
|
||||
p0GbMJDyR4e9T04ZZwIDAQAB
|
||||
-----END PUBLIC KEY-----');
|
||||
-----END PUBLIC KEY-----')
|
||||
->withHash('sha1')
|
||||
->withMGFHash('sha1');
|
||||
|
||||
$sig = pack('H*', '1bd29a1d704a906cd7f726370ce1c63d8fb7b9a620871a05f3141a311c0d6e75fefb5d36dfb50d3ea2d37cd67992471419bfadd35da6e13b494' .
|
||||
'058ddc9b568d4cfea13ddc3c62b86a6256f5f296980d1131d3eaec6089069a3de79983f73eae20198a18721338b4a66e9cfe80e4f8e4fcef7a5bead5cbb' .
|
||||
@ -72,22 +73,24 @@ p0GbMJDyR4e9T04ZZwIDAQAB
|
||||
public function testSmallModulo()
|
||||
{
|
||||
$plaintext = 'x';
|
||||
$n = new BigInteger(base64_decode('272435F22706FA96DE26E980D22DFF67'), 256);
|
||||
$e = new BigInteger(base64_decode('158753FF2AF4D1E5BBAB574D5AE6B54D'), 256);
|
||||
|
||||
$rsa = new RSA();
|
||||
$rsa->load(['n' => $n, 'e' => $e]);
|
||||
$key = PKCS8::savePublicKey(
|
||||
new BigInteger(base64_decode('272435F22706FA96DE26E980D22DFF67'), 256), // n
|
||||
new BigInteger(base64_decode('158753FF2AF4D1E5BBAB574D5AE6B54D'), 256) // e
|
||||
);
|
||||
$rsa = PublicKeyLoader::load($key);
|
||||
|
||||
$rsa->encrypt($plaintext);
|
||||
}
|
||||
|
||||
public function testPKCS1LooseVerify()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->load('-----BEGIN RSA PUBLIC KEY-----
|
||||
$rsa = PublicKeyLoader::load('-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBAMuqkz8ij+ESAaNvgocVGmapjlrIldmhRo4h2NX4e6IXiCLTSxASQtY4
|
||||
iqRnmyxqQSfaan2okTfQ6sP95bl8Qz8lgneW3ClC6RXG/wpJgsx7TXQ2kodlcKBF
|
||||
m4k72G75QXhZ+I40ZG7cjBf1/9egakR0a0X0MpeOrKCzMBLv9+mpAgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----');
|
||||
-----END RSA PUBLIC KEY-----')
|
||||
->withPadding(RSA::SIGNATURE_RELAXED_PKCS1);
|
||||
|
||||
$message = base64_decode('MYIBLjAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xNDA1MTUxNDM4MzRaMC8GCSqGSIb3DQEJBDEiBCBLzLIBGdOf0L2WRrIY' .
|
||||
'9KTwiHnReBW48S9C7LNRaPp5mDCBwgYLKoZIhvcNAQkQAi8xgbIwga8wgawwgakEIJDB9ZGwihf+TaiwrHQNkNHkqbN8Nuws0e77QNObkvFZMIGEMHCkbjBs' .
|
||||
@ -97,16 +100,14 @@ m4k72G75QXhZ+I40ZG7cjBf1/9egakR0a0X0MpeOrKCzMBLv9+mpAgMBAAE=
|
||||
$sig = base64_decode('XDSZWw6IcUj8ICxRJf04HzF8stzoiFAZSR2a0Rw3ziZxTOT0/NVUYJO5+9TaaREXEgxuCLpgmA+6W2SWrrGoxbbNfaI90ZoKeOAws4IX+9RfiWuooibjKcvt' .
|
||||
'GJYVVOCcjvQYxUUNbQ4EjCUonk3h7ECXfCCmWqbeq2LsyXeeYGE=');
|
||||
|
||||
$this->assertTrue($rsa->verify($message, $sig, RSA::PADDING_RELAXED_PKCS1));
|
||||
$this->assertTrue($rsa->verify($message, $sig));
|
||||
}
|
||||
|
||||
public function testZeroLengthSalt()
|
||||
{
|
||||
$plaintext = 'a';
|
||||
|
||||
$rsa = new RSA();
|
||||
|
||||
$privatekey = '-----BEGIN RSA PRIVATE KEY-----
|
||||
$rsa = PublicKeyLoader::load('-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
||||
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
|
||||
@ -118,96 +119,17 @@ L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
|
||||
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
|
||||
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$rsa->load($privatekey);
|
||||
$rsa->setSaltLength(0);
|
||||
$rsa->setHash('sha1');
|
||||
$rsa->setMGFHash('sha1');
|
||||
-----END RSA PRIVATE KEY-----')
|
||||
->withSaltLength(0)
|
||||
->withHash('sha1')
|
||||
->withMGFHash('sha1');
|
||||
|
||||
// Check we generate the correct signature.
|
||||
$sig = pack('H*', '0ddfc93548e21d015c0a289a640b3b79aecfdfae045f583c5925b91cc5c399bba181616ad6ae20d9662d966f0eb2fddb550f4733268e34d640f4c9dadcaf25b3c82c42130a5081c6ebad7883331c65b25b6a37ffa7c4233a468dae56180787e2718ed87c48d8d50b72f5850e4a40963b4f36710be250ecef6fe0bb91249261a3');
|
||||
$this->assertEquals($sig, $rsa->sign($plaintext));
|
||||
|
||||
// Check we can verify the signature correctly.
|
||||
$rsa->load($rsa->getPublicKey());
|
||||
$rsa = $rsa->getPublicKey();
|
||||
$this->assertTrue($rsa->verify($plaintext, $sig));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \phpseclib\Exception\UnsupportedOperationException
|
||||
*/
|
||||
public function testPrivateEncrypt()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$privatekey = '-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
||||
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
|
||||
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
|
||||
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
|
||||
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
|
||||
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
|
||||
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
|
||||
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
|
||||
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$rsa->load($privatekey);
|
||||
|
||||
$rsa->encrypt('hello, world!');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \phpseclib\Exception\UnsupportedOperationException
|
||||
*/
|
||||
public function testPublicSign()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->load('-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBAMuqkz8ij+ESAaNvgocVGmapjlrIldmhRo4h2NX4e6IXiCLTSxASQtY4
|
||||
iqRnmyxqQSfaan2okTfQ6sP95bl8Qz8lgneW3ClC6RXG/wpJgsx7TXQ2kodlcKBF
|
||||
m4k72G75QXhZ+I40ZG7cjBf1/9egakR0a0X0MpeOrKCzMBLv9+mpAgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----');
|
||||
|
||||
$rsa->sign('hello, world!');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \phpseclib\Exception\UnsupportedOperationException
|
||||
*/
|
||||
public function testPublicDecrypt()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$rsa->load('-----BEGIN RSA PUBLIC KEY-----
|
||||
MIGJAoGBAMuqkz8ij+ESAaNvgocVGmapjlrIldmhRo4h2NX4e6IXiCLTSxASQtY4
|
||||
iqRnmyxqQSfaan2okTfQ6sP95bl8Qz8lgneW3ClC6RXG/wpJgsx7TXQ2kodlcKBF
|
||||
m4k72G75QXhZ+I40ZG7cjBf1/9egakR0a0X0MpeOrKCzMBLv9+mpAgMBAAE=
|
||||
-----END RSA PUBLIC KEY-----');
|
||||
|
||||
$rsa->decrypt('zzz');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \phpseclib\Exception\UnsupportedOperationException
|
||||
*/
|
||||
public function testPrivateVerify()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$privatekey = '-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
||||
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
|
||||
3tx4VgMtrQ+WEgCjhoTwo23KMBAuJGSYnRmoBZM3lMfTKevIkAidPExvYCdm5dYq3XToLkkLv5L2
|
||||
pIIVOFMDG+KESnAFV7l2c+cnzRMW0+b6f8mR1CJzZuxVLL6Q02fvLi55/mbSYxECQQDeAw6fiIQX
|
||||
GukBI4eMZZt4nscy2o12KyYner3VpoeE+Np2q+Z3pvAMd/aNzQ/W9WaI+NRfcxUJrmfPwIGm63il
|
||||
AkEAxCL5HQb2bQr4ByorcMWm/hEP2MZzROV73yF41hPsRC9m66KrheO9HPTJuo3/9s5p+sqGxOlF
|
||||
L0NDt4SkosjgGwJAFklyR1uZ/wPJjj611cdBcztlPdqoxssQGnh85BzCj/u3WqBpE2vjvyyvyI5k
|
||||
X6zk7S0ljKtt2jny2+00VsBerQJBAJGC1Mg5Oydo5NwD6BiROrPxGo2bpTbu/fhrT8ebHkTz2epl
|
||||
U9VQQSQzY1oZMVX8i1m5WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ
|
||||
37sJ5QsW+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$rsa->load($privatekey);
|
||||
|
||||
$rsa->verify('hello, world!', 'dummysignature');
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
use phpseclib\File\X509;
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\PublicKeyLoader;
|
||||
|
||||
class Unit_File_X509_CSRTest extends PhpseclibTestCase
|
||||
{
|
||||
@ -98,10 +99,9 @@ draiRBZruwMPwPIP
|
||||
// on PHP 7.1, with older versions of phpseclib, this would produce a "A non-numeric value encountered" warning
|
||||
public function testNewCSR()
|
||||
{
|
||||
$rsa = new RSA();
|
||||
$x509 = new X509();
|
||||
|
||||
$rsa->load('-----BEGIN RSA PRIVATE KEY-----
|
||||
$rsa = PublicKeyLoader::load('-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXAIBAAKBgQCqGKukO1De7zhZj6+H0qtjTkVxwTCpvKe4eCZ0FPqri0cb2JZfXJ/DgYSF6vUp
|
||||
wmJG8wVQZKjeGcjDOL5UlsuusFncCzWBQ7RKNUSesmQRMSGkVb1/3j+skZ6UtW+5u09lHNsj6tQ5
|
||||
1s1SPrCBkedbNf0Tp0GbMJDyR4e9T04ZZwIDAQABAoGAFijko56+qGyN8M0RVyaRAXz++xTqHBLh
|
||||
|
@ -46,7 +46,7 @@ class Unit_File_X509_SPKACTest extends PhpseclibTestCase
|
||||
|
||||
public function testSaveSPKAC()
|
||||
{
|
||||
extract(RSA::createKey());
|
||||
$privatekey = RSA::createKey();
|
||||
|
||||
$x509 = new X509();
|
||||
$x509->setPrivateKey($privatekey);
|
||||
|
@ -9,6 +9,7 @@ use phpseclib\File\ASN1;
|
||||
use phpseclib\File\ASN1\Element;
|
||||
use phpseclib\File\X509;
|
||||
use phpseclib\Crypt\RSA;
|
||||
use phpseclib\Crypt\PublicKeyLoader;
|
||||
|
||||
class Unit_File_X509_X509Test extends PhpseclibTestCase
|
||||
{
|
||||
@ -133,7 +134,7 @@ ulvKGQSy068Bsn5fFNum21K5mvMSf3yinDtvmX3qUA12IxL/92ZzKbeVCq3Yi7Le
|
||||
IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==
|
||||
-----END CERTIFICATE-----');
|
||||
|
||||
$value = $this->_encodeOID('1.2.3.4');
|
||||
$value = ASN1::encodeOID('1.2.3.4');
|
||||
$ext = chr(ASN1::TYPE_OBJECT_IDENTIFIER) . ASN1::encodeLength(strlen($value)) . $value;
|
||||
$value = 'zzzzzzzzz';
|
||||
$ext.= chr(ASN1::TYPE_OCTET_STRING) . ASN1::encodeLength(strlen($value)) . $value;
|
||||
@ -151,8 +152,7 @@ IOkKcGQRCMha8X2e7GmlpdWC1ycenlbN0nbVeSv3JUMcafC4+Q==
|
||||
*/
|
||||
public function testSaveNullRSAParam()
|
||||
{
|
||||
$privKey = new RSA();
|
||||
$privKey->load('-----BEGIN RSA PRIVATE KEY-----
|
||||
$privKey = PublicKeyLoader::load('-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQDMswfEpAgnUDWA74zZw5XcPsWh1ly1Vk99tsqwoFDkLF7jvXy1
|
||||
dDLHYfuquvfxCgcp8k/4fQhx4ubR8bbGgEq9B05YRnViK0R0iBB5Ui4IaxWYYhKE
|
||||
8xqAEH2fL+/7nsqqNFKkEN9KeFwc7WbMY49U2adlMrpBdRjk1DqIEW3QTwIDAQAB
|
||||
@ -168,9 +168,7 @@ aBtsWpliLSex/HHhtRW9AkBGcq67zKmEpJ9kXcYLEjJii3flFS+Ct/rNm+Hhm1l7
|
||||
4vca9v/F2hGVJuHIMJ8mguwYlNYzh2NqoIDJTtgOkBmt
|
||||
-----END RSA PRIVATE KEY-----');
|
||||
|
||||
$pubKey = new RSA();
|
||||
$pubKey->load($privKey->getPublicKey());
|
||||
$pubKey->setPublicKey();
|
||||
$pubKey = $privKey->getPublicKey();
|
||||
|
||||
$subject = new X509();
|
||||
$subject->setDNProp('id-at-organizationName', 'phpseclib demo cert');
|
||||
@ -192,37 +190,12 @@ aBtsWpliLSex/HHhtRW9AkBGcq67zKmEpJ9kXcYLEjJii3flFS+Ct/rNm+Hhm1l7
|
||||
$this->assertArrayHasKey('parameters', $cert['tbsCertificate']['signature']);
|
||||
}
|
||||
|
||||
private function _encodeOID($oid)
|
||||
{
|
||||
if ($oid === false) {
|
||||
user_error('Invalid OID');
|
||||
return false;
|
||||
}
|
||||
$value = '';
|
||||
$parts = explode('.', $oid);
|
||||
$value = chr(40 * $parts[0] + $parts[1]);
|
||||
for ($i = 2; $i < count($parts); $i++) {
|
||||
$temp = '';
|
||||
if (!$parts[$i]) {
|
||||
$temp = "\0";
|
||||
} else {
|
||||
while ($parts[$i]) {
|
||||
$temp = chr(0x80 | ($parts[$i] & 0x7F)) . $temp;
|
||||
$parts[$i] >>= 7;
|
||||
}
|
||||
$temp[strlen($temp) - 1] = $temp[strlen($temp) - 1] & chr(0x7F);
|
||||
}
|
||||
$value.= $temp;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function testGetOID()
|
||||
{
|
||||
// load the OIDs
|
||||
new X509();
|
||||
$this->assertEquals(ASN1::getOID('2.16.840.1.101.3.4.2.1'), '2.16.840.1.101.3.4.2.1');
|
||||
$this->assertEquals(ASN1::getOID('id-sha256'), '2.16.840.1.101.3.4.2.1');
|
||||
$this->assertEquals(ASN1::getOID('1.2.840.113549.1.1.5'), '1.2.840.113549.1.1.5');
|
||||
$this->assertEquals(ASN1::getOID('sha1WithRSAEncryption'), '1.2.840.113549.1.1.5');
|
||||
$this->assertEquals(ASN1::getOID('zzz'), 'zzz');
|
||||
}
|
||||
|
||||
@ -383,7 +356,8 @@ Mj93S
|
||||
// fixed by #1104
|
||||
public function testMultipleDomainNames()
|
||||
{
|
||||
extract(RSA::createKey(512));
|
||||
$privatekey = RSA::createKey(512);
|
||||
$publickey = $privatekey->getPublicKey();
|
||||
|
||||
$subject = new X509();
|
||||
$subject->setDomain('example.com', 'example.net');
|
||||
@ -578,8 +552,7 @@ keSg3sfr4VWT545guJlTe+6vvelxbPFIXCXnyVLoePBYZtEe8FQhIBxd3EQHsxuJ
|
||||
iSoMCxKCa8r5P1DrxKaJAkBBP87OdahRq0CBQjTFg0wmPs66PoTXA4hZvSxV77CO
|
||||
tMPj6Pas7Muejogm6JkmxXC/uT6Tzfknd0B3XSmtDzGL
|
||||
-----END RSA PRIVATE KEY-----';
|
||||
$cakey = new RSA();
|
||||
$cakey->load($pemcakey);
|
||||
$cakey = PublicKeyLoader::load($pemcakey);
|
||||
$pemca = '-----BEGIN CERTIFICATE-----
|
||||
MIICADCCAWmgAwIBAgIUJXQulcz5xkTam8UGC/yn6iVaiWwwDQYJKoZIhvcNAQEF
|
||||
BQAwHDEaMBgGA1UECgwRcGhwc2VjbGliIGRlbW8gQ0EwHhcNMTgwMTIxMTc0NzM0
|
||||
|
Loading…
x
Reference in New Issue
Block a user