[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/phpseclib/phpseclib/phpseclib/Crypt/Common/Formats/Keys/ -> PKCS8.php (source)

   1  <?php
   2  
   3  /**
   4   * PKCS#8 Formatted Key Handler
   5   *
   6   * PHP version 5
   7   *
   8   * Used by PHP's openssl_public_encrypt() and openssl's rsautl (when -pubin is set)
   9   *
  10   * Processes keys with the following headers:
  11   *
  12   * -----BEGIN ENCRYPTED PRIVATE KEY-----
  13   * -----BEGIN PRIVATE KEY-----
  14   * -----BEGIN PUBLIC KEY-----
  15   *
  16   * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
  17   * is specific to private keys it's basically creating a DER-encoded wrapper
  18   * for keys. This just extends that same concept to public keys (much like ssh-keygen)
  19   *
  20   * @category  Crypt
  21   * @package   Common
  22   * @author    Jim Wigginton <[email protected]>
  23   * @copyright 2015 Jim Wigginton
  24   * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  25   * @link      http://phpseclib.sourceforge.net
  26   */
  27  
  28  namespace phpseclib3\Crypt\Common\Formats\Keys;
  29  
  30  use ParagonIE\ConstantTime\Base64;
  31  use phpseclib3\Common\Functions\Strings;
  32  use phpseclib3\Crypt\AES;
  33  use phpseclib3\Crypt\DES;
  34  use phpseclib3\Crypt\Random;
  35  use phpseclib3\Crypt\RC2;
  36  use phpseclib3\Crypt\RC4;
  37  use phpseclib3\Crypt\TripleDES;
  38  use phpseclib3\Exception\InsufficientSetupException;
  39  use phpseclib3\Exception\UnsupportedAlgorithmException;
  40  use phpseclib3\File\ASN1;
  41  use phpseclib3\File\ASN1\Maps;
  42  
  43  /**
  44   * PKCS#8 Formatted Key Handler
  45   *
  46   * @package Common
  47   * @author  Jim Wigginton <[email protected]>
  48   * @access  public
  49   */
  50  abstract class PKCS8 extends PKCS
  51  {
  52      /**
  53       * Default encryption algorithm
  54       *
  55       * @var string
  56       * @access private
  57       */
  58      private static $defaultEncryptionAlgorithm = 'id-PBES2';
  59  
  60      /**
  61       * Default encryption scheme
  62       *
  63       * Only used when defaultEncryptionAlgorithm is id-PBES2
  64       *
  65       * @var string
  66       * @access private
  67       */
  68      private static $defaultEncryptionScheme = 'aes128-CBC-PAD';
  69  
  70      /**
  71       * Default PRF
  72       *
  73       * Only used when defaultEncryptionAlgorithm is id-PBES2
  74       *
  75       * @var string
  76       * @access private
  77       */
  78      private static $defaultPRF = 'id-hmacWithSHA256';
  79  
  80      /**
  81       * Default Iteration Count
  82       *
  83       * @var int
  84       * @access private
  85       */
  86      private static $defaultIterationCount = 2048;
  87  
  88      /**
  89       * OIDs loaded
  90       *
  91       * @var bool
  92       * @access private
  93       */
  94      private static $oidsLoaded = false;
  95  
  96      /**
  97       * Sets the default encryption algorithm
  98       *
  99       * @access public
 100       * @param string $algo
 101       */
 102      public static function setEncryptionAlgorithm($algo)
 103      {
 104          self::$defaultEncryptionAlgorithm = $algo;
 105      }
 106  
 107      /**
 108       * Sets the default encryption algorithm for PBES2
 109       *
 110       * @access public
 111       * @param string $algo
 112       */
 113      public static function setEncryptionScheme($algo)
 114      {
 115          self::$defaultEncryptionScheme = $algo;
 116      }
 117  
 118      /**
 119       * Sets the iteration count
 120       *
 121       * @access public
 122       * @param int $count
 123       */
 124      public static function setIterationCount($count)
 125      {
 126          self::$defaultIterationCount = $count;
 127      }
 128  
 129      /**
 130       * Sets the PRF for PBES2
 131       *
 132       * @access public
 133       * @param string $algo
 134       */
 135      public static function setPRF($algo)
 136      {
 137          self::$defaultPRF = $algo;
 138      }
 139  
 140      /**
 141       * Returns a SymmetricKey object based on a PBES1 $algo
 142       *
 143       * @return \phpseclib3\Crypt\Common\SymmetricKey
 144       * @access public
 145       * @param string $algo
 146       */
 147      private static function getPBES1EncryptionObject($algo)
 148      {
 149          $algo = preg_match('#^pbeWith(?:MD2|MD5|SHA1|SHA)And(.*?)-CBC$#', $algo, $matches) ?
 150              $matches[1] :
 151              substr($algo, 13); // strlen('pbeWithSHAAnd') == 13
 152  
 153          switch ($algo) {
 154              case 'DES':
 155                  $cipher = new DES('cbc');
 156                  break;
 157              case 'RC2':
 158                  $cipher = new RC2('cbc');
 159                  break;
 160              case '3-KeyTripleDES':
 161                  $cipher = new TripleDES('cbc');
 162                  break;
 163              case '2-KeyTripleDES':
 164                  $cipher = new TripleDES('cbc');
 165                  $cipher->setKeyLength(128);
 166                  break;
 167              case '128BitRC2':
 168                  $cipher = new RC2('cbc');
 169                  $cipher->setKeyLength(128);
 170                  break;
 171              case '40BitRC2':
 172                  $cipher = new RC2('cbc');
 173                  $cipher->setKeyLength(40);
 174                  break;
 175              case '128BitRC4':
 176                  $cipher = new RC4();
 177                  $cipher->setKeyLength(128);
 178                  break;
 179              case '40BitRC4':
 180                  $cipher = new RC4();
 181                  $cipher->setKeyLength(40);
 182                  break;
 183              default:
 184                  throw new UnsupportedAlgorithmException("$algo is not a supported algorithm");
 185          }
 186  
 187          return $cipher;
 188      }
 189  
 190      /**
 191       * Returns a hash based on a PBES1 $algo
 192       *
 193       * @return string
 194       * @access public
 195       * @param string $algo
 196       */
 197      private static function getPBES1Hash($algo)
 198      {
 199          if (preg_match('#^pbeWith(MD2|MD5|SHA1|SHA)And.*?-CBC$#', $algo, $matches)) {
 200              return $matches[1] == 'SHA' ? 'sha1' : $matches[1];
 201          }
 202  
 203          return 'sha1';
 204      }
 205  
 206      /**
 207       * Returns a KDF baesd on a PBES1 $algo
 208       *
 209       * @return string
 210       * @access public
 211       * @param string $algo
 212       */
 213      private static function getPBES1KDF($algo)
 214      {
 215          switch ($algo) {
 216              case 'pbeWithMD2AndDES-CBC':
 217              case 'pbeWithMD2AndRC2-CBC':
 218              case 'pbeWithMD5AndDES-CBC':
 219              case 'pbeWithMD5AndRC2-CBC':
 220              case 'pbeWithSHA1AndDES-CBC':
 221              case 'pbeWithSHA1AndRC2-CBC':
 222                  return 'pbkdf1';
 223          }
 224  
 225          return 'pkcs12';
 226      }
 227  
 228      /**
 229       * Returns a SymmetricKey object baesd on a PBES2 $algo
 230       *
 231       * @return SymmetricKey
 232       * @access public
 233       * @param string $algo
 234       */
 235      private static function getPBES2EncryptionObject($algo)
 236      {
 237          switch ($algo) {
 238              case 'desCBC':
 239                  $cipher = new TripleDES('cbc');
 240                  break;
 241              case 'des-EDE3-CBC':
 242                  $cipher = new TripleDES('cbc');
 243                  break;
 244              case 'rc2CBC':
 245                  $cipher = new RC2('cbc');
 246                  // in theory this can be changed
 247                  $cipher->setKeyLength(128);
 248                  break;
 249              case 'rc5-CBC-PAD':
 250                  throw new UnsupportedAlgorithmException('rc5-CBC-PAD is not supported for PBES2 PKCS#8 keys');
 251              case 'aes128-CBC-PAD':
 252              case 'aes192-CBC-PAD':
 253              case 'aes256-CBC-PAD':
 254                  $cipher = new AES('cbc');
 255                  $cipher->setKeyLength(substr($algo, 3, 3));
 256                  break;
 257              default:
 258                  throw new UnsupportedAlgorithmException("$algo is not supported");
 259          }
 260  
 261          return $cipher;
 262      }
 263  
 264      /**
 265       * Initialize static variables
 266       *
 267       * @access private
 268       */
 269      private static function initialize_static_variables()
 270      {
 271          if (!isset(static::$childOIDsLoaded)) {
 272              throw new InsufficientSetupException('This class should not be called directly');
 273          }
 274  
 275          if (!static::$childOIDsLoaded) {
 276              ASN1::loadOIDs(is_array(static::OID_NAME) ?
 277                  array_combine(static::OID_NAME, static::OID_VALUE) :
 278                  [static::OID_NAME => static::OID_VALUE]);
 279              static::$childOIDsLoaded = true;
 280          }
 281          if (!self::$oidsLoaded) {
 282              // from https://tools.ietf.org/html/rfc2898
 283              ASN1::loadOIDs([
 284                 // PBES1 encryption schemes
 285                 'pbeWithMD2AndDES-CBC' => '1.2.840.113549.1.5.1',
 286                 'pbeWithMD2AndRC2-CBC' => '1.2.840.113549.1.5.4',
 287                 'pbeWithMD5AndDES-CBC' => '1.2.840.113549.1.5.3',
 288                 'pbeWithMD5AndRC2-CBC' => '1.2.840.113549.1.5.6',
 289                 'pbeWithSHA1AndDES-CBC' => '1.2.840.113549.1.5.10',
 290                 'pbeWithSHA1AndRC2-CBC' => '1.2.840.113549.1.5.11',
 291  
 292                 // from PKCS#12:
 293                 // https://tools.ietf.org/html/rfc7292
 294                 'pbeWithSHAAnd128BitRC4' => '1.2.840.113549.1.12.1.1',
 295                 'pbeWithSHAAnd40BitRC4' => '1.2.840.113549.1.12.1.2',
 296                 'pbeWithSHAAnd3-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.3',
 297                 'pbeWithSHAAnd2-KeyTripleDES-CBC' => '1.2.840.113549.1.12.1.4',
 298                 'pbeWithSHAAnd128BitRC2-CBC' => '1.2.840.113549.1.12.1.5',
 299                 'pbeWithSHAAnd40BitRC2-CBC' => '1.2.840.113549.1.12.1.6',
 300  
 301                 'id-PBKDF2' => '1.2.840.113549.1.5.12',
 302                 'id-PBES2' => '1.2.840.113549.1.5.13',
 303                 'id-PBMAC1' => '1.2.840.113549.1.5.14',
 304  
 305                 // from PKCS#5 v2.1:
 306                 // http://www.rsa.com/rsalabs/pkcs/files/h11302-wp-pkcs5v2-1-password-based-cryptography-standard.pdf
 307                 'id-hmacWithSHA1' => '1.2.840.113549.2.7',
 308                 'id-hmacWithSHA224' => '1.2.840.113549.2.8',
 309                 'id-hmacWithSHA256' => '1.2.840.113549.2.9',
 310                 'id-hmacWithSHA384' => '1.2.840.113549.2.10',
 311                 'id-hmacWithSHA512' => '1.2.840.113549.2.11',
 312                 'id-hmacWithSHA512-224' => '1.2.840.113549.2.12',
 313                 'id-hmacWithSHA512-256' => '1.2.840.113549.2.13',
 314  
 315                 'desCBC'       => '1.3.14.3.2.7',
 316                 'des-EDE3-CBC' => '1.2.840.113549.3.7',
 317                 'rc2CBC' => '1.2.840.113549.3.2',
 318                 'rc5-CBC-PAD' => '1.2.840.113549.3.9',
 319  
 320                 'aes128-CBC-PAD' => '2.16.840.1.101.3.4.1.2',
 321                 'aes192-CBC-PAD' => '2.16.840.1.101.3.4.1.22',
 322                 'aes256-CBC-PAD' => '2.16.840.1.101.3.4.1.42'
 323              ]);
 324              self::$oidsLoaded = true;
 325          }
 326      }
 327  
 328      /**
 329       * Break a public or private key down into its constituent components
 330       *
 331       * @access public
 332       * @param string $key
 333       * @param string $password optional
 334       * @return array
 335       */
 336      protected static function load($key, $password = '')
 337      {
 338          $decoded = self::preParse($key);
 339  
 340          $meta = [];
 341  
 342          $decrypted = ASN1::asn1map($decoded[0], Maps\EncryptedPrivateKeyInfo::MAP);
 343          if (strlen($password) && is_array($decrypted)) {
 344              $algorithm = $decrypted['encryptionAlgorithm']['algorithm'];
 345              switch ($algorithm) {
 346                  // PBES1
 347                  case 'pbeWithMD2AndDES-CBC':
 348                  case 'pbeWithMD2AndRC2-CBC':
 349                  case 'pbeWithMD5AndDES-CBC':
 350                  case 'pbeWithMD5AndRC2-CBC':
 351                  case 'pbeWithSHA1AndDES-CBC':
 352                  case 'pbeWithSHA1AndRC2-CBC':
 353                  case 'pbeWithSHAAnd3-KeyTripleDES-CBC':
 354                  case 'pbeWithSHAAnd2-KeyTripleDES-CBC':
 355                  case 'pbeWithSHAAnd128BitRC2-CBC':
 356                  case 'pbeWithSHAAnd40BitRC2-CBC':
 357                  case 'pbeWithSHAAnd128BitRC4':
 358                  case 'pbeWithSHAAnd40BitRC4':
 359                      $cipher = self::getPBES1EncryptionObject($algorithm);
 360                      $hash = self::getPBES1Hash($algorithm);
 361                      $kdf = self::getPBES1KDF($algorithm);
 362  
 363                      $meta['meta']['algorithm'] = $algorithm;
 364  
 365                      $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
 366                      extract(ASN1::asn1map($temp[0], Maps\PBEParameter::MAP));
 367                      $iterationCount = (int) $iterationCount->toString();
 368                      $cipher->setPassword($password, $kdf, $hash, $salt, $iterationCount);
 369                      $key = $cipher->decrypt($decrypted['encryptedData']);
 370                      $decoded = ASN1::decodeBER($key);
 371                      if (empty($decoded)) {
 372                          throw new \RuntimeException('Unable to decode BER 2');
 373                      }
 374  
 375                      break;
 376                  case 'id-PBES2':
 377                      $meta['meta']['algorithm'] = $algorithm;
 378  
 379                      $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
 380                      $temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP);
 381                      extract($temp);
 382  
 383                      $cipher = self::getPBES2EncryptionObject($encryptionScheme['algorithm']);
 384                      $meta['meta']['cipher'] = $encryptionScheme['algorithm'];
 385  
 386                      $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
 387                      $temp = ASN1::asn1map($temp[0], Maps\PBES2params::MAP);
 388                      extract($temp);
 389  
 390                      if (!$cipher instanceof RC2) {
 391                          $cipher->setIV($encryptionScheme['parameters']['octetString']);
 392                      } else {
 393                          $temp = ASN1::decodeBER($encryptionScheme['parameters']);
 394                          extract(ASN1::asn1map($temp[0], Maps\RC2CBCParameter::MAP));
 395                          $effectiveKeyLength = (int) $rc2ParametersVersion->toString();
 396                          switch ($effectiveKeyLength) {
 397                              case 160:
 398                                  $effectiveKeyLength = 40;
 399                                  break;
 400                              case 120:
 401                                  $effectiveKeyLength = 64;
 402                                  break;
 403                              case 58:
 404                                  $effectiveKeyLength = 128;
 405                                  break;
 406                              //default: // should be >= 256
 407                          }
 408                          $cipher->setIV($iv);
 409                          $cipher->setKeyLength($effectiveKeyLength);
 410                      }
 411  
 412                      $meta['meta']['keyDerivationFunc'] = $keyDerivationFunc['algorithm'];
 413                      switch ($keyDerivationFunc['algorithm']) {
 414                          case 'id-PBKDF2':
 415                              $temp = ASN1::decodeBER($keyDerivationFunc['parameters']);
 416                              $prf = ['algorithm' => 'id-hmacWithSHA1'];
 417                              $params = ASN1::asn1map($temp[0], Maps\PBKDF2params::MAP);
 418                              extract($params);
 419                              $meta['meta']['prf'] = $prf['algorithm'];
 420                              $hash = str_replace('-', '/', substr($prf['algorithm'], 11));
 421                              $params = [
 422                                  $password,
 423                                  'pbkdf2',
 424                                  $hash,
 425                                  $salt,
 426                                  (int) $iterationCount->toString()
 427                              ];
 428                              if (isset($keyLength)) {
 429                                  $params[] = (int) $keyLength->toString();
 430                              }
 431                              $cipher->setPassword(...$params);
 432                              $key = $cipher->decrypt($decrypted['encryptedData']);
 433                              $decoded = ASN1::decodeBER($key);
 434                              if (empty($decoded)) {
 435                                  throw new \RuntimeException('Unable to decode BER 3');
 436                              }
 437                              break;
 438                          default:
 439                              throw new UnsupportedAlgorithmException('Only PBKDF2 is supported for PBES2 PKCS#8 keys');
 440                      }
 441                      break;
 442                  case 'id-PBMAC1':
 443                      //$temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']);
 444                      //$value = ASN1::asn1map($temp[0], Maps\PBMAC1params::MAP);
 445                      // since i can't find any implementation that does PBMAC1 it is unsupported
 446                      throw new UnsupportedAlgorithmException('Only PBES1 and PBES2 PKCS#8 keys are supported.');
 447                  // at this point we'll assume that the key conforms to PublicKeyInfo
 448              }
 449          }
 450  
 451          $private = ASN1::asn1map($decoded[0], Maps\OneAsymmetricKey::MAP);
 452          if (is_array($private)) {
 453              if (isset($private['privateKeyAlgorithm']['parameters']) && !$private['privateKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][1]['content'][1])) {
 454                  $temp = $decoded[0]['content'][1]['content'][1];
 455                  $private['privateKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length']));
 456              }
 457              if (is_array(static::OID_NAME)) {
 458                  if (!in_array($private['privateKeyAlgorithm']['algorithm'], static::OID_NAME)) {
 459                      throw new UnsupportedAlgorithmException($private['privateKeyAlgorithm']['algorithm'] . ' is not a supported key type');
 460                  }
 461              } else {
 462                  if ($private['privateKeyAlgorithm']['algorithm'] != static::OID_NAME) {
 463                      throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $private['privateKeyAlgorithm']['algorithm'] . ' key');
 464                  }
 465              }
 466              if (isset($private['publicKey'])) {
 467                  if ($private['publicKey'][0] != "\0") {
 468                      throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($private['publicKey'][0]));
 469                  }
 470                  $private['publicKey'] = substr($private['publicKey'], 1);
 471              }
 472              return $private + $meta;
 473          }
 474  
 475          // EncryptedPrivateKeyInfo and PublicKeyInfo have largely identical "signatures". the only difference
 476          // is that the former has an octet string and the later has a bit string. the first byte of a bit
 477          // string represents the number of bits in the last byte that are to be ignored but, currently,
 478          // bit strings wanting a non-zero amount of bits trimmed are not supported
 479          $public = ASN1::asn1map($decoded[0], Maps\PublicKeyInfo::MAP);
 480  
 481          if (is_array($public)) {
 482              if ($public['publicKey'][0] != "\0") {
 483                  throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($public['publicKey'][0]));
 484              }
 485              if (is_array(static::OID_NAME)) {
 486                  if (!in_array($public['publicKeyAlgorithm']['algorithm'], static::OID_NAME)) {
 487                      throw new UnsupportedAlgorithmException($public['publicKeyAlgorithm']['algorithm'] . ' is not a supported key type');
 488                  }
 489              } else {
 490                  if ($public['publicKeyAlgorithm']['algorithm'] != static::OID_NAME) {
 491                      throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $public['publicKeyAlgorithm']['algorithm'] . ' key');
 492                  }
 493              }
 494              if (isset($public['publicKeyAlgorithm']['parameters']) && !$public['publicKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][0]['content'][1])) {
 495                  $temp = $decoded[0]['content'][0]['content'][1];
 496                  $public['publicKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length']));
 497              }
 498              $public['publicKey'] = substr($public['publicKey'], 1);
 499              return $public;
 500          }
 501  
 502          throw new \RuntimeException('Unable to parse using either OneAsymmetricKey or PublicKeyInfo ASN1 maps');
 503      }
 504  
 505      /**
 506       * Wrap a private key appropriately
 507       *
 508       * @access public
 509       * @param string $key
 510       * @param string $attr
 511       * @param mixed $params
 512       * @param string $password
 513       * @param string $oid optional
 514       * @param string $publicKey optional
 515       * @param array $options optional
 516       * @return string
 517       */
 518      protected static function wrapPrivateKey($key, $attr, $params, $password, $oid = null, $publicKey = '', array $options = [])
 519      {
 520          self::initialize_static_variables();
 521  
 522          $key = [
 523              'version' => 'v1',
 524              'privateKeyAlgorithm' => [
 525                  'algorithm' => is_string(static::OID_NAME) ? static::OID_NAME : $oid
 526               ],
 527              'privateKey' => $key
 528          ];
 529          if ($oid != 'id-Ed25519' && $oid != 'id-Ed448') {
 530              $key['privateKeyAlgorithm']['parameters'] = $params;
 531          }
 532          if (!empty($attr)) {
 533              $key['attributes'] = $attr;
 534          }
 535          if (!empty($publicKey)) {
 536              $key['version'] = 'v2';
 537              $key['publicKey'] = $publicKey;
 538          }
 539          $key = ASN1::encodeDER($key, Maps\OneAsymmetricKey::MAP);
 540          if (!empty($password) && is_string($password)) {
 541              $salt = Random::string(8);
 542  
 543              $iterationCount = isset($options['iterationCount']) ? $options['iterationCount'] : self::$defaultIterationCount;
 544              $encryptionAlgorithm = isset($options['encryptionAlgorithm']) ? $options['encryptionAlgorithm'] : self::$defaultEncryptionAlgorithm;
 545              $encryptionScheme = isset($options['encryptionScheme']) ? $options['encryptionScheme'] : self::$defaultEncryptionScheme;
 546              $prf = isset($options['PRF']) ? $options['PRF'] : self::$defaultPRF;
 547  
 548              if ($encryptionAlgorithm == 'id-PBES2') {
 549                  $crypto = self::getPBES2EncryptionObject($encryptionScheme);
 550                  $hash = str_replace('-', '/', substr($prf, 11));
 551                  $kdf = 'pbkdf2';
 552                  $iv = Random::string($crypto->getBlockLength() >> 3);
 553  
 554                  $PBKDF2params = [
 555                      'salt' => $salt,
 556                      'iterationCount' => $iterationCount,
 557                      'prf' => ['algorithm' => $prf, 'parameters' => null]
 558                  ];
 559                  $PBKDF2params = ASN1::encodeDER($PBKDF2params, Maps\PBKDF2params::MAP);
 560  
 561                  if (!$crypto instanceof RC2) {
 562                      $params = ['octetString' => $iv];
 563                  } else {
 564                      $params = [
 565                          'rc2ParametersVersion' => 58,
 566                          'iv' => $iv
 567                      ];
 568                      $params = ASN1::encodeDER($params, Maps\RC2CBCParameter::MAP);
 569                      $params = new ASN1\Element($params);
 570                  }
 571  
 572                  $params = [
 573                      'keyDerivationFunc' => [
 574                          'algorithm' => 'id-PBKDF2',
 575                          'parameters' => new ASN1\Element($PBKDF2params)
 576                      ],
 577                      'encryptionScheme' => [
 578                          'algorithm' => $encryptionScheme,
 579                          'parameters' => $params
 580                      ]
 581                  ];
 582                  $params = ASN1::encodeDER($params, Maps\PBES2params::MAP);
 583  
 584                  $crypto->setIV($iv);
 585              } else {
 586                  $crypto = self::getPBES1EncryptionObject($encryptionAlgorithm);
 587                  $hash = self::getPBES1Hash($encryptionAlgorithm);
 588                  $kdf = self::getPBES1KDF($encryptionAlgorithm);
 589  
 590                  $params = [
 591                      'salt' => $salt,
 592                      'iterationCount' => $iterationCount
 593                  ];
 594                  $params = ASN1::encodeDER($params, Maps\PBEParameter::MAP);
 595              }
 596              $crypto->setPassword($password, $kdf, $hash, $salt, $iterationCount);
 597              $key = $crypto->encrypt($key);
 598  
 599              $key = [
 600                  'encryptionAlgorithm' => [
 601                      'algorithm' => $encryptionAlgorithm,
 602                      'parameters' => new ASN1\Element($params)
 603                  ],
 604                  'encryptedData' => $key
 605              ];
 606  
 607              $key = ASN1::encodeDER($key, Maps\EncryptedPrivateKeyInfo::MAP);
 608  
 609              return "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
 610                     chunk_split(Base64::encode($key), 64) .
 611                     "-----END ENCRYPTED PRIVATE KEY-----";
 612          }
 613  
 614          return "-----BEGIN PRIVATE KEY-----\r\n" .
 615                 chunk_split(Base64::encode($key), 64) .
 616                 "-----END PRIVATE KEY-----";
 617      }
 618  
 619      /**
 620       * Wrap a public key appropriately
 621       *
 622       * @access public
 623       * @param string $key
 624       * @param mixed $params
 625       * @param string $oid
 626       * @return string
 627       */
 628      protected static function wrapPublicKey($key, $params, $oid = null)
 629      {
 630          self::initialize_static_variables();
 631  
 632          $key = [
 633              'publicKeyAlgorithm' => [
 634                  'algorithm' => is_string(static::OID_NAME) ? static::OID_NAME : $oid,
 635                  'parameters' => $params
 636              ],
 637              'publicKey' => "\0" . $key
 638          ];
 639  
 640          $key = ASN1::encodeDER($key, Maps\PublicKeyInfo::MAP);
 641  
 642          return "-----BEGIN PUBLIC KEY-----\r\n" .
 643                 chunk_split(Base64::encode($key), 64) .
 644                 "-----END PUBLIC KEY-----";
 645      }
 646  
 647      /**
 648       * Perform some preliminary parsing of the key
 649       *
 650       * @param string $key
 651       * @return array
 652       */
 653      private static function preParse(&$key)
 654      {
 655          self::initialize_static_variables();
 656  
 657          if (!Strings::is_stringable($key)) {
 658              throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
 659          }
 660  
 661          if (self::$format != self::MODE_DER) {
 662              $decoded = ASN1::extractBER($key);
 663              if ($decoded !== false) {
 664                  $key = $decoded;
 665              } elseif (self::$format == self::MODE_PEM) {
 666                  throw new \UnexpectedValueException('Expected base64-encoded PEM format but was unable to decode base64 text');
 667              }
 668          }
 669  
 670          $decoded = ASN1::decodeBER($key);
 671          if (empty($decoded)) {
 672              throw new \RuntimeException('Unable to decode BER');
 673          }
 674  
 675          return $decoded;
 676      }
 677  
 678      /**
 679       * Returns the encryption parameters used by the key
 680       *
 681       * @param string $key
 682       * @return array
 683       */
 684      public static function extractEncryptionAlgorithm($key)
 685      {
 686          $decoded = self::preParse($key);
 687  
 688          $r = ASN1::asn1map($decoded[0], ASN1\Maps\EncryptedPrivateKeyInfo::MAP);
 689          if (!is_array($r)) {
 690              throw new \RuntimeException('Unable to parse using EncryptedPrivateKeyInfo map');
 691          }
 692  
 693          if ($r['encryptionAlgorithm']['algorithm'] == 'id-PBES2') {
 694              $decoded = ASN1::decodeBER($r['encryptionAlgorithm']['parameters']->element);
 695              $r['encryptionAlgorithm']['parameters'] = ASN1::asn1map($decoded[0], ASN1\Maps\PBES2params::MAP);
 696  
 697              $kdf = &$r['encryptionAlgorithm']['parameters']['keyDerivationFunc'];
 698              switch ($kdf['algorithm']) {
 699                  case 'id-PBKDF2':
 700                      $decoded = ASN1::decodeBER($kdf['parameters']->element);
 701                      $kdf['parameters'] = ASN1::asn1map($decoded[0], Maps\PBKDF2params::MAP);
 702              }
 703          }
 704  
 705          return $r['encryptionAlgorithm'];
 706      }
 707  }


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