[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/ -> PublicKey.php (source)

   1  <?php
   2  
   3  /**
   4   * EC Public Key
   5   *
   6   * @author    Jim Wigginton <terrafrost@php.net>
   7   * @copyright 2015 Jim Wigginton
   8   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
   9   * @link      http://phpseclib.sourceforge.net
  10   */
  11  
  12  namespace phpseclib3\Crypt\EC;
  13  
  14  use phpseclib3\Common\Functions\Strings;
  15  use phpseclib3\Crypt\Common;
  16  use phpseclib3\Crypt\EC;
  17  use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
  18  use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
  19  use phpseclib3\Crypt\EC\Curves\Ed25519;
  20  use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
  21  use phpseclib3\Crypt\EC\Formats\Signature\ASN1 as ASN1Signature;
  22  use phpseclib3\Crypt\Hash;
  23  use phpseclib3\Exception\UnsupportedOperationException;
  24  use phpseclib3\Math\BigInteger;
  25  
  26  /**
  27   * EC Public Key
  28   *
  29   * @author  Jim Wigginton <terrafrost@php.net>
  30   */
  31  final class PublicKey extends EC implements Common\PublicKey
  32  {
  33      use Common\Traits\Fingerprint;
  34  
  35      /**
  36       * Verify a signature
  37       *
  38       * @see self::verify()
  39       * @param string $message
  40       * @param string $signature
  41       * @return mixed
  42       */
  43      public function verify($message, $signature)
  44      {
  45          if ($this->curve instanceof MontgomeryCurve) {
  46              throw new UnsupportedOperationException('Montgomery Curves cannot be used to create signatures');
  47          }
  48  
  49          $shortFormat = $this->shortFormat;
  50          $format = $this->sigFormat;
  51          if ($format === false) {
  52              return false;
  53          }
  54  
  55          $order = $this->curve->getOrder();
  56  
  57          if ($this->curve instanceof TwistedEdwardsCurve) {
  58              if ($shortFormat == 'SSH2') {
  59                  list(, $signature) = Strings::unpackSSH2('ss', $signature);
  60              }
  61  
  62              if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) {
  63                  return sodium_crypto_sign_verify_detached($signature, $message, $this->toString('libsodium'));
  64              }
  65  
  66              $curve = $this->curve;
  67              if (strlen($signature) != 2 * $curve::SIZE) {
  68                  return false;
  69              }
  70  
  71              $R = substr($signature, 0, $curve::SIZE);
  72              $S = substr($signature, $curve::SIZE);
  73  
  74              try {
  75                  $R = PKCS1::extractPoint($R, $curve);
  76                  $R = $this->curve->convertToInternal($R);
  77              } catch (\Exception $e) {
  78                  return false;
  79              }
  80  
  81              $S = strrev($S);
  82              $S = new BigInteger($S, 256);
  83  
  84              if ($S->compare($order) >= 0) {
  85                  return false;
  86              }
  87  
  88              $A = $curve->encodePoint($this->QA);
  89  
  90              if ($curve instanceof Ed25519) {
  91                  $dom2 = !isset($this->context) ? '' :
  92                      'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context;
  93              } else {
  94                  $context = isset($this->context) ? $this->context : '';
  95                  $dom2 = 'SigEd448' . "\0" . chr(strlen($context)) . $context;
  96              }
  97  
  98              $hash = new Hash($curve::HASH);
  99              $k = $hash->hash($dom2 . substr($signature, 0, $curve::SIZE) . $A . $message);
 100              $k = strrev($k);
 101              $k = new BigInteger($k, 256);
 102              list(, $k) = $k->divide($order);
 103  
 104              $qa = $curve->convertToInternal($this->QA);
 105  
 106              $lhs = $curve->multiplyPoint($curve->getBasePoint(), $S);
 107              $rhs = $curve->multiplyPoint($qa, $k);
 108              $rhs = $curve->addPoint($rhs, $R);
 109              $rhs = $curve->convertToAffine($rhs);
 110  
 111              return $lhs[0]->equals($rhs[0]) && $lhs[1]->equals($rhs[1]);
 112          }
 113  
 114          $params = $format::load($signature);
 115          if ($params === false || count($params) != 2) {
 116              return false;
 117          }
 118          extract($params);
 119  
 120          if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
 121              $sig = $format != 'ASN1' ? ASN1Signature::save($r, $s) : $signature;
 122  
 123              $result = openssl_verify($message, $sig, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());
 124  
 125              if ($result != -1) {
 126                  return (bool) $result;
 127              }
 128          }
 129  
 130          $n_1 = $order->subtract(self::$one);
 131          if (!$r->between(self::$one, $n_1) || !$s->between(self::$one, $n_1)) {
 132              return false;
 133          }
 134  
 135          $e = $this->hash->hash($message);
 136          $e = new BigInteger($e, 256);
 137  
 138          $Ln = $this->hash->getLength() - $order->getLength();
 139          $z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e;
 140  
 141          $w = $s->modInverse($order);
 142          list(, $u1) = $z->multiply($w)->divide($order);
 143          list(, $u2) = $r->multiply($w)->divide($order);
 144  
 145          $u1 = $this->curve->convertInteger($u1);
 146          $u2 = $this->curve->convertInteger($u2);
 147  
 148          list($x1, $y1) = $this->curve->multiplyAddPoints(
 149              [$this->curve->getBasePoint(), $this->QA],
 150              [$u1, $u2]
 151          );
 152  
 153          $x1 = $x1->toBigInteger();
 154          list(, $x1) = $x1->divide($order);
 155  
 156          return $x1->equals($r);
 157      }
 158  
 159      /**
 160       * Returns the public key
 161       *
 162       * @param string $type
 163       * @param array $options optional
 164       * @return string
 165       */
 166      public function toString($type, array $options = [])
 167      {
 168          $type = self::validatePlugin('Keys', $type, 'savePublicKey');
 169  
 170          return $type::savePublicKey($this->curve, $this->QA, $options);
 171      }
 172  }