add ECDSA / EdDSA support

This commit is contained in:
terrafrost 2018-10-24 20:00:37 -05:00
parent faa073ff2a
commit 0398f7a815
146 changed files with 11933 additions and 707 deletions

View File

@ -16,6 +16,7 @@
namespace phpseclib\Common\Functions;
use phpseclib\Math\BigInteger;
use phpseclib\Math\Common\FiniteField;
/**
* Common String Functions
@ -106,9 +107,8 @@ abstract class Strings
* @param string $format
* @param $data
* @return mixed
* @access public
*/
public static function unpackSSH2($format, $data)
public static function unpackSSH2($format, &$data)
{
$result = [];
for ($i = 0; $i < strlen($format); $i++) {
@ -205,8 +205,8 @@ abstract class Strings
$result.= pack('Na*', strlen($element), $element);
break;
case 'i':
if (!$element instanceof BigInteger) {
throw new \InvalidArgumentException('A phpseclib\Math\BigInteger object was expected.');
if (!$element instanceof BigInteger && !$element instanceof FiniteField\Integer) {
throw new \InvalidArgumentException('A phpseclib\Math\BigInteger or phpseclib\Math\Common\FiniteField\Integer object was expected.');
}
$element = $element->toBytes(true);
$result.= pack('Na*', strlen($element), $element);
@ -224,4 +224,95 @@ abstract class Strings
}
return $result;
}
/**
* Convert binary data into bits
*
* bin2hex / hex2bin refer to base-256 encoded data as binary, whilst
* decbin / bindec refer to base-2 encoded data as binary. For the purposes
* of this function, bin refers to base-256 encoded data whilst bits refers
* to base-2 encoded data
*
* @access public
* @param string $x
* @return string
*/
public static function bits2bin($x)
{
/*
// the pure-PHP approach is faster than the GMP approach
if (function_exists('gmp_export')) {
return strlen($x) ? gmp_export(gmp_init($x, 2)) : gmp_init(0);
}
*/
if (preg_match('#[^01]#', $x)) {
throw new \RuntimeException('The only valid characters are 0 and 1');
}
if (!defined('PHP_INT_MIN')) {
define('PHP_INT_MIN', ~PHP_INT_MAX);
}
$length = strlen($x);
if (!$length) {
return '';
}
$block_size = PHP_INT_SIZE << 3;
$pad = $block_size - ($length % $block_size);
if ($pad != $block_size) {
$x = str_repeat('0', $pad) . $x;
}
$parts = str_split($x, $block_size);
$str = '';
foreach ($parts as $part) {
$xor = $part[0] == '1' ? PHP_INT_MIN : 0;
$part[0] = '0';
$str.= pack(
PHP_INT_SIZE == 4 ? 'N' : 'J',
$xor ^ eval('return 0b' . $part . ';')
);
}
return ltrim($str, "\0");
}
/**
* Convert bits to binary data
*
* @access public
* @param string $x
* @return string
*/
public static function bin2bits($x)
{
/*
// the pure-PHP approach is slower than the GMP approach BUT
// i want to the pure-PHP version to be easily unit tested as well
if (function_exists('gmp_import')) {
return gmp_strval(gmp_import($x), 2);
}
*/
$len = strlen($x);
$mod = $len % PHP_INT_SIZE;
if ($mod) {
$x = str_pad($x, $len + PHP_INT_SIZE - $mod, "\0", STR_PAD_LEFT);
}
$bits = '';
if (PHP_INT_SIZE == 4) {
$digits = unpack('N*', $x);
foreach ($digits as $digit) {
$bits.= sprintf('%032b', $digit);
}
} else {
$digits = unpack('J*', $x);
foreach ($digits as $digit) {
$bits.= sprintf('%064b', $digit);
}
}
return ltrim($bits, '0');
}
}

View File

