1<?php
2
3/**
4 * OpenSSH Formatted RSA Key Handler
5 *
6 * PHP version 5
7 *
8 * Place in $HOME/.ssh/authorized_keys
9 *
10 * @category  Crypt
11 * @package   RSA
12 * @author    Jim Wigginton <terrafrost@php.net>
13 * @copyright 2015 Jim Wigginton
14 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
15 * @link      http://phpseclib.sourceforge.net
16 */
17
18namespace phpseclib3\Crypt\RSA\Formats\Keys;
19
20use phpseclib3\Common\Functions\Strings;
21use phpseclib3\Crypt\Common\Formats\Keys\OpenSSH as Progenitor;
22use phpseclib3\Math\BigInteger;
23
24/**
25 * OpenSSH Formatted RSA Key Handler
26 *
27 * @package RSA
28 * @author  Jim Wigginton <terrafrost@php.net>
29 * @access  public
30 */
31abstract class OpenSSH extends Progenitor
32{
33    /**
34     * Supported Key Types
35     *
36     * @var array
37     */
38    protected static $types = ['ssh-rsa'];
39
40    /**
41     * Break a public or private key down into its constituent components
42     *
43     * @access public
44     * @param string $key
45     * @param string $password optional
46     * @return array
47     */
48    public static function load($key, $password = '')
49    {
50        static $one;
51        if (!isset($one)) {
52            $one = new BigInteger(1);
53        }
54
55        $parsed = parent::load($key, $password);
56
57        if (isset($parsed['paddedKey'])) {
58            list($type) = Strings::unpackSSH2('s', $parsed['paddedKey']);
59            if ($type != $parsed['type']) {
60                throw new \RuntimeException("The public and private keys are not of the same type ($type vs $parsed[type])");
61            }
62
63            $primes = $coefficients = [];
64
65            list(
66                $modulus,
67                $publicExponent,
68                $privateExponent,
69                $coefficients[2],
70                $primes[1],
71                $primes[2],
72                $comment,
73            ) = Strings::unpackSSH2('i6s', $parsed['paddedKey']);
74
75            $temp = $primes[1]->subtract($one);
76            $exponents = [1 => $publicExponent->modInverse($temp)];
77            $temp = $primes[2]->subtract($one);
78            $exponents[] = $publicExponent->modInverse($temp);
79
80            $isPublicKey = false;
81
82            return compact('publicExponent', 'modulus', 'privateExponent', 'primes', 'coefficients', 'exponents', 'comment', 'isPublicKey');
83        }
84
85        list($publicExponent, $modulus) = Strings::unpackSSH2('ii', $parsed['publicKey']);
86
87        return [
88            'isPublicKey' => true,
89            'modulus' => $modulus,
90            'publicExponent' => $publicExponent,
91            'comment' => $parsed['comment']
92        ];
93    }
94
95    /**
96     * Convert a public key to the appropriate format
97     *
98     * @access public
99     * @param \phpseclib3\Math\BigInteger $n
100     * @param \phpseclib3\Math\BigInteger $e
101     * @param array $options optional
102     * @return string
103     */
104    public static function savePublicKey(BigInteger $n, BigInteger $e, array $options = [])
105    {
106        $RSAPublicKey = Strings::packSSH2('sii', 'ssh-rsa', $e, $n);
107
108        if (isset($options['binary']) ? $options['binary'] : self::$binary) {
109            return $RSAPublicKey;
110        }
111
112        $comment = isset($options['comment']) ? $options['comment'] : self::$comment;
113        $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $comment;
114
115        return $RSAPublicKey;
116    }
117
118    /**
119     * Convert a private key to the appropriate format.
120     *
121     * @access public
122     * @param \phpseclib3\Math\BigInteger $n
123     * @param \phpseclib3\Math\BigInteger $e
124     * @param \phpseclib3\Math\BigInteger $d
125     * @param array $primes
126     * @param array $exponents
127     * @param array $coefficients
128     * @param string $password optional
129     * @param array $options optional
130     * @return string
131     */
132    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
133    {
134        $publicKey = self::savePublicKey($n, $e, ['binary' => true]);
135        $privateKey = Strings::packSSH2('si6', 'ssh-rsa', $n, $e, $d, $coefficients[2], $primes[1], $primes[2]);
136
137        return self::wrapPrivateKey($publicKey, $privateKey, $password, $options);
138    }
139}
140