1<?php
2
3/**
4 * Raw RSA Key Handler
5 *
6 * PHP version 5
7 *
8 * An array containing two \phpseclib3\Math\BigInteger objects.
9 *
10 * The exponent can be indexed with any of the following:
11 *
12 * 0, e, exponent, publicExponent
13 *
14 * The modulus can be indexed with any of the following:
15 *
16 * 1, n, modulo, modulus
17 *
18 * @category  Crypt
19 * @package   RSA
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
26namespace phpseclib3\Crypt\RSA\Formats\Keys;
27
28use phpseclib3\Math\BigInteger;
29
30/**
31 * Raw RSA Key Handler
32 *
33 * @package RSA
34 * @author  Jim Wigginton <terrafrost@php.net>
35 * @access  public
36 */
37abstract class Raw
38{
39    /**
40     * Break a public or private key down into its constituent components
41     *
42     * @access public
43     * @param string $key
44     * @param string $password optional
45     * @return array
46     */
47    public static function load($key, $password = '')
48    {
49        if (!is_array($key)) {
50            throw new \UnexpectedValueException('Key should be a array - not a ' . gettype($key));
51        }
52
53        $key = array_change_key_case($key, CASE_LOWER);
54
55        $components = ['isPublicKey' => false];
56
57        foreach (['e', 'exponent', 'publicexponent', 0, 'privateexponent', 'd'] as $index) {
58            if (isset($key[$index])) {
59                $components['publicExponent'] = $key[$index];
60                break;
61            }
62        }
63
64        foreach (['n', 'modulo', 'modulus', 1] as $index) {
65            if (isset($key[$index])) {
66                $components['modulus'] = $key[$index];
67                break;
68            }
69        }
70
71        if (!isset($components['publicExponent']) || !isset($components['modulus'])) {
72            throw new \UnexpectedValueException('Modulus / exponent not present');
73        }
74
75        if (isset($key['primes'])) {
76            $components['primes'] = $key['primes'];
77        } elseif (isset($key['p']) && isset($key['q'])) {
78            $indices = [
79                ['p', 'q'],
80                ['prime1', 'prime2']
81            ];
82            foreach ($indices as $index) {
83                list($i0, $i1) = $index;
84                if (isset($key[$i0]) && isset($key[$i1])) {
85                    $components['primes'] = [1 => $key[$i0], $key[$i1]];
86                }
87            }
88        }
89
90        if (isset($key['exponents'])) {
91            $components['exponents'] = $key['exponents'];
92        } else {
93            $indices = [
94                ['dp', 'dq'],
95                ['exponent1', 'exponent2']
96            ];
97            foreach ($indices as $index) {
98                list($i0, $i1) = $index;
99                if (isset($key[$i0]) && isset($key[$i1])) {
100                    $components['exponents'] = [1 => $key[$i0], $key[$i1]];
101                }
102            }
103        }
104
105        if (isset($key['coefficients'])) {
106            $components['coefficients'] = $key['coefficients'];
107        } else {
108            foreach (['inverseq', 'q\'', 'coefficient'] as $index) {
109                if (isset($key[$index])) {
110                    $components['coefficients'] = [2 => $key[$index]];
111                }
112            }
113        }
114
115        if (!isset($components['primes'])) {
116            $components['isPublicKey'] = true;
117            return $components;
118        }
119
120        if (!isset($components['exponents'])) {
121            $one = new BigInteger(1);
122            $temp = $components['primes'][1]->subtract($one);
123            $exponents = [1 => $components['publicExponent']->modInverse($temp)];
124            $temp = $components['primes'][2]->subtract($one);
125            $exponents[] = $components['publicExponent']->modInverse($temp);
126            $components['exponents'] = $exponents;
127        }
128
129        if (!isset($components['coefficients'])) {
130            $components['coefficients'] = [2 => $components['primes'][2]->modInverse($components['primes'][1])];
131        }
132
133        foreach (['privateexponent', 'd'] as $index) {
134            if (isset($key[$index])) {
135                $components['privateExponent'] = $key[$index];
136                break;
137            }
138        }
139
140        return $components;
141    }
142
143    /**
144     * Convert a private key to the appropriate format.
145     *
146     * @access public
147     * @param \phpseclib3\Math\BigInteger $n
148     * @param \phpseclib3\Math\BigInteger $e
149     * @param \phpseclib3\Math\BigInteger $d
150     * @param array $primes
151     * @param array $exponents
152     * @param array $coefficients
153     * @param string $password optional
154     * @param array $options optional
155     * @return array
156     */
157    public static function savePrivateKey(BigInteger $n, BigInteger $e, BigInteger $d, array $primes, array $exponents, array $coefficients, $password = '', array $options = [])
158    {
159        if (!empty($password) && is_string($password)) {
160            throw new UnsupportedFormatException('Raw private keys do not support encryption');
161        }
162
163        return [
164            'e' => clone $e,
165            'n' => clone $n,
166            'd' => clone $d,
167            'primes' => array_map(function ($var) {
168                return clone $var;
169            }, $primes),
170            'exponents' => array_map(function ($var) {
171                return clone $var;
172            }, $exponents),
173            'coefficients' => array_map(function ($var) {
174                return clone $var;
175            }, $coefficients)
176        ];
177    }
178
179    /**
180     * Convert a public key to the appropriate format
181     *
182     * @access public
183     * @param \phpseclib3\Math\BigInteger $n
184     * @param \phpseclib3\Math\BigInteger $e
185     * @return array
186     */
187    public static function savePublicKey(BigInteger $n, BigInteger $e)
188    {
189        return ['e' => clone $e, 'n' => clone $n];
190    }
191}
192