1<?php
2
3/**
4 * PuTTY Formatted RSA Key Handler
5 *
6 * PHP version 5
7 *
8 * @category  Crypt
9 * @package   RSA
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
16namespace phpseclib3\Crypt\RSA\Formats\Keys;
17
18use phpseclib3\Common\Functions\Strings;
19use phpseclib3\Crypt\Common\Formats\Keys\PuTTY as Progenitor;
20use phpseclib3\Math\BigInteger;
21
22/**
23 * PuTTY Formatted RSA Key Handler
24 *
25 * @package RSA
26 * @author  Jim Wigginton <terrafrost@php.net>
27 * @access  public
28 */
29abstract class PuTTY extends Progenitor
30{
31    /**
32     * Public Handler
33     *
34     * @var string
35     * @access private
36     */
37    const PUBLIC_HANDLER = 'phpseclib3\Crypt\RSA\Formats\Keys\OpenSSH';
38
39    /**
40     * Algorithm Identifier
41     *
42     * @var array
43     * @access private
44     */
45    protected static $types = ['ssh-rsa'];
46
47    /**
48     * Break a public or private key down into its constituent components
49     *
50     * @access public
51     * @param string $key
52     * @param string $password optional
53     * @return array
54     */
55    public static function load($key, $password = '')
56    {
57        static $one;
58        if (!isset($one)) {
59            $one = new BigInteger(1);
60        }
61
62        $components = parent::load($key, $password);
63        if (!isset($components['private'])) {
64            return $components;
65        }
66        extract($components);
67        unset($components['public'], $components['private']);
68
69        $isPublicKey = false;
70
71        $result = Strings::unpackSSH2('ii', $public);
72        if ($result === false) {
73            throw new \UnexpectedValueException('Key appears to be malformed');
74        }
75        list($publicExponent, $modulus) = $result;
76
77        $result = Strings::unpackSSH2('iiii', $private);
78        if ($result === false) {
79            throw new \UnexpectedValueException('Key appears to be malformed');
80        }
81        $primes = $coefficients = [];
82        list($privateExponent, $primes[1], $primes[2], $coefficients[2]) = $result;
83
84        $temp = $primes[1]->subtract($one);
85        $exponents = [1 => $publicExponent->modInverse($temp)];
86        $temp = $primes[2]->subtract($one);
87        $exponents[] = $publicExponent->modInverse($temp);
88
89        return compact('publicExponent', 'modulus', 'privateExponent', 'primes', 'coefficients', 'exponents', 'comment', 'isPublicKey');
90    }
91
92    /**
93     * Convert a private key to the appropriate format.
94     *
95     * @access public
96     * @param \phpseclib3\Math\BigInteger $n
97     * @param \phpseclib3\Math\BigInteger $e
98     * @param \phpseclib3\Math\BigInteger $d
99     * @param array $primes
100     * @param array $exponents
101     * @param array $coefficients
102     * @param string $password optional
103     * @param array $options optional
104     * @return string
105     */
106    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
107    {
108        if (count($primes) != 2) {
109            throw new \InvalidArgumentException('PuTTY does not support multi-prime RSA keys');
110        }
111
112        $public =  Strings::packSSH2('ii', $e, $n);
113        $private = Strings::packSSH2('iiii', $d, $primes[1], $primes[2], $coefficients[2]);
114
115        return self::wrapPrivateKey($public, $private, 'ssh-rsa', $password, $options);
116    }
117
118    /**
119     * Convert a public key to the appropriate format
120     *
121     * @access public
122     * @param \phpseclib3\Math\BigInteger $n
123     * @param \phpseclib3\Math\BigInteger $e
124     * @return string
125     */
126    public static function savePublicKey(BigInteger $n, BigInteger $e)
127    {
128        return self::wrapPublicKey(Strings::packSSH2('ii', $e, $n), 'ssh-rsa');
129    }
130}
131