1
0
mirror of https://github.com/danog/tgseclib.git synced 2024-12-15 10:27:01 +01:00
tgseclib/phpseclib/Crypt/Common/AsymmetricKey.php

459 lines
11 KiB
PHP
Raw Normal View History

2016-12-23 17:02:07 +01:00
<?php
/**
* Base Class for all asymmetric key ciphers
*
* PHP version 5
*
* @category Crypt
* @package AsymmetricKey
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2016 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://phpseclib.sourceforge.net
*/
namespace phpseclib\Crypt\Common;
use phpseclib\Exception\UnsupportedFormatException;
use phpseclib\Exception\NoKeyLoadedException;
2016-12-23 17:02:07 +01:00
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\Hash;
use phpseclib\Crypt\RSA;
use phpseclib\Crypt\DSA;
use phpseclib\Crypt\ECDSA;
2016-12-23 17:02:07 +01:00
/**
* Base Class for all stream cipher classes
*
* @package AsymmetricKey
* @author Jim Wigginton <terrafrost@php.net>
*/
abstract class AsymmetricKey
{
/**
* Precomputed Zero
*
* @var \phpseclib\Math\BigInteger
* @access private
*/
protected static $zero;
/**
* Precomputed One
*
* @var \phpseclib\Math\BigInteger
* @access private
*/
protected static $one;
/**
* Format of the loaded key
2016-12-23 17:02:07 +01:00
*
* @var string
* @access private
*/
protected $format;
2016-12-23 17:02:07 +01:00
/**
* Hash function
2016-12-23 17:02:07 +01:00
*
* @var \phpseclib\Crypt\Hash
2016-12-23 17:02:07 +01:00
* @access private
*/
protected $hash;
2016-12-23 17:02:07 +01:00
/**
* HMAC function
2016-12-23 17:02:07 +01:00
*
* @var \phpseclib\Crypt\Hash
2016-12-23 17:02:07 +01:00
* @access private
*/
private $hmac;
2016-12-23 17:02:07 +01:00
/**
* Enable Blinding?
2016-12-23 17:02:07 +01:00
*
* @var bool
2016-12-23 17:02:07 +01:00
* @access private
*/
protected static $enableBlinding = true;
2016-12-23 17:02:07 +01:00
2018-10-25 03:00:37 +02:00
/**
* Supported plugins (lower case)
2018-10-25 03:00:37 +02:00
*
* @see self::initialize_static_variables()
* @var array
2018-10-25 03:00:37 +02:00
* @access private
*/
private static $plugins = [];
2018-10-25 03:00:37 +02:00
2016-12-23 17:02:07 +01:00
/**
* Supported plugins (original case)
2016-12-23 17:02:07 +01:00
*
* @see self::initialize_static_variables()
* @var array
2016-12-23 17:02:07 +01:00
* @access private
*/
private static $origPlugins = [];
2016-12-23 17:02:07 +01:00
/**
* Supported signature formats (lower case)
2016-12-23 17:02:07 +01:00
*
* @see self::initialize_static_variables()
* @var array
2016-12-23 17:02:07 +01:00
* @access private
*/
private static $signatureFormats = [];
2016-12-23 17:02:07 +01:00
/**
* Supported signature formats (original case)
*
* @see self::initialize_static_variables()
* @var array
* @access private
*/
private static $signatureFileFormats = [];
2016-12-23 17:02:07 +01:00
/**
2018-10-25 03:00:37 +02:00
* Available Engines
2016-12-23 17:02:07 +01:00
*
2018-10-25 03:00:37 +02:00
* @var boolean[]
* @access private
2016-12-23 17:02:07 +01:00
*/
2018-10-25 03:00:37 +02:00
protected static $engines = [];
2016-12-23 17:02:07 +01:00
/**
* The constructor
*/
protected function __construct()
2016-12-23 17:02:07 +01:00
{
self::initialize_static_variables();
$this->hash = new Hash('sha256');
$this->hmac = new Hash('sha256');
}
/**
* Initialize static variables
*/
protected static function initialize_static_variables()
{
if (!isset(self::$zero)) {
self::$zero= new BigInteger(0);
self::$one = new BigInteger(1);
}
self::loadPlugins('Keys');
if (static::ALGORITHM != 'RSA') {
self::loadPlugins('Signature');
}
}
/**
* Load the key
*
* @param string $key
* @param string $type
* @param string $password
2017-08-03 09:16:16 +02:00
* @return array|bool
2016-12-23 17:02:07 +01:00
*/
protected static function load($key, $type, $password)
2016-12-23 17:02:07 +01:00
{
self::initialize_static_variables();
2016-12-23 17:02:07 +01:00
$components = false;
if ($type === false) {
foreach (self::$plugins[static::ALGORITHM]['Keys'] as $format) {
try {
$components = $format::load($key, $password);
2016-12-23 17:02:07 +01:00
} 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);
2016-12-23 17:02:07 +01:00
}
}
if ($components === false) {
throw new NoKeyLoadedException('Unable to read key');
2016-12-23 17:02:07 +01:00
}
$components['format'] = $format;
2016-12-23 17:02:07 +01:00
return $components;
}
/**
* Validate Plugin
2016-12-23 17:02:07 +01:00
*
* @access private
* @param string $format
2016-12-23 17:02:07 +01:00
* @param string $type
* @param string $method optional
* @return mixed
2016-12-23 17:02:07 +01:00
*/
protected static function validatePlugin($format, $type, $method = NULL)
2016-12-23 17:02:07 +01:00
{
$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
*
* @access private
* @param $format
*/
private static function loadPlugins($format)
{
if (!isset(self::$plugins[static::ALGORITHM][$format])) {
self::$plugins[static::ALGORITHM][$format] = [];
foreach (new \DirectoryIterator(__DIR__ . '/../' . static::ALGORITHM . '/' . $format . '/') as $file) {
if ($file->getExtension() != 'php') {
2016-12-23 17:02:07 +01:00
continue;
}
$name = $file->getBasename('.php');
$type = 'phpseclib\Crypt\\' . static::ALGORITHM . '\\' . $format . '\\' . $name;
$reflect = new \ReflectionClass($type);
if ($reflect->isTrait()) {
continue;
2016-12-23 17:02:07 +01:00
}
self::$plugins[static::ALGORITHM][$format][strtolower($name)] = $type;
self::$origPlugins[static::ALGORITHM][$format][] = $name;
2016-12-23 17:02:07 +01:00
}
}
}
/**
* Returns a list of supported formats.
*
* @access public
* @return array
*/
public static function getSupportedKeyFormats()
{
self::initialize_static_variables();
return self::$plugins[static::ALGORITHM]['Keys'];
}
/**
* Add a fileformat plugin
*
* The plugin needs to either already be loaded or be auto-loadable.
* Loading a plugin whose shortname overwrite an existing shortname will overwrite the old plugin.
*
* @see self::load()
* @param string $fullname
* @access public
* @return bool
*/
public static function addFileFormat($fullname)
{
self::initialize_static_variables();
if (class_exists($fullname)) {
2018-10-25 03:00:37 +02:00
$meta = new \ReflectionClass($fullname);
2016-12-23 17:02:07 +01:00
$shortname = $meta->getShortName();
self::$plugins[static::ALGORITHM]['Keys'][strtolower($shortname)] = $fullname;
self::$origPlugins[static::ALGORITHM]['Keys'][] = $shortname;
}
}
/**
* Returns the format of the loaded key.
2016-12-23 17:02:07 +01:00
*
* If the key that was loaded wasn't in a valid or if the key was auto-generated
* with RSA::createKey() then this will return false.
2016-12-23 17:02:07 +01:00
*
* @see self::load()
2016-12-23 17:02:07 +01:00
* @access public
* @return mixed
*/
public function getLoadedFormat()
2016-12-23 17:02:07 +01:00
{
if ($this->format === false) {
2016-12-23 17:02:07 +01:00
return false;
}
$meta = new \ReflectionClass($this->format);
return $meta->getShortName();
2016-12-23 17:02:07 +01:00
}
2018-10-25 03:00:37 +02:00
/**
* Tests engine validity
2018-10-25 03:00:37 +02:00
*
* @access public
* @param int $val
2018-10-25 03:00:37 +02:00
*/
public static function useBestEngine()
2018-10-25 03:00:37 +02:00
{
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')
];
2018-10-25 03:00:37 +02:00
return static::$engines;
2018-10-25 03:00:37 +02:00
}
2016-12-23 17:02:07 +01:00
/**
* Flag to use internal engine only (useful for unit testing)
2016-12-23 17:02:07 +01:00
*
* @access public
*/
public static function useInternalEngine()
2016-12-23 17:02:07 +01:00
{
static::$engines = [
'PHP' => true,
'OpenSSL' => false,
'libsodium' => false
];
2016-12-23 17:02:07 +01:00
}
/**
* __toString() magic method
2016-12-23 17:02:07 +01:00
*
* @return string
2016-12-23 17:02:07 +01:00
*/
public function __toString()
2016-12-23 17:02:07 +01:00
{
return $this->toString('PKCS8');
2016-12-23 17:02:07 +01:00
}
/**
* Determines which hashing function should be used
*
* @access public
* @param string $hash
*/
public function withHash($hash)
2016-12-23 17:02:07 +01:00
{
$new = clone $this;
$new->hash = new Hash($hash);
$new->hmac = new Hash($hash);
return $new;
2016-12-23 17:02:07 +01:00
}
/**
* Compute the pseudorandom k for signature generation,
* using the process specified for deterministic DSA.
*
* @access public
* @param string $h1
* @return string
*/
protected function computek($h1)
{
$v = str_repeat("\1", strlen($h1));
$k = str_repeat("\0", strlen($h1));
$x = $this->int2octets($this->x);
$h1 = $this->bits2octets($h1);
$this->hmac->setKey($k);
$k = $this->hmac->hash($v . "\0" . $x . $h1);
$this->hmac->setKey($k);
$v = $this->hmac->hash($v);
$k = $this->hmac->hash($v . "\1" . $x . $h1);
$this->hmac->setKey($k);
$v = $this->hmac->hash($v);
$qlen = $this->q->getLengthInBytes();
while (true) {
$t = '';
while (strlen($t) < $qlen) {
$v = $this->hmac->hash($v);
$t = $t . $v;
}
$k = $this->bits2int($t);
if (!$k->equals(self::$zero) && $k->compare($this->q) < 0) {
break;
}
$k = $this->hmac->hash($v . "\0");
$this->hmac->setKey($k);
$v = $this->hmac->hash($v);
}
return $k;
}
/**
* Integer to Octet String
*
* @access private
* @param \phpseclib\Math\BigInteger $v
* @return string
*/
private function int2octets($v)
{
$out = $v->toBytes();
$rolen = $this->q->getLengthInBytes();
if (strlen($out) < $rolen) {
return str_pad($out, $rolen, "\0", STR_PAD_LEFT);
} else if (strlen($out) > $rolen) {
return substr($out, -$rolen);
} else {
return $out;
}
}
/**
* Bit String to Integer
*
* @access private
* @param string $in
* @return \phpseclib\Math\BigInteger
*/
protected function bits2int($in)
{
$v = new BigInteger($in, 256);
$vlen = strlen($in) << 3;
$qlen = $this->q->getLength();
if ($vlen > $qlen) {
return $v->bitwise_rightShift($vlen - $qlen);
}
return $v;
}
/**
* Bit String to Octet String
*
* @access private
* @param string $in
* @return string
*/
private function bits2octets($in)
{
$z1 = $this->bits2int($in);
$z2 = $z1->subtract($this->q);
return $z2->compare(self::$zero) < 0 ?
$this->int2octets($z1) :
$this->int2octets($z2);
}
}