[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/vendor/phpseclib/phpseclib/phpseclib/Crypt/EC/Formats/Keys/ -> PKCS1.php (source)

   1  <?php
   2  
   3  /**
   4   * "PKCS1" (RFC5915) Formatted EC Key Handler
   5   *
   6   * PHP version 5
   7   *
   8   * Used by File/X509.php
   9   *
  10   * Processes keys with the following headers:
  11   *
  12   * -----BEGIN EC PRIVATE KEY-----
  13   * -----BEGIN EC PARAMETERS-----
  14   *
  15   * Technically, PKCS1 is for RSA keys, only, but we're using PKCS1 to describe
  16   * DSA, whose format isn't really formally described anywhere, so might as well
  17   * use it to describe this, too. PKCS1 is easier to remember than RFC5915, after
  18   * all. I suppose this could also be named IETF but idk
  19   *
  20   * @author    Jim Wigginton <terrafrost@php.net>
  21   * @copyright 2015 Jim Wigginton
  22   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  23   * @link      http://phpseclib.sourceforge.net
  24   */
  25  
  26  namespace phpseclib3\Crypt\EC\Formats\Keys;
  27  
  28  use phpseclib3\Common\Functions\Strings;
  29  use phpseclib3\Crypt\Common\Formats\Keys\PKCS1 as Progenitor;
  30  use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
  31  use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve;
  32  use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
  33  use phpseclib3\Exception\UnsupportedCurveException;
  34  use phpseclib3\File\ASN1;
  35  use phpseclib3\File\ASN1\Maps;
  36  use phpseclib3\Math\BigInteger;
  37  
  38  /**
  39   * "PKCS1" (RFC5915) Formatted EC Key Handler
  40   *
  41   * @author  Jim Wigginton <terrafrost@php.net>
  42   */
  43  abstract class PKCS1 extends Progenitor
  44  {
  45      use Common;
  46  
  47      /**
  48       * Break a public or private key down into its constituent components
  49       *
  50       * @param string $key
  51       * @param string $password optional
  52       * @return array
  53       */
  54      public static function load($key, $password = '')
  55      {
  56          self::initialize_static_variables();
  57  
  58          if (!Strings::is_stringable($key)) {
  59              throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
  60          }
  61  
  62          if (strpos($key, 'BEGIN EC PARAMETERS') && strpos($key, 'BEGIN EC PRIVATE KEY')) {
  63              $components = [];
  64  
  65              preg_match('#-*BEGIN EC PRIVATE KEY-*[^-]*-*END EC PRIVATE KEY-*#s', $key, $matches);
  66              $decoded = parent::load($matches[0], $password);
  67              $decoded = ASN1::decodeBER($decoded);
  68              if (!$decoded) {
  69                  throw new \RuntimeException('Unable to decode BER');
  70              }
  71  
  72              $ecPrivate = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP);
  73              if (!is_array($ecPrivate)) {
  74                  throw new \RuntimeException('Unable to perform ASN1 mapping');
  75              }
  76  
  77              if (isset($ecPrivate['parameters'])) {
  78                  $components['curve'] = self::loadCurveByParam($ecPrivate['parameters']);
  79              }
  80  
  81              preg_match('#-*BEGIN EC PARAMETERS-*[^-]*-*END EC PARAMETERS-*#s', $key, $matches);
  82              $decoded = parent::load($matches[0], '');
  83              $decoded = ASN1::decodeBER($decoded);
  84              if (!$decoded) {
  85                  throw new \RuntimeException('Unable to decode BER');
  86              }
  87              $ecParams = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP);
  88              if (!is_array($ecParams)) {
  89                  throw new \RuntimeException('Unable to perform ASN1 mapping');
  90              }
  91              $ecParams = self::loadCurveByParam($ecParams);
  92  
  93              // comparing $ecParams and $components['curve'] directly won't work because they'll have different Math\Common\FiniteField classes
  94              // even if the modulo is the same
  95              if (isset($components['curve']) && self::encodeParameters($ecParams, false, []) != self::encodeParameters($components['curve'], false, [])) {
  96                  throw new \RuntimeException('EC PARAMETERS does not correspond to EC PRIVATE KEY');
  97              }
  98  
  99              if (!isset($components['curve'])) {
 100                  $components['curve'] = $ecParams;
 101              }
 102  
 103              $components['dA'] = new BigInteger($ecPrivate['privateKey'], 256);
 104              $components['curve']->rangeCheck($components['dA']);
 105              $components['QA'] = isset($ecPrivate['publicKey']) ?
 106                  self::extractPoint($ecPrivate['publicKey'], $components['curve']) :
 107                  $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);
 108  
 109              return $components;
 110          }
 111  
 112          $key = parent::load($key, $password);
 113  
 114          $decoded = ASN1::decodeBER($key);
 115          if (!$decoded) {
 116              throw new \RuntimeException('Unable to decode BER');
 117          }
 118  
 119          $key = ASN1::asn1map($decoded[0], Maps\ECParameters::MAP);
 120          if (is_array($key)) {
 121              return ['curve' => self::loadCurveByParam($key)];
 122          }
 123  
 124          $key = ASN1::asn1map($decoded[0], Maps\ECPrivateKey::MAP);
 125          if (!is_array($key)) {
 126              throw new \RuntimeException('Unable to perform ASN1 mapping');
 127          }
 128          if (!isset($key['parameters'])) {
 129              throw new \RuntimeException('Key cannot be loaded without parameters');
 130          }
 131  
 132          $components = [];
 133          $components['curve'] = self::loadCurveByParam($key['parameters']);
 134          $components['dA'] = new BigInteger($key['privateKey'], 256);
 135          $components['QA'] = isset($ecPrivate['publicKey']) ?
 136              self::extractPoint($ecPrivate['publicKey'], $components['curve']) :
 137              $components['curve']->multiplyPoint($components['curve']->getBasePoint(), $components['dA']);
 138  
 139          return $components;
 140      }
 141  
 142      /**
 143       * Convert EC parameters to the appropriate format
 144       *
 145       * @return string
 146       */
 147      public static function saveParameters(BaseCurve $curve, array $options = [])
 148      {
 149          self::initialize_static_variables();
 150  
 151          if ($curve instanceof TwistedEdwardsCurve || $curve instanceof MontgomeryCurve) {
 152              throw new UnsupportedCurveException('TwistedEdwards and Montgomery Curves are not supported');
 153          }
 154  
 155          $key = self::encodeParameters($curve, false, $options);
 156  
 157          return "-----BEGIN EC PARAMETERS-----\r\n" .
 158                 chunk_split(Strings::base64_encode($key), 64) .
 159                 "-----END EC PARAMETERS-----\r\n";
 160      }
 161  
 162      /**
 163       * Convert a private key to the appropriate format.
 164       *
 165       * @param \phpseclib3\Math\BigInteger $privateKey
 166       * @param \phpseclib3\Crypt\EC\BaseCurves\Base $curve
 167       * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
 168       * @param string $secret optional
 169       * @param string $password optional
 170       * @param array $options optional
 171       * @return string
 172       */
 173      public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, array $publicKey, $secret = null, $password = '', array $options = [])
 174      {
 175          self::initialize_static_variables();
 176  
 177          if ($curve instanceof TwistedEdwardsCurve  || $curve instanceof MontgomeryCurve) {
 178              throw new UnsupportedCurveException('TwistedEdwards Curves are not supported');
 179          }
 180  
 181          $publicKey = "\4" . $publicKey[0]->toBytes() . $publicKey[1]->toBytes();
 182  
 183          $key = [
 184              'version' => 'ecPrivkeyVer1',
 185              'privateKey' => $privateKey->toBytes(),
 186              'parameters' => new ASN1\Element(self::encodeParameters($curve)),
 187              'publicKey' => "\0" . $publicKey
 188          ];
 189  
 190          $key = ASN1::encodeDER($key, Maps\ECPrivateKey::MAP);
 191  
 192          return self::wrapPrivateKey($key, 'EC', $password, $options);
 193      }
 194  }