Subversion Repositories oidplus

Rev

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

  1. <?php
  2.  
  3. /**
  4.  * PuTTY Formatted EC Key Handler
  5.  *
  6.  * PHP version 5
  7.  *
  8.  * @category  Crypt
  9.  * @package   EC
  10.  * @author    Jim Wigginton <terrafrost@php.net>
  11.  * @copyright 2015 Jim Wigginton
  12.  * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
  13.  * @link      http://phpseclib.sourceforge.net
  14.  */
  15.  
  16. namespace phpseclib3\Crypt\EC\Formats\Keys;
  17.  
  18. use ParagonIE\ConstantTime\Base64;
  19. use phpseclib3\Common\Functions\Strings;
  20. use phpseclib3\Crypt\Common\Formats\Keys\PuTTY as Progenitor;
  21. use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve;
  22. use phpseclib3\Crypt\EC\BaseCurves\TwistedEdwards as TwistedEdwardsCurve;
  23. use phpseclib3\Math\BigInteger;
  24.  
  25. /**
  26.  * PuTTY Formatted EC Key Handler
  27.  *
  28.  * @package EC
  29.  * @author  Jim Wigginton <terrafrost@php.net>
  30.  * @access  public
  31.  */
  32. abstract class PuTTY extends Progenitor
  33. {
  34.     use Common;
  35.  
  36.     /**
  37.      * Public Handler
  38.      *
  39.      * @var string
  40.      * @access private
  41.      */
  42.     const PUBLIC_HANDLER = 'phpseclib3\Crypt\EC\Formats\Keys\OpenSSH';
  43.  
  44.     /**
  45.      * Supported Key Types
  46.      *
  47.      * @var array
  48.      * @access private
  49.      */
  50.     protected static $types = [
  51.         'ecdsa-sha2-nistp256',
  52.         'ecdsa-sha2-nistp384',
  53.         'ecdsa-sha2-nistp521',
  54.         'ssh-ed25519'
  55.     ];
  56.  
  57.     /**
  58.      * Break a public or private key down into its constituent components
  59.      *
  60.      * @access public
  61.      * @param string $key
  62.      * @param string $password optional
  63.      * @return array
  64.      */
  65.     public static function load($key, $password = '')
  66.     {
  67.         $components = parent::load($key, $password);
  68.         if (!isset($components['private'])) {
  69.             return $components;
  70.         }
  71.  
  72.         $private = $components['private'];
  73.  
  74.         $temp = Base64::encode(Strings::packSSH2('s', $components['type']) . $components['public']);
  75.         $components = OpenSSH::load($components['type'] . ' ' . $temp . ' ' . $components['comment']);
  76.  
  77.         if ($components['curve'] instanceof TwistedEdwardsCurve) {
  78.             if (Strings::shift($private, 4) != "\0\0\0\x20") {
  79.                 throw new \RuntimeException('Length of ssh-ed25519 key should be 32');
  80.             }
  81.             $components['dA'] = $components['curve']->extractSecret($private);
  82.         } else {
  83.             list($components['dA']) = Strings::unpackSSH2('i', $private);
  84.             $components['curve']->rangeCheck($components['dA']);
  85.         }
  86.  
  87.         return $components;
  88.     }
  89.  
  90.     /**
  91.      * Convert a private key to the appropriate format.
  92.      *
  93.      * @access public
  94.      * @param \phpseclib3\Math\BigInteger $privateKey
  95.      * @param \phpseclib3\Crypt\EC\BaseCurves\Base $curve
  96.      * @param \phpseclib3\Math\Common\FiniteField\Integer[] $publicKey
  97.      * @param string $password optional
  98.      * @param array $options optional
  99.      * @return string
  100.      */
  101.     public static function savePrivateKey(BigInteger $privateKey, BaseCurve $curve, array $publicKey, $password = false, array $options = [])
  102.     {
  103.         self::initialize_static_variables();
  104.  
  105.         $public = explode(' ', OpenSSH::savePublicKey($curve, $publicKey));
  106.         $name = $public[0];
  107.         $public = Base64::decode($public[1]);
  108.         list(, $length) = unpack('N', Strings::shift($public, 4));
  109.         Strings::shift($public, $length);
  110.  
  111.         // PuTTY pads private keys with a null byte per the following:
  112.         // https://github.com/github/putty/blob/a3d14d77f566a41fc61dfdc5c2e0e384c9e6ae8b/sshecc.c#L1926
  113.         if (!$curve instanceof TwistedEdwardsCurve) {
  114.             $private = $privateKey->toBytes();
  115.             if (!(strlen($privateKey->toBits()) & 7)) {
  116.                 $private = "\0$private";
  117.             }
  118.         }
  119.  
  120.         $private = $curve instanceof TwistedEdwardsCurve ?
  121.             Strings::packSSH2('s', $privateKey->secret) :
  122.             Strings::packSSH2('s', $private);
  123.  
  124.         return self::wrapPrivateKey($public, $private, $name, $password, $options);
  125.     }
  126.  
  127.     /**
  128.      * Convert an EC public key to the appropriate format
  129.      *
  130.      * @access public
  131.      * @param \phpseclib3\Crypt\EC\BaseCurves\Base $curve
  132.      * @param \phpseclib3\Math\Common\FiniteField[] $publicKey
  133.      * @return string
  134.      */
  135.     public static function savePublicKey(BaseCurve $curve, array $publicKey)
  136.     {
  137.         $public = explode(' ', OpenSSH::savePublicKey($curve, $publicKey));
  138.         $type = $public[0];
  139.         $public = Base64::decode($public[1]);
  140.         list(, $length) = unpack('N', Strings::shift($public, 4));
  141.         Strings::shift($public, $length);
  142.  
  143.         return self::wrapPublicKey($public, $type);
  144.     }
  145. }
  146.