2019-05-19 22:35:29 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ECDSA Public Key
|
|
|
|
*
|
|
|
|
* @category Crypt
|
|
|
|
* @package ECDSA
|
|
|
|
* @author Jim Wigginton <terrafrost@php.net>
|
|
|
|
* @copyright 2015 Jim Wigginton
|
|
|
|
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
|
|
|
* @link http://phpseclib.sourceforge.net
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace phpseclib\Crypt\ECDSA;
|
|
|
|
|
|
|
|
use phpseclib\Crypt\ECDSA;
|
|
|
|
use phpseclib\Crypt\Hash;
|
|
|
|
use phpseclib\Math\BigInteger;
|
2019-06-25 05:44:10 +02:00
|
|
|
use phpseclib\Crypt\ECDSA\Formats\Signature\ASN1 as ASN1Signature;
|
2019-05-19 22:35:29 +02:00
|
|
|
use phpseclib\Crypt\ECDSA\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
|
|
|
|
use phpseclib\Crypt\ECDSA\Curves\Ed25519;
|
2019-06-25 05:44:10 +02:00
|
|
|
use phpseclib\Crypt\ECDSA\Formats\Keys\PKCS1;
|
|
|
|
use phpseclib\Crypt\ECDSA\Formats\Keys\PKCS8;
|
2019-05-19 22:35:29 +02:00
|
|
|
use phpseclib\Crypt\Common;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ECDSA Public Key
|
|
|
|
*
|
|
|
|
* @package ECDSA
|
|
|
|
* @author Jim Wigginton <terrafrost@php.net>
|
|
|
|
* @access public
|
|
|
|
*/
|
|
|
|
class PublicKey extends ECDSA implements Common\PublicKey
|
|
|
|
{
|
|
|
|
use Common\Fingerprint;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Verify a signature
|
|
|
|
*
|
|
|
|
* @see self::verify()
|
|
|
|
* @access public
|
|
|
|
* @param string $message
|
|
|
|
* @param string $signature
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
public function verify($message, $signature)
|
|
|
|
{
|
|
|
|
$order = $this->curve->getOrder();
|
|
|
|
|
|
|
|
if ($this->curve instanceof TwistedEdwardsCurve) {
|
|
|
|
if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) {
|
|
|
|
return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium'));
|
|
|
|
}
|
|
|
|
|
|
|
|
$curve = $this->curve;
|
|
|
|
if (strlen($signature) != 2 * $curve::SIZE) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$R = substr($signature, 0, $curve::SIZE);
|
|
|
|
$S = substr($signature, $curve::SIZE);
|
|
|
|
|
|
|
|
try {
|
|
|
|
$R = PKCS1::extractPoint($R, $curve);
|
|
|
|
$R = $this->curve->convertToInternal($R);
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$S = strrev($S);
|
|
|
|
$S = new BigInteger($S, 256);
|
|
|
|
|
|
|
|
if ($S->compare($order) >= 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$A = $curve->encodePoint($this->QA);
|
|
|
|
|
|
|
|
if ($curve instanceof Ed25519) {
|
|
|
|
$dom2 = !isset($this->context) ? '' :
|
|
|
|
'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context;
|
|
|
|
} else {
|
|
|
|
$context = isset($this->context) ? $this->context : '';
|
|
|
|
$dom2 = 'SigEd448' . "\0" . chr(strlen($context)) . $context;
|
|
|
|
}
|
|
|
|
|
|
|
|
$hash = new Hash($curve::HASH);
|
|
|
|
$k = $hash->hash($dom2 . substr($signature, 0, $curve::SIZE) . $A . $message);
|
|
|
|
$k = strrev($k);
|
|
|
|
$k = new BigInteger($k, 256);
|
|
|
|
list(, $k) = $k->divide($order);
|
|
|
|
|
|
|
|
$qa = $curve->convertToInternal($this->QA);
|
|
|
|
|
|
|
|
$lhs = $curve->multiplyPoint($curve->getBasePoint(), $curve->convertInteger($S));
|
|
|
|
$rhs = $curve->multiplyPoint($qa, $curve->convertInteger($k));
|
|
|
|
$rhs = $curve->addPoint($rhs, $R);
|
|
|
|
$rhs = $curve->convertToAffine($rhs);
|
|
|
|
|
|
|
|
return $lhs[0]->equals($rhs[0]) && $lhs[1]->equals($rhs[1]);
|
|
|
|
}
|
|
|
|
|
|
|
|
$format = $this->format;
|
|
|
|
|
|
|
|
$params = $format::load($signature);
|
|
|
|
if ($params === false || count($params) != 2) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
extract($params);
|
|
|
|
|
|
|
|
if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
|
|
|
|
$sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
|
|
|
|
|
2019-06-03 15:16:13 +02:00
|
|
|
$result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());
|
2019-05-19 22:35:29 +02:00
|
|
|
|
|
|
|
if ($result != -1) {
|
|
|
|
return (bool) $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$n_1 = $order->subtract(self::$one);
|
|
|
|
if (!$r->between(self::$one, $n_1) || !$s->between(self::$one, $n_1)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
$e = $this->hash->hash($message);
|
|
|
|
$e = new BigInteger($e, 256);
|
|
|
|
|
|
|
|
$Ln = $this->hash->getLength() - $order->getLength();
|
|
|
|
$z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e;
|
|
|
|
|
|
|
|
$w = $s->modInverse($order);
|
|
|
|
list(, $u1) = $z->multiply($w)->divide($order);
|
|
|
|
list(, $u2) = $r->multiply($w)->divide($order);
|
|
|
|
|
|
|
|
$u1 = $this->curve->convertInteger($u1);
|
|
|
|
$u2 = $this->curve->convertInteger($u2);
|
|
|
|
|
|
|
|
list($x1, $y1) = $this->curve->multiplyAddPoints(
|
|
|
|
[$this->curve->getBasePoint(), $this->QA],
|
|
|
|
[$u1, $u2]
|
|
|
|
);
|
|
|
|
|
|
|
|
$x1 = $x1->toBigInteger();
|
|
|
|
list(, $x1) = $x1->divide($order);
|
|
|
|
|
|
|
|
return $x1->equals($r);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the public key
|
|
|
|
*
|
|
|
|
* @param string $type
|
2019-06-01 20:23:11 +02:00
|
|
|
* @param array $options optional
|
2019-05-19 22:35:29 +02:00
|
|
|
* @return string
|
|
|
|
*/
|
2019-06-02 17:02:30 +02:00
|
|
|
public function toString($type, array $options = [])
|
2019-05-19 22:35:29 +02:00
|
|
|
{
|
|
|
|
$type = self::validatePlugin('Keys', $type, 'savePublicKey');
|
|
|
|
|
2019-06-01 20:23:11 +02:00
|
|
|
return $type::savePublicKey($this->curve, $this->QA, $options);
|
2019-05-19 22:35:29 +02:00
|
|
|
}
|
|
|
|
}
|