[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

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

   1  <?php
   2  
   3  /**
   4   * EC Private Key
   5   *
   6   * @category  Crypt
   7   * @package   EC
   8   * @author    Jim Wigginton <[email protected]>
   9   * @copyright 2015 Jim Wigginton
  10   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  11   * @link      http://phpseclib.sourceforge.net
  12   */
  13  
  14  namespace phpseclib3\Crypt\EC;
  15  
  16  use phpseclib3\Common\Functions\Strings;
  17  use phpseclib3\Crypt\Common;
  18  use phpseclib3\Crypt\EC;
  19  use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
  20  use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
  21  use phpseclib3\Crypt\EC\Curves\Curve25519;
  22  use phpseclib3\Crypt\EC\Curves\Ed25519;
  23  use phpseclib3\Crypt\EC\Formats\Keys\PKCS1;
  24  use phpseclib3\Crypt\EC\Formats\Signature\ASN1 as ASN1Signature;
  25  use phpseclib3\Crypt\Hash;
  26  use phpseclib3\Exception\UnsupportedOperationException;
  27  use phpseclib3\Math\BigInteger;
  28  
  29  /**
  30   * EC Private Key
  31   *
  32   * @package EC
  33   * @author  Jim Wigginton <[email protected]>
  34   * @access  public
  35   */
  36  class PrivateKey extends EC implements Common\PrivateKey
  37  {
  38      use Common\Traits\PasswordProtected;
  39  
  40      /**
  41       * Private Key dA
  42       *
  43       * sign() converts this to a BigInteger so one might wonder why this is a FiniteFieldInteger instead of
  44       * a BigInteger. That's because a FiniteFieldInteger, when converted to a byte string, is null padded by
  45       * a certain amount whereas a BigInteger isn't.
  46       *
  47       * @var object
  48       */
  49      protected $dA;
  50  
  51      /**
  52       * Multiplies an encoded point by the private key
  53       *
  54       * Used by ECDH
  55       *
  56       * @param string $coordinates
  57       * @return string
  58       */
  59      public function multiply($coordinates)
  60      {
  61          if ($this->curve instanceof MontgomeryCurve) {
  62              if ($this->curve instanceof Curve25519 && self::$engines['libsodium']) {
  63                  return sodium_crypto_scalarmult($this->dA->toBytes(), $coordinates);
  64              }
  65  
  66              $point = [$this->curve->convertInteger(new BigInteger(strrev($coordinates), 256))];
  67              $point = $this->curve->multiplyPoint($point, $this->dA);
  68              return strrev($point[0]->toBytes(true));
  69          }
  70          if (!$this->curve instanceof TwistedEdwardsCurve) {
  71              $coordinates = "\0$coordinates";
  72          }
  73          $point = PKCS1::extractPoint($coordinates, $this->curve);
  74          $point = $this->curve->multiplyPoint($point, $this->dA);
  75          if ($this->curve instanceof TwistedEdwardsCurve) {
  76              return $this->curve->encodePoint($point);
  77          }
  78          if (empty($point)) {
  79              throw new \RuntimeException('The infinity point is invalid');
  80          }
  81          return "\4" . $point[0]->toBytes(true) . $point[1]->toBytes(true);
  82      }
  83  
  84      /**
  85       * Create a signature
  86       *
  87       * @see self::verify()
  88       * @access public
  89       * @param string $message
  90       * @return mixed
  91       */
  92      public function sign($message)
  93      {
  94          if ($this->curve instanceof MontgomeryCurve) {
  95              throw new UnsupportedOperationException('Montgomery Curves cannot be used to create signatures');
  96          }
  97  
  98          $dA = $this->dA;
  99          $order = $this->curve->getOrder();
 100  
 101          $shortFormat = $this->shortFormat;
 102          $format = $this->sigFormat;
 103          if ($format === false) {
 104              return false;
 105          }
 106  
 107          if ($this->curve instanceof TwistedEdwardsCurve) {
 108              if ($this->curve instanceof Ed25519 && self::$engines['libsodium'] && !isset($this->context)) {
 109                  $result = sodium_crypto_sign_detached($message, $this->withPassword()->toString('libsodium'));
 110                  return $shortFormat == 'SSH2' ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $result) : $result;
 111              }
 112  
 113              // contexts (Ed25519ctx) are supported but prehashing (Ed25519ph) is not.
 114              // quoting https://tools.ietf.org/html/rfc8032#section-8.5 ,
 115              // "The Ed25519ph and Ed448ph variants ... SHOULD NOT be used"
 116              $A = $this->curve->encodePoint($this->QA);
 117              $curve = $this->curve;
 118              $hash = new Hash($curve::HASH);
 119  
 120              $secret = substr($hash->hash($this->dA->secret), $curve::SIZE);
 121  
 122              if ($curve instanceof Ed25519) {
 123                  $dom = !isset($this->context) ? '' :
 124                      'SigEd25519 no Ed25519 collisions' . "\0" . chr(strlen($this->context)) . $this->context;
 125              } else {
 126                  $context = isset($this->context) ? $this->context : '';
 127                  $dom = 'SigEd448' . "\0" . chr(strlen($context)) . $context;
 128              }
 129              // SHA-512(dom2(F, C) || prefix || PH(M))
 130              $r = $hash->hash($dom . $secret . $message);
 131              $r = strrev($r);
 132              $r = new BigInteger($r, 256);
 133              list(, $r) = $r->divide($order);
 134              $R = $curve->multiplyPoint($curve->getBasePoint(), $r);
 135              $R = $curve->encodePoint($R);
 136              $k = $hash->hash($dom . $R . $A . $message);
 137              $k = strrev($k);
 138              $k = new BigInteger($k, 256);
 139              list(, $k) = $k->divide($order);
 140              $S = $k->multiply($dA)->add($r);
 141              list(, $S) = $S->divide($order);
 142              $S = str_pad(strrev($S->toBytes()), $curve::SIZE, "\0");
 143              return $shortFormat == 'SSH2' ? Strings::packSSH2('ss', 'ssh-' . strtolower($this->getCurve()), $R . $S) : $R . $S;
 144          }
 145  
 146          if (self::$engines['OpenSSL'] && in_array($this->hash->getHash(), openssl_get_md_methods())) {
 147              $signature = '';
 148              // altho PHP's OpenSSL bindings only supported EC key creation in PHP 7.1 they've long
 149              // supported signing / verification
 150              // we use specified curves to avoid issues with OpenSSL possibly not supporting a given named curve;
 151              // doing this may mean some curve-specific optimizations can't be used but idk if OpenSSL even
 152              // has curve-specific optimizations
 153              $result = openssl_sign($message, $signature, $this->toString('PKCS8', ['namedCurve' => false]), $this->hash->getHash());
 154  
 155              if ($result) {
 156                  if ($shortFormat == 'ASN1') {
 157                      return $signature;
 158                  }
 159  
 160                  extract(ASN1Signature::load($signature));
 161  
 162                  return $shortFormat == 'SSH2' ? $format::save($r, $s, $this->getCurve()) : $format::save($r, $s);
 163              }
 164          }
 165  
 166          $e = $this->hash->hash($message);
 167          $e = new BigInteger($e, 256);
 168  
 169          $Ln = $this->hash->getLength() - $order->getLength();
 170          $z = $Ln > 0 ? $e->bitwise_rightShift($Ln) : $e;
 171  
 172          while (true) {
 173              $k = BigInteger::randomRange(self::$one, $order->subtract(self::$one));
 174              list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $k);
 175              $x = $x->toBigInteger();
 176              list(, $r) = $x->divide($order);
 177              if ($r->equals(self::$zero)) {
 178                  continue;
 179              }
 180              $kinv = $k->modInverse($order);
 181              $temp = $z->add($dA->multiply($r));
 182              $temp = $kinv->multiply($temp);
 183              list(, $s) = $temp->divide($order);
 184              if (!$s->equals(self::$zero)) {
 185                  break;
 186              }
 187          }
 188  
 189          // the following is an RFC6979 compliant implementation of deterministic ECDSA
 190          // it's unused because it's mainly intended for use when a good CSPRNG isn't
 191          // available. if phpseclib's CSPRNG isn't good then even key generation is
 192          // suspect
 193          /*
 194          // if this were actually being used it'd probably be better if this lived in load() and createKey()
 195          $this->q = $this->curve->getOrder();
 196          $dA = $this->dA->toBigInteger();
 197          $this->x = $dA;
 198  
 199          $h1 = $this->hash->hash($message);
 200          $k = $this->computek($h1);
 201          list($x, $y) = $this->curve->multiplyPoint($this->curve->getBasePoint(), $k);
 202          $x = $x->toBigInteger();
 203          list(, $r) = $x->divide($this->q);
 204          $kinv = $k->modInverse($this->q);
 205          $h1 = $this->bits2int($h1);
 206          $temp = $h1->add($dA->multiply($r));
 207          $temp = $kinv->multiply($temp);
 208          list(, $s) = $temp->divide($this->q);
 209          */
 210  
 211          return $shortFormat == 'SSH2' ? $format::save($r, $s, $this->getCurve()) : $format::save($r, $s);
 212      }
 213  
 214      /**
 215       * Returns the private key
 216       *
 217       * @param string $type
 218       * @param array $options optional
 219       * @return string
 220       */
 221      public function toString($type, array $options = [])
 222      {
 223          $type = self::validatePlugin('Keys', $type, 'savePrivateKey');
 224  
 225          return $type::savePrivateKey($this->dA, $this->curve, $this->QA, $this->password, $options);
 226      }
 227  
 228      /**
 229       * Returns the public key
 230       *
 231       * @see self::getPrivateKey()
 232       * @access public
 233       * @return mixed
 234       */
 235      public function getPublicKey()
 236      {
 237          $format = 'PKCS8';
 238          if ($this->curve instanceof MontgomeryCurve) {
 239              $format = 'MontgomeryPublic';
 240          }
 241  
 242          $type = self::validatePlugin('Keys', $format, 'savePublicKey');
 243  
 244          $key = $type::savePublicKey($this->curve, $this->QA);
 245          $key = EC::loadFormat($format, $key);
 246          if ($this->curve instanceof MontgomeryCurve) {
 247              return $key;
 248          }
 249          $key = $key
 250              ->withHash($this->hash->getHash())
 251              ->withSignatureFormat($this->shortFormat);
 252          if ($this->curve instanceof TwistedEdwardsCurve) {
 253              $key = $key->withContext($this->context);
 254          }
 255          return $key;
 256      }
 257  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer