Subversion Repositories oidplus

Rev

Rev 846 | Rev 1042 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. <?php
  2.  
  3. /**
  4.  * PKCS#8 Formatted DSA Key Handler
  5.  *
  6.  * PHP version 5
  7.  *
  8.  * Processes keys with the following headers:
  9.  *
  10.  * -----BEGIN ENCRYPTED PRIVATE KEY-----
  11.  * -----BEGIN PRIVATE KEY-----
  12.  * -----BEGIN PUBLIC KEY-----
  13.  *
  14.  * Analogous to ssh-keygen's pkcs8 format (as specified by -m). Although PKCS8
  15.  * is specific to private keys it's basically creating a DER-encoded wrapper
  16.  * for keys. This just extends that same concept to public keys (much like ssh-keygen)
  17.  *
  18.  * @category  Crypt
  19.  * @package   DSA
  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\DSA\Formats\Keys;
  27.  
  28. use phpseclib3\Common\Functions\Strings;
  29. use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor;
  30. use phpseclib3\File\ASN1;
  31. use phpseclib3\File\ASN1\Maps;
  32. use phpseclib3\Math\BigInteger;
  33.  
  34. /**
  35.  * PKCS#8 Formatted DSA Key Handler
  36.  *
  37.  * @package DSA
  38.  * @author  Jim Wigginton <terrafrost@php.net>
  39.  * @access  public
  40.  */
  41. abstract class PKCS8 extends Progenitor
  42. {
  43.     /**
  44.      * OID Name
  45.      *
  46.      * @var string
  47.      * @access private
  48.      */
  49.     const OID_NAME = 'id-dsa';
  50.  
  51.     /**
  52.      * OID Value
  53.      *
  54.      * @var string
  55.      * @access private
  56.      */
  57.     const OID_VALUE = '1.2.840.10040.4.1';
  58.  
  59.     /**
  60.      * Child OIDs loaded
  61.      *
  62.      * @var bool
  63.      * @access private
  64.      */
  65.     protected static $childOIDsLoaded = false;
  66.  
  67.     /**
  68.      * Break a public or private key down into its constituent components
  69.      *
  70.      * @access public
  71.      * @param string $key
  72.      * @param string $password optional
  73.      * @return array
  74.      */
  75.     public static function load($key, $password = '')
  76.     {
  77.         if (!Strings::is_stringable($key)) {
  78.             throw new \UnexpectedValueException('Key should be a string - not a ' . gettype($key));
  79.         }
  80.  
  81.         $isPublic = strpos($key, 'PUBLIC') !== false;
  82.  
  83.         $key = parent::load($key, $password);
  84.  
  85.         $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey';
  86.  
  87.         switch (true) {
  88.             case !$isPublic && $type == 'publicKey':
  89.                 throw new \UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key');
  90.             case $isPublic && $type == 'privateKey':
  91.                 throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key');
  92.         }
  93.  
  94.         $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element);
  95.         if (empty($decoded)) {
  96.             throw new \RuntimeException('Unable to decode BER of parameters');
  97.         }
  98.         $components = ASN1::asn1map($decoded[0], Maps\DSAParams::MAP);
  99.         if (!is_array($components)) {
  100.             throw new \RuntimeException('Unable to perform ASN1 mapping on parameters');
  101.         }
  102.  
  103.         $decoded = ASN1::decodeBER($key[$type]);
  104.         if (empty($decoded)) {
  105.             throw new \RuntimeException('Unable to decode BER');
  106.         }
  107.  
  108.         $var = $type == 'privateKey' ? 'x' : 'y';
  109.         $components[$var] = ASN1::asn1map($decoded[0], Maps\DSAPublicKey::MAP);
  110.         if (!$components[$var] instanceof BigInteger) {
  111.             throw new \RuntimeException('Unable to perform ASN1 mapping');
  112.         }
  113.  
  114.         if (isset($key['meta'])) {
  115.             $components['meta'] = $key['meta'];
  116.         }
  117.  
  118.         return $components;
  119.     }
  120.  
  121.     /**
  122.      * Convert a private key to the appropriate format.
  123.      *
  124.      * @access public
  125.      * @param \phpseclib3\Math\BigInteger $p
  126.      * @param \phpseclib3\Math\BigInteger $q
  127.      * @param \phpseclib3\Math\BigInteger $g
  128.      * @param \phpseclib3\Math\BigInteger $y
  129.      * @param \phpseclib3\Math\BigInteger $x
  130.      * @param string $password optional
  131.      * @param array $options optional
  132.      * @return string
  133.      */
  134.     public static function savePrivateKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, BigInteger $x, $password = '', array $options = [])
  135.     {
  136.         $params = [
  137.             'p' => $p,
  138.             'q' => $q,
  139.             'g' => $g
  140.         ];
  141.         $params = ASN1::encodeDER($params, Maps\DSAParams::MAP);
  142.         $params = new ASN1\Element($params);
  143.         $key = ASN1::encodeDER($x, Maps\DSAPublicKey::MAP);
  144.         return self::wrapPrivateKey($key, [], $params, $password, null, '', $options);
  145.     }
  146.  
  147.     /**
  148.      * Convert a public key to the appropriate format
  149.      *
  150.      * @access public
  151.      * @param \phpseclib3\Math\BigInteger $p
  152.      * @param \phpseclib3\Math\BigInteger $q
  153.      * @param \phpseclib3\Math\BigInteger $g
  154.      * @param \phpseclib3\Math\BigInteger $y
  155.      * @param array $options optional
  156.      * @return string
  157.      */
  158.     public static function savePublicKey(BigInteger $p, BigInteger $q, BigInteger $g, BigInteger $y, array $options = [])
  159.     {
  160.         $params = [
  161.             'p' => $p,
  162.             'q' => $q,
  163.             'g' => $g
  164.         ];
  165.         $params = ASN1::encodeDER($params, Maps\DSAParams::MAP);
  166.         $params = new ASN1\Element($params);
  167.         $key = ASN1::encodeDER($y, Maps\DSAPublicKey::MAP);
  168.         return self::wrapPublicKey($key, $params);
  169.     }
  170. }
  171.