@ -18,6 +18,8 @@ namespace phpseclib\Crypt\Common;
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\Hash;
use ParagonIE\ConstantTime\Base64;
use phpseclib\Exception\UnsupportedOperationException;
use phpseclib\Exception\FileNotFoundException;
/**
* Base Class for all stream cipher classes
@ -43,16 +45,6 @@ abstract class AsymmetricKey
*/
protected static $one;
/**
* Engine
*
* This is only used for key generation. Valid values are RSA::ENGINE_INTERNAL and RSA::ENGINE_OPENSSL
*
* @var int
* @access private
*/
protected static $engine = NULL;
/**
* OpenSSL configuration file name.
*
@ -132,6 +124,17 @@ abstract class AsymmetricKey
*/
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
*
@ -148,21 +151,13 @@ abstract class AsymmetricKey
*/
private $hmac;
/**#@+
* @access private
* @see self::__construct()
*/
/**
* To use the pure-PHP implementation
*/
const ENGINE_INTERNAL = 1;
/**
* To use the OpenSSL library
* Available Engines
*
* (if enabled; otherwise, the internal implementation will be used)
* @var boolean[]
* @access private
*/
const ENGINE_OPENSSL = 2;
/**#@-*/
protected static $engines = [];
/**
* The constructor
@ -180,57 +175,35 @@ abstract class AsymmetricKey
/**
* Tests engine validity
*
* @return boolean
* @access public
* @param int $val
*/
public static function isValidEngine($val)
public static function useBestEngine()
{
switch ($val) {
case self::ENGINE_OPENSSL:
return extension_loaded('openssl') && file_exists(self::$configFile);
case self::ENGINE_INTERNAL:
return true;
}
return false;
}
/**
* Sets the engine
*
* Only used in RSA::createKey. Valid values are RSA::ENGINE_OPENSSL and RSA::ENGINE_INTERNAL
*
* @access public
* @param int $val
*/
public static function setPreferredEngine($val)
{
static::$engine = null;
$candidateEngines = [
$val,
self::ENGINE_OPENSSL
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')
];
foreach ($candidateEngines as $engine) {
if (static::isValidEngine($engine)) {
static::$engine = $engine;
break;
}
}
if (!isset(static::$engine)) {
static::$engine = self::ENGINE_INTERNAL;
}
return static::$engines;
}
/**
* Returns the engine
* Flag to use internal engine only (useful for unit testing)
*
* @access public
* @return int
*/
public static function getEngine()
public static function useInternalEngine()
{
return self::$engine;
static::$engines = [
'PHP' => true,
'OpenSSL' => false,
'libsodium' => false
];
}
/**
@ -243,7 +216,7 @@ abstract class AsymmetricKey
if (!isset(self::$zero)) {
self::$zero= new BigInteger(0);
self::$one = new BigInteger(1);
self::$configFile = __DIR__ . '/../openssl.cnf';
self::$configFile = __DIR__ . '/../../openssl.cnf';
}
self::loadPlugins('Keys');
@ -268,6 +241,10 @@ abstract class AsymmetricKey
}
$name = $file->getBasename('.php');
$type = 'phpseclib\Crypt\\' . static::ALGORITHM . '\\' . $format . '\\' . $name;
$reflect = new \ReflectionClass($type);
if ($reflect->isTrait()) {
continue;
}
self::$plugins[static::ALGORITHM][$format][strtolower($name)] = $type;
self::$origPlugins[static::ALGORITHM][$format][] = $name;
}
@ -305,7 +282,7 @@ abstract class AsymmetricKey
* @param string $type
* @return array|bool
*/
public function load($key, $type)
protected function load($key, $type)
{
$components = false;
if ($type === false) {
@ -343,9 +320,9 @@ abstract class AsymmetricKey
* @access private
* @param string $key
* @param string $type
* @return array|bool
* @return array
*/
public function setPublicKey($key, $type)
protected function setPublicKey($key, $type)
{
$components = false;
if ($type === false) {
@ -409,7 +386,7 @@ abstract class AsymmetricKey
self::initialize_static_variables();
if (class_exists($fullname)) {
$meta = new \ReflectionClass($path);
$meta = new \ReflectionClass($fullname);
$shortname = $meta->getShortName();
self::$plugins[static::ALGORITHM]['Keys'][strtolower($shortname)] = $fullname;
self::$origPlugins[static::ALGORITHM]['Keys'][] = $shortname;
@ -471,6 +448,15 @@ abstract class AsymmetricKey
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 '';
@ -499,6 +485,16 @@ abstract class AsymmetricKey
*/
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;
}
@ -511,9 +507,47 @@ abstract class AsymmetricKey
*/
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.
*

View File

@ -64,12 +64,12 @@ abstract class OpenSSH
* @access public
* @param string $key
* @param string $type
* @return array|bool
* @return array
*/
public static function load($key, $type)
{
if (!is_string($key)) {
return false;
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
$parts = explode(' ', $key, 3);
@ -79,21 +79,20 @@ abstract class OpenSSH
$comment = isset($parts[1]) ? $parts[1] : false;
} else {
if ($parts[0] != $type) {
return false;
throw new \UnexpectedValueException('Expected a ' . $type . ' key - got a ' . $parts[0] . ' key');
}
$key = Base64::decode($parts[1]);
$comment = isset($parts[2]) ? $parts[2] : false;
}
if ($key === false) {
return false;
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
if (substr($key, 0, 11) != "\0\0\0\7$type") {
return false;
if (Strings::shift($key, strlen($type) + 4) != "\0\0\0" . chr(strlen($type)) . $type) {
throw new \UnexpectedValueException('Key appears to be malformed');
}
Strings::shift($key, 11);
if (strlen($key) <= 4) {
return false;
throw new \UnexpectedValueException('Key appears to be malformed');
}
return $key;

View File

@ -22,6 +22,7 @@ use phpseclib\Crypt\AES;
use phpseclib\Crypt\DES;
use phpseclib\Crypt\TripleDES;
use phpseclib\File\ASN1;
use phpseclib\Exception\UnsupportedAlgorithmException;
/**
* PKCS1 Formatted Key Handler
@ -93,7 +94,7 @@ abstract class PKCS1 extends PKCS
case preg_match("#^DES-$modes$#", $algo, $matches):
return new DES(self::getEncryptionMode($matches[1]));
default:
throw new \UnexpectedValueException('Unsupported encryption algorithmn');
throw new UnsupportedAlgorithmException($algo . ' is not a supported algorithm');
}
}
@ -122,12 +123,12 @@ abstract class PKCS1 extends PKCS
* @access public
* @param string $key
* @param string $password optional
* @return array|bool
* @return array
*/
protected static function load($key, $password)
{
if (!is_string($key)) {
return false;
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
@ -163,7 +164,7 @@ abstract class PKCS1 extends PKCS
if ($decoded !== false) {
$key = $decoded;
} elseif (self::$format == self::MODE_PEM) {
return false;
throw new \UnexpectedValueException('Expected base64-encoded PEM format but was unable to decode base64 text');
}
}
}

View File

@ -138,6 +138,7 @@ abstract class PKCS8 extends PKCS
/**
* Returns a SymmetricKey object based on a PBES1 $algo
*
* @return \phpseclib\Crypt\Common\SymmetricKey
* @access public
* @param string $algo
@ -267,51 +268,54 @@ abstract class PKCS8 extends PKCS
private static function initialize_static_variables()
{
if (!static::$childOIDsLoaded) {
ASN1::loadOIDs([static::OID_VALUE => static::OID_NAME]);
ASN1::loadOIDs(is_array(static::OID_NAME) ?
array_combine(static::OID_NAME, static::OID_VALUE) :
[static::OID_NAME => static::OID_VALUE]
);
static::$childOIDsLoaded = true;
}
if (!self::$oidsLoaded) {
// from https://tools.ietf.org/html/rfc2898
ASN1::loadOIDs([
// PBES1 encryption schemes
'1.2.840.113549.1.5.1' => 'pbeWithMD2AndDES-CBC',
'1.2.840.113549.1.5.4' => 'pbeWithMD2AndRC2-CBC',
'1.2.840.113549.1.5.3' => 'pbeWithMD5AndDES-CBC',
'1.2.840.113549.1.5.6' => 'pbeWithMD5AndRC2-CBC',
'1.2.840.113549.1.5.10'=> 'pbeWithSHA1AndDES-CBC',
'1.2.840.113549.1.5.11'=> 'pbeWithSHA1AndRC2-CBC',
// PBES1 encryption schemes
'pbeWithMD2AndDES-CBC' => '1.2.840.113549.1.5.1',
'pbeWithMD2AndRC2-CBC' => '1.2.840.113549.1.5.4',
'pbeWithMD5AndDES-CBC' => '1.2.840.113549.1.5.3',
'pbeWithMD5AndRC2-CBC' => '1.2.840.113549.1.5.6',
'pbeWithSHA1AndDES-CBC'=> '1.2.840.113549.1.5.10',
'pbeWithSHA1AndRC2-CBC'=> '1.2.840.113549.1.5.11',
// from PKCS#12:
// https://tools.ietf.org/html/rfc7292
'1.2.840.113549.1.12.1.1' => 'pbeWithSHAAnd128BitRC4',
'1.2.840.113549.1.12.1.2' => 'pbeWithSHAAnd40BitRC4',
'1.2.840.113549.1.12.1.3' => 'pbeWithSHAAnd3-KeyTripleDES-CBC',
'1.2.840.113549.1.12.1.4' => 'pbeWithSHAAnd2-KeyTripleDES-CBC',
'1.2.840.113549.1.12.1.5' => 'pbeWithSHAAnd128BitRC2-CBC',
'1.2.840.113549.1.12.1.6' => 'pbeWithSHAAnd40BitRC2-CBC',
// from PKCS#12:
// https://tools.ietf.org/html/rfc7292
'pbeWithSHAAnd128BitRC4' => '1.2.840.113549.1.12.1.1',
'pbeWithSHAAnd40BitRC4' => '1.2.840.113549.1.12.1.2',
'pbeWithSHAAnd3-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.3',
'pbeWithSHAAnd2-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.4',
'pbeWithSHAAnd128BitRC2-CBC' => '1.2.840.113549.1.12.1.5',
'pbeWithSHAAnd40BitRC2-CBC' => '1.2.840.113549.1.12.1.6',
'1.2.840.113549.1.5.12' => 'id-PBKDF2',
'1.2.840.113549.1.5.13' => 'id-PBES2',
'1.2.840.113549.1.5.14' => 'id-PBMAC1',
'id-PBKDF2' => '1.2.840.113549.1.5.12',
'id-PBES2' => '1.2.840.113549.1.5.13',
'id-PBMAC1' => '1.2.840.113549.1.5.14',
// from PKCS#5 v2.1:
// http://www.rsa.com/rsalabs/pkcs/files/h11302-wp-pkcs5v2-1-password-based-cryptography-standard.pdf
'1.2.840.113549.2.7' => 'id-hmacWithSHA1',
'1.2.840.113549.2.8' => 'id-hmacWithSHA224',
'1.2.840.113549.2.9' => 'id-hmacWithSHA256',
'1.2.840.113549.2.10'=> 'id-hmacWithSHA384',
'1.2.840.113549.2.11'=> 'id-hmacWithSHA512',
'1.2.840.113549.2.12'=> 'id-hmacWithSHA512-224',
'1.2.840.113549.2.13'=> 'id-hmacWithSHA512-256',
// from PKCS#5 v2.1:
// http://www.rsa.com/rsalabs/pkcs/files/h11302-wp-pkcs5v2-1-password-based-cryptography-standard.pdf
'id-hmacWithSHA1' => '1.2.840.113549.2.7',
'id-hmacWithSHA224' => '1.2.840.113549.2.8',
'id-hmacWithSHA256' => '1.2.840.113549.2.9',
'id-hmacWithSHA384'=> '1.2.840.113549.2.10',
'id-hmacWithSHA512'=> '1.2.840.113549.2.11',
'id-hmacWithSHA512-224'=> '1.2.840.113549.2.12',
'id-hmacWithSHA512-256'=> '1.2.840.113549.2.13',
'1.3.14.3.2.7' => 'desCBC',
'1.2.840.113549.3.7' => 'des-EDE3-CBC',
'1.2.840.113549.3.2' => 'rc2CBC',
'1.2.840.113549.3.9' => 'rc5-CBC-PAD',
'desCBC' => '1.3.14.3.2.7',
'des-EDE3-CBC' => '1.2.840.113549.3.7',
'rc2CBC' => '1.2.840.113549.3.2',
'rc5-CBC-PAD' => '1.2.840.113549.3.9',
'2.16.840.1.101.3.4.1.2' => 'aes128-CBC-PAD',
'2.16.840.1.101.3.4.1.22'=> 'aes192-CBC-PAD',
'2.16.840.1.101.3.4.1.42'=> 'aes256-CBC-PAD'
'aes128-CBC-PAD' => '2.16.840.1.101.3.4.1.2',
'aes192-CBC-PAD'=> '2.16.840.1.101.3.4.1.22',
'aes256-CBC-PAD'=> '2.16.840.1.101.3.4.1.42'
]);
self::$oidsLoaded = true;
}
@ -323,14 +327,14 @@ abstract class PKCS8 extends PKCS
* @access public
* @param string $key
* @param string $password optional
* @return array|bool
* @return array
*/
protected static function load($key, $password = '')
{
self::initialize_static_variables();
if (!is_string($key)) {
return false;
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
if (self::$format != self::MODE_DER) {
@ -338,13 +342,13 @@ abstract class PKCS8 extends PKCS
if ($decoded !== false) {
$key = $decoded;
} elseif (self::$format == self::MODE_PEM) {
return false;
throw new \UnexpectedValueException('Expected base64-encoded PEM format but was unable to decode base64 text');
}
}
$decoded = ASN1::decodeBER($key);
if (empty($decoded)) {
return false;
throw new \RuntimeException('Unable to decode BER');
}
$meta = [];
@ -379,7 +383,7 @@ abstract class PKCS8 extends PKCS
$key = $cipher->decrypt($decrypted['encryptedData']);
$decoded = ASN1::decodeBER($key);
if (empty($decoded)) {
return false;
throw new \RuntimeException('Unable to decode BER 2');
}
break;
@ -442,7 +446,7 @@ abstract class PKCS8 extends PKCS
$key = $cipher->decrypt($decrypted['encryptedData']);
$decoded = ASN1::decodeBER($key);
if (empty($decoded)) {
return false;
throw new \RuntimeException('Unable to decode BER 3');
}
break;
default:
@ -458,11 +462,22 @@ abstract class PKCS8 extends PKCS
}
}
$private = ASN1::asn1map($decoded[0], Maps\PrivateKeyInfo::MAP);
$private = ASN1::asn1map($decoded[0], Maps\OneAsymmetricKey::MAP);
if (is_array($private)) {
return $private['privateKeyAlgorithm']['algorithm'] == static::OID_NAME ?
$private + $meta :
false;
if (isset($private['privateKeyAlgorithm']['parameters']) && !$private['privateKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][1]['content'][1])) {
$temp = $decoded[0]['content'][1]['content'][1];
$private['privateKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length']));
}
if (is_array(static::OID_NAME)) {
if (!in_array($private['privateKeyAlgorithm']['algorithm'], static::OID_NAME)) {
throw new UnsupportedAlgorithmException($private['privateKeyAlgorithm']['algorithm'] . ' is not a supported key type');
}
} else {
if ($private['privateKeyAlgorithm']['algorithm'] != static::OID_NAME) {
throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $private['privateKeyAlgorithm']['algorithm'] . ' key');
}
}
return $private + $meta;
}
// EncryptedPrivateKeyInfo and PublicKeyInfo have largely identical "signatures". the only difference
@ -470,9 +485,23 @@ abstract class PKCS8 extends PKCS
// string represents the number of bits in the last byte that are to be ignored but, currently,
// bit strings wanting a non-zero amount of bits trimmed are not supported
$public = ASN1::asn1map($decoded[0], Maps\PublicKeyInfo::MAP);
if (is_array($public)) {
if ($public['publicKey'][0] != "\0" || $public['publicKeyAlgorithm']['algorithm'] != static::OID_NAME) {
return false;
if ($public['publicKey'][0] != "\0") {
throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . Hex::encode($val));
}
if (is_array(static::OID_NAME)) {
if (!in_array($public['publicKeyAlgorithm']['algorithm'], static::OID_NAME)) {
throw new UnsupportedAlgorithmException($private['publicKeyAlgorithm']['algorithm'] . ' is not a supported key type');
}
} else {
if ($public['publicKeyAlgorithm']['algorithm'] != static::OID_NAME) {
throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $private['publicKeyAlgorithm']['algorithm'] . ' key');
}
}
if (isset($public['publicKeyAlgorithm']['parameters']) && !$public['publicKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][0]['content'][1])) {
$temp = $decoded[0]['content'][0]['content'][1];
$public['publicKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length']));
}
$public['publicKey'] = substr($public['publicKey'], 1);
return $public;
@ -489,16 +518,18 @@ abstract class PKCS8 extends PKCS
* @param string $attr
* @param mixed $params
* @param string $password
* @param string $oid optional
* @param string $publicKey optional
* @return string
*/
protected static function wrapPrivateKey($key, $attr, $params, $password)
protected static function wrapPrivateKey($key, $attr, $params, $password, $oid = null, $publicKey = '')
{
self::initialize_static_variables();
$key = [
'version' => 'v1',
'privateKeyAlgorithm' => [
'algorithm' => static::OID_NAME,
'algorithm' => is_string(static::OID_NAME) ? static::OID_NAME : $oid,
'parameters' => $params
],
'privateKey' => $key
@ -506,7 +537,11 @@ abstract class PKCS8 extends PKCS
if (!empty($attr)) {
$key['attributes'] = $attr;
}
$key = ASN1::encodeDER($key, Maps\PrivateKeyInfo::MAP);
if (!empty($publicKey)) {
$key['version'] = 'v2';
$key['publicKey'] = $publicKey;
}
$key = ASN1::encodeDER($key, Maps\OneAsymmetricKey::MAP);
if (!empty($password) && is_string($password)) {
$salt = Random::string(8);
$iterationCount = self::$defaultIterationCount;
@ -590,13 +625,13 @@ abstract class PKCS8 extends PKCS
* @param mixed $params
* @return string
*/
protected static function wrapPublicKey($key, $params)
protected static function wrapPublicKey($key, $params, $oid = null)
{
self::initialize_static_variables();
$key = [
'publicKeyAlgorithm' => [
'algorithm' => static::OID_NAME,
'algorithm' => is_string(static::OID_NAME) ? static::OID_NAME : $oid,
'parameters' => $params
],
'publicKey' => "\0" . $key

View File

@ -21,6 +21,7 @@ use phpseclib\Crypt\AES;
use phpseclib\Crypt\Hash;
use phpseclib\Crypt\Random;
use phpseclib\Common\Functions\Strings;
use phpseclib\Exception\UnsupportedAlgorithmException;
/**
* PuTTY Formatted Key Handler
@ -75,26 +76,26 @@ abstract class PuTTY
* @access public
* @param string $key
* @param string $password
* @return array|bool
* @return array
*/
protected static function load($key, $password)
{
if (!is_string($key)) {
return false;
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
if (strpos($key, 'BEGIN SSH2 PUBLIC KEY')) {
if (strpos($key, 'BEGIN SSH2 PUBLIC KEY') !== false) {
$data = preg_split('#[\r\n]+#', $key);
$data = array_splice($data, 2, -1);
$data = implode('', $data);
$components = call_user_func([static::PUBLIC_HANDLER, 'load'], $data);
if ($components === false) {
return false;
throw new \UnexpectedValueException('Unable to decode public key');
}
if (!preg_match('#Comment: "(.+)"#', $key, $matches)) {
return false;
throw new \UnexpectedValueException('Key is missing a comment');
}
$components['comment'] = str_replace(['\\\\', '\"'], ['\\', '"'], $matches[1]);
@ -105,8 +106,12 @@ abstract class PuTTY
$key = preg_split('#\r\n|\r|\n#', trim($key));
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
if ($type != static::TYPE) {
return false;
$components['type'] = $type;
if (!in_array($type, static::$types)) {
$error = count(static::$types) == 1 ?
'Only ' . static::$types[0] . ' keys are supported. ' :
'';
throw new UnsupportedAlgorithmException($error . 'This is an unsupported ' . $type . ' key');
}
$encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
$components['comment'] = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
@ -114,12 +119,12 @@ abstract class PuTTY
$publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
$public = Base64::decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
$source = Strings::packSSH2('ssss', static::TYPE, $encryption, $components['comment'], $public);
$source = Strings::packSSH2('ssss', $type, $encryption, $components['comment'], $public);
extract(unpack('Nlength', Strings::shift($public, 4)));
/** @var integer $length */
if (Strings::shift($public, $length) != static::TYPE) {
return false;
$newtype = Strings::shift($public, $length);
if ($newtype != $type) {
throw new \RuntimeException('The binary type does not match the human readable type field');
}
$components['public'] = $public;
@ -165,19 +170,20 @@ abstract class PuTTY
* @access private
* @param string $public
* @param string $private
* @param string $type
* @param string $password
* @return string
*/
protected static function wrapPrivateKey($public, $private, $password)
protected static function wrapPrivateKey($public, $private, $type, $password)
{
$key = "PuTTY-User-Key-File-2: " . static::TYPE . "\r\nEncryption: ";
$key = "PuTTY-User-Key-File-2: " . $type . "\r\nEncryption: ";
$encryption = (!empty($password) || is_string($password)) ? 'aes256-cbc' : 'none';
$key.= $encryption;
$key.= "\r\nComment: " . self::$comment . "\r\n";
$public = Strings::packSSH2('s', static::TYPE) . $public;
$public = Strings::packSSH2('s', $type) . $public;
$source = Strings::packSSH2('ssss', static::TYPE, $encryption, self::$comment, $public);
$source = Strings::packSSH2('ssss', $type, $encryption, self::$comment, $public);
$public = Base64::encode($public);
$key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
@ -215,11 +221,12 @@ abstract class PuTTY
*
* @access private
* @param string $key
* @param string $type
* @return string
*/
protected static function wrapPublicKey($key)
protected static function wrapPublicKey($key, $type)
{
$key = pack('Na*a*', strlen(static::TYPE), static::TYPE, $key);
$key = pack('Na*a*', strlen($type), $type, $key);
$key = "---- BEGIN SSH2 PUBLIC KEY ----\r\n" .
'Comment: "' . str_replace(['\\', '"'], ['\\\\', '\"'], self::$comment) . "\"\r\n" .
chunk_split(Base64::encode($key), 64) .

View File

@ -34,7 +34,8 @@ use ParagonIE\ConstantTime\Base64;
use phpseclib\File\ASN1;
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\Common\AsymmetricKey;
use phpseclib\Common\Functions\Strings;
use phpseclib\Math\PrimeField;
use phpseclib\Crypt\ECDSA\Signature\ASN1 as ASN1Signature;
/**
* Pure-PHP FIPS 186-4 compliant implementation of DSA.
@ -95,14 +96,6 @@ class DSA extends AsymmetricKey
*/
private $y;
/**
* Parameters Format
*
* @var string
* @access private
*/
private $parametersFormat = 'PKCS1';
/**
* Create DSA parameters
*
@ -111,10 +104,14 @@ class DSA extends AsymmetricKey
* @param int $N
* @return \phpseclib\Crypt\DSA|bool
*/
static function createParameters($L = 2048, $N = 224)
public static function createParameters($L = 2048, $N = 224)
{
self::initialize_static_variables();
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
switch (true) {
case $N == 160:
/*
@ -186,10 +183,14 @@ class DSA extends AsymmetricKey
* @access public
* @return array|DSA
*/
static function createKey(...$args)
public static function createKey(...$args)
{
self::initialize_static_variables();
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if (count($args) == 2 && is_int($args[0]) && is_int($args[1])) {
$private = self::createParameters($args[0], $args[1]);
} else if (count($args) == 1 && $args[0] instanceof DSA) {
@ -220,6 +221,12 @@ class DSA extends AsymmetricKey
*/
public function load($key, $type = false)
{
self::initialize_static_variables();
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
if ($key instanceof DSA) {
$this->privateKeyFormat = $key->privateKeyFormat;
$this->publicKeyFormat = $key->publicKeyFormat;
@ -236,6 +243,13 @@ class DSA extends AsymmetricKey
$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;
}
@ -252,9 +266,7 @@ class DSA extends AsymmetricKey
$this->g = $components['g'];
}
if (isset($components['x'])) {
$this->x = $components['x'];
}
$this->x = isset($components['x']) ? $components['x'] : null;
if (isset($components['y'])) {
$this->y = $components['y'];
@ -281,27 +293,6 @@ class DSA extends AsymmetricKey
['L' => 0, 'N' => 0];
}
/**
* __toString() magic method
*
* @access public
* @return string
*/
public function __toString()
{
$key = parent::__toString();
if (!empty($key)) {
return $key;
}
try {
$key = $this->getParameters($this->parametersFormat);
return is_string($key) ? $key : '';
} catch (\Exception $e) {
return '';
}
}
/**
* Returns the private key
*
@ -331,6 +322,28 @@ class DSA extends AsymmetricKey
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
*
@ -354,8 +367,14 @@ class DSA extends AsymmetricKey
* @param string $type optional
* @return mixed
*/
public function getPublicKey($type = 'PKCS8')
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;
@ -368,7 +387,15 @@ class DSA extends AsymmetricKey
$this->y = $this->g->powMod($this->x, $this->p);
}
return $type::savePublicKey($this->p, $this->q, $this->g, $this->y);
$key = $type::savePublicKey($this->p, $this->q, $this->g, $this->y);
if (!$returnObj) {
return $key;
}
$public = clone $this;
$public->load($key, 'PKCS8');
return $public;
}
/**
@ -397,6 +424,20 @@ class DSA extends AsymmetricKey
return $type::saveParameters($this->p, $this->q, $this->g);
}
/**
* Returns the current engine being used
*
* @see self::useInternalEngine()
* @see self::useBestEngine()
* @access public
* @return string
*/
public function getEngine()
{
return self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods()) ?
'OpenSSL' : 'PHP';
}
/**
* Create a signature
*
@ -406,8 +447,9 @@ class DSA extends AsymmetricKey
* @param string $format optional
* @return mixed
*/
function sign($message, $format = 'Raw')
public function sign($message, $format = 'ASN1')
{
$shortFormat = $format;
$format = self::validatePlugin('Signature', $format);
if ($format === false) {
return false;
@ -417,6 +459,24 @@ class DSA extends AsymmetricKey
return false;
}
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);
@ -425,8 +485,6 @@ class DSA extends AsymmetricKey
continue;
}
$kinv = $k->modInverse($this->q);
$h = $this->hash->hash($message);
$h = $this->bits2int($h);
$temp = $h->add($this->x->multiply($r));
$temp = $kinv->multiply($temp);
list(, $s) = $temp->divide($this->q);
@ -464,7 +522,7 @@ class DSA extends AsymmetricKey
* @param string $format optional
* @return mixed
*/
function verify($message, $signature, $format = 'Raw')
public function verify($message, $signature, $format = 'ASN1')
{
$format = self::validatePlugin('Signature', $format);
if ($format === false) {
@ -481,6 +539,16 @@ class DSA extends AsymmetricKey
return false;
}
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;
@ -496,6 +564,6 @@ class DSA extends AsymmetricKey
list(, $v) = $v1->multiply($v2)->divide($this->p);
list(, $v) = $v->divide($this->q);
return Strings::equals($v->toBytes(), $r->toBytes());
return $v->equals($r);
}
}

View File

@ -37,18 +37,15 @@ abstract class OpenSSH extends Progenitor
* @access public
* @param string $key
* @param string $password optional
* @return array|bool
* @return array
*/
public static function load($key, $password = '')
{
$key = parent::load($key, 'ssh-dss');
if ($key === false) {
return false;
}
$result = Strings::unpackSSH2('iiii', $key);
if ($result === false) {
return false;
throw new \UnexpectedValueException('Key appears to be malformed');
}
list($p, $q, $g, $y) = $result;

View File

@ -15,6 +15,10 @@
*
* Analogous to ssh-keygen's pem format (as specified by -m)
*
* Also, technically, PKCS1 decribes RSA but I am not aware of a formal specification for DSA.
* The DSA private key format seems to have been adapted from the RSA private key format so
* we're just re-using that as the name.
*
* @category Crypt
* @package DSA
* @author Jim Wigginton <terrafrost@php.net>
@ -32,7 +36,7 @@ use phpseclib\File\ASN1\Maps;
use ParagonIE\ConstantTime\Base64;
/**
* PKCS#1 Formatted RSA Key Handler
* PKCS#1 Formatted DSA Key Handler
*
* @package RSA
* @author Jim Wigginton <terrafrost@php.net>
@ -46,22 +50,15 @@ abstract class PKCS1 extends Progenitor
* @access public
* @param string $key
* @param string $password optional
* @return array|bool
* @return array
*/
public static function load($key, $password = '')
{
if (!is_string($key)) {
return false;
}
$key = parent::load($key, $password);
if ($key === false) {
return false;
}
$decoded = ASN1::decodeBER($key);
if (empty($decoded)) {
return false;
throw new \RuntimeException('Unable to decode BER');
}
$key = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
@ -75,7 +72,11 @@ abstract class PKCS1 extends Progenitor
}
$key = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
return is_array($key) ? $key : false;
if (is_array($key)) {
return $key;
}
throw new \RuntimeException('Unable to perform ASN1 mapping');
}
/**

View File

@ -69,47 +69,45 @@ abstract class PKCS8 extends Progenitor
* @access public
* @param string $key
* @param string $password optional
* @return array|bool
* @return array
*/
public static function load($key, $password = '')
{
if (!is_string($key)) {
return false;
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
$isPublic = strpos($key, 'PUBLIC') !== false;
$key = parent::load($key, $password);
if ($key === false) {
return false;
}
$type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';
switch (true) {
case !$isPublic && $type == 'publicKey':
throw new \UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key');
case $isPublic && $type == 'privateKey':
return false;
throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key');
}
$decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
if (empty($decoded)) {
return false;
throw new \RuntimeException('Unable to decode BER of parameters');
}
$components = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
if (!is_array($components)) {
return false;
throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
}
$decoded = ASN1::decodeBER($key[$type]);
if (empty($decoded)) {
return false;
throw new \RuntimeException('Unable to decode BER');
}
$var = $type == 'privateKey' ? 'x' : 'y';
$components[$var] = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
if (!$components[$var] instanceof BigInteger) {
return false;
throw new \RuntimeException('Unable to perform ASN1 mapping');
}
if (isset($key['meta'])) {

View File

@ -44,10 +44,10 @@ abstract class PuTTY extends Progenitor
/**
* Algorithm Identifier
*
* @var string
* @var array
* @access private
*/
const TYPE = 'ssh-dss';
protected static $types = ['ssh-dss'];
/**
* Break a public or private key down into its constituent components
@ -55,31 +55,29 @@ abstract class PuTTY extends Progenitor
* @access public
* @param string $key
* @param string $password optional
* @return array|bool
* @return array
*/
public static function load($key, $password = '')
{
$components = parent::load($key, $password);
if ($components === false || !isset($components['private'])) {
if (!isset($components['private'])) {
return $components;
}
extract($components);
unset($components['public'], $components['private']);
$result = Strings::unpackSSH2('iiii', $components['public']);
$result = Strings::unpackSSH2('iiii', $public);
if ($result === false) {
return false;
throw new \UnexpectedValueException('Key appears to be malformed');
}
list($p, $q, $g, $y) = $result;
$result = Strings::unpackSSH2('i', $components['private']);
$result = Strings::unpackSSH2('i', $private);
if ($result === false) {
return false;
throw new \UnexpectedValueException('Key appears to be malformed');
}
list($x) = $result;
if (isset($components['comment'])) {
$comment = $components['comment'];
}
return compact('p', 'q', 'g', 'y', 'x', 'comment');
}
@ -95,7 +93,7 @@ abstract class PuTTY extends Progenitor
* @param string $password optional
* @return string
*/
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '')
public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = false)
{
if ($q->getLength() != 160) {
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
@ -104,7 +102,7 @@ abstract class PuTTY extends Progenitor
$public = Strings::packSSH2('iiii', $p, $q, $g, $y);
$private = Strings::packSSH2('i', $x);
return self::wrapPrivateKey($public, $private, $password);
return self::wrapPrivateKey($public, $private, 'ssh-dsa', $password);
}
/**
@ -123,6 +121,6 @@ abstract class PuTTY extends Progenitor
throw new \InvalidArgumentException('SSH only supports keys with an N (length of Group Order q) of 160');
}
return self::wrapPublicKey(Strings::packSSH2('iiii', $p, $q, $g, $y));
return self::wrapPublicKey(Strings::packSSH2('iiii', $p, $q, $g, $y), 'ssh-dsa');
}
}

View File

@ -34,12 +34,12 @@ abstract class Raw
* @access public
* @param array $key
* @param string $password optional
* @return array|bool
* @return array
*/
public static function load($key, $password = '')
{
if (!is_array($key)) {
return false;
throw new \UnexpectedValueException('Key should be a array - not a ' . gettype($key));
}
switch (true) {
@ -50,7 +50,7 @@ abstract class Raw
case !isset($key['x']) && !isset($key['y']):
case isset($key['x']) && !$key['x'] instanceof BigInteger:
case isset($key['y']) && !$key['y'] instanceof BigInteger:
return false;
throw new \UnexpectedValueException('Key appears to be malformed');
}
$options = ['p' => 1, 'q' => 1, 'g' => 1, 'x' => 1, 'y' => 1];

View File

@ -39,12 +39,12 @@ abstract class XML
* @access public
* @param string $key
* @param string $password optional
* @return array|bool
* @return array
*/
public static function load($key, $password = '')
{
if (!is_string($key)) {
return false;
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
$use_errors = libxml_use_internal_errors(true);
@ -54,7 +54,7 @@ abstract class XML
$key = '<xml>' . $key . '</xml>';
}
if (!$dom->loadXML($key)) {
return false;
throw new \UnexpectedValueException('Key does not appear to contain XML');
}
$xpath = new \DOMXPath($dom);
$keys = ['p', 'q', 'g', 'y', 'j', 'seed', 'pgencounter'];
@ -95,7 +95,7 @@ abstract class XML
libxml_use_internal_errors($use_errors);
if (!isset($components['y'])) {
return false;
throw new \UnexpectedValueException('Key is missing y component');
}
switch (true) {

View File

@ -1,7 +1,7 @@
<?php
/**
* PKCS Signature Handler
* ASN1 Signature Handler
*
* PHP version 5
*
@ -19,17 +19,17 @@
namespace phpseclib\Crypt\DSA\Signature;
use phpseclib\Math\BigInteger;
use phpseclib\File\ASN1;
use phpseclib\File\ASN1 as Encoder;
use phpseclib\File\ASN1\Maps;
/**
* PKCS Signature Handler
* ASN1 Signature Handler
*
* @package Common
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class PKCS
abstract class ASN1
{
/**
* Loads a signature
@ -44,11 +44,11 @@ abstract class PKCS
return false;
}
$decoded = ASN1::decodeBER($sig);
$decoded = Encoder::decodeBER($sig);
if (empty($decoded)) {
return false;
}
$components = ASN1::asn1map($decoded[0], Maps\DssSigValue::MAP);
$components = Encoder::asn1map($decoded[0], Maps\DssSigValue::MAP);
return $components;
}

708
phpseclib/Crypt/ECDSA.php Normal file
View File

@ -0,0 +1,708 @@
<?php
/**
* Pure-PHP implementation of ECDSA.
*
* PHP version 5
*
* Here's an example of how to create signatures and verify signatures with this library:
* <code>
* <?php
* include 'vendor/autoload.php';
*
* extract(\phpseclib\Crypt\ECDSA::createKey());
*
* $plaintext = 'terrafrost';
*
* $signature = $privatekey->sign($plaintext, 'ASN1');
*
* echo $publickey->verify($plaintext, $signature) ? 'verified' : 'unverified';
* ?>
* </code>
*
* @category Crypt
* @package ECDSA
* @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;
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\Common\AsymmetricKey;
use phpseclib\Exception\UnsupportedCurveException;
use phpseclib\File\ASN1;
use phpseclib\File\ASN1\Maps\ECParameters;
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\ECDSA\Signature\ASN1 as ASN1Signature;
/**
* Pure-PHP implementation of ECDSA.
*
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class ECDSA extends AsymmetricKey
{
/**
* Algorithm Name
*
* @var string
* @access private
*/
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;
/**
* Curve
*
* @var \phpseclib\Crypt\ECDSA\BaseCurves\Base
*/
private $curve;
/**
* Curve Name
*
* @var string
*/
private $curveName;
/**
* Curve Order
*
* Used for deterministic ECDSA
*
* @var \phpseclib\Math\BigInteger
*/
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;
/**
* Create public / private key pair.
*
* @access public
* @param string $curve
* @return \phpseclib\Crypt\ECDSA[]
*/
public static function createKey($curve)
{
self::initialize_static_variables();
if (!isset(self::$engines['PHP'])) {
self::useBestEngine();
}
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));
$publickey = new static();
$publickey->load(sodium_crypto_sign_publickey($kp));
$publickey->curveName = $privatekey->curveName = $curve;
return compact('privatekey', 'publickey');
}
$privatekey = new static();
$curveName = $curve;
$curve = '\phpseclib\Crypt\ECDSA\Curves\\' . $curve;
if (!class_exists($curve)) {
throw new UnsupportedCurveException('Named Curve of ' . $curve . ' is not supported');
}
$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->curveName = $privatekey->curveName = $curveName;
return compact('privatekey', 'publickey');
}
/**
* 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)
*
* @access public
* @param string $key
* @param int $type optional
*/
public function load($key, $type = false)
{
self::initialize_static_variables();
if (!isset(self::$engines['PHP'])) {
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;
return true;
}
$components = parent::load($key, $type);
if ($components === false) {
$this->format = null;
$this->dA = null;
$this->QA = null;
$this->curve = null;
return false;
}
$this->curve = $components['curve'];
$this->QA = $components['QA'];
$this->dA = isset($components['dA']) ? $components['dA'] : null;
return true;
}
/**
* Returns the curve
*
* Returns a string if it's a named curve, an array if not
*
* @access public
* @return string|array
*/
public function getCurve()
{
if ($this->curveName) {
return $this->curveName;
}
if ($this->curve instanceof TwistedEdwardsCurve) {
$this->curveName = $this->curve instanceof Ed25519 ? 'Ed25519' : 'Ed448';
return $this->curveName;
}
$namedCurves = PKCS1::isUsingNamedCurves();
PKCS1::useNamedCurve();
$params = $this->getParameters();
$decoded = ASN1::extractBER($params);
$decoded = ASN1::decodeBER($decoded);
$decoded = ASN1::asn1map($decoded[0], ECParameters::MAP);
if (isset($decoded['namedCurve'])) {
$this->curveName = $decoded['namedCurve'];
if (!$namedCurves) {
PKCS1::useSpecifiedCurve();
}
return $decoded['namedCurve'];
}
if (!$namedCurves) {
PKCS1::useSpecifiedCurve();
}
return $decoded;
}
/**
* Returns the key size
*
* Quoting https://tools.ietf.org/html/rfc5656#section-2,
*
* "The size of a set of elliptic curve domain parameters on a prime
* curve is defined as the number of bits in the binary representation
* of the field order, commonly denoted by p. Size on a
* characteristic-2 curve is defined as the number of bits in the binary
* representation of the field, commonly denoted by m. A set of
* elliptic curve domain parameters defines a group of order n generated
* by a base point P"
*
* @access public
* @return int
*/
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
*
* @see self::useInternalEngine()
* @see self::useBestEngine()
* @access public
* @return string
*/
public function getEngine()
{
if (!isset($this->curve)) {
throw new \RuntimeException('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';
}
return self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods()) ?
'OpenSSL' : 'PHP';
}
/**
* Sets the context
*
* Used by Ed25519 / Ed448.
*
* @see self::sign()
* @see self::verify()
* @access public
* @param string $context optional
*/
public function setContext($context = null)
{
if (!isset($context)) {
$this->context = null;
return;
}
if (!is_string($context)) {
throw new \RuntimeException('setContext expects a string');
}
if (strlen($context) > 255) {
throw new \RuntimeException('The context is supposed to be, at most, 255 bytes long');
}
$this->context = $context;
}
/**
* 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)) {
return false;
}
$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)) {
return false;
}
$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);
}
}

View File

@ -0,0 +1,220 @@
<?php
/**
* Curve methods common to all curves
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\BaseCurves;
use phpseclib\Math\Common\FiniteField;
use phpseclib\Math\BigInteger;
/**
* Base
*
* @package Prime
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class Base
{
/**
* Doubles
*
* @var object[]
*/
protected $doubles;
/**
* NAF Points
*
* @var int[]
*/
private $naf;
/**
* The Order
*
* @var BigInteger
*/
protected $order;
/**
* Finite Field Integer factory
*
* @var \phpseclib\Math\FiniteField\Integer
*/
protected $factory;
/**
* Returns a random integer
*
* @return object
*/
public function randomInteger()
{
return $this->factory->randomInteger();
}
/**
* Converts a BigInteger to a FiniteField integer
*
* @return object
*/
public function convertInteger(BigInteger $x)
{
return $this->factory->newInteger($x);
}
/**
* Returns the length, in bytes, of the modulo
*
* @return integer
*/
public function getLengthInBytes()
{
return $this->factory->getLengthInBytes();
}
/**
* Returns the length, in bits, of the modulo
*
* @return integer
*/
public function getLength()
{
return $this->factory->getLength();
}
/**
* Multiply a point on the curve by a scalar
*
* Uses the montgomery ladder technique as described here:
*
* https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Montgomery_ladder
* https://github.com/phpecc/phpecc/issues/16#issuecomment-59176772
*
* @return array
*/
public function multiplyPoint(array $p, FiniteField\Integer $d)
{
$alreadyInternal = isset($p[2]);
$r = $alreadyInternal ?
[[], $p] :
[[], $this->convertToInternal($p)];
$d = $d->toBits();
for ($i = 0; $i < strlen($d); $i++) {
$d_i = (int) $d[$i];
$r[1 - $d_i] = $this->addPoint($r[0], $r[1]);
$r[$d_i] = $this->doublePoint($r[$d_i]);
}
return $alreadyInternal ? $r[0] : $this->convertToAffine($r[0]);
}
/**
* Creates a random scalar multiplier
*
* @return FiniteField
*/
public function createRandomMultiplier()
{
static $one;
if (!isset($one)) {
$one = new BigInteger(1);
}
$dA = BigInteger::randomRange($one, $this->order->subtract($one));
return $this->factory->newInteger($dA);
}
/**
* Sets the Order
*/
public function setOrder(BigInteger $order)
{
$this->order = $order;
}
/**
* Returns the Order
*
* @return \phpseclib\Math\BigInteger
*/
public function getOrder()
{
return $this->order;
}
/**
* Use a custom defined modular reduction function
*
* @return object
*/
public function setReduction(callable $func)
{
$this->factory->setReduction($func);
}
/**
* Returns the affine point
*
* @return object[]
*/
public function convertToAffine(array $p)
{
return $p;
}
/**
* Converts an affine point to a jacobian coordinate
*
* @return object[]
*/
public function convertToInternal(array $p)
{
return $p;
}
/**
* Negates a point
*
* @return object[]
*/
public function negatePoint(array $p)
{
$temp = [
$p[0],
$p[1]->negate()
];
if (isset($p[2])) {
$temp[] = $p[2];
}
return $temp;
}
/**
* Multiply and Add Points
*
* @return int[]
*/
public function multiplyAddPoints(array $points, array $scalars)
{
$p1 = $this->convertToInternal($points[0]);
$p2 = $this->convertToInternal($points[1]);
$p1 = $this->multiplyPoint($p1, $scalars[0]);
$p2 = $this->multiplyPoint($p2, $scalars[1]);
$r = $this->addPoint($p1, $p2);
return $this->convertToAffine($r);
}
}

View File

@ -0,0 +1,378 @@
<?php
/**
* Curves over y^2 + x*y = x^3 + a*x^2 + b
*
* These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf
* The curve is a weierstrass curve with a[3] and a[2] set to 0.
*
* Uses Jacobian Coordinates for speed if able:
*
* https://en.wikipedia.org/wiki/Jacobian_curve
* https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\BaseCurves;
use phpseclib\Common\Functions\Strings;
use phpseclib\Math\BinaryField;
use phpseclib\Math\BigInteger;
use phpseclib\Math\BinaryField\Integer as BinaryInteger;
/**
* Curves over y^2 + x*y = x^3 + a*x^2 + b
*
* @package Binary
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Binary extends Base
{
/**
* Binary Field Integer factory
*
* @var \phpseclib\Math\BinaryFields
*/
protected $factory;
/**
* Cofficient for x^1
*
* @var object
*/
protected $a;
/**
* Cofficient for x^0
*
* @var object
*/
protected $b;
/**
* Base Point
*
* @var object
*/
protected $p;
/**
* The number one over the specified finite field
*
* @var object
*/
protected $one;
/**
* The modulo
*
* @var BigInteger
*/
protected $modulo;
/**
* The Order
*
* @var BigInteger
*/
protected $order;
/**
* Sets the modulo
*/
public function setModulo(...$modulo)
{
$this->modulo = $modulo;
$this->factory = new BinaryField(...$modulo);
$this->one = $this->factory->newInteger("\1");
}
/**
* Set coefficients a and b
*
* @param string $a
* @param string $b
*/
public function setCoefficients($a, $b)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->a = $this->factory->newInteger(pack('H*', $a));
$this->b = $this->factory->newInteger(pack('H*', $b));
}
/**
* Set x and y coordinates for the base point
*
* @param string|BinaryInteger $x
* @param string|BinaryInteger $y
*/
public function setBasePoint($x, $y)
{
switch (true) {
case !is_string($x) && !$x instanceof BinaryInteger:
throw new \UnexpectedValueException('Argument 1 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\Integer');
case !is_string($y) && !$y instanceof BinaryInteger:
throw new \UnexpectedValueException('Argument 2 passed to Binary::setBasePoint() must be a string or an instance of BinaryField\Integer');
}
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->p = [
is_string($x) ? $this->factory->newInteger(pack('H*', $x)) : $x,
is_string($y) ? $this->factory->newInteger(pack('H*', $y)) : $y
];
}
/**
* Retrieve the base point as an array
*
* @return array
*/
public function getBasePoint()
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
/*
if (!isset($this->p)) {
throw new \RuntimeException('setBasePoint needs to be called before this method');
}
*/
return $this->p;
}
/**
* Adds two points on the curve
*
* @return FiniteField[]
*/
public function addPoint(array $p, array $q)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!count($p) || !count($q)) {
if (count($q)) {
return $q;
}
if (count($p)) {
return $p;
}
return [];
}
if (!isset($p[2]) || !isset($q[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
if ($p[0]->equals($q[0])) {
return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
}
// formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html
list($x1, $y1, $z1) = $p;
list($x2, $y2, $z2) = $q;
$o1 = $z1->multiply($z1);
$b = $x2->multiply($o1);
if ($z2->equals($this->one)) {
$d = $y2->multiply($o1)->multiply($z1);
$e = $x1->add($b);
$f = $y1->add($d);
$z3 = $e->multiply($z1);
$h = $f->multiply($x2)->add($z3->multiply($y2));
$i = $f->add($z3);
$g = $z3->multiply($z3);
$p1 = $this->a->multiply($g);
$p2 = $f->multiply($i);
$p3 = $e->multiply($e)->multiply($e);
$x3 = $p1->add($p2)->add($p3);
$y3 = $i->multiply($x3)->add($g->multiply($h));
return [$x3, $y3, $z3];
}
$o2 = $z2->multiply($z2);
$a = $x1->multiply($o2);
$c = $y1->multiply($o2)->multiply($z2);
$d = $y2->multiply($o1)->multiply($z1);
$e = $a->add($b);
$f = $c->add($d);
$g = $e->multiply($z1);
$h = $f->multiply($x2)->add($g->multiply($y2));
$z3 = $g->multiply($z2);
$i = $f->add($z3);
$p1 = $this->a->multiply($z3->multiply($z3));
$p2 = $f->multiply($i);
$p3 = $e->multiply($e)->multiply($e);
$x3 = $p1->add($p2)->add($p3);
$y3 = $i->multiply($x3)->add($g->multiply($g)->multiply($h));
return [$x3, $y3, $z3];
}
/**
* Doubles a point on a curve
*
* @return FiniteField[]
*/
public function doublePoint(array $p)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!count($p)) {
return [];
}
if (!isset($p[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
// formulas from http://hyperelliptic.org/EFD/g12o/auto-shortw-jacobian.html
list($x1, $y1, $z1) = $p;
$a = $x1->multiply($x1);
$b = $a->multiply($a);
if ($z1->equals($this->one)) {
$x3 = $b->add($this->b);
$z3 = clone $x1;
$p1 = $a->add($y1)->add($z3)->multiply($this->b);
$p2 = $a->add($y1)->multiply($b);
$y3 = $p1->add($p2);
return [$x3, $y3, $z3];
}
$c = $z1->multiply($z1);
$d = $c->multiply($c);
$x3 = $b->add($this->b->multiply($d->multiply($d)));
$z3 = $x1->multiply($c);
$p1 = $b->multiply($z3);
$p2 = $a->add($y1->multiply($z1))->add($z3)->multiply($x3);
$y3 = $p1->add($p2);
return [$x3, $y3, $z3];
}
/**
* Returns the X coordinate and the derived Y coordinate
*
* Not supported because it is covered by patents.
* Quoting https://www.openssl.org/docs/man1.1.0/apps/ecparam.html ,
*
* "Due to patent issues the compressed option is disabled by default for binary curves
* and can be enabled by defining the preprocessor macro OPENSSL_EC_BIN_PT_COMP at
* compile time."
*
* @return array
*/
public function derivePoint($m)
{
throw new \RuntimeException('Point compression on binary finite field elliptic curves is not supported');
}
/**
* Tests whether or not the x / y values satisfy the equation
*
* @return boolean
*/
public function verifyPoint(array $p)
{
list($x, $y) = $p;
$lhs = $y->multiply($y);
$lhs = $lhs->add($x->multiply($y));
$x2 = $x->multiply($x);
$x3 = $x2->multiply($x);
$rhs = $x3->add($this->a->multiply($x2))->add($this->b);
return $lhs->equals($rhs);
}
/**
* Returns the modulo
*
* @return \phpseclib\Math\BigInteger
*/
public function getModulo()
{
return $this->modulo;
}
/**
* Returns the a coefficient
*
* @return \phpseclib\Math\PrimeField\Integer
*/
public function getA()
{
return $this->a;
}
/**
* Returns the a coefficient
*
* @return \phpseclib\Math\PrimeField\Integer
*/
public function getB()
{
return $this->b;
}
/**
* Returns the affine point
*
* A Jacobian Coordinate is of the form (x, y, z).
* To convert a Jacobian Coordinate to an Affine Point
* you do (x / z^2, y / z^3)
*
* @return \phpseclib\Math\PrimeField\Integer[]
*/
public function convertToAffine(array $p)
{
if (!isset($p[2])) {
return $p;
}
list($x, $y, $z) = $p;
$z = $this->one->divide($z);
$z2 = $z->multiply($z);
return [
$x->multiply($z2),
$y->multiply($z2)->multiply($z)
];
}
/**
* Converts an affine point to a jacobian coordinate
*
* @return \phpseclib\Math\PrimeField\Integer[]
*/
public function convertToInternal(array $p)
{
if (isset($p[2])) {
return $p;
}
$p[2] = clone $this->one;
$p['fresh'] = true;
return $p;
}
}

View File

@ -0,0 +1,324 @@
<?php
/**
* Generalized Koblitz Curves over y^2 = x^3 + b.
*
* According to http://www.secg.org/SEC2-Ver-1.0.pdf Koblitz curves are over the GF(2**m)
* finite field. Both the $a$ and $b$ coefficients are either 0 or 1. However, SEC2
* generalizes the definition to include curves over GF(P) "which possess an efficiently
* computable endomorphism".
*
* For these generalized Koblitz curves $b$ doesn't have to be 0 or 1. Whether or not $a$
* has any restrictions on it is unclear, however, for all the GF(P) Koblitz curves defined
* in SEC2 v1.0 $a$ is $0$ so all of the methods defined herein will assume that it is.
*
* I suppose we could rename the $b$ coefficient to $a$, however, the documentation refers
* to $b$ so we'll just keep it.
*
* If a later version of SEC2 comes out wherein some $a$ values are non-zero we can create a
* new method for those. eg. KoblitzA1Prime.php or something.
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\BaseCurves;
use phpseclib\Common\Functions\Strings;
use phpseclib\Math\PrimeField;
use phpseclib\Math\BigInteger;
use phpseclib\Math\PrimeField\Integer as PrimeInteger;
/**
* Curves over y^2 = x^3 + b
*
* @package KoblitzPrime
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class KoblitzPrime extends Prime
{
// don't overwrite setCoefficients() with one that only accepts one parameter so that
// one might be able to switch between KoblitzPrime and Prime more easily (for benchmarking
// purposes).
/**
* Multiply and Add Points
*
* Uses a efficiently computable endomorphism to achieve a slight speedup
*
* Adapted from https://git.io/vxbrP
*
* @return int[]
*/
public function multiplyAddPoints(array $points, array $scalars)
{
static $zero, $one, $two;
if (!isset($two)) {
$two = new BigInteger(2);
$one = new BigInteger(1);
}
if (!isset($this->beta)) {
// get roots
$inv = $this->one->divide($this->two)->negate();
$s = $this->three->negate()->squareRoot()->multiply($inv);
$betas = [
$inv->add($s),
$inv->subtract($s)
];
$this->beta = $betas[0]->compare($betas[1]) < 0 ? $betas[0] : $betas[1];
//echo strtoupper($this->beta->toHex(true)) . "\n"; exit;
}
if (!isset($this->basis)) {
$factory = new PrimeField($this->order);
$tempOne = $factory->newInteger($one);
$tempTwo = $factory->newInteger($two);
$tempThree = $factory->newInteger(new BigInteger(3));
$inv = $tempOne->divide($tempTwo)->negate();
$s = $tempThree->negate()->squareRoot()->multiply($inv);
$lambdas = [
$inv->add($s),
$inv->subtract($s)
];
$lhs = $this->multiplyPoint($this->p, $lambdas[0])[0];
$rhs = $this->p[0]->multiply($this->beta);
$lambda = $lhs->equals($rhs) ? $lambdas[0] : $lambdas[1];
$this->basis = static::extendedGCD($lambda->toBigInteger(), $this->order);
///*
foreach ($this->basis as $basis) {
echo strtoupper($basis['a']->toHex(true)) . "\n";
echo strtoupper($basis['b']->toHex(true)) . "\n\n";
}
exit;
//*/
}
$npoints = $nscalars = [];
for ($i = 0; $i < count($points); $i++) {
$p = $points[$i];
$k = $scalars[$i]->toBigInteger();
// begin split
list($v1, $v2) = $this->basis;
$c1 = $v2['b']->multiply($k);
list($c1, $r) = $c1->divide($this->order);
if ($this->order->compare($r->multiply($two)) <= 0) {
$c1 = $c1->add($one);
}
$c2 = $v1['b']->negate()->multiply($k);
list($c2, $r) = $c2->divide($this->order);
if ($this->order->compare($r->multiply($two)) <= 0) {
$c2 = $c2->add($one);
}
$p1 = $c1->multiply($v1['a']);
$p2 = $c2->multiply($v2['a']);
$q1 = $c1->multiply($v1['b']);
$q2 = $c2->multiply($v2['b']);
$k1 = $k->subtract($p1)->subtract($p2);
$k2 = $q1->add($q2)->negate();
// end split
$beta = [
$p[0]->multiply($this->beta),
$p[1],
clone $this->one
];
if (isset($p['naf'])) {
$beta['naf'] = array_map(function($p) {
return [
$p[0]->multiply($this->beta),
$p[1],
clone $this->one
];
}, $p['naf']);
$beta['nafwidth'] = $p['nafwidth'];
}
if ($k1->isNegative()) {
$k1 = $k1->negate();
$p = $this->negatePoint($p);
}
if ($k2->isNegative()) {
$k2 = $k2->negate();
$beta = $this->negatePoint($beta);
}
$pos = 2 * $i;
$npoints[$pos] = $p;
$nscalars[$pos] = $this->factory->newInteger($k1);
$pos++;
$npoints[$pos] = $beta;
$nscalars[$pos] = $this->factory->newInteger($k2);
}
return parent::multiplyAddPoints($npoints, $nscalars);
}
/**
* Returns the numerator and denominator of the slope
*
* @return FiniteField[]
*/
protected function doublePointHelper(array $p)
{
$numerator = $this->three->multiply($p[0])->multiply($p[0]);
$denominator = $this->two->multiply($p[1]);
return [$numerator, $denominator];
}
/**
* Doubles a jacobian coordinate on the curve
*
* See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
*
* @return FiniteField[]
*/
protected function jacobianDoublePoint(array $p)
{
list($x1, $y1, $z1) = $p;
$a = $x1->multiply($x1);
$b = $y1->multiply($y1);
$c = $b->multiply($b);
$d = $x1->add($b);
$d = $d->multiply($d)->subtract($a)->subtract($c)->multiply($this->two);
$e = $this->three->multiply($a);
$f = $e->multiply($e);
$x3 = $f->subtract($this->two->multiply($d));
$y3 = $e->multiply($d->subtract($x3))->subtract(
$this->eight->multiply($c));
$z3 = $this->two->multiply($y1)->multiply($z1);
return [$x3, $y3, $z3];
}
/**
* Doubles a "fresh" jacobian coordinate on the curve
*
* See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-mdbl-2007-bl
*
* @return FiniteField[]
*/
protected function jacobianDoublePointMixed(array $p)
{
list($x1, $y1) = $p;
$xx = $x1->multiply($x1);
$yy = $y1->multiply($y1);
$yyyy = $yy->multiply($yy);
$s = $x1->add($yy);
$s = $s->multiply($s)->subtract($xx)->subtract($yyyy)->multiply($this->two);
$m = $this->three->multiply($xx);
$t = $m->multiply($m)->subtract($this->two->multiply($s));
$x3 = $t;
$y3 = $s->subtract($t);
$y3 = $m->multiply($y3)->subtract($this->eight->multiply($yyyy));
$z3 = $this->two->multiply($y1);
return [$x3, $y3, $z3];
}
/**
* Tests whether or not the x / y values satisfy the equation
*
* @return boolean
*/
public function verifyPoint(array $p)
{
list($x, $y) = $p;
$lhs = $y->multiply($y);
$temp = $x->multiply($x)->multiply($x);
$rhs = $temp->add($this->b);
return $lhs->equals($rhs);
}
/**
* Calculates the parameters needed from the Euclidean algorithm as discussed at
* http://diamond.boisestate.edu/~liljanab/MATH308/GuideToECC.pdf#page=148
*
* @param BigInteger $n
* @return BigInteger[]
*/
protected static function extendedGCD(BigInteger $u, BigInteger $v)
{
$one = new BigInteger(1);
$zero = new BigInteger();
$a = clone $one;
$b = clone $zero;
$c = clone $zero;
$d = clone $one;
$stop = $v->bitwise_rightShift($v->getLength() >> 1);
$a1 = clone $zero;
$b1 = clone $zero;
$a2 = clone $zero;
$b2 = clone $zero;
$postGreatestIndex = 0;
while (!$v->equals($zero)) {
list($q) = $u->divide($v);
$temp = $u;
$u = $v;
$v = $temp->subtract($v->multiply($q));
$temp = $a;
$a = $c;
$c = $temp->subtract($a->multiply($q));
$temp = $b;
$b = $d;
$d = $temp->subtract($b->multiply($q));
if ($v->compare($stop) > 0) {
$a0 = $v;
$b0 = $c;
} else {
$postGreatestIndex++;
}
if ($postGreatestIndex == 1) {
$a1 = $v;
$b1 = $c->negate();
}
if ($postGreatestIndex == 2) {
$rhs = $a0->multiply($a0)->add($b0->multiply($b0));
$lhs = $v->multiply($v)->add($b->multiply($b));
if ($lhs->compare($rhs) <= 0) {
$a2 = $a0;
$b2 = $b0->negate();
} else {
$a2 = $v;
$b2 = $c->negate();
}
break;
}
}
return [
['a' => $a1, 'b' => $b1],
['a' => $a2, 'b' => $b2]
];
}
}

View File

@ -0,0 +1,774 @@
<?php
/**
* Curves over y^2 = x^3 + a*x + b
*
* These are curves used in SEC 2 over prime fields: http://www.secg.org/SEC2-Ver-1.0.pdf
* The curve is a weierstrass curve with a[1], a[3] and a[2] set to 0.
*
* Uses Jacobian Coordinates for speed if able:
*
* https://en.wikipedia.org/wiki/Jacobian_curve
* https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\BaseCurves;
use phpseclib\Math\Common\FiniteField\Integer;
use phpseclib\Common\Functions\Strings;
use phpseclib\Math\PrimeField;
use phpseclib\Math\BigInteger;
use phpseclib\Math\PrimeField\Integer as PrimeInteger;
/**
* Curves over y^2 = x^3 + a*x + b
*
* @package Prime
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class Prime extends Base
{
/**
* Prime Field Integer factory
*
* @var \phpseclib\Math\PrimeFields
*/
protected $factory;
/**
* Cofficient for x^1
*
* @var object
*/
protected $a;
/**
* Cofficient for x^0
*
* @var object
*/
protected $b;
/**
* Base Point
*
* @var object
*/
protected $p;
/**
* The number one over the specified finite field
*
* @var object
*/
protected $one;
/**
* The number two over the specified finite field
*
* @var object
*/
protected $two;
/**
* The number three over the specified finite field
*
* @var object
*/
protected $three;
/**
* The number four over the specified finite field
*
* @var object
*/
protected $four;
/**
* The number eight over the specified finite field
*
* @var object
*/
protected $eight;
/**
* The modulo
*
* @var BigInteger
*/
protected $modulo;
/**
* The Order
*
* @var BigInteger
*/
protected $order;
/**
* Sets the modulo
*/
public function setModulo(BigInteger $modulo)
{
$this->modulo = $modulo;
$this->factory = new PrimeField($modulo);
$this->two = $this->factory->newInteger(new BigInteger(2));
$this->three = $this->factory->newInteger(new BigInteger(3));
// used by jacobian coordinates
$this->one = $this->factory->newInteger(new BigInteger(1));
$this->four = $this->factory->newInteger(new BigInteger(4));
$this->eight = $this->factory->newInteger(new BigInteger(8));
}
/**
* Set coefficients a and b
*/
public function setCoefficients(BigInteger $a, BigInteger $b)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->a = $this->factory->newInteger($a);
$this->b = $this->factory->newInteger($b);
}
/**
* Set x and y coordinates for the base point
*
* @param BigInteger|PrimeInteger $x
* @param BigInteger|PrimeInteger $y
* @return PrimeInteger[]
*/
public function setBasePoint($x, $y)
{
switch (true) {
case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
}
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->p = [
$x instanceof BigInteger ? $this->factory->newInteger($x) : $x,
$y instanceof BigInteger ? $this->factory->newInteger($y) : $y
];
}
/**
* Retrieve the base point as an array
*
* @return array
*/
public function getBasePoint()
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
/*
if (!isset($this->p)) {
throw new \RuntimeException('setBasePoint needs to be called before this method');
}
*/
return $this->p;
}
/**
* Adds two "fresh" jacobian form on the curve
*
* @return FiniteField[]
*/
protected function jacobianAddPointMixedXY(array $p, array $q)
{
list($u1, $s1) = $p;
list($u2, $s2) = $q;
if ($u1->equals($u2)) {
if (!$s1->equals($s2)) {
return [];
} else {
return $this->doublePoint($p);
}
}
$h = $u2->subtract($u1);
$r = $s2->subtract($s1);
$h2 = $h->multiply($h);
$h3 = $h2->multiply($h);
$v = $u1->multiply($h2);
$x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
$y3 = $r->multiply(
$v->subtract($x3))->subtract(
$s1->multiply($h3));
return [$x3, $y3, $h];
}
/**
* Adds one "fresh" jacobian form on the curve
*
* The second parameter should be the "fresh" one
*
* @return FiniteField[]
*/
protected function jacobianAddPointMixedX(array $p, array $q)
{
list($u1, $s1, $z1) = $p;
list($x2, $y2) = $q;
$z12 = $z1->multiply($z1);
$u2 = $x2->multiply($z12);
$s2 = $y2->multiply($z12->multiply($z1));
if ($u1->equals($u2)) {
if (!$s1->equals($s2)) {
return [];
} else {
return $this->doublePoint($p);
}
}
$h = $u2->subtract($u1);
$r = $s2->subtract($s1);
$h2 = $h->multiply($h);
$h3 = $h2->multiply($h);
$v = $u1->multiply($h2);
$x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
$y3 = $r->multiply(
$v->subtract($x3))->subtract(
$s1->multiply($h3));
$z3 = $h->multiply($z1);
return [$x3, $y3, $z3];
}
/**
* Adds two jacobian coordinates on the curve
*
* @return FiniteField[]
*/
protected function jacobianAddPoint(array $p, array $q)
{
list($x1, $y1, $z1) = $p;
list($x2, $y2, $z2) = $q;
$z12 = $z1->multiply($z1);
$z22 = $z2->multiply($z2);
$u1 = $x1->multiply($z22);
$u2 = $x2->multiply($z12);
$s1 = $y1->multiply($z22->multiply($z2));
$s2 = $y2->multiply($z12->multiply($z1));
if ($u1->equals($u2)) {
if (!$s1->equals($s2)) {
return [];
} else {
return $this->doublePoint($p);
}
}
$h = $u2->subtract($u1);
$r = $s2->subtract($s1);
$h2 = $h->multiply($h);
$h3 = $h2->multiply($h);
$v = $u1->multiply($h2);
$x3 = $r->multiply($r)->subtract($h3)->subtract($v->multiply($this->two));
$y3 = $r->multiply(
$v->subtract($x3))->subtract(
$s1->multiply($h3));
$z3 = $h->multiply($z1)->multiply($z2);
return [$x3, $y3, $z3];
}
/**
* Adds two points on the curve
*
* @return FiniteField[]
*/
public function addPoint(array $p, array $q)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!count($p) || !count($q)) {
if (count($q)) {
return $q;
}
if (count($p)) {
return $p;
}
return [];
}
// use jacobian coordinates
if (isset($p[2]) && isset($q[2])) {
if (isset($p['fresh']) && isset($q['fresh'])) {
return $this->jacobianAddPointMixedXY($p, $q);
}
if (isset($p['fresh'])) {
return $this->jacobianAddPointMixedX($q, $p);
}
if (isset($q['fresh'])) {
return $this->jacobianAddPointMixedX($p, $q);
}
return $this->jacobianAddPoint($p, $q);
}
if (isset($p[2]) || isset($q[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to Jacobi coordinates or vice versa');
}
if ($p[0]->equals($q[0])) {
if (!$p[1]->equals($q[1])) {
return [];
} else { // eg. doublePoint
list($numerator, $denominator) = $this->doublePointHelper($p);
}
} else {
$numerator = $q[1]->subtract($p[1]);
$denominator = $q[0]->subtract($p[0]);
}
$slope = $numerator->divide($denominator);
$x = $slope->multiply($slope)->subtract($p[0])->subtract($q[0]);
$y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]);
return [$x, $y];
}
/**
* Returns the numerator and denominator of the slope
*
* @return FiniteField[]
*/
protected function doublePointHelper(array $p)
{
$numerator = $this->three->multiply($p[0])->multiply($p[0])->add($this->a);
$denominator = $this->two->multiply($p[1]);
return [$numerator, $denominator];
}
/**
* Doubles a jacobian coordinate on the curve
*
* @return FiniteField[]
*/
protected function jacobianDoublePoint(array $p)
{
list($x, $y, $z) = $p;
$x2 = $x->multiply($x);
$y2 = $y->multiply($y);
$z2 = $z->multiply($z);
$s = $this->four->multiply($x)->multiply($y2);
$m1 = $this->three->multiply($x2);
$m2 = $this->a->multiply($z2->multiply($z2));
$m = $m1->add($m2);
$x1 = $m->multiply($m)->subtract($this->two->multiply($s));
$y1 = $m->multiply($s->subtract($x1))->subtract(
$this->eight->multiply($y2->multiply($y2)));
$z1 = $this->two->multiply($y)->multiply($z);
return [$x1, $y1, $z1];
}
/**
* Doubles a "fresh" jacobian coordinate on the curve
*
* @return FiniteField[]
*/
protected function jacobianDoublePointMixed(array $p)
{
list($x, $y) = $p;
$x2 = $x->multiply($x);
$y2 = $y->multiply($y);
$s = $this->four->multiply($x)->multiply($y2);
$m1 = $this->three->multiply($x2);
$m = $m1->add($this->a);
$x1 = $m->multiply($m)->subtract($this->two->multiply($s));
$y1 = $m->multiply($s->subtract($x1))->subtract(
$this->eight->multiply($y2->multiply($y2)));
$z1 = $this->two->multiply($y);
return [$x1, $y1, $z1];
}
/**
* Doubles a point on a curve
*
* @return FiniteField[]
*/
public function doublePoint(array $p)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!count($p)) {
return [];
}
// use jacobian coordinates
if (isset($p[2])) {
if (isset($p['fresh'])) {
return $this->jacobianDoublePointMixed($p);
}
return $this->jacobianDoublePoint($p);
}
list($numerator, $denominator) = $this->doublePointHelper($p);
$slope = $numerator->divide($denominator);
$x = $slope->multiply($slope)->subtract($p[0])->subtract($p[0]);
$y = $slope->multiply($p[0]->subtract($x))->subtract($p[1]);
return [$x, $y];
}
/**
* Returns the X coordinate and the derived Y coordinate
*
* @return array
*/
public function derivePoint($m)
{
$y = ord(Strings::shift($m));
$x = new BigInteger($m, 256);
$xp = $this->convertInteger($x);
switch ($y) {
case 2: $ypn = false; break;
case 3: $ypn = true; break;
default:
throw new \RuntimeException('Coordinate not in recognized format');
}
$temp = $xp->multiply($this->a);
$temp = $xp->multiply($xp)->multiply($xp)->add($temp);
$temp = $temp->add($this->b);
$b = $temp->squareRoot();
if (!$b) {
throw new \RuntimeException('Unable to derive Y coordinate');
}
$bn = $b->isOdd();
$yp = $ypn == $bn ? $b : $b->negate();
return [$xp, $yp];
}
/**
* Tests whether or not the x / y values satisfy the equation
*
* @return boolean
*/
public function verifyPoint(array $p)
{
list($x, $y) = $p;
$lhs = $y->multiply($y);
$temp = $x->multiply($this->a);
$temp = $x->multiply($x)->multiply($x)->add($temp);
$rhs = $temp->add($this->b);
return $lhs->equals($rhs);
}
/**
* Returns the modulo
*
* @return \phpseclib\Math\BigInteger
*/
public function getModulo()
{
return $this->modulo;
}
/**
* Returns the a coefficient
*
* @return \phpseclib\Math\PrimeField\Integer
*/
public function getA()
{
return $this->a;
}
/**
* Returns the a coefficient
*
* @return \phpseclib\Math\PrimeField\Integer
*/
public function getB()
{
return $this->b;
}
/**
* Multiply and Add Points
*
* Adapted from https://git.io/vxPUH
*
* @return int[]
*/
public function multiplyAddPoints(array $points, array $scalars)
{
$length = count($points);
foreach ($points as &$point) {
$point = $this->convertToInternal($point);
}
$wnd = [$this->getNAFPoints($points[0], 7)];
$wndWidth = [isset($points[0]['nafwidth']) ? $points[0]['nafwidth'] : 7];
for ($i = 1; $i < $length; $i++) {
$wnd[] = $this->getNAFPoints($points[$i], 1);
$wndWidth[] = isset($points[$i]['nafwidth']) ? $points[$i]['nafwidth'] : 1;
}
$naf = [];
// comb all window NAFs
$max = 0;
for ($i = $length - 1; $i >= 1; $i-= 2) {
$a = $i - 1;
$b = $i;
if ($wndWidth[$a] != 1 || $wndWidth[$b] != 1) {
$naf[$a] = $scalars[$a]->getNAF($wndWidth[$a]);
$naf[$b] = $scalars[$b]->getNAF($wndWidth[$b]);
$max = max(count($naf[$a]), count($naf[$b]), $max);
continue;
}
$comb = [
$points[$a], // 1
null, // 3
null, // 5
$points[$b] // 7
];
$comb[1] = $this->addPoint($points[$a], $points[$b]);
$comb[2] = $this->addPoint($points[$a], $this->negatePoint($points[$b]));
$index = [
-3, /* -1 -1 */
-1, /* -1 0 */
-5, /* -1 1 */
-7, /* 0 -1 */
0, /* 0 -1 */
7, /* 0 1 */
5, /* 1 -1 */
1, /* 1 0 */
3 /* 1 1 */
];
$jsf = self::getJSFPoints($scalars[$a], $scalars[$b]);
$max = max(count($jsf[0]), $max);
if ($max > 0) {
$naf[$a] = array_fill(0, $max, 0);
$naf[$b] = array_fill(0, $max, 0);
} else {
$naf[$a] = [];
$naf[$b] = [];
}
for ($j = 0; $j < $max; $j++) {
$ja = isset($jsf[0][$j]) ? $jsf[0][$j] : 0;
$jb = isset($jsf[1][$j]) ? $jsf[1][$j] : 0;
$naf[$a][$j] = $index[3 * ($ja + 1) + $jb + 1];
$naf[$b][$j] = 0;
$wnd[$a] = $comb;
}
}
$acc = [];
$temp = [0, 0, 0, 0];
for ($i = $max; $i >= 0; $i--) {
$k = 0;
while ($i >= 0) {
$zero = true;
for ($j = 0; $j < $length; $j++) {
$temp[$j] = isset($naf[$j][$i]) ? $naf[$j][$i] : 0;
if ($temp[$j] != 0) {
$zero = false;
}
}
if (!$zero) {
break;
}
$k++;
$i--;
}
if ($i >= 0) {
$k++;
}
while ($k--) {
$acc = $this->doublePoint($acc);
}
if ($i < 0) {
break;
}
for ($j = 0; $j < $length; $j++) {
$z = $temp[$j];
$p = null;
if ($z == 0) {
continue;
}
$p = $z > 0 ?
$wnd[$j][($z - 1) >> 1] :
$this->negatePoint($wnd[$j][(-$z - 1) >> 1]);
$acc = $this->addPoint($acc, $p);
}
}
return $this->convertToAffine($acc);
}
/**
* Precomputes NAF points
*
* Adapted from https://git.io/vxY1f
*
* @return int[]
*/
private function getNAFPoints($point, $wnd)
{
if (isset($point['naf'])) {
return $point['naf'];
}
$res = [$point];
$max = (1 << $wnd) - 1;
$dbl = $max == 1 ? null : $this->doublePoint($point);
for ($i = 1; $i < $max; $i++) {
$res[] = $this->addPoint($res[$i - 1], $dbl);
}
$point['naf'] = $res;
/*
$str = '';
foreach ($res as $re) {
$re[0] = bin2hex($re[0]->toBytes());
$re[1] = bin2hex($re[1]->toBytes());
$str.= " ['$re[0]', '$re[1]'],\r\n";
}
file_put_contents('temp.txt', $str);
exit;
*/
return $res;
}
/**
* Precomputes points in Joint Sparse Form
*
* Adapted from https://git.io/vxrpD
*
* @return int[]
*/
private static function getJSFPoints(Integer $k1, Integer $k2)
{
static $three;
if (!isset($three)) {
$three = new BigInteger(3);
}
$jsf = [[], []];
$k1 = $k1->toBigInteger();
$k2 = $k2->toBigInteger();
$d1 = 0;
$d2 = 0;
while ($k1->compare(new BigInteger(-$d1)) > 0 || $k2->compare(new BigInteger(-$d2)) > 0) {
// first phase
$m14 = $k1->testBit(0) + 2 * $k1->testBit(1);
$m14+= $d1;
$m14&= 3;
$m24 = $k2->testBit(0) + 2 * $k2->testBit(1);
$m24+= $d2;
$m24&= 3;
if ($m14 == 3) {
$m14 = -1;
}
if ($m24 == 3) {
$m24 = -1;
}
$u1 = 0;
if ($m14 & 1) { // if $m14 is odd
$m8 = $k1->testBit(0) + 2 * $k1->testBit(1) + 4 * $k1->testBit(2);
$m8+= $d1;
$m8&= 7;
$u1 = ($m8 == 3 || $m8 == 5) && $m24 == 2 ? -$m14 : $m14;
}
$jsf[0][] = $u1;
$u2 = 0;
if ($m24 & 1) { // if $m24 is odd
$m8 = $k2->testBit(0) + 2 * $k2->testBit(1) + 4 * $k2->testBit(2);
$m8+= $d2;
$m8&= 7;
$u2 = ($m8 == 3 || $m8 == 5) && $m14 == 2 ? -$m24 : $m24;
}
$jsf[1][] = $u2;
// second phase
if (2 * $d1 == $u1 + 1) {
$d1 = 1 - $d1;
}
if (2 * $d2 == $u2 + 1) {
$d2 = 1 - $d2;
}
$k1 = $k1->bitwise_rightShift(1);
$k2 = $k2->bitwise_rightShift(1);
}
return $jsf;
}
/**
* Returns the affine point
*
* A Jacobian Coordinate is of the form (x, y, z).
* To convert a Jacobian Coordinate to an Affine Point
* you do (x / z^2, y / z^3)
*
* @return \phpseclib\Math\PrimeField\Integer[]
*/
public function convertToAffine(array $p)
{
if (!isset($p[2])) {
return $p;
}
list($x, $y, $z) = $p;
$z = $this->one->divide($z);
$z2 = $z->multiply($z);
return [
$x->multiply($z2),
$y->multiply($z2)->multiply($z)
];
}
/**
* Converts an affine point to a jacobian coordinate
*
* @return \phpseclib\Math\PrimeField\Integer[]
*/
public function convertToInternal(array $p)
{
if (isset($p[2])) {
return $p;
}
$p[2] = clone $this->one;
$p['fresh'] = true;
return $p;
}
}

View File

@ -0,0 +1,236 @@
<?php
/**
* Curves over a*x^2 + y^2 = 1 + d*x^2*y^2
*
* http://www.secg.org/SEC2-Ver-1.0.pdf provides for curves with custom parameters.
* ie. the coefficients can be arbitrary set through specially formatted keys, etc.
* As such, Prime.php is built very generically and it's not able to take full
* advantage of curves with 0 coefficients to produce simplified point doubling,
* point addition. Twisted Edwards curves, in contrast, do not have a way, currently,
* to customize them. As such, we can omit the super generic stuff from this class
* and let the named curves (Ed25519 and Ed448) define their own custom tailored
* point addition and point doubling methods.
*
* More info:
*
* https://en.wikipedia.org/wiki/Twisted_Edwards_curve
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\BaseCurves;
use phpseclib\Math\PrimeField;
use phpseclib\Math\BigInteger;
use phpseclib\Math\PrimeField\Integer as PrimeInteger;
/**
* Curves over a*x^2 + y^2 = 1 + d*x^2*y^2
*
* @package Prime
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
class TwistedEdwards extends Base
{
/**
* The modulo
*
* @var BigInteger
*/
protected $modulo;
/**
* Cofficient for x^2
*
* @var object
*/
protected $a;
/**
* Cofficient for x^2*y^2
*
* @var object
*/
protected $d;
/**
* Base Point
*
* @var object[]
*/
protected $p;
/**
* The number zero over the specified finite field
*
* @var object
*/
protected $zero;
/**
* The number one over the specified finite field
*
* @var object
*/
protected $one;
/**
* The number two over the specified finite field
*
* @var object
*/
protected $two;
/**
* Sets the modulo
*/
public function setModulo(BigInteger $modulo)
{
$this->modulo = $modulo;
$this->factory = new PrimeField($modulo);
$this->zero = $this->factory->newInteger(new BigInteger(0));
$this->one = $this->factory->newInteger(new BigInteger(1));
$this->two = $this->factory->newInteger(new BigInteger(2));
}
/**
* Set coefficients a and b
*/
public function setCoefficients(BigInteger $a, BigInteger $d)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->a = $this->factory->newInteger($a);
$this->d = $this->factory->newInteger($d);
}
/**
* Set x and y coordinates for the base point
*/
public function setBasePoint($x, $y)
{
switch (true) {
case !$x instanceof BigInteger && !$x instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 1 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
case !$y instanceof BigInteger && !$y instanceof PrimeInteger:
throw new \UnexpectedValueException('Argument 2 passed to Prime::setBasePoint() must be an instance of either BigInteger or PrimeField\Integer');
}
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
$this->p = [
$x instanceof BigInteger ? $this->factory->newInteger($x) : $x,
$y instanceof BigInteger ? $this->factory->newInteger($y) : $y
];
}
/**
* Returns the a coefficient
*
* @return \phpseclib\Math\PrimeField\Integer
*/
public function getA()
{
return $this->a;
}
/**
* Returns the a coefficient
*
* @return \phpseclib\Math\PrimeField\Integer
*/
public function getD()
{
return $this->d;
}
/**
* Retrieve the base point as an array
*
* @return array
*/
public function getBasePoint()
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
/*
if (!isset($this->p)) {
throw new \RuntimeException('setBasePoint needs to be called before this method');
}
*/
return $this->p;
}
/**
* Returns the affine point
*
* @return \phpseclib\Math\PrimeField\Integer[]
*/
public function convertToAffine(array $p)
{
if (!isset($p[2])) {
return $p;
}
list($x, $y, $z) = $p;
$z = $this->one->divide($z);
return [
$x->multiply($z),
$y->multiply($z)
];
}
/**
* Returns the modulo
*
* @return \phpseclib\Math\BigInteger
*/
public function getModulo()
{
return $this->modulo;
}
/**
* Tests whether or not the x / y values satisfy the equation
*
* @return boolean
*/
public function verifyPoint(array $p)
{
list($x, $y) = $p;
$x2 = $x->multiply($x);
$y2 = $y->multiply($y);
$lhs = $this->a->multiply($x2)->add($y2);
$rhs = $this->d->multiply($x2)->multiply($y2)->add($this->one);
return $lhs->equals($rhs);
}
/**
* Tests whether or not the x / y values satisfy the equation
*
* @return boolean
*/
public function get(array $p)
{
list($x, $y) = $p;
$x2 = $x->multiply($x);
$y2 = $y->multiply($y);
$lhs = $this->a->multiply($x2)->add($y2);
$rhs = $this->d->multiply($x2)->multiply($y2)->add($this->one);
return $lhs->equals($rhs);
}
}

View File

@ -0,0 +1,334 @@
<?php
/**
* Ed25519
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards;
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\Hash;
use phpseclib\Crypt\Random;
class Ed25519 extends TwistedEdwards
{
const HASH = 'sha512';
/*
Per https://tools.ietf.org/html/rfc8032#page-6 EdDSA has several parameters, one of which is b:
2. An integer b with 2^(b-1) > p. EdDSA public keys have exactly b
bits, and EdDSA signatures have exactly 2*b bits. b is
recommended to be a multiple of 8, so public key and signature
lengths are an integral number of octets.
SIZE corresponds to b
*/
const SIZE = 32;
public function __construct()
{
// 2^255 - 19
$this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED', 16));
$this->setCoefficients(
// -1
new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEC', 16), // a
// -121665/121666
new BigInteger('52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3', 16) // d
);
$this->setBasePoint(
new BigInteger('216936D3CD6E53FEC0A4E231FDD6DC5C692CC7609525A7B2C9562D608F25D51A', 16),
new BigInteger('6666666666666666666666666666666666666666666666666666666666666658', 16)
);
$this->setOrder(new BigInteger('1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED', 16));
// algorithm 14.47 from http://cacr.uwaterloo.ca/hac/about/chap14.pdf#page=16
/*
$this->setReduction(function($x) {
$parts = $x->bitwise_split(255);
$className = $this->className;
if (count($parts) > 2) {
list(, $r) = $x->divide($className::$modulo);
return $r;
}
$zero = new BigInteger();
$c = new BigInteger(19);
switch (count($parts)) {
case 2:
list($qi, $ri) = $parts;
break;
case 1:
$qi = $zero;
list($ri) = $parts;
break;
case 0:
return $zero;
}
$r = $ri;
while ($qi->compare($zero) > 0) {
$temp = $qi->multiply($c)->bitwise_split(255);
if (count($temp) == 2) {
list($qi, $ri) = $temp;
} else {
$qi = $zero;
list($ri) = $temp;
}
$r = $r->add($ri);
}
while ($r->compare($className::$modulo) > 0) {
$r = $r->subtract($className::$modulo);
}
return $r;
});
*/
}
/**
* Recover X from Y
*
* Implements steps 2-4 at https://tools.ietf.org/html/rfc8032#section-5.1.3
*
* Used by ECDSA\Keys\Common.php
*
* @param BigInteger $x
* @param boolean $sign
* @return object[]
*/
public function recoverX(BigInteger $y, $sign)
{
$y = $this->factory->newInteger($y);
$y2 = $y->multiply($y);
$u = $y2->subtract($this->one);
$v = $this->d->multiply($y2)->add($this->one);
$x2 = $u->divide($v);
if ($x2->equals($this->zero)) {
if ($sign) {
throw new \RuntimeException('Unable to recover X coordinate (x2 = 0)');
}
return clone $this->zero;
}
// find the square root
/* we don't do $x2->squareRoot() because, quoting from
https://tools.ietf.org/html/rfc8032#section-5.1.1:
"For point decoding or "decompression", square roots modulo p are
needed. They can be computed using the Tonelli-Shanks algorithm or
the special case for p = 5 (mod 8). To find a square root of a,
first compute the candidate root x = a^((p+3)/8) (mod p)."
*/
$exp = $this->getModulo()->add(new BigInteger(3));
$exp = $exp->bitwise_rightShift(3);
$x = $x2->pow($exp);
// If v x^2 = -u (mod p), set x <-- x * 2^((p-1)/4), which is a square root.
if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) {
$temp = $this->getModulo()->subtract(new BigInteger(1));
$temp = $temp->bitwise_rightShift(2);
$temp = $this->two->pow($temp);
$x = $x->multiply($temp);
if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) {
throw new \RuntimeException('Unable to recover X coordinate');
}
}
if ($x->isOdd() != $sign) {
$x = $x->negate();
}
return [$x, $y];
}
/**
* Extract Secret Scalar
*
* Implements steps 1-3 at https://tools.ietf.org/html/rfc8032#section-5.1.5
*
* Used by the various key handlers
*
* @param string $str
* @return \phpseclib\Math\PrimeField\Integer
*/
public function extractSecret($str)
{
if (strlen($str) != 32) {
throw new \LengthException('Private Key should be 32-bytes long');
}
// 1. Hash the 32-byte private key using SHA-512, storing the digest in
// a 64-octet large buffer, denoted h. Only the lower 32 bytes are
// used for generating the public key.
$hash = new Hash('sha512');
$h = $hash->hash($str);
$h = substr($h, 0, 32);
// 2. Prune the buffer: The lowest three bits of the first octet are
// cleared, the highest bit of the last octet is cleared, and the
// second highest bit of the last octet is set.
$h[0] = $h[0] & chr(0xF8);
$h = strrev($h);
$h[0] = ($h[0] & chr(0x3F)) | chr(0x40);
// 3. Interpret the buffer as the little-endian integer, forming a
// secret scalar s.
$dA = new BigInteger($h, 256);
$dA = $this->factory->newInteger($dA);
$dA->secret = $str;
return $dA;
}
/**
* Encode a point as a string
*
* @param string $str
* @return string
*/
public function encodePoint($point)
{
list($x, $y) = $point;
$y = $y->toBytes();
$y[0] = $y[0] & chr(0x7F);
if ($x->isOdd()) {
$y[0] = $y[0] | chr(0x80);
}
$y = strrev($y);
return $y;
}
/**
* Creates a random scalar multiplier
*
* @return \phpseclib\Math\PrimeField\Integer
*/
public function createRandomMultiplier()
{
return $this->extractSecret(Random::string(32));
}
/**
* Converts an affine point to an extended homogeneous coordinate
*
* From https://tools.ietf.org/html/rfc8032#section-5.1.4 :
*
* A point (x,y) is represented in extended homogeneous coordinates (X, Y, Z, T),
* with x = X/Z, y = Y/Z, x * y = T/Z.
*
* @return \phpseclib\Math\PrimeField\Integer[]
*/
public function convertToInternal(array $p)
{
if (empty($p)) {
return [clone $this->zero, clone $this->one, clone $this->one, clone $this->zero];
}
if (isset($p[2])) {
return $p;
}
$p[2] = clone $this->one;
$p[3] = $p[0]->multiply($p[1]);
return $p;
}
/**
* Doubles a point on a curve
*
* @return FiniteField[]
*/
public function doublePoint(array $p)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!count($p)) {
return [];
}
if (!isset($p[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
// from https://tools.ietf.org/html/rfc8032#page-12
list($x1, $y1, $z1, $t1) = $p;
$a = $x1->multiply($x1);
$b = $y1->multiply($y1);
$c = $this->two->multiply($z1)->multiply($z1);
$h = $a->add($b);
$temp = $x1->add($y1);
$e = $h->subtract($temp->multiply($temp));
$g = $a->subtract($b);
$f = $c->add($g);
$x3 = $e->multiply($f);
$y3 = $g->multiply($h);
$t3 = $e->multiply($h);
$z3 = $f->multiply($g);
return [$x3, $y3, $z3, $t3];
}
/**
* Adds two points on the curve
*
* @return FiniteField[]
*/
public function addPoint(array $p, array $q)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!count($p) || !count($q)) {
if (count($q)) {
return $q;
}
if (count($p)) {
return $p;
}
return [];
}
if (!isset($p[2]) || !isset($q[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
if ($p[0]->equals($q[0])) {
return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
}
// from https://tools.ietf.org/html/rfc8032#page-12
list($x1, $y1, $z1, $t1) = $p;
list($x2, $y2, $z2, $t2) = $q;
$a = $y1->subtract($x1)->multiply($y2->subtract($x2));
$b = $y1->add($x1)->multiply($y2->add($x2));
$c = $t1->multiply($this->two)->multiply($this->d)->multiply($t2);
$d = $z1->multiply($this->two)->multiply($z2);
$e = $b->subtract($a);
$f = $d->subtract($c);
$g = $d->add($c);
$h = $b->add($a);
$x3 = $e->multiply($f);
$y3 = $g->multiply($h);
$t3 = $e->multiply($h);
$z3 = $f->multiply($g);
return [$x3, $y3, $z3, $t3];
}
}

View File

@ -0,0 +1,267 @@
<?php
/**
* Ed448
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards;
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\Hash;
use phpseclib\Crypt\Random;
class Ed448 extends TwistedEdwards
{
const HASH = 'shake256-912';
const SIZE = 57;
public function __construct()
{
// 2^448 - 2^224 - 1
$this->setModulo(new BigInteger(
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' .
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger(1),
// -39081
new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE' .
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6756', 16)
);
$this->setBasePoint(
new BigInteger('4F1970C66BED0DED221D15A622BF36DA9E146570470F1767EA6DE324' .
'A3D3A46412AE1AF72AB66511433B80E18B00938E2626A82BC70CC05E', 16),
new BigInteger('693F46716EB6BC248876203756C9C7624BEA73736CA3984087789C1E' .
'05A0C2D73AD3FF1CE67C39C4FDBD132C4ED7C8AD9808795BF230FA14', 16)
);
$this->setOrder(new BigInteger(
'3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
'7CCA23E9C44EDB49AED63690216CC2728DC58F552378C292AB5844F3', 16));
}
/**
* Recover X from Y
*
* Implements steps 2-4 at https://tools.ietf.org/html/rfc8032#section-5.2.3
*
* Used by ECDSA\Keys\Common.php
*
* @param BigInteger $x
* @param boolean $sign
* @return object[]
*/
public function recoverX(BigInteger $y, $sign)
{
$y = $this->factory->newInteger($y);
$y2 = $y->multiply($y);
$u = $y2->subtract($this->one);
$v = $this->d->multiply($y2)->subtract($this->one);
$x2 = $u->divide($v);
if ($x2->equals($this->zero)) {
if ($sign) {
throw new \RuntimeException('Unable to recover X coordinate (x2 = 0)');
}
return clone $this->zero;
}
// find the square root
$exp = $this->getModulo()->add(new BigInteger(1));
$exp = $exp->bitwise_rightShift(2);
$x = $x2->pow($exp);
if (!$x->multiply($x)->subtract($x2)->equals($this->zero)) {
throw new \RuntimeException('Unable to recover X coordinate');
}
if ($x->isOdd() != $sign) {
$x = $x->negate();
}
return [$x, $y];
}
/**
* Extract Secret Scalar
*
* Implements steps 1-3 at https://tools.ietf.org/html/rfc8032#section-5.2.5
*
* Used by the various key handlers
*
* @param string $str
* @return \phpseclib\Math\PrimeField\Integer
*/
public function extractSecret($str)
{
if (strlen($str) != 57) {
throw new \LengthException('Private Key should be 57-bytes long');
}
// 1. Hash the 57-byte private key using SHAKE256(x, 114), storing the
// digest in a 114-octet large buffer, denoted h. Only the lower 57
// bytes are used for generating the public key.
$hash = new Hash('shake256-912');
$h = $hash->hash($str);
$h = substr($h, 0, 57);
// 2. Prune the buffer: The two least significant bits of the first
// octet are cleared, all eight bits the last octet are cleared, and
// the highest bit of the second to last octet is set.
$h[0] = $h[0] & chr(0xFC);
$h = strrev($h);
$h[0] = "\0";
$h[1] = $h[1] | chr(0x80);
// 3. Interpret the buffer as the little-endian integer, forming a
// secret scalar s.
$dA = new BigInteger($h, 256);
$dA = $this->factory->newInteger($dA);
$dA->secret = $str;
return $dA;
}
/**
* Encode a point as a string
*
* @param string $str
* @return string
*/
public function encodePoint($point)
{
list($x, $y) = $point;
$y = "\0" . $y->toBytes();
if ($x->isOdd()) {
$y[0] = $y[0] | chr(0x80);
}
$y = strrev($y);
return $y;
}
/**
* Creates a random scalar multiplier
*
* @return \phpseclib\Math\PrimeField\Integer
*/
public function createRandomMultiplier()
{
return $this->extractSecret(Random::string(57));
}
/**
* Converts an affine point to an extended homogeneous coordinate
*
* From https://tools.ietf.org/html/rfc8032#section-5.2.4 :
*
* A point (x,y) is represented in extended homogeneous coordinates (X, Y, Z, T),
* with x = X/Z, y = Y/Z, x * y = T/Z.
*
* @return \phpseclib\Math\PrimeField\Integer[]
*/
public function convertToInternal(array $p)
{
if (empty($p)) {
return [clone $this->zero, clone $this->one, clone $this->one];
}
if (isset($p[2])) {
return $p;
}
$p[2] = clone $this->one;
return $p;
}
/**
* Doubles a point on a curve
*
* @return FiniteField[]
*/
public function doublePoint(array $p)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!count($p)) {
return [];
}
if (!isset($p[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
// from https://tools.ietf.org/html/rfc8032#page-18
list($x1, $y1, $z1) = $p;
$b = $x1->add($y1);
$b = $b->multiply($b);
$c = $x1->multiply($x1);
$d = $y1->multiply($y1);
$e = $c->add($d);
$h = $z1->multiply($z1);
$j = $e->subtract($this->two->multiply($h));
$x3 = $b->subtract($e)->multiply($j);
$y3 = $c->subtract($d)->multiply($e);
$z3 = $e->multiply($j);
return [$x3, $y3, $z3];
}
/**
* Adds two points on the curve
*
* @return FiniteField[]
*/
public function addPoint(array $p, array $q)
{
if (!isset($this->factory)) {
throw new \RuntimeException('setModulo needs to be called before this method');
}
if (!count($p) || !count($q)) {
if (count($q)) {
return $q;
}
if (count($p)) {
return $p;
}
return [];
}
if (!isset($p[2]) || !isset($q[2])) {
throw new \RuntimeException('Affine coordinates need to be manually converted to "Jacobi" coordinates or vice versa');
}
if ($p[0]->equals($q[0])) {
return !$p[1]->equals($q[1]) ? [] : $this->doublePoint($p);
}
// from https://tools.ietf.org/html/rfc8032#page-17
list($x1, $y1, $z1) = $p;
list($x2, $y2, $z2) = $q;
$a = $z1->multiply($z2);
$b = $a->multiply($a);
$c = $x1->multiply($x2);
$d = $y1->multiply($y2);
$e = $this->d->multiply($c)->multiply($d);
$f = $b->subtract($e);
$g = $b->add($e);
$h = $x1->add($y1)->multiply($x2->add($y2));
$x3 = $a->multiply($f)->multiply($h->subtract($c)->subtract($d));
$y3 = $a->multiply($g)->multiply($d->subtract($c));
$z3 = $f->multiply($g);
return [$x3, $y3, $z3];
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* brainpoolP160r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP160r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620F', 16));
$this->setCoefficients(
new BigInteger('340E7BE2A280EB74E2BE61BADA745D97E8F7C300', 16),
new BigInteger('1E589A8595423412134FAA2DBDEC95C8D8675E58', 16)
);
$this->setBasePoint(
new BigInteger('BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3', 16),
new BigInteger('1667CB477A1A8EC338F94741669C976316DA6321', 16)
);
$this->setOrder(new BigInteger('E95E4A5F737059DC60DF5991D45029409E60FC09', 16));
}
}

View File

@ -0,0 +1,49 @@
<?php
/**
* brainpoolP160t1
*
* This curve is a twisted version of brainpoolP160r1 with A = -3. With brainpool,
* the curves ending in r1 are the "regular" curves and the curves ending in "t1"
* are the twisted version of the r1 curves. Per https://tools.ietf.org/html/rfc5639#page-7
* you can convert a point on an r1 curve to a point on a t1 curve thusly:
*
* F(x,y) := (x*Z^2, y*Z^3)
*
* The advantage of A = -3 is that some of the point doubling and point addition can be
* slightly optimized. See http://hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html
* vs http://hyperelliptic.org/EFD/g1p/auto-shortw-projective.html for example.
*
* phpseclib does not currently take advantage of this optimization opportunity
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP160t1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620F', 16));
$this->setCoefficients(
new BigInteger('E95E4A5F737059DC60DFC7AD95B3D8139515620C', 16), // eg. -3
new BigInteger('7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380', 16)
);
$this->setBasePoint(
new BigInteger('B199B13B9B34EFC1397E64BAEB05ACC265FF2378', 16),
new BigInteger('ADD6718B7C7C1961F0991B842443772152C9E0AD', 16)
);
$this->setOrder(new BigInteger('E95E4A5F737059DC60DF5991D45029409E60FC09', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* brainpoolP192r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP192r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297', 16));
$this->setCoefficients(
new BigInteger('6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF', 16),
new BigInteger('469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9', 16)
);
$this->setBasePoint(
new BigInteger('C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD6', 16),
new BigInteger('14B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F', 16)
);
$this->setOrder(new BigInteger('C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* brainpoolP192t1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP192t1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297', 16));
$this->setCoefficients(
new BigInteger('C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294', 16), // eg. -3
new BigInteger('13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79', 16)
);
$this->setBasePoint(
new BigInteger('3AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129', 16),
new BigInteger('097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9', 16)
);
$this->setOrder(new BigInteger('C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* brainpoolP224r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP224r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF', 16));
$this->setCoefficients(
new BigInteger('68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43', 16),
new BigInteger('2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B', 16)
);
$this->setBasePoint(
new BigInteger('0D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D', 16),
new BigInteger('58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD', 16)
);
$this->setOrder(new BigInteger('D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* brainpoolP224t1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP224t1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF', 16));
$this->setCoefficients(
new BigInteger('D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC', 16), // eg. -3
new BigInteger('4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D', 16)
);
$this->setBasePoint(
new BigInteger('6AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D580', 16),
new BigInteger('0374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C', 16)
);
$this->setOrder(new BigInteger('D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* brainpoolP256r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP256r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377', 16));
$this->setCoefficients(
new BigInteger('7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9', 16),
new BigInteger('26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6', 16)
);
$this->setBasePoint(
new BigInteger('8BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262', 16),
new BigInteger('547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997', 16)
);
$this->setOrder(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* brainpoolP256t1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP256t1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377', 16));
$this->setCoefficients(
new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374', 16), // eg. -3
new BigInteger('662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04', 16)
);
$this->setBasePoint(
new BigInteger('A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F4', 16),
new BigInteger('2D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE', 16)
);
$this->setOrder(new BigInteger('A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7', 16));
}
}

View File

@ -0,0 +1,42 @@
<?php
/**
* brainpoolP320r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP320r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F9' .
'2B9EC7893EC28FCD412B1F1B32E27', 16));
$this->setCoefficients(
new BigInteger('3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F4' .
'92F375A97D860EB4', 16),
new BigInteger('520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD88453981' .
'6F5EB4AC8FB1F1A6', 16)
);
$this->setBasePoint(
new BigInteger('43BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C7' .
'10AF8D0D39E20611', 16),
new BigInteger('14FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7' .
'D35245D1692E8EE1', 16)
);
$this->setOrder(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D4' .
'82EC7EE8658E98691555B44C59311', 16));
}
}

View File

@ -0,0 +1,42 @@
<?php
/**
* brainpoolP320t1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP320t1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F9' .
'2B9EC7893EC28FCD412B1F1B32E27', 16));
$this->setCoefficients(
new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28' .
'FCD412B1F1B32E24', 16), // eg. -3
new BigInteger('A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CE' .
'B5B4FEF422340353', 16)
);
$this->setBasePoint(
new BigInteger('925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF' .
'3357F624A21BED52', 16),
new BigInteger('63BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B' .
'1B9BC0455FB0D2C3', 16)
);
$this->setOrder(new BigInteger('D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D4' .
'82EC7EE8658E98691555B44C59311', 16));
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* brainpoolP384r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP384r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger(
'8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A7' .
'1874700133107EC53', 16));
$this->setCoefficients(
new BigInteger(
'7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503' .
'AD4EB04A8C7DD22CE2826', 16),
new BigInteger(
'4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DB' .
'C9943AB78696FA504C11', 16)
);
$this->setBasePoint(
new BigInteger(
'1D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D' .
'646AAEF87B2E247D4AF1E', 16),
new BigInteger(
'8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E464621779' .
'1811142820341263C5315', 16)
);
$this->setOrder(new BigInteger(
'8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC31' .
'03B883202E9046565', 16));
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* brainpoolP384t1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP384t1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger(
'8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A7' .
'1874700133107EC53', 16));
$this->setCoefficients(
new BigInteger(
'8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901' .
'D1A71874700133107EC50', 16), // eg. -3
new BigInteger(
'7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B8' .
'8805CED70355A33B471EE', 16)
);
$this->setBasePoint(
new BigInteger(
'18DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946' .
'A5F54D8D0AA2F418808CC', 16),
new BigInteger(
'25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC' .
'2B2912675BF5B9E582928', 16)
);
$this->setOrder(new BigInteger(
'8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC31' .
'03B883202E9046565', 16));
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* brainpoolP512r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP512r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger(
'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC' .
'66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3', 16));
$this->setCoefficients(
new BigInteger(
'7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA82' .
'53AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA', 16),
new BigInteger(
'3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C' .
'1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723', 16)
);
$this->setBasePoint(
new BigInteger(
'81AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D' .
'0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F822', 16),
new BigInteger(
'7DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5' .
'F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892', 16)
);
$this->setOrder(new BigInteger(
'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA' .
'92619418661197FAC10471DB1D381085DDADDB58796829CA90069', 16));
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* brainpoolP512t1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class brainpoolP512t1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger(
'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC' .
'66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3', 16));
$this->setCoefficients(
new BigInteger(
'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC' .
'66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0', 16), // eg. -3
new BigInteger(
'7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA23049' .
'76540F6450085F2DAE145C22553B465763689180EA2571867423E', 16)
);
$this->setBasePoint(
new BigInteger(
'640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CD' .
'B3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA', 16),
new BigInteger(
'5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEE' .
'F216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332', 16)
);
$this->setOrder(new BigInteger(
'AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA' .
'92619418661197FAC10471DB1D381085DDADDB58796829CA90069', 16));
}
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistb233
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistb233 extends sect233r1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistb409
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistb409 extends sect409r1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistk163
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistk163 extends sect163k1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistk233
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistk233 extends sect233k1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* sect283k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistk283 extends sect283k1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistk409
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistk409 extends sect409k1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistp192
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistp192 extends secp192r1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistp224
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistp224 extends secp224r1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistp256
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistp256 extends secp256r1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistp384
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistp384 extends secp384r1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistp521
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistp521 extends secp521r1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* nistt571
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class nistt571 extends sect571k1
{
}

View File

@ -0,0 +1,20 @@
<?php
/**
* prime192v1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class prime192v1 extends secp192r1
{
}

View File

@ -0,0 +1,36 @@
<?php
/**
* prime192v2
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class prime192v2 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC', 16),
new BigInteger('CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953', 16)
);
$this->setBasePoint(
new BigInteger('EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A', 16),
new BigInteger('6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15', 16)
);
$this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* prime192v3
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class prime192v3 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC', 16),
new BigInteger('22123DC2395A05CAA7423DAECCC94760A7D462256BD56916', 16)
);
$this->setBasePoint(
new BigInteger('7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896', 16),
new BigInteger('38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0', 16)
);
$this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* prime239v1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class prime239v1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC', 16),
new BigInteger('6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A', 16)
);
$this->setBasePoint(
new BigInteger('0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF', 16),
new BigInteger('7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE', 16)
);
$this->setOrder(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* prime239v2
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class prime239v2 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC', 16),
new BigInteger('617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C', 16)
);
$this->setBasePoint(
new BigInteger('38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7', 16),
new BigInteger('5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA', 16)
);
$this->setOrder(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* prime239v3
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class prime239v3 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC', 16),
new BigInteger('255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E', 16)
);
$this->setBasePoint(
new BigInteger('6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A', 16),
new BigInteger('1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3', 16)
);
$this->setOrder(new BigInteger('7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551', 16));
}
}

View File

@ -0,0 +1,20 @@
<?php
/**
* prime256v1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
final class prime256v1 extends secp256r1
{
}

View File

@ -0,0 +1,36 @@
<?php
/**
* secp112r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp112r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('DB7C2ABF62E35E668076BEAD208B', 16));
$this->setCoefficients(
new BigInteger('DB7C2ABF62E35E668076BEAD2088', 16),
new BigInteger('659EF8BA043916EEDE8911702B22', 16)
);
$this->setBasePoint(
new BigInteger('09487239995A5EE76B55F9C2F098', 16),
new BigInteger('A89CE5AF8724C0A23E0E0FF77500', 16)
);
$this->setOrder(new BigInteger('DB7C2ABF62E35E7628DFAC6561C5', 16));
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* secp112r2
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp112r2 extends Prime
{
public function __construct()
{
// same modulo as secp112r1
$this->setModulo(new BigInteger('DB7C2ABF62E35E668076BEAD208B', 16));
$this->setCoefficients(
new BigInteger('6127C24C05F38A0AAAF65C0EF02C', 16),
new BigInteger('51DEF1815DB5ED74FCC34C85D709', 16)
);
$this->setBasePoint(
new BigInteger('4BA30AB5E892B4E1649DD0928643', 16),
new BigInteger('ADCD46F5882E3747DEF36E956E97', 16)
);
$this->setOrder(new BigInteger('36DF0AAFD8B8D7597CA10520D04B', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* secp128r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp128r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger('FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC', 16),
new BigInteger('E87579C11079F43DD824993C2CEE5ED3', 16)
);
$this->setBasePoint(
new BigInteger('161FF7528B899B2D0C28607CA52C5B86', 16),
new BigInteger('CF5AC8395BAFEB13C02DA292DDED7A83', 16)
);
$this->setOrder(new BigInteger('FFFFFFFE0000000075A30D1B9038A115', 16));
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* secp128r2
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp128r2 extends Prime
{
public function __construct()
{
// same as secp128r1
$this->setModulo(new BigInteger('FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger('D6031998D1B3BBFEBF59CC9BBFF9AEE1', 16),
new BigInteger('5EEEFCA380D02919DC2C6558BB6D8A5D', 16)
);
$this->setBasePoint(
new BigInteger('7B6AA5D85E572983E6FB32A7CDEBC140', 16),
new BigInteger('27B6916A894D3AEE7106FE805FC34B44', 16)
);
$this->setOrder(new BigInteger('3FFFFFFF7FFFFFFFBE0024720613B5A3', 16));
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* secp160k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\KoblitzPrime;
use phpseclib\Math\BigInteger;
class secp160k1 extends KoblitzPrime
{
public function __construct()
{
// same as secp160r2
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73', 16));
$this->setCoefficients(
new BigInteger('0000000000000000000000000000000000000000', 16),
new BigInteger('0000000000000000000000000000000000000007', 16)
);
$this->setBasePoint(
new BigInteger('3B4C382CE37AA192A4019E763036F4F5DD4D7EBB', 16),
new BigInteger('938CF935318FDCED6BC28286531733C3F03C4FEE', 16)
);
$this->setOrder(new BigInteger('0100000000000000000001B8FA16DFAB9ACA16B6B3', 16));
$this->basis = [];
$this->basis[] = [
'a' => new BigInteger('0096341F1138933BC2F505', -16),
'b' => new BigInteger('FF6E9D0418C67BB8D5F562', -16)
];
$this->basis[] = [
'a' => new BigInteger('01BDCB3A09AAAABEAFF4A8', -16),
'b' => new BigInteger('04D12329FF0EF498EA67', -16)
];
$this->beta = $this->factory->newInteger(new BigInteger('645B7345A143464942CC46D7CF4D5D1E1E6CBB68', -16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* secp160r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp160r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF', 16));
$this->setCoefficients(
new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC', 16),
new BigInteger('1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45', 16)
);
$this->setBasePoint(
new BigInteger('4A96B5688EF573284664698968C38BB913CBFC82', 16),
new BigInteger('23A628553168947D59DCC912042351377AC5FB32', 16)
);
$this->setOrder(new BigInteger('0100000000000000000001F4C8F927AED3CA752257', 16));
}
}

View File

@ -0,0 +1,37 @@
<?php
/**
* secp160r2
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp160r2 extends Prime
{
public function __construct()
{
// same as secp160k1
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73', 16));
$this->setCoefficients(
new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70', 16),
new BigInteger('B4E134D3FB59EB8BAB57274904664D5AF50388BA', 16)
);
$this->setBasePoint(
new BigInteger('52DCB034293A117E1F4FF11B30F7199D3144CE6D', 16),
new BigInteger('FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E', 16)
);
$this->setOrder(new BigInteger('0100000000000000000000351EE786A818F3A1A16B', 16));
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* secp192k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\KoblitzPrime;
use phpseclib\Math\BigInteger;
class secp192k1 extends KoblitzPrime
{
public function __construct()
{
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37', 16));
$this->setCoefficients(
new BigInteger('000000000000000000000000000000000000000000000000', 16),
new BigInteger('000000000000000000000000000000000000000000000003', 16)
);
$this->setBasePoint(
new BigInteger('DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D', 16),
new BigInteger('9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D', 16)
);
$this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D', 16));
$this->basis = [];
$this->basis[] = [
'a' => new BigInteger('00B3FB3400DEC5C4ADCEB8655C', -16),
'b' => new BigInteger('8EE96418CCF4CFC7124FDA0F', -16)
];
$this->basis[] = [
'a' => new BigInteger('01D90D03E8F096B9948B20F0A9', -16),
'b' => new BigInteger('42E49819ABBA9474E1083F6B', -16)
];
$this->beta = $this->factory->newInteger(new BigInteger('447A96E6C647963E2F7809FEAAB46947F34B0AA3CA0BBA74', -16));
}
}

View File

@ -0,0 +1,80 @@
<?php
/**
* secp192r1
*
* This is the NIST P-192 curve
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp192r1 extends Prime
{
public function __construct()
{
$modulo = new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF', 16);
$this->setModulo($modulo);
// algorithm 2.27 from http://diamond.boisestate.edu/~liljanab/MATH308/GuideToECC.pdf#page=66
/* in theory this should be faster than regular modular reductions save for one small issue.
to convert to / from base-2**8 with BCMath you have to call bcmul() and bcdiv() a lot.
to convert to / from base-2**8 with PHP64 you have to call base256_rshift() a lot.
in short, converting to / from base-2**8 is pretty expensive and that expense is
enough to offset whatever else might be gained by a simplified reduction algorithm.
now, if PHP supported unsigned integers things might be different. no bit-shifting
would be required for the PHP engine and it'd be a lot faster. but as is, BigInteger
uses base-2**31 or base-2**26 depending on whether or not the system is has a 32-bit
or a 64-bit OS.
*/
/*
$m_length = $this->getLengthInBytes();
$this->setReduction(function($c) use ($m_length) {
$cBytes = $c->toBytes();
$className = $this->className;
if (strlen($cBytes) > 2 * $m_length) {
list(, $r) = $c->divide($className::$modulo);
return $r;
}
$c = str_pad($cBytes, 48, "\0", STR_PAD_LEFT);
$c = array_reverse(str_split($c, 8));
$null = "\0\0\0\0\0\0\0\0";
$s1 = new BigInteger($c[2] . $c[1] . $c[0], 256);
$s2 = new BigInteger($null . $c[3] . $c[3], 256);
$s3 = new BigInteger($c[4] . $c[4] . $null, 256);
$s4 = new BigInteger($c[5] . $c[5] . $c[5], 256);
$r = $s1->add($s2)->add($s3)->add($s4);
while ($r->compare($className::$modulo) >= 0) {
$r = $r->subtract($className::$modulo);
}
return $r;
});
*/
$this->setCoefficients(
new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC', 16),
new BigInteger('64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1', 16)
);
$this->setBasePoint(
new BigInteger('188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012', 16),
new BigInteger('07192B95FFC8DA78631011ED6B24CDD573F977A11E794811', 16)
);
$this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831', 16));
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* secp224k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\KoblitzPrime;
use phpseclib\Math\BigInteger;
class secp224k1 extends KoblitzPrime
{
public function __construct()
{
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D', 16));
$this->setCoefficients(
new BigInteger('00000000000000000000000000000000000000000000000000000000', 16),
new BigInteger('00000000000000000000000000000000000000000000000000000005', 16)
);
$this->setBasePoint(
new BigInteger('A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C', 16),
new BigInteger('7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5', 16)
);
$this->setOrder(new BigInteger('010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7', 16));
$this->basis = [];
$this->basis[] = [
'a' => new BigInteger('00B8ADF1378A6EB73409FA6C9C637D', -16),
'b' => new BigInteger('94730F82B358A3776A826298FA6F', -16)
];
$this->basis[] = [
'a' => new BigInteger('01DCE8D2EC6184CAF0A972769FCC8B', -16),
'b' => new BigInteger('4D2100BA3DC75AAB747CCF355DEC', -16)
];
$this->beta = $this->factory->newInteger(new BigInteger('01F178FFA4B17C89E6F73AECE2AAD57AF4C0A748B63C830947B27E04', -16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* secp224r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp224r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001', 16));
$this->setCoefficients(
new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE', 16),
new BigInteger('B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4', 16)
);
$this->setBasePoint(
new BigInteger('B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21', 16),
new BigInteger('BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34', 16)
);
$this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D', 16));
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* secp256k1
*
* This is the curve used in Bitcoin
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
//use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Crypt\ECDSA\BaseCurves\KoblitzPrime;
use phpseclib\Math\BigInteger;
//class secp256k1 extends Prime
class secp256k1 extends KoblitzPrime
{
public function __construct()
{
$this->setModulo(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 16));
$this->setCoefficients(
new BigInteger('0000000000000000000000000000000000000000000000000000000000000000', 16),
new BigInteger('0000000000000000000000000000000000000000000000000000000000000007', 16)
);
$this->setOrder(new BigInteger('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16));
$this->setBasePoint(
new BigInteger('79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 16),
new BigInteger('483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8', 16)
);
$this->basis = [];
$this->basis[] = [
'a' => new BigInteger('3086D221A7D46BCDE86C90E49284EB15', -16),
'b' => new BigInteger('FF1BBC8129FEF177D790AB8056F5401B3D', -16)
];
$this->basis[] = [
'a' => new BigInteger('114CA50F7A8E2F3F657C1108D9D44CFD8', -16),
'b' => new BigInteger('3086D221A7D46BCDE86C90E49284EB15', -16)
];
$this->beta = $this->factory->newInteger(new BigInteger('7AE96A2B657C07106E64479EAC3434E99CF0497512F58995C1396C28719501EE', -16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* secp256r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp256r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF', 16));
$this->setCoefficients(
new BigInteger('FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC', 16),
new BigInteger('5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B', 16)
);
$this->setBasePoint(
new BigInteger('6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296', 16),
new BigInteger('4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5', 16)
);
$this->setOrder(new BigInteger('FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551', 16));
}
}

View File

@ -0,0 +1,54 @@
<?php
/**
* secp384r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp384r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger(
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF',
16
));
$this->setCoefficients(
new BigInteger(
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC',
16
),
new BigInteger(
'B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF',
16
)
);
$this->setBasePoint(
new BigInteger(
'AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7',
16
),
new BigInteger(
'3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F',
16
)
);
$this->setOrder(new BigInteger(
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973',
16
));
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* secp521r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime;
use phpseclib\Math\BigInteger;
class secp521r1 extends Prime
{
public function __construct()
{
$this->setModulo(new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
'FFFF', 16));
$this->setCoefficients(
new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
'FFFC', 16),
new BigInteger('0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF1' .
'09E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B50' .
'3F00', 16)
);
$this->setBasePoint(
new BigInteger('00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D' .
'3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5' .
'BD66', 16),
new BigInteger('011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E' .
'662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD1' .
'6650', 16)
);
$this->setOrder(new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
'FFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E9138' .
'6409', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect113r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect113r1 extends Binary
{
public function __construct()
{
$this->setModulo(113, 9, 0);
$this->setCoefficients(
'003088250CA6E7C7FE649CE85820F7',
'00E8BEE4D3E2260744188BE0E9C723'
);
$this->setBasePoint(
'009D73616F35F4AB1407D73562C10F',
'00A52830277958EE84D1315ED31886'
);
$this->setOrder(new BigInteger('0100000000000000D9CCEC8A39E56F', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect113r2
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect113r2 extends Binary
{
public function __construct()
{
$this->setModulo(113, 9, 0);
$this->setCoefficients(
'00689918DBEC7E5A0DD6DFC0AA55C7',
'0095E9A9EC9B297BD4BF36E059184F'
);
$this->setBasePoint(
'01A57A6A7B26CA5EF52FCDB8164797',
'00B3ADC94ED1FE674C06E695BABA1D'
);
$this->setOrder(new BigInteger('010000000000000108789B2496AF93', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect131r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect131r1 extends Binary
{
public function __construct()
{
$this->setModulo(131, 8, 3, 2, 0);
$this->setCoefficients(
'07A11B09A76B562144418FF3FF8C2570B8',
'0217C05610884B63B9C6C7291678F9D341'
);
$this->setBasePoint(
'0081BAF91FDF9833C40F9C181343638399',
'078C6E7EA38C001F73C8134B1B4EF9E150'
);
$this->setOrder(new BigInteger('0400000000000000023123953A9464B54D', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect131r2
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect131r2 extends Binary
{
public function __construct()
{
$this->setModulo(131, 8, 3, 2, 0);
$this->setCoefficients(
'03E5A88919D7CAFCBF415F07C2176573B2',
'04B8266A46C55657AC734CE38F018F2192'
);
$this->setBasePoint(
'0356DCD8F2F95031AD652D23951BB366A8',
'0648F06D867940A5366D9E265DE9EB240F'
);
$this->setOrder(new BigInteger('0400000000000000016954A233049BA98F', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect163k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect163k1 extends Binary
{
public function __construct()
{
$this->setModulo(163, 7, 6, 3, 0);
$this->setCoefficients(
'000000000000000000000000000000000000000001',
'000000000000000000000000000000000000000001'
);
$this->setBasePoint(
'02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8',
'0289070FB05D38FF58321F2E800536D538CCDAA3D9'
);
$this->setOrder(new BigInteger('04000000000000000000020108A2E0CC0D99F8A5EF', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect163r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect163r1 extends Binary
{
public function __construct()
{
$this->setModulo(163, 7, 6, 3, 0);
$this->setCoefficients(
'07B6882CAAEFA84F9554FF8428BD88E246D2782AE2',
'0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9'
);
$this->setBasePoint(
'0369979697AB43897789566789567F787A7876A654',
'00435EDB42EFAFB2989D51FEFCE3C80988F41FF883'
);
$this->setOrder(new BigInteger('03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect163r2
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect163r2 extends Binary
{
public function __construct()
{
$this->setModulo(163, 7, 6, 3, 0);
$this->setCoefficients(
'000000000000000000000000000000000000000001',
'020A601907B8C953CA1481EB10512F78744A3205FD'
);
$this->setBasePoint(
'03F0EBA16286A2D57EA0991168D4994637E8343E36',
'00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1'
);
$this->setOrder(new BigInteger('040000000000000000000292FE77E70C12A4234C33', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect193r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect193r1 extends Binary
{
public function __construct()
{
$this->setModulo(193, 15, 0);
$this->setCoefficients(
'0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01',
'00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814'
);
$this->setBasePoint(
'01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1',
'0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05'
);
$this->setOrder(new BigInteger('01000000000000000000000000C7F34A778F443ACC920EBA49', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect193r2
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect193r2 extends Binary
{
public function __construct()
{
$this->setModulo(193, 15, 0);
$this->setCoefficients(
'0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B',
'00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE'
);
$this->setBasePoint(
'00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F',
'01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C'
);
$this->setOrder(new BigInteger('010000000000000000000000015AAB561B005413CCD4EE99D5', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect233k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect233k1 extends Binary
{
public function __construct()
{
$this->setModulo(233, 74, 0);
$this->setCoefficients(
'000000000000000000000000000000000000000000000000000000000000',
'000000000000000000000000000000000000000000000000000000000001'
);
$this->setBasePoint(
'017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126',
'01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3'
);
$this->setOrder(new BigInteger('8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect233r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect233r1 extends Binary
{
public function __construct()
{
$this->setModulo(233, 74, 0);
$this->setCoefficients(
'000000000000000000000000000000000000000000000000000000000001',
'0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD'
);
$this->setBasePoint(
'00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B',
'01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052'
);
$this->setOrder(new BigInteger('01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect239k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wiggint on <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect239k1 extends Binary
{
public function __construct()
{
$this->setModulo(239, 158, 0);
$this->setCoefficients(
'000000000000000000000000000000000000000000000000000000000000',
'000000000000000000000000000000000000000000000000000000000001'
);
$this->setBasePoint(
'29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC',
'76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA'
);
$this->setOrder(new BigInteger('2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect283k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wiggint on <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect283k1 extends Binary
{
public function __construct()
{
$this->setModulo(283, 12, 7, 5, 0);
$this->setCoefficients(
'000000000000000000000000000000000000000000000000000000000000000000000000',
'000000000000000000000000000000000000000000000000000000000000000000000001'
);
$this->setBasePoint(
'0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836',
'01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259'
);
$this->setOrder(new BigInteger('01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61', 16));
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* sect283r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wiggint on <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect283r1 extends Binary
{
public function __construct()
{
$this->setModulo(283, 12, 7, 5, 0);
$this->setCoefficients(
'000000000000000000000000000000000000000000000000000000000000000000000001',
'027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5'
);
$this->setBasePoint(
'05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053',
'03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4'
);
$this->setOrder(new BigInteger('03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307', 16));
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* sect409k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wiggint on <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect409k1 extends Binary
{
public function __construct()
{
$this->setModulo(409, 87, 0);
$this->setCoefficients(
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001'
);
$this->setBasePoint(
'0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746',
'01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B'
);
$this->setOrder(new BigInteger(
'7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F' .
'83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF', 16
));
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* sect409r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wiggint on <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect409r1 extends Binary
{
public function __construct()
{
$this->setModulo(409, 87, 0);
$this->setCoefficients(
'00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001',
'0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F'
);
$this->setBasePoint(
'015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7',
'0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706'
);
$this->setOrder(new BigInteger(
'010000000000000000000000000000000000000000000000000001E2' .
'AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173', 16
));
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* sect571k1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wiggint on <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect571k1 extends Binary
{
public function __construct()
{
$this->setModulo(571, 10, 5, 2, 0);
$this->setCoefficients(
'000000000000000000000000000000000000000000000000000000000000000000000000' .
'000000000000000000000000000000000000000000000000000000000000000000000000',
'000000000000000000000000000000000000000000000000000000000000000000000000' .
'000000000000000000000000000000000000000000000000000000000000000000000001'
);
$this->setBasePoint(
'026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA443709584' .
'93B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972',
'0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0' .
'AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3'
);
$this->setOrder(new BigInteger(
'020000000000000000000000000000000000000000000000000000000000000000000000' .
'131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001 ', 16
));
}
}

View File

@ -0,0 +1,43 @@
<?php
/**
* sect571r1
*
* PHP version 5 and 7
*
* @category Crypt
* @package ECDSA
* @author Jim Wiggint on <terrafrost@php.net>
* @copyright 2017 Jim Wigginton
* @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link http://pear.php.net/package/Math_BigInteger
*/
namespace phpseclib\Crypt\ECDSA\Curves;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary;
use phpseclib\Math\BigInteger;
class sect571r1 extends Binary
{
public function __construct()
{
$this->setModulo(571, 10, 5, 2, 0);
$this->setCoefficients(
'000000000000000000000000000000000000000000000000000000000000000000000000' .
'000000000000000000000000000000000000000000000000000000000000000000000001',
'02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD' .
'8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A'
);
$this->setBasePoint(
'0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950' .
'F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19',
'037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43' .
'BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B'
);
$this->setOrder(new BigInteger(
'03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' .
'E661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47 ', 16
));
}
}

View File

@ -0,0 +1,558 @@
<?php
/**
* Generic ECDSA Key Parsing Helper functions
*
* PHP version 5
*
* @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\Keys;
use ParagonIE\ConstantTime\Hex;
use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime as PrimeCurve;
use phpseclib\Crypt\ECDSA\BaseCurves\Binary as BinaryCurve;
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib\Common\Functions\Strings;
use phpseclib\Math\BigInteger;
use phpseclib\Math\PrimeField;
use phpseclib\File\ASN1;
use phpseclib\File\ASN1\Maps;
use phpseclib\Exception\UnsupportedCurveException;
/**
* Generic ECDSA Key Parsing Helper functions
*
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
trait Common
{
/**
* Curve OIDs
*
* @var array
*/
private static $curveOIDs = [];
/**
* Child OIDs loaded
*
* @var bool
*/
protected static $childOIDsLoaded = false;
/**
* Use Named Curves
*
* @var bool
*/
private static $useNamedCurves = true;
/**
* Initialize static variables
*/
private static function initialize_static_variables()
{
if (empty(self::$curveOIDs)) {
// the sec* curves are from the standards for efficient cryptography group
// sect* curves are curves over binary finite fields
// secp* curves are curves over prime finite fields
// sec*r* curves are regular curves; sec*k* curves are koblitz curves
// brainpool*r* curves are regular prime finite field curves
// brainpool*t* curves are twisted versions of the brainpool*r* curves
self::$curveOIDs = [
// from https://tools.ietf.org/html/rfc5915
'secp192r1' => '1.2.840.10045.3.1.1', // aka prime192v1
'sect163k1' => '1.3.132.0.1',
'sect163r2' => '1.3.132.0.15',
'secp224r1' => '1.3.132.0.33',
'sect233k1'=> '1.3.132.0.26',
'sect233r1'=> '1.3.132.0.27',
'secp256r1' => '1.2.840.10045.3.1.7', // aka prime256v1
'sect283k1' => '1.3.132.0.16',
'sect283r1' => '1.3.132.0.17',
'secp384r1' => '1.3.132.0.34',
'sect409k1' => '1.3.132.0.36',
'sect409r1' => '1.3.132.0.37',
'secp521r1' => '1.3.132.0.35',
'sect571k1' => '1.3.132.0.38',
'sect571r1' => '1.3.132.0.39',
// from http://www.secg.org/SEC2-Ver-1.0.pdf
'secp112r1' => '1.3.132.0.6',
'secp112r2' => '1.3.132.0.7',
'secp128r1' => '1.3.132.0.28',
'secp128r2' => '1.3.132.0.29',
'secp160k1' => '1.3.132.0.9',
'secp160r1' => '1.3.132.0.8',
'secp160r2' => '1.3.132.0.30',
'secp192k1' => '1.3.132.0.31',
'secp224k1' => '1.3.132.0.32',
'secp256k1' => '1.3.132.0.10',
'sect113r1' => '1.3.132.0.4',
'sect113r2' => '1.3.132.0.5',
'sect131r1' => '1.3.132.0.22',
'sect131r2' => '1.3.132.0.23',
'sect163r1' => '1.3.132.0.2',
'sect193r1' => '1.3.132.0.24',
'sect193r2' => '1.3.132.0.25',
'sect239k1' => '1.3.132.0.3',
// from http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.202.2977&rep=rep1&type=pdf#page=36
/*
'c2pnb163v1' => '1.2.840.10045.3.0.1', // J.4.1, example 1
'c2pnb163v2' => '1.2.840.10045.3.0.2', // J.4.1, example 2
'c2pnb163v3' => '1.2.840.10045.3.0.3', // J.4.1, example 3
'c2pnb172w1' => '1.2.840.10045.3.0.4', // J.4.2, example 1
'c2tnb191v1' => '1.2.840.10045.3.0.5', // J.4.3, example 1
'c2tnb191v2' => '1.2.840.10045.3.0.6', // J.4.3, example 2
'c2tnb191v3' => '1.2.840.10045.3.0.7', // J.4.3, example 3
'c2onb191v4' => '1.2.840.10045.3.0.8', // J.4.3, example 4
'c2onb191v5' => '1.2.840.10045.3.0.9', // J.4.3, example 5
'c2pnb208w1' => '1.2.840.10045.3.0.10', // J.4.4, example 1
'c2tnb239v1' => '1.2.840.10045.3.0.11', // J.4.5, example 1
'c2tnb239v2' => '1.2.840.10045.3.0.12', // J.4.5, example 2
'c2tnb239v3' => '1.2.840.10045.3.0.13', // J.4.5, example 3
'c2onb239v4' => '1.2.840.10045.3.0.14', // J.4.5, example 4
'c2onb239v5' => '1.2.840.10045.3.0.15', // J.4.5, example 5
'c2pnb272w1' => '1.2.840.10045.3.0.16', // J.4.6, example 1
'c2pnb304w1' => '1.2.840.10045.3.0.17', // J.4.7, example 1
'c2tnb359v1' => '1.2.840.10045.3.0.18', // J.4.8, example 1
'c2pnb368w1' => '1.2.840.10045.3.0.19', // J.4.9, example 1
'c2tnb431r1' => '1.2.840.10045.3.0.20', // J.4.10, example 1
*/
'prime192v1' => '1.2.840.10045.3.1.1', // J.5.1, example 1 (aka secp192r1)
'prime192v2' => '1.2.840.10045.3.1.2', // J.5.1, example 2
'prime192v3' => '1.2.840.10045.3.1.3', // J.5.1, example 3
'prime239v1' => '1.2.840.10045.3.1.4', // J.5.2, example 1
'prime239v2' => '1.2.840.10045.3.1.5', // J.5.2, example 2
'prime239v3' => '1.2.840.10045.3.1.6', // J.5.2, example 3
'prime256v1' => '1.2.840.10045.3.1.7', // J.5.3, example 1 (aka secp256r1)
// https://tools.ietf.org/html/rfc5656#section-10
'nistp256' => '1.2.840.10045.3.1.7', // aka secp256r1
'nistp384' => '1.3.132.0.34', // aka secp384r1
'nistp521' => '1.3.132.0.35', // aka secp521r1
'nistk163' => '1.3.132.0.1', // aka sect163k1
'nistp192' => '1.2.840.10045.3.1.1', // aka secp192r1
'nistp224' => '1.3.132.0.33', // aka secp224r1
'nistk233' => '1.3.132.0.26', // aka sect233k1
'nistb233' => '1.3.132.0.27', // aka sect233r1
'nistk283' => '1.3.132.0.16', // aka sect283k1
'nistk409' => '1.3.132.0.36', // aka sect409k1
'nistb409' => '1.3.132.0.37', // aka sect409r1
'nistt571' => '1.3.132.0.38', // aka sect571k1
// http://www.ecc-brainpool.org/download/Domain-parameters.pdf
// https://tools.ietf.org/html/rfc5639
'brainpoolP160r1' => '1.3.36.3.3.2.8.1.1.1',
'brainpoolP160t1' => '1.3.36.3.3.2.8.1.1.2',
'brainpoolP192r1' => '1.3.36.3.3.2.8.1.1.3',
'brainpoolP192t1' => '1.3.36.3.3.2.8.1.1.4',
'brainpoolP224r1' => '1.3.36.3.3.2.8.1.1.5',
'brainpoolP224t1' => '1.3.36.3.3.2.8.1.1.6',
'brainpoolP256r1' => '1.3.36.3.3.2.8.1.1.7',
'brainpoolP256t1' => '1.3.36.3.3.2.8.1.1.8',
'brainpoolP320r1' => '1.3.36.3.3.2.8.1.1.9',
'brainpoolP320t1' => '1.3.36.3.3.2.8.1.1.10',
'brainpoolP384r1' => '1.3.36.3.3.2.8.1.1.11',
'brainpoolP384t1' => '1.3.36.3.3.2.8.1.1.12',
'brainpoolP512r1' => '1.3.36.3.3.2.8.1.1.13',
'brainpoolP512t1' => '1.3.36.3.3.2.8.1.1.14'
];
ASN1::loadOIDs([
'prime-field' => '1.2.840.10045.1.1',
'characteristic-two-field' => '1.2.840.10045.1.2',
'characteristic-two-basis' => '1.2.840.10045.1.2.3',
// per http://www.secg.org/SEC1-Ver-1.0.pdf#page=84, gnBasis "not used here"
'gnBasis' => '1.2.840.10045.1.2.3.1', // NULL
'tpBasis' => '1.2.840.10045.1.2.3.2', // Trinomial
'ppBasis' => '1.2.840.10045.1.2.3.3' // Pentanomial
] + self::$curveOIDs);
}
}
/**
* Explicitly set the curve
*
* If the key contains an implicit curve phpseclib needs the curve
* to be explicitly provided
*
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
*/
public static function setImplicitCurve(BaseCurve $curve)
{
self::$implicitCurve = $curve;
}
/**
* Returns an instance of \phpseclib\Crypt\ECDSA\BaseCurves\Base based
* on the curve parameters
*
* @param array $params
* @return \phpseclib\Crypt\ECDSA\BaseCurves\Base|false
*/
protected static function loadCurveByParam(array $params)
{
if (count($params) > 1) {
throw new \RuntimeException('No parameters are present');
}
if (isset($params['namedCurve'])) {
$curve = '\phpseclib\Crypt\ECDSA\Curves\\' . $params['namedCurve'];
if (!class_exists($curve)) {
throw new UnsupportedCurveException('Named Curve of ' . $params['namedCurve'] . ' is not supported');
}
return new $curve();
}
if (isset($params['implicitCurve'])) {
if (!isset(self::$implicitCurve)) {
throw new \RuntimeException('Implicit curves can be provided by calling setImplicitCurve');
}
return self::$implicitCurve;
}
if (isset($params['specifiedCurve'])) {
$data = $params['specifiedCurve'];
switch ($data['fieldID']['fieldType']) {
case 'prime-field':
$curve = new PrimeCurve();
$curve->setModulo($data['fieldID']['parameters']);
$curve->setCoefficients(
new BigInteger($data['curve']['a'], 256),
new BigInteger($data['curve']['b'], 256)
);
$point = self::extractPoint("\0" . $data['base'], $curve);
$curve->setBasePoint(...$point);
$curve->setOrder($data['order']);
return $curve;
case 'characteristic-two-field':
$curve = new BinaryCurve();
$params = ASN1::decodeBER($data['fieldID']['parameters']);
$params = ASN1::asn1map($params[0], Maps\Characteristic_two::MAP);
$modulo = [(int) $params['m']->toString()];
switch ($params['basis']) {
case 'tpBasis':
$modulo[] = (int) $params['parameters']->toString();
break;
case 'ppBasis':
$temp = ASN1::decodeBER($params['parameters']);
$temp = ASN1::asn1map($temp[0], Maps\Pentanomial::MAP);
$modulo[] = (int) $temp['k3']->toString();
$modulo[] = (int) $temp['k2']->toString();
$modulo[] = (int) $temp['k1']->toString();
}
$modulo[] = 0;
$curve->setModulo(...$modulo);
$len = ceil($modulo[0] / 8);
$curve->setCoefficients(
Hex::encode($data['curve']['a']),
Hex::encode($data['curve']['b'])
);
$point = self::extractPoint("\0" . $data['base'], $curve);
$curve->setBasePoint(...$point);
$curve->setOrder($data['order']);
return $curve;
default:
throw new UnsupportedCurveException('Field Type of ' . $data['fieldID']['fieldType'] . ' is not supported');
}
}
throw new \RuntimeException('No valid parameters are present');
}
/**
* Extract points from a string
*
* Supports both compressed and uncompressed points
*
* @param string $str
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @return object[]
*/
public static function extractPoint($str, BaseCurve $curve)
{
if ($curve instanceof TwistedEdwardsCurve) {
// first step of point deciding as discussed at the following URL's:
// https://tools.ietf.org/html/rfc8032#section-5.1.3
// https://tools.ietf.org/html/rfc8032#section-5.2.3
$y = $str;
$y = strrev($y);
$sign = (bool) (ord($y[0]) & 0x80);
$y[0] = $y[0] & chr(0x7F);
$y = new BigInteger($y, 256);
if ($y->compare($curve->getModulo()) >= 0) {
throw new \RuntimeException('The Y coordinate should not be >= the modulo');
}
$point = $curve->recoverX($y, $sign);
if (!$curve->verifyPoint($point)) {
throw new \RuntimeException('Unable to verify that point exists on curve');
}
return $point;
}
// the first byte of a bit string represents the number of bits in the last byte that are to be ignored but,
// currently, bit strings wanting a non-zero amount of bits trimmed are not supported
if (($val = Strings::shift($str)) != "\0") {
throw new \UnexpectedValueException('extractPoint expects the first byte to be null - not ' . Hex::encode($val));
}
if ($str == "\0") {
return [];
}
$keylen = strlen($str);
$order = $curve->getLengthInBytes();
// point compression is being used
if ($keylen == $order + 1) {
return $curve->derivePoint($str);
}
// point compression is not being used
if ($keylen == 2 * $order + 1) {
preg_match("#(.)(.{{$order}})(.{{$order}})#s", $str, $matches);
list(, $w, $x, $y) = $matches;
if ($w != "\4") {
throw new \UnexpectedValueException('The first byte of an uncompressed point should be 04 - not ' . Hex::encode($val));
}
$point = [
$curve->convertInteger(new BigInteger($x, 256)),
$curve->convertInteger(new BigInteger($y, 256))
];
if (!$curve->verifyPoint($point)) {
throw new \RuntimeException('Unable to verify that point exists on curve');
}
return $point;
}
throw new \UnexpectedValueException('The string representation of the points is not of an appropriate length');
}
/**
* Encode Parameters
*
* @todo Maybe at some point this could be moved to __toString() for each of the curves?
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param bool $returnArray
* @return string|false
*/
private static function encodeParameters(BaseCurve $curve, $returnArray = false)
{
$reflect = new \ReflectionClass($curve);
$name = $reflect->getShortName();
if (isset(self::$curveOIDs[$name]) && self::$useNamedCurves) {
return $returnArray ?
['namedCurve' => $name] :
ASN1::encodeDER(['namedCurve' => $name], Maps\ECParameters::MAP);
}
if (self::$useNamedCurves) {
foreach (new \DirectoryIterator(__DIR__ . '/../Curves/') as $file) {
if ($file->getExtension() != 'php') {
continue;
}
$testName = $file->getBasename('.php');
$class = 'phpseclib\Crypt\ECDSA\Curves\\' . $testName;
$reflect = new \ReflectionClass($class);
if ($reflect->isFinal()) {
continue;
}
$candidate = new $class();
switch ($name) {
case 'Prime':
if (!$candidate instanceof PrimeCurve) {
break;
}
if (!$candidate->getModulo()->equals($curve->getModulo())) {
break;
}
if ($candidate->getA()->toBytes() != $curve->getA()->toBytes()) {
break;
}
if ($candidate->getB()->toBytes() != $curve->getB()->toBytes()) {
break;
}
list($candidateX, $candidateY) = $candidate->getBasePoint();
list($curveX, $curveY) = $curve->getBasePoint();
if ($candidateX->toBytes() != $curveX->toBytes()) {
break;
}
if ($candidateY->toBytes() != $curveY->toBytes()) {
break;
}
return $returnArray ?
['namedCurve' => $testName] :
ASN1::encodeDER(['namedCurve' => $testName], Maps\ECParameters::MAP);
case 'Binary':
if (!$candidate instanceof BinaryCurve) {
break;
}
if ($candidate->getModulo() != $curve->getModulo()) {
break;
}
if ($candidate->getA()->toBytes() != $curve->getA()->toBytes()) {
break;
}
if ($candidate->getB()->toBytes() != $curve->getB()->toBytes()) {
break;
}
list($candidateX, $candidateY) = $candidate->getBasePoint();
list($curveX, $curveY) = $curve->getBasePoint();
if ($candidateX->toBytes() != $curveX->toBytes()) {
break;
}
if ($candidateY->toBytes() != $curveY->toBytes()) {
break;
}
return $returnArray ?
['namedCurve' => $testName] :
ASN1::encodeDER(['namedCurve' => $testName], Maps\ECParameters::MAP);
}
}
}
$order = $curve->getOrder();
// we could try to calculate the order thusly:
// https://crypto.stackexchange.com/a/27914/4520
// https://en.wikipedia.org/wiki/Schoof%E2%80%93Elkies%E2%80%93Atkin_algorithm
if (!$order) {
throw new \RuntimeException('Specified Curves need the order to be specified');
}
$point = $curve->getBasePoint();
$x = $point[0]->toBytes();
$y = $point[1]->toBytes();
if ($curve instanceof PrimeCurve) {
/*
* valid versions are:
*
* ecdpVer1:
* - neither the curve or the base point are generated verifiably randomly.
* ecdpVer2:
* - curve and base point are generated verifiably at random and curve.seed is present
* ecdpVer3:
* - base point is generated verifiably at random but curve is not. curve.seed is present
*/
// other (optional) parameters can be calculated using the methods discused at
// https://crypto.stackexchange.com/q/28947/4520
$data = [
'version' => 'ecdpVer1',
'fieldID' => [
'fieldType' => 'prime-field',
'parameters' => $curve->getModulo()
],
'curve' => [
'a' => $curve->getA()->toBytes(),
'b' => $curve->getB()->toBytes()
],
'base' => "\4" . $x . $y,
'order' => $order
];
return $returnArray ?
['specifiedCurve' => $data] :
ASN1::encodeDER(['specifiedCurve' => $data], Maps\ECParameters::MAP);
}
if ($curve instanceof BinaryCurve) {
$modulo = $curve->getModulo();
$basis = count($modulo);
$m = array_shift($modulo);
array_pop($modulo); // the last parameter should always be 0
//rsort($modulo);
switch ($basis) {
case 3:
$basis = 'tpBasis';
$modulo = new BigInteger($modulo[0]);
break;
case 5:
$basis = 'ppBasis';
// these should be in strictly ascending order (hence the commented out rsort above)
$modulo = [
'k1' => new BigInteger($modulo[2]),
'k2' => new BigInteger($modulo[1]),
'k3' => new BigInteger($modulo[0])
];
$modulo = ASN1::encodeDER($modulo, Maps\Pentanomial::MAP);
$modulo = new ASN1\Element($modulo);
}
$params = ASN1::encodeDER([
'm' => new BigInteger($m),
'basis' => $basis,
'parameters' => $modulo
], Maps\Characteristic_two::MAP);
$params = new ASN1\Element($params);
$a = ltrim($curve->getA()->toBytes(), "\0");
if (!strlen($a)) {
$a = "\0";
}
$b = ltrim($curve->getB()->toBytes(), "\0");
if (!strlen($b)) {
$b = "\0";
}
$data = [
'version' => 'ecdpVer1',
'fieldID' => [
'fieldType' => 'characteristic-two-field',
'parameters' => $params
],
'curve' => [
'a' => $a,
'b' => $b
],
'base' => "\4" . $x . $y,
'order' => $order
];
return $returnArray ?
['specifiedCurve' => $data] :
ASN1::encodeDER(['specifiedCurve' => $data], Maps\ECParameters::MAP);
}
throw new UnsupportedCurveException('Curve cannot be serialized');
}
/**
* Use Specified Curve
*
* A specified curve has all the coefficients, the base points, etc, explicitely included.
* A specified curve is a more verbose way of representing a curve
*/
public static function useSpecifiedCurve()
{
self::$useNamedCurves = false;
}
/**
* Use Named Curve
*
* A named curve does not include any parameters. It is up to the ECDSA parameters to
* know what the coefficients, the base points, etc, are from the name of the curve.
* A named curve is a more concise way of representing a curve
*/
public static function useNamedCurve()
{
self::$useNamedCurves = true;
}
/**
* Returns true if named curves are being used by default
*
* If a named curve is not being used by default than specified curves are being utilized
*/
public static function isUsingNamedCurves()
{
return self::$useNamedCurves;
}
}

View File

@ -0,0 +1,275 @@
<?php
/**
* OpenSSH Formatted ECDSA Key Handler
*
* PHP version 5
*
* Place in $HOME/.ssh/authorized_keys
*
* @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\Keys;
use ParagonIE\ConstantTime\Base64;
use phpseclib\Math\BigInteger;
use phpseclib\Common\Functions\Strings;
use phpseclib\Crypt\Common\Keys\OpenSSH as Progenitor;
use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve;
use phpseclib\Exception\UnsupportedCurveException;
use phpseclib\Crypt\ECDSA\Curves\Ed25519;
use phpseclib\Math\Common\FiniteField\Integer;
use phpseclib\Crypt\Random;
/**
* OpenSSH Formatted ECDSA Key Handler
*
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class OpenSSH extends Progenitor
{
use Common;
/**
* Supported Key Types
*
* @var array
*/
private static $types = [
'ecdsa-sha2-nistp256',
'ecdsa-sha2-nistp384',
'ecdsa-sha2-nistp521',
'ssh-ed25519'
];
/**
* Break a public or private key down into its constituent components
*
* @access public
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
/*
key format is described here:
https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=HEAD
this is only supported for ECDSA because of Ed25519. ssh-keygen doesn't generate a
PKCS1/8 formatted private key for Ed25519 - it generates an OpenSSH formatted
private key. probably because, at the time of this writing, there's not an actual
IETF RFC describing an Ed25519 format
*/
if (strpos($key, 'BEGIN OPENSSH PRIVATE KEY') !== false) {
$key = preg_replace('#(?:^-.*?-[\r\n]*$)|\s#ms', '', $key);
$key = Base64::decode($key);
$magic = Strings::shift($key, 15);
if ($magic != "openssh-key-v1\0") {
throw new \RuntimeException('Expected openssh-key-v1');
}
list($ciphername, $kdfname, $kdfoptions, $numKeys) = Strings::unpackSSH2('sssN', $key);
if ($numKeys != 1) {
throw new \RuntimeException('Although the OpenSSH private key format supports multiple keys phpseclib does not');
}
if (strlen($kdfoptions) || $kdfname != 'none' || $ciphername != 'none') {
/*
OpenSSH private keys use a customized version of bcrypt. specifically, instead of encrypting
OrpheanBeholderScryDoubt 64 times OpenSSH's bcrypt variant encrypts
OxychromaticBlowfishSwatDynamite 64 times. so we can't use crypt().
bcrypt is basically Blowfish with an altered key expansion. whereas Blowfish just runs the
key through the key expansion bcrypt interleaves the key expansion with the salt and
password. this renders openssl / mcrypt unusuable. this forces us to use a pure-PHP implementation
of bcrypt. the problem with that is that pure-PHP is too slow to be practically useful.
in addition to encrypting a different string 64 times the OpenSSH also performs bcrypt from
scratch $rounds times. calling crypt() 64x with bcrypt takes 0.7s. PHP is going to be naturally
slower. pure-PHP is 215x slower than OpenSSL for AES and pure-PHP is 43x slower for bcrypt.
43 * 0.7 = 30s. no one wants to wait 30s to load a private key.
another way to think about this.. according to wikipedia's article on Blowfish,
"Each new key requires pre-processing equivalent to encrypting about 4 kilobytes of text".
key expansion is done (9+64*2)*160 times. multiply that by 4 and it turns out that Blowfish,
OpenSSH style, is the equivalent of encrypting ~80mb of text.
more supporting evidence: sodium_compat does not implement Argon2 (another password hashing
algorithm) because "It's not feasible to polyfill scrypt or Argon2 into PHP and get reasonable
performance. Users would feel motivated to select parameters that downgrade security to avoid
denial of service (DoS) attacks. The only winning move is not to play"
-- https://github.com/paragonie/sodium_compat/blob/master/README.md
*/
throw new \RuntimeException('Encrypted OpenSSH private keys are not supported');
//list($salt, $rounds) = Strings::unpackSSH2('sN', $kdfoptions);
}
list($publicKey, $paddedKey) = Strings::unpackSSH2('ss', $key);
list($type, $publicKey) = Strings::unpackSSH2('ss', $publicKey);
if ($type != 'ssh-ed25519') {
throw new UnsupportedCurveException('ssh-ed25519 is the only supported curve for OpenSSH public keys');
}
list($checkint1, $checkint2, $type, $publicKey2, $privateKey, $comment) = Strings::unpackSSH2('NNssss', $paddedKey);
// any leftover bytes in $paddedKey are for padding? but they should be sequential bytes. eg. 1, 2, 3, etc.
if ($checkint1 != $checkint2) {
throw new \RuntimeException('The two checkints do not match');
}
if ($type != 'ssh-ed25519') {
throw new UnsupportedCurveException('ssh-ed25519 is the only supported curve for OpenSSH private keys');
}
if ($publicKey != $publicKey2 || $publicKey2 != substr($privateKey, 32)) {
throw new \RuntimeException('The public keys do not match up');
}
$privateKey = substr($privateKey, 0, 32);
$curve = new Ed25519();
return [
'curve' => $curve,
'dA' => $curve->extractSecret($privateKey),
'QA' => self::extractPoint($publicKey, $curve),
'comment' => $comment
];
}
$parts = explode(' ', $key, 3);
if (!isset($parts[1])) {
$key = Base64::decode($parts[0]);
$comment = isset($parts[1]) ? $parts[1] : false;
} else {
$asciiType = $parts[0];
if (!in_array($asciiType, self::$types)) {
throw new \RuntimeException('Keys of type ' . $asciiType . ' are not supported');
}
$key = Base64::decode($parts[1]);
$comment = isset($parts[2]) ? $parts[2] : false;
}
list($binaryType) = Strings::unpackSSH2('s', $key);
if (isset($asciiType) && $asciiType != $binaryType) {
throw new \RuntimeException('Two different types of keys are claimed: ' . $asciiType . ' and ' . $binaryType);
} elseif (!isset($asciiType) && !in_array($binaryType, self::$types)) {
throw new \RuntimeException('Keys of type ' . $binaryType . ' are not supported');
}
if ($binaryType == 'ssh-ed25519') {
if (Strings::shift($key, 4) != "\0\0\0\x20") {
throw new \RuntimeException('Length of ssh-ed25519 key should be 32');
}
$curve = new Ed25519();
$qa = self::extractPoint($key, $curve);
} else {
list($curveName, $publicKey) = Strings::unpackSSH2('ss', $key);
$curveName = '\phpseclib\Crypt\ECDSA\Curves\\' . $curveName;
$curve = new $curveName();
$qa = self::extractPoint("\0" . $publicKey, $curve);
}
return [
'curve' => $curve,
'QA' => $qa,
'comment' => $comment
];
}
/**
* Convert an ECDSA public key to the appropriate format
*
* @access public
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @return string
*/
public static function savePublicKey(BaseCurve $curve, array $publicKey)
{
if ($curve instanceof Ed25519) {
$key = Strings::packSSH2('ss', 'ssh-ed25519', $curve->encodePoint($publicKey));
$key = 'ssh-ed25519 ' . Base64::encode($key) . ' ' . self::$comment;
return $key;
}
self::initialize_static_variables();
$reflect = new \ReflectionClass($curve);
$name = $reflect->getShortName();
$oid = self::$curveOIDs[$name];
$aliases = array_filter(self::$curveOIDs, function($v) use ($oid) {
return $v == $oid;
});
$aliases = array_keys($aliases);
for ($i = 0; $i < count($aliases); $i++) {
if (in_array('ecdsa-sha2-' . $aliases[$i], self::$types)) {
$alias = $aliases[$i];
break;
}
}
if (!isset($alias)) {
throw new UnsupportedCurveException($name . ' is not a curve that the OpenSSH plugin supports');
}
$points = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
$key = Strings::packSSH2('sss', 'ecdsa-sha2-' . $alias, $alias, $points);
if (self::$binary) {
return $key;
}
$key = 'ecdsa-sha2-' . $alias . ' ' . Base64::encode($key) . ' ' . self::$comment;
return $key;
}
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\Common\FiniteField\Integer $privateKey
* @param \phpseclib\Crypt\ECDSA\Curves\Ed25519 $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param string $password optional
* @return string
*/
public static function savePrivateKey(Integer $privateKey, Ed25519 $curve, array $publicKey, $password = '')
{
if (!isset($privateKey->secret)) {
throw new \RuntimeException('Private Key does not have a secret set');
}
if (strlen($privateKey->secret) != 32) {
throw new \RuntimeException('Private Key secret is not of the correct length');
}
list(, $checkint) = unpack('N', Random::string(4));
$pubKey = $curve->encodePoint($publicKey);
$publicKey = Strings::packSSH2('ss', 'ssh-ed25519', $pubKey);
$paddedKey = Strings::packSSH2('NNssss', $checkint, $checkint, 'ssh-ed25519', $pubKey, $privateKey->secret . $pubKey, self::$comment);
/*
from http://tools.ietf.org/html/rfc4253#section-6 :
Note that the length of the concatenation of 'packet_length',
'padding_length', 'payload', and 'random padding' MUST be a multiple
of the cipher block size or 8, whichever is larger.
*/
$paddingLength = (7 * strlen($paddedKey)) % 8;
for ($i = 1; $i <= $paddingLength; $i++) {
$paddedKey.= chr($i);
}
$key = Strings::packSSH2('sssNss', 'none', 'none', '', 1, $publicKey, $paddedKey);
$key = "openssh-key-v1\0$key";
return "-----BEGIN OPENSSH PRIVATE KEY-----\r\n" .
chunk_split(Base64::encode($key), 70) .
"-----END OPENSSH PRIVATE KEY-----";
}
}

View File

@ -0,0 +1,141 @@
<?php
/**
* "PKCS1" (RFC5915) Formatted ECDSA Key Handler
*
* PHP version 5
*
* Used by File/X509.php
*
* Processes keys with the following headers:
*
* -----BEGIN EC PRIVATE KEY-----
* -----BEGIN EC PARAMETERS-----
*
* Technically, PKCS1 is for RSA keys, only, but we're using PKCS1 to describe
* DSA, whose format isn't really formally described anywhere, so might as well
* use it to describe this, too. PKCS1 is easier to remember than RFC5915, after
* all. I suppose this could also be named IETF but idk
*
* @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\Keys;
use phpseclib\Math\Common\FiniteField\Integer;
use phpseclib\Crypt\Common\Keys\PKCS1 as Progenitor;
use phpseclib\File\ASN1;
use phpseclib\File\ASN1\Maps;
use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve;
use phpseclib\Math\BigInteger;
use ParagonIE\ConstantTime\Base64;
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib\Exception\UnsupportedCurveException;
/**
* "PKCS1" (RFC5915) Formatted ECDSA Key Handler
*
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class PKCS1 extends Progenitor
{
use Common;
/**
* Break a public or private key down into its constituent components
*
* @access public
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
self::initialize_static_variables();
$key = parent::load($key, $password);
$decoded = ASN1::decodeBER($key);
if (empty($decoded)) {
throw new \RuntimeException('Unable to decode BER');
}
$key = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP);
if (is_array($key)) {
return ['curve' => self::loadCurveByParam($key)];
}
$key = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP);
if (!is_array($key)) {
throw new \RuntimeException('Unable to perform ASN1 mapping');
}
$components = [];
$components['curve'] = self::loadCurveByParam($key['parameters']);
$temp = new BigInteger($key['privateKey'], 256);
$components['dA'] = $components['curve']->convertInteger($temp);
$components['QA'] = self::extractPoint($key['publicKey'], $components['curve']);
return $components;
}
/**
* Convert ECDSA parameters to the appropriate format
*
* @access public
* @return string
*/
public static function saveParameters(BaseCurve $curve)
{
self::initialize_static_variables();
if ($curve instanceof TwistedEdwardsCurve) {
throw new UnsupportedCurveException('TwistedEdwards Curves are not supported');
}
$key = self::encodeParameters($curve);
return "-----BEGIN EC PARAMETERS-----\r\n" .
chunk_split(Base64::encode($key), 64) .
"-----END EC PARAMETERS-----\r\n";
}
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\Common\FiniteField\Integer $privateKey
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param string $password optional
* @return string
*/
public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = '')
{
self::initialize_static_variables();
if ($curve instanceof TwistedEdwardsCurve) {
throw new UnsupportedCurveException('TwistedEdwards Curves are not supported');
}
$publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
$key = [
'version' => 'ecPrivkeyVer1',
'privateKey' => $privateKey->toBytes(),
'parameters' => new ASN1\Element(self::encodeParameters($curve)),
'publicKey' => "\0" . $publicKey
];
$key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP);
return self::wrapPrivateKey($key, 'EC', $password);
}
}

View File

@ -0,0 +1,233 @@
<?php
/**
* PKCS#8 Formatted ECDSA Key Handler
*
* PHP version 5
*
* Processes keys with the following headers:
*
* -----BEGIN ENCRYPTED PRIVATE KEY-----
* -----BEGIN PRIVATE KEY-----
* -----BEGIN PUBLIC KEY-----
*
* Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
* is specific to private keys it's basically creating a DER-encoded wrapper
* for keys. This just extends that same concept to public keys (much like ssh-keygen)
*
* @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\Keys;
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\Common\Keys\PKCS8 as Progenitor;
use phpseclib\File\ASN1;
use phpseclib\File\ASN1\Maps;
use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve;
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib\Math\Common\FiniteField\Integer;
use phpseclib\Crypt\ECDSA\Curves\Ed25519;
use phpseclib\Crypt\ECDSA\Curves\Ed448;
/**
* PKCS#8 Formatted ECDSA Key Handler
*
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class PKCS8 extends Progenitor
{
use Common;
/**
* OID Name
*
* @var array
* @access private
*/
const OID_NAME = ['id-ecPublicKey', 'id-Ed25519', 'id-Ed448'];
/**
* OID Value
*
* @var string
* @access private
*/
const OID_VALUE = ['1.2.840.10045.2.1', '1.3.101.112', '1.3.101.113'];
/**
* Break a public or private key down into its constituent components
*
* @access public
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
// initialize_static_variables() is defined in both the trait and the parent class
// when it's defined in two places it's the traits one that's called
// the parent one is needed, as well, but the parent one is called by other methods
// in the parent class as needed and in the context of the parent it's the parent
// one that's called
self::initialize_static_variables();
if (!is_string($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
$isPublic = strpos($key, 'PUBLIC') !== false;
$key = parent::load($key, $password);
$type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';
switch (true) {
case !$isPublic && $type == 'publicKey':
throw new \UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key');
case $isPublic && $type == 'privateKey':
throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key');
}
switch ($key[$type . 'Algorithm']['algorithm']) {
case 'id-Ed25519':
case 'id-Ed448':
return self::loadEdDSA($key);
}
$decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
$params = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP);
$components = [];
$components['curve'] = self::loadCurveByParam($params);
if ($isPublic) {
$components['QA'] = self::extractPoint("\0" . $key['publicKey'], $components['curve']);
return $components;
}
$decoded = ASN1::decodeBER($key['privateKey']);
$key = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP);
if (isset($key['parameters']) && $params != $key['parameters']) {
throw new \RuntimeException('The PKCS8 parameter field does not match the private key parameter field');
}
$temp = new BigInteger($key['privateKey'], 256);
$components['dA'] = $components['curve']->convertInteger($temp);
$components['QA'] = self::extractPoint($key['publicKey'], $components['curve']);
return $components;
}
/**
* Break a public or private EdDSA key down into its constituent components
*
* @return array
*/
private static function loadEdDSA(array $key)
{
$components = [];
if (isset($key['privateKey'])) {
$components['curve'] = $key['privateKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448();
// 0x04 == octet string
// 0x20 == length (32 bytes)
if (substr($key['privateKey'], 0, 2) != "\x04\x20") {
throw new \RuntimeException('The first two bytes of the private key field should be 0x0420');
}
$components['dA'] = $components['curve']->extractSecret(substr($key['privateKey'], 2));
}
if (isset($key['publicKey'])) {
if (!isset($components['curve'])) {
$components['curve'] = $key['publicKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448();
}
$components['QA'] = self::extractPoint(substr($key['publicKey'], 1), $components['curve']);
}
if (isset($key['privateKey']) && !isset($components['QA'])) {
$components['QA'] = $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);
}
return $components;
}
/**
* Convert an ECDSA public key to the appropriate format
*
* @access public
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @return string
*/
public static function savePublicKey(BaseCurve $curve, array $publicKey)
{
self::initialize_static_variables();
if ($curve instanceof TwistedEdwardsCurve) {
return self::wrapPublicKey(
$curve->encodePoint($publicKey),
null,
$curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448'
);
}
$params = new ASN1\Element(self::encodeParameters($curve));
$key = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
return self::wrapPublicKey($key, $params, 'id-ecPublicKey');
}
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\Common\FiniteField\Integer $privateKey
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param string $password optional
* @return string
*/
public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = '')
{
self::initialize_static_variables();
if ($curve instanceof TwistedEdwardsCurve) {
return self::wrapPrivateKey(
"\x04\x20" . $privateKey->secret,
[],
null,
$password,
$curve instanceof Ed25519 ? 'id-Ed25519' : 'id-Ed448',
$curve->encodePoint($publicKey)
);
}
$publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
$params = new ASN1\Element(self::encodeParameters($curve));
$key = [
'version' => 'ecPrivkeyVer1',
'privateKey' => $privateKey->toBytes(),
//'parameters' => $params,
'publicKey' => "\0" . $publicKey
];
$key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP);
return self::wrapPrivateKey($key, [], $params, $password, 'id-ecPublicKey');
}
}

View File

@ -0,0 +1,145 @@
<?php
/**
* PuTTY Formatted ECDSA Key Handler
*
* PHP version 5
*
* @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\Keys;
use ParagonIE\ConstantTime\Base64;
use phpseclib\Math\BigInteger;
use phpseclib\Common\Functions\Strings;
use phpseclib\Crypt\Common\Keys\PuTTY as Progenitor;
use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve;
use phpseclib\Math\Common\FiniteField\Integer;
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
/**
* PuTTY Formatted ECDSA Key Handler
*
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class PuTTY extends Progenitor
{
use Common;
/**
* Public Handler
*
* @var string
* @access private
*/
const PUBLIC_HANDLER = 'phpseclib\Crypt\ECDSA\Keys\OpenSSH';
/**
* Supported Key Types
*
* @var array
* @access private
*/
protected static $types = [
'ecdsa-sha2-nistp256',
'ecdsa-sha2-nistp384',
'ecdsa-sha2-nistp521',
'ssh-ed25519'
];
/**
* Break a public or private key down into its constituent components
*
* @access public
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
$components = parent::load($key, $password);
if (!isset($components['private'])) {
return $components;
}
$private = $components['private'];
$temp = Base64::encode(Strings::packSSH2('s', $components['type']) . $components['public']);
$components = OpenSSH::load($components['type'] . ' ' . $temp . ' ' . $components['comment']);
if ($components['curve'] instanceof TwistedEdwardsCurve) {
if (Strings::shift($private, 4) != "\0\0\0\x20") {
throw new \RuntimeException('Length of ssh-ed25519 key should be 32');
}
$components['dA'] = $components['curve']->extractSecret($private);
} else {
list($temp) = Strings::unpackSSH2('i', $private);
$components['dA'] = $components['curve']->convertInteger($temp);
}
return $components;
}
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\Common\FiniteField\Integer $privateKey
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param string $password optional
* @return string
*/
public static function savePrivateKey(Integer $privateKey, BaseCurve $curve, array $publicKey, $password = false)
{
self::initialize_static_variables();
$public = explode(' ', OpenSSH::savePublicKey($curve, $publicKey));
$name = $public[0];
$public = Base64::decode($public[1]);
list(, $length) = unpack('N', Strings::shift($public, 4));
Strings::shift($public, $length);
// PuTTY pads private keys with a null byte per the following:
// https://github.com/github/putty/blob/a3d14d77f566a41fc61dfdc5c2e0e384c9e6ae8b/sshecc.c#L1926
if (!$curve instanceof TwistedEdwardsCurve) {
$private = $privateKey->toBytes();
if (!(strlen($privateKey->toBits()) & 7)) {
$private ="\0$private";
}
}
$private = $curve instanceof TwistedEdwardsCurve ?
Strings::packSSH2('s', $privateKey->secret) :
Strings::packSSH2('s', $private);
return self::wrapPrivateKey($public, $private, $name, $password);
}
/**
* Convert an ECDSA public key to the appropriate format
*
* @access public
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField[] $publicKey
* @return string
*/
public static function savePublicKey(BaseCurve $curve, array $publicKey)
{
$public = explode(' ', OpenSSH::savePublicKey($curve, $publicKey));
$type = $public[0];
$public = Base64::decode($public[1]);
list(, $length) = unpack('N', Strings::shift($public, 4));
Strings::shift($public, $length);
return self::wrapPublicKey($public, $type);
}
}

View File

@ -0,0 +1,480 @@
<?php
/**
* XML Formatted ECDSA Key Handler
*
* More info:
*
* https://www.w3.org/TR/xmldsig-core/#sec-ECKeyValue
* http://en.wikipedia.org/wiki/XML_Signature
*
* PHP version 5
*
* @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\Keys;
use ParagonIE\ConstantTime\Base64;
use phpseclib\Math\BigInteger;
use phpseclib\Crypt\ECDSA\BaseCurves\Base as BaseCurve;
use phpseclib\Crypt\ECDSA\BaseCurves\Prime as PrimeCurve;
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
use phpseclib\Exception\UnsupportedCurveException;
/**
* XML Formatted ECDSA Key Handler
*
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class XML
{
use Common;
/**
* Default namespace
*
* @var string
*/
private static $namespace;
/**
* Flag for using RFC4050 syntax
*
* @var bool
*/
private static $rfc4050 = false;
/**
* Break a public or private key down into its constituent components
*
* @access public
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
self::initialize_static_variables();
if (!is_string($key)) {
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
$use_errors = libxml_use_internal_errors(true);
$temp = self::isolateNamespace($key, 'http://www.w3.org/2009/xmldsig11#');
if ($temp) {
$key = $temp;
}
$temp = self::isolateNamespace($key, 'http://www.w3.org/2001/04/xmldsig-more#');
if ($temp) {
$key = $temp;
}
$dom = new \DOMDocument();
if (substr($key, 0, 5) != '<?xml') {
$key = '<xml>' . $key . '</xml>';
}
if (!$dom->loadXML($key)) {
libxml_use_internal_errors($use_errors);
throw new \UnexpectedValueException('Key does not appear to contain XML');
}
$xpath = new \DOMXPath($dom);
libxml_use_internal_errors($use_errors);
$curve = self::loadCurveByParam($xpath);
$pubkey = self::query($xpath, 'publickey', 'Public Key is not present');
$QA = self::query($xpath, 'ecdsakeyvalue')->length ?
self::extractPointRFC4050($xpath, $curve) :
self::extractPoint("\0" . $pubkey, $curve);
libxml_use_internal_errors($use_errors);
return compact('curve', 'QA');
}
/**
* Case-insensitive xpath query
*
* @param \DOMXPath $xpath
* @param string $name
* @param string $error optional
* @param bool $decode optional
* @return \DOMNodeList
*/
private static function query($xpath, $name, $error = null, $decode = true)
{
$query = '/';
$names = explode('/', $name);
foreach ($names as $name) {
$query.= "/*[translate(local-name(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')='$name']";
}
$result = $xpath->query($query);
if (!isset($error)) {
return $result;
}
if (!$result->length) {
throw new \RuntimeException($error);
}
return $decode ? self::decodeValue($result->item(0)->textContent) : $result->item(0)->textContent;
}
/**
* Finds the first element in the relevant namespace, strips the namespacing and returns the XML for that element.
*
* @param string $xml
* @param string $ns
*/
private static function isolateNamespace($xml, $ns)
{
$dom = new \DOMDocument();
if (!$dom->loadXML($xml)) {
return false;
}
$xpath = new \DOMXPath($dom);
$nodes = $xpath->query("//*[namespace::*[.='$ns'] and not(../namespace::*[.='$ns'])]");
if (!$nodes->length) {
return false;
}
$node = $nodes->item(0);
$ns_name = $node->lookupPrefix($ns);
$node->removeAttributeNS($ns, $ns_name);
return $dom->saveXML($node);
}
/**
* Decodes the value
*
* @param string $value
*/
private static function decodeValue($value)
{
return Base64::decode(str_replace(["\r", "\n", ' ', "\t"], '', $value));
}
/**
* Extract points from an XML document
*
* @param \DOMXPath $xpath
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @return object[]
*/
private static function extractPointRFC4050(\DOMXPath $xpath, BaseCurve $curve)
{
$x = self::query($xpath, 'publickey/x');
$y = self::query($xpath, 'publickey/y');
if (!$x->length || !$x->item(0)->hasAttribute('Value')) {
throw new \RuntimeException('Public Key / X coordinate not found');
}
if (!$y->length || !$y->item(0)->hasAttribute('Value')) {
throw new \RuntimeException('Public Key / Y coordinate not found');
}
$point = [
$curve->convertInteger(new BigInteger($x->item(0)->getAttribute('Value'))),
$curve->convertInteger(new BigInteger($y->item(0)->getAttribute('Value')))
];
if (!$curve->verifyPoint($point)) {
throw new \RuntimeException('Unable to verify that point exists on curve');
}
return $point;
}
/**
* Returns an instance of \phpseclib\Crypt\ECDSA\BaseCurves\Base based
* on the curve parameters
*
* @param \DomXPath $xpath
* @return \phpseclib\Crypt\ECDSA\BaseCurves\Base|false
*/
private static function loadCurveByParam(\DOMXPath $xpath)
{
$namedCurve = self::query($xpath, 'namedcurve');
if ($namedCurve->length == 1) {
$oid = $namedCurve->item(0)->getAttribute('URN');
$oid = preg_replace('#[^\d.]#', '', $oid);
$name = array_search($oid, self::$curveOIDs);
if ($name === false) {
throw new UnsupportedCurveException('Curve with OID of ' . $oid . ' is not supported');
}
$curve = '\phpseclib\Crypt\ECDSA\Curves\\' . $name;
if (!class_exists($curve)) {
throw new UnsupportedCurveException('Named Curve of ' . $name . ' is not supported');
}
return new $curve();
}
$params = self::query($xpath, 'explicitparams');
if ($params->length) {
return self::loadCurveByParamRFC4050($xpath);
}
$params = self::query($xpath, 'ecparameters');
if (!$params->length) {
throw new \RuntimeException('No parameters are present');
}
$fieldTypes = [
'prime-field' => ['fieldid/prime/p'],
'gnb' => ['fieldid/gnb/m'],
'tnb' => ['fieldid/tnb/k'],
'pnb' => ['fieldid/pnb/k1', 'fieldid/pnb/k2', 'fieldid/pnb/k3'],
'unknown' => []
];
foreach ($fieldTypes as $type => $queries) {
foreach ($queries as $query) {
$result = self::query($xpath, $query);
if (!$result->length) {
continue 2;
}
$param = preg_replace('#.*/#', '', $query);
$$param = self::decodeValue($result->item(0)->textContent);
}
break;
}
$a = self::query($xpath, 'curve/a', 'A coefficient is not present');
$b = self::query($xpath, 'curve/b', 'B coefficient is not present');
$base = self::query($xpath, 'base', 'Base point is not present');
$order = self::query($xpath, 'order', 'Order is not present');
switch ($type) {
case 'prime-field':
$curve = new PrimeCurve();
$curve->setModulo(new BigInteger($p, 256));
$curve->setCoefficients(
new BigInteger($a, 256),
new BigInteger($b, 256)
);
$point = self::extractPoint("\0" . $base, $curve);
$curve->setBasePoint(...$point);
$curve->setOrder(new BigInteger($order, 256));
return $curve;
case 'gnb':
case 'tnb':
case 'pnb':
default:
throw new UnsupportedCurveException('Field Type of ' . $type . ' is not supported');
}
}
/**
* Returns an instance of \phpseclib\Crypt\ECDSA\BaseCurves\Base based
* on the curve parameters
*
* @param \DomXPath $xpath
* @return \phpseclib\Crypt\ECDSA\BaseCurves\Base|false
*/
private static function loadCurveByParamRFC4050(\DOMXPath $xpath)
{
$fieldTypes = [
'prime-field' => ['primefieldparamstype/p'],
'unknown' => []
];
foreach ($fieldTypes as $type => $queries) {
foreach ($queries as $query) {
$result = self::query($xpath, $query);
if (!$result->length) {
continue 2;
}
$param = preg_replace('#.*/#', '', $query);
$$param = $result->item(0)->textContent;
}
break;
}
$a = self::query($xpath, 'curveparamstype/a', 'A coefficient is not present', false);
$b = self::query($xpath, 'curveparamstype/b', 'B coefficient is not present', false);
$x = self::query($xpath, 'basepointparams/basepoint/ecpointtype/x', 'Base Point X is not present', false);
$y = self::query($xpath, 'basepointparams/basepoint/ecpointtype/y', 'Base Point Y is not present', false);
$order = self::query($xpath, 'order', 'Order is not present', false);
switch ($type) {
case 'prime-field':
$curve = new PrimeCurve();
$p = str_replace(["\r", "\n", ' ', "\t"], '', $p);
$curve->setModulo(new BigInteger($p));
$a = str_replace(["\r", "\n", ' ', "\t"], '', $a);
$b = str_replace(["\r", "\n", ' ', "\t"], '', $b);
$curve->setCoefficients(
new BigInteger($a),
new BigInteger($b)
);
$x = str_replace(["\r", "\n", ' ', "\t"], '', $x);
$y = str_replace(["\r", "\n", ' ', "\t"], '', $y);
$curve->setBasePoint(
new BigInteger($x),
new BigInteger($y)
);
$order = str_replace(["\r", "\n", ' ', "\t"], '', $order);
$curve->setOrder(new BigInteger($order));
return $curve;
default:
throw new UnsupportedCurveException('Field Type of ' . $type . ' is not supported');
}
}
/**
* Sets the namespace. dsig11 is the most common one.
*
* Set to null to unset. Used only for creating public keys.
*
* @param string $namespace
*/
public static function setNamespace($namespace)
{
self::$namespace = $namespace;
}
/**
* Uses the XML syntax specified in https://tools.ietf.org/html/rfc4050
*/
public static function enableRFC4050Syntax()
{
self::$rfc4050 = true;
}
/**
* Uses the XML syntax specified in https://www.w3.org/TR/xmldsig-core/#sec-ECParameters
*/
public static function disableRFC4050Syntax()
{
self::$rfc4050 = false;
}
/**
* Convert a public key to the appropriate format
*
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @return string
*/
public static function savePublicKey(BaseCurve $curve, array $publicKey)
{
self::initialize_static_variables();
if ($curve instanceof TwistedEdwardsCurve) {
throw new UnsupportedCurveException('TwistedEdwards Curves are not supported');
}
if (empty(static::$namespace)) {
$pre = $post = '';
} else {
$pre = static::$namespace . ':';
$post = ':' . static::$namespace;
}
if (self::$rfc4050) {
return '<' . $pre . 'ECDSAKeyValue xmlns' . $post . '="http://www.w3.org/2001/04/xmldsig-more#">' . "\r\n" .
self::encodeXMLParameters($curve, $pre) . "\r\n" .
'<' . $pre . 'PublicKey>' . "\r\n" .
'<' . $pre . 'X Value="' . $publicKey[0] . '" />' . "\r\n" .
'<' . $pre . 'Y Value="' . $publicKey[1] . '" />' . "\r\n" .
'</' . $pre . 'PublicKey>' . "\r\n" .
'</' . $pre . 'ECDSAKeyValue>';
}
$publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
return '<' . $pre . 'ECKeyValue xmlns' . $post . '="http://www.w3.org/2009/xmldsig11#">' . "\r\n" .
self::encodeXMLParameters($curve, $pre) . "\r\n" .
'<' . $pre . 'PublicKey>' . Base64::encode($publicKey) . '</' . $pre . 'PublicKey>' . "\r\n" .
'</' . $pre . 'ECKeyValue>';
}
/**
* Encode Parameters
*
* @param \phpseclib\Crypt\ECDSA\BaseCurves\Base $curve
* @param string $pre
* @return string|false
*/
private static function encodeXMLParameters(BaseCurve $curve, $pre)
{
$result = self::encodeParameters($curve, true);
if (isset($result['namedCurve'])) {
$namedCurve = '<' . $pre . 'NamedCurve URI="urn:oid:' . self::$curveOIDs[$result['namedCurve']] . '" />';
return self::$rfc4050 ?
'<DomainParameters>' . str_replace('URI', 'URN', $namedCurve) . '</DomainParameters>' :
$namedCurve;
}
if (self::$rfc4050) {
$xml = '<' . $pre . 'ExplicitParams>' . "\r\n" .
'<' . $pre . 'FieldParams>' . "\r\n";
$temp = $result['specifiedCurve'];
switch ($temp['fieldID']['fieldType']) {
case 'prime-field':
$xml.= '<' . $pre . 'PrimeFieldParamsType>' . "\r\n" .
'<' . $pre . 'P>' . $temp['fieldID']['parameters'] . '</' . $pre . 'P>' . "\r\n" .
'</' . $pre . 'PrimeFieldParamsType>' . "\r\n";
$a = $curve->getA();
$b = $curve->getB();
list($x, $y) = $curve->getBasePoint();
break;
default:
throw new UnsupportedCurveException('Field Type of ' . $temp['fieldID']['fieldType'] . ' is not supported');
}
$xml.= '</' . $pre . 'FieldParams>' . "\r\n" .
'<' . $pre . 'CurveParamsType>' . "\r\n" .
'<' . $pre . 'A>' . $a . '</' . $pre . 'A>' . "\r\n" .
'<' . $pre . 'B>' . $b . '</' . $pre . 'B>' . "\r\n" .
'</' . $pre . 'CurveParamsType>' . "\r\n" .
'<' . $pre . 'BasePointParams>' . "\r\n" .
'<' . $pre . 'BasePoint>' . "\r\n" .
'<' . $pre . 'ECPointType>' . "\r\n" .
'<' . $pre . 'X>' . $x . '</' . $pre . 'X>' . "\r\n" .
'<' . $pre . 'Y>' . $y . '</' . $pre . 'Y>' . "\r\n" .
'</' . $pre . 'ECPointType>' . "\r\n" .
'</' . $pre . 'BasePoint>' . "\r\n" .
'<' . $pre . 'Order>' . $curve->getOrder() . '</' . $pre . 'Order>' . "\r\n" .
'</' . $pre . 'BasePointParams>' . "\r\n" .
'</' . $pre . 'ExplicitParams>' . "\r\n";
return $xml;
}
if (isset($result['specifiedCurve'])) {
$xml = '<' . $pre . 'ECParameters>' . "\r\n" .
'<' . $pre . 'FieldID>' . "\r\n";
$temp = $result['specifiedCurve'];
switch ($temp['fieldID']['fieldType']) {
case 'prime-field':
$xml.= '<' . $pre . 'Prime>' . "\r\n" .
'<' . $pre . 'P>' . Base64::encode($temp['fieldID']['parameters']->toBytes()) . '</' . $pre . 'P>' . "\r\n" .
'</' . $pre . 'Prime>' . "\r\n" ;
break;
default:
throw new UnsupportedCurveException('Field Type of ' . $temp['fieldID']['fieldType'] . ' is not supported');
}
$xml.= '</' . $pre . 'FieldID>' . "\r\n" .
'<' . $pre . 'Curve>' . "\r\n" .
'<' . $pre . 'A>' . Base64::encode($temp['curve']['a']) . '</' . $pre . 'A>' . "\r\n" .
'<' . $pre . 'B>' . Base64::encode($temp['curve']['b']) . '</' . $pre . 'B>' . "\r\n" .
'</' . $pre . 'Curve>' . "\r\n" .
'<' . $pre . 'Base>' . Base64::encode($temp['base']) . '</' . $pre . 'Base>' . "\r\n" .
'<' . $pre . 'Order>' . Base64::encode($temp['order']) . '</' . $pre . 'Order>' . "\r\n" .
'</' . $pre . 'ECParameters>';
return $xml;
}
}
}

View File

@ -0,0 +1,111 @@
<?php
/**
* libsodium Key Handler
*
* Different NaCl implementations store the key differently.
* https://blog.mozilla.org/warner/2011/11/29/ed25519-keys/ elaborates.
* libsodium appears to use the same format as SUPERCOP.
*
* PHP version 5
*
* @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\Keys;
use phpseclib\Crypt\ECDSA\Curves\Ed25519;
use phpseclib\Math\Common\FiniteField\Integer;
/**
* libsodium Key Handler
*
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class libsodium
{
use Common;
/**
* Break a public or private key down into its constituent components
*
* @access public
* @param string $key
* @param string $password optional
* @return array
*/
public static function load($key, $password = '')
{
switch (strlen($key)) {
case 32:
$public = $key;
break;
case 64:
$private = substr($key, 0, 32);
$public = substr($key, -32);
break;
case 96:
$public = substr($key, -32);
if (substr($key, 32, 32) != $public) {
throw new \RuntimeException('Keys with 96 bytes should have the 2nd and 3rd set of 32 bytes match');
}
$private = substr($key, 0, 32);
break;
default:
throw new \RuntimeException('libsodium keys need to either be 32 bytes long, 64 bytes long or 96 bytes long');
}
$curve = new Ed25519();
$components = ['curve' => $curve];
if (isset($private)) {
$components['dA'] = $curve->extractSecret($private);
}
$components['QA'] = isset($public) ?
self::extractPoint($public, $curve) :
$curve->multiplyPoint($curve->getBasePoint(), $components['dA']);
return $components;
}
/**
* Convert an ECDSA public key to the appropriate format
*
* @access public
* @param \phpseclib\Crypt\ECDSA\Curves\Ed25519 $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @return string
*/
public static function savePublicKey(Ed25519 $curve, array $publicKey)
{
return $curve->encodePoint($publicKey);
}
/**
* Convert a private key to the appropriate format.
*
* @access public
* @param \phpseclib\Math\Common\FiniteField\Integer $privateKey
* @param \phpseclib\Crypt\ECDSA\Curves\Ed25519 $curve
* @param \phpseclib\Math\Common\FiniteField\Integer[] $publicKey
* @param string $password optional
* @return string
*/
public static function savePrivateKey(Integer $privateKey, Ed25519 $curve, array $publicKey, $password = '')
{
if (!isset($privateKey->secret)) {
throw new \RuntimeException('Private Key does not have a secret set');
}
if (strlen($privateKey->secret) != 32) {
throw new \RuntimeException('Private Key secret is not of the correct length');
}
return $privateKey->secret . $curve->encodePoint($publicKey);
}
}

View File

@ -0,0 +1,68 @@
<?php
/**
* ASN1 Signature Handler
*
* PHP version 5
*
* Handles signatures in the format described in
* https://tools.ietf.org/html/rfc3279#section-2.2.3
*
* @category Crypt
* @package Common
* @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\ECDSA\Signature;
use phpseclib\Math\BigInteger;
use phpseclib\File\ASN1 as Encoder;
use phpseclib\File\ASN1\Maps\EcdsaSigValue;
/**
* ASN1 Signature Handler
*
* @package Common
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class ASN1
{
/**
* Loads a signature
*
* @access public
* @param array $key
* @return array
*/
public static function load($sig)
{
if (!is_string($sig)) {
return false;
}
$decoded = Encoder::decodeBER($sig);
if (empty($decoded)) {
return false;
}
$components = Encoder::asn1map($decoded[0], EcdsaSigValue::MAP);
return $components;
}
/**
* Returns a signature in the appropriate format
*
* @access public
* @param \phpseclib\Math\BigInteger $r
* @param \phpseclib\Math\BigInteger $s
* @return string
*/
public static function save(BigInteger $r, BigInteger $s)
{
return Encoder::encodeDER(compact('r', 's'), EcdsaSigValue::MAP);
}
}

View File

@ -0,0 +1,29 @@
<?php
/**
* Raw ECDSA Signature Handler
*
* PHP version 5
*
* @category Crypt
* @package DSA
* @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\ECDSA\Signature;
use phpseclib\Crypt\Common\Signature\Raw as Progenitor;
/**
* Raw DSA Signature Handler
*
* @package ECDSA
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class Raw extends Progenitor
{
}

View File

@ -0,0 +1,95 @@
<?php
/**
* SSH2 Signature Handler
*
* PHP version 5
*
* Handles signatures in the format used by SSH2
*
* @category Crypt
* @package Common
* @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\ECDSA\Signature;
use phpseclib\Math\BigInteger;
use phpseclib\Common\Functions\Strings;
/**
* SSH2 Signature Handler
*
* @package Common
* @author Jim Wigginton <terrafrost@php.net>
* @access public
*/
abstract class SSH2
{
/**
* Loads a signature
*
* @access public
* @param string $sig
* @return mixed
*/
public static function load($sig)
{
if (!is_string($sig)) {
return false;
}
$result = Strings::unpackSSH2('ss', $sig);
if ($result === false) {
return false;
}
list($type, $blob) = $result;
switch ($type) {
// see https://tools.ietf.org/html/rfc5656#section-3.1.2
case 'ecdsa-sha2-nistp256':
case 'ecdsa-sha2-nistp384':
case 'ecdsa-sha2-nistp521':
break;
default:
return false;
}
$length = ceil(substr($type, 16) / 8);
return [
'r' => new BigInteger(substr($blob, 0, $length), 256),
's' => new BigInteger(substr($blob, $length), 256)
];
}
/**
* Returns a signature in the appropriate format
*
* @access public
* @param \phpseclib\Math\BigInteger $r
* @param \phpseclib\Math\BigInteger $s
* @param string $curve
* @return string
*/
public static function save(BigInteger $r, BigInteger $s, $curve)
{
switch ($curve) {
case 'nistp256':
case 'nistp384':
case 'nistp521':
break;
default:
return false;
}
$length = ceil(substr($curve, 5) / 8);
return Strings::packSSH2('ss', 'ecdsa-sha2-' . $curve,
str_pad($r->toBytes(), $length, "\0", STR_PAD_LEFT) .
str_pad($s->toBytes(), $length, "\0", STR_PAD_LEFT)
);
}
}

View File

@ -45,7 +45,6 @@
namespace phpseclib\Crypt;
use ParagonIE\ConstantTime\Base64;
use phpseclib\File\ASN1;
use phpseclib\Math\BigInteger;
use phpseclib\Common\Functions\Strings;
@ -203,14 +202,6 @@ class RSA extends AsymmetricKey
*/
private $sLen;
/**
* Comment
*
* @var string
* @access private
*/
private $comment;
/**
* Hash function for the Mask Generation Function
*
@ -332,40 +323,11 @@ class RSA extends AsymmetricKey
* @return array
* @access public
* @param int $bits
*
*/
public static function createKey($bits = 2048)
{
self::initialize_static_variables();
if (!isset(self::$engine)) {
self::setPreferredEngine(self::ENGINE_OPENSSL);
}
// OpenSSL uses 65537 as the exponent and requires RSA keys be 384 bits minimum
if (self::$engine == self::ENGINE_OPENSSL && $bits >= 384 && self::$defaultExponent == 65537) {
$config = [];
if (isset(self::$configFile)) {
$config['config'] = self::$configFile;
}
$rsa = openssl_pkey_new(['private_key_bits' => $bits] + $config);
openssl_pkey_export($rsa, $privatekeystr, null, $config);
$privatekey = new RSA();
$privatekey->load($privatekeystr);
$publickeyarr = openssl_pkey_get_details($rsa);
$publickey = new RSA();
$publickey->load($publickeyarr['key']);
$publickey->setPublicKey();
// clear the buffer of error strings stemming from a minimalistic openssl.cnf
while (openssl_error_string() !== false) {
}
return compact('privatekey', 'publickey');
}
static $e;
if (!isset($e)) {
$e = new BigInteger(self::$defaultExponent);
@ -488,7 +450,8 @@ class RSA extends AsymmetricKey
$this->isPublic = $key->isPublic;
if (is_object($key->hash)) {
$this->hash = new Hash($key->hash->getHash());
$this->hashName = $key->hash->getHash();
$this->hash = new Hash($this->hashName);
}
if (is_object($key->mgfHash)) {
$this->mgfHash = new Hash($key->mgfHash->getHash());
@ -531,6 +494,7 @@ class RSA extends AsymmetricKey
$this->exponents = null;
$this->coefficients = null;
$this->publicExponent = null;
$this->isPublic = false;
return false;
}
@ -652,6 +616,19 @@ class RSA extends AsymmetricKey
return !isset($this->modulus) ? 0 : $this->modulus->getLength();
}
/**
* Returns the current engine being used
*
* @see self::useInternalEngine()
* @see self::useBestEngine()
* @access public
* @return string
*/
public function getEngine()
{
return 'PHP';
}
/**
* Defines the public key
*
@ -704,15 +681,25 @@ class RSA extends AsymmetricKey
}
/**
* Does the key self-identify as being a public key or not?
* Is the key a public key?
*
* @see self::isPublicKey()
* @access public
* @return bool
*/
public function isPublicKey()
{
return $this->isPublic();
return $this->isPublic;
}
/**
* Is the key a private key?
*
* @access public
* @return bool
*/
public function isPrivateKey()
{
return !$this->isPublic && isset($this->modulus);
}
/**
@ -735,6 +722,7 @@ class RSA extends AsymmetricKey
{
if ($key === false && !empty($this->publicExponent)) {
$this->publicExponent = false;
$this->isPublic = false;
return true;
}
@ -743,6 +731,7 @@ class RSA extends AsymmetricKey
return false;
}
$rsa->publicExponent = false;
$rsa->isPublic = false;
// don't overwrite the old key if the new key is invalid
$this->load($rsa);
@ -761,8 +750,14 @@ class RSA extends AsymmetricKey
* @param string $type optional
* @return mixed
*/
public function getPublicKey($type = 'PKCS8')
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;
@ -772,7 +767,15 @@ class RSA extends AsymmetricKey
return false;
}
return $type::savePublicKey($this->modulus, $this->publicExponent);
$key = $type::savePublicKey($this->modulus, $this->publicExponent);
if (!$returnObj) {
return $key;
}
$public = clone $this;
$public->load($key, 'PKCS8');
return $public;
}
/**
@ -1704,17 +1707,17 @@ class RSA extends AsymmetricKey
static $oids;
if (!isset($oids)) {
$oids = [
'1.2.840.113549.2.2' => 'md2',
'1.2.840.113549.2.4' => 'md4', // from PKCS1 v1.5
'1.2.840.113549.2.5' => 'md5',
'1.3.14.3.2.26' => 'id-sha1',
'2.16.840.1.101.3.4.2.1' => 'id-sha256',
'2.16.840.1.101.3.4.2.2' => 'id-sha384',
'2.16.840.1.101.3.4.2.3' => 'id-sha512',
'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
'2.16.840.1.101.3.4.2.4' => 'id-sha224',
'2.16.840.1.101.3.4.2.5' => 'id-sha512/224',
'2.16.840.1.101.3.4.2.6' => 'id-sha512/256',
'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);
}
@ -1724,7 +1727,7 @@ class RSA extends AsymmetricKey
return false;
}
if (!in_array($decoded['digestAlgorithm']['algorithm'], $oids)) {
if (!isset($oids[$decoded['digestAlgorithm']['algorithm']])) {
return false;
}

View File

@ -71,18 +71,21 @@ abstract class MSBLOB
* @access public
* @param string $key
* @param string $password optional
* @return array|bool
* @return array
*/
public static function load($key, $password = '')
{
if (!is_string($key)) {
return false;
throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
}
$key = Base64::decode($key);
if (!is_string($key) || strlen($key) < 20) {
return false;
if (!is_string($key)) {
throw new \UnexpectedValueException('Base64 decoding produced an error');
}
if (strlen($key) < 20) {
throw new \UnexpectedValueException('Key appears to be malformed');
}
// PUBLICKEYSTRUC publickeystruc
@ -103,7 +106,7 @@ abstract class MSBLOB
$publickey = false;
break;
default:
return false;
throw new \UnexpectedValueException('Key appears to be malformed');
}
$components = ['isPublicKey' => $publickey];
@ -114,7 +117,7 @@ abstract class MSBLOB
case self::CALG_RSA_SIGN:
break;
default:
return false;
throw new \UnexpectedValueException('Key appears to be malformed');
}
// RSAPUBKEY rsapubkey
@ -132,12 +135,12 @@ abstract class MSBLOB
case self::RSA1:
break;
default:
return false;
throw new \UnexpectedValueException('Key appears to be malformed');
}
$baseLength = $bitlen / 16;
if (strlen($key) != 2 * $baseLength && strlen($key) != 9 * $baseLength) {
return false;
throw new \UnexpectedValueException('Key appears to be malformed');
}
$components[$components['isPublicKey'] ? 'publicExponent' : 'privateExponent'] = new BigInteger(strrev($pubexp), 256);

Some files were not shown because too many files have changed in this diff Show More