1<?php
2
3/**
4 * Pure-PHP (EC)DH implementation
5 *
6 * PHP version 5
7 *
8 * Here's an example of how to compute a shared secret with this library:
9 * <code>
10 * <?php
11 * include 'vendor/autoload.php';
12 *
13 * $ourPrivate = \phpseclib3\Crypt\DH::createKey();
14 * $secret = DH::computeSecret($ourPrivate, $theirPublic);
15 *
16 * ?>
17 * </code>
18 *
19 * @author    Jim Wigginton <terrafrost@php.net>
20 * @copyright 2016 Jim Wigginton
21 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
22 * @link      http://phpseclib.sourceforge.net
23 */
24
25namespace phpseclib3\Crypt;
26
27use phpseclib3\Crypt\Common\AsymmetricKey;
28use phpseclib3\Crypt\DH\Parameters;
29use phpseclib3\Crypt\DH\PrivateKey;
30use phpseclib3\Crypt\DH\PublicKey;
31use phpseclib3\Exception\NoKeyLoadedException;
32use phpseclib3\Exception\UnsupportedOperationException;
33use phpseclib3\Math\BigInteger;
34
35/**
36 * Pure-PHP (EC)DH implementation
37 *
38 * @author  Jim Wigginton <terrafrost@php.net>
39 */
40abstract class DH extends AsymmetricKey
41{
42    /**
43     * Algorithm Name
44     *
45     * @var string
46     */
47    const ALGORITHM = 'DH';
48
49    /**
50     * DH prime
51     *
52     * @var \phpseclib3\Math\BigInteger
53     */
54    protected $prime;
55
56    /**
57     * DH Base
58     *
59     * Prime divisor of p-1
60     *
61     * @var \phpseclib3\Math\BigInteger
62     */
63    protected $base;
64
65    /**
66     * Public Key
67     *
68     * @var \phpseclib3\Math\BigInteger
69     */
70    protected $publicKey;
71
72    /**
73     * Create DH parameters
74     *
75     * This method is a bit polymorphic. It can take any of the following:
76     *  - two BigInteger's (prime and base)
77     *  - an integer representing the size of the prime in bits (the base is assumed to be 2)
78     *  - a string (eg. diffie-hellman-group14-sha1)
79     *
80     * @return Parameters
81     */
82    public static function createParameters(...$args)
83    {
84        $class = new \ReflectionClass(static::class);
85        if ($class->isFinal()) {
86            throw new \RuntimeException('createParameters() should not be called from final classes (' . static::class . ')');
87        }
88
89        $params = new Parameters();
90        if (count($args) == 2 && $args[0] instanceof BigInteger && $args[1] instanceof BigInteger) {
91            //if (!$args[0]->isPrime()) {
92            //    throw new \InvalidArgumentException('The first parameter should be a prime number');
93            //}
94            $params->prime = $args[0];
95            $params->base = $args[1];
96            return $params;
97        } elseif (count($args) == 1 && is_numeric($args[0])) {
98            $params->prime = BigInteger::randomPrime($args[0]);
99            $params->base = new BigInteger(2);
100            return $params;
101        } elseif (count($args) != 1 || !is_string($args[0])) {
102            throw new \InvalidArgumentException('Valid parameters are either: two BigInteger\'s (prime and base), a single integer (the length of the prime; base is assumed to be 2) or a string');
103        }
104        switch ($args[0]) {
105            // see http://tools.ietf.org/html/rfc2409#section-6.2 and
106            // http://tools.ietf.org/html/rfc2412, appendex E
107            case 'diffie-hellman-group1-sha1':
108                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
109                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
110                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
111                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF';
112                break;
113            // see http://tools.ietf.org/html/rfc3526#section-3
114            case 'diffie-hellman-group14-sha1': // 2048-bit MODP Group
115            case 'diffie-hellman-group14-sha256':
116                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
117                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
118                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
119                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
120                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
121                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
122                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
123                         '3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF';
124                break;
125            // see https://tools.ietf.org/html/rfc3526#section-4
126            case 'diffie-hellman-group15-sha512': // 3072-bit MODP Group
127                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
128                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
129                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
130                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
131                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
132                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
133                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
134                         '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
135                         'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
136                         'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
137                         'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
138                         '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF';
139                break;
140            // see https://tools.ietf.org/html/rfc3526#section-5
141            case 'diffie-hellman-group16-sha512': // 4096-bit MODP Group
142                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
143                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
144                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
145                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
146                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
147                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
148                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
149                         '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
150                         'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
151                         'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
152                         'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
153                         '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' .
154                         '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' .
155                         'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' .
156                         '233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' .
157                         '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF';
158                break;
159            // see https://tools.ietf.org/html/rfc3526#section-6
160            case 'diffie-hellman-group17-sha512': // 6144-bit MODP Group
161                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
162                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
163                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
164                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
165                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
166                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
167                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
168                         '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
169                         'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
170                         'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
171                         'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
172                         '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' .
173                         '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' .
174                         'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' .
175                         '233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' .
176                         '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026' .
177                         'C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AE' .
178                         'B06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B' .
179                         'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92EC' .
180                         'F032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E' .
181                         '59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA' .
182                         'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76' .
183                         'F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468' .
184                         '043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF';
185                break;
186            // see https://tools.ietf.org/html/rfc3526#section-7
187            case 'diffie-hellman-group18-sha512': // 8192-bit MODP Group
188                $prime = 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
189                         '020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
190                         '4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
191                         'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
192                         '98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
193                         '9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
194                         'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
195                         '3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33' .
196                         'A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7' .
197                         'ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864' .
198                         'D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E2' .
199                         '08E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7' .
200                         '88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8' .
201                         'DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2' .
202                         '233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9' .
203                         '93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026' .
204                         'C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AE' .
205                         'B06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B' .
206                         'DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92EC' .
207                         'F032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E' .
208                         '59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA' .
209                         'CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76' .
210                         'F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468' .
211                         '043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4' .
212                         '38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED' .
213                         '2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652D' .
214                         'E3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B' .
215                         '4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A6' .
216                         '6D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851D' .
217                         'F9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92' .
218                         '4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA' .
219                         '9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF';
220                break;
221            default:
222                throw new \InvalidArgumentException('Invalid named prime provided');
223        }
224
225        $params->prime = new BigInteger($prime, 16);
226        $params->base = new BigInteger(2);
227
228        return $params;
229    }
230
231    /**
232     * Create public / private key pair.
233     *
234     * The rationale for the second parameter is described in http://tools.ietf.org/html/rfc4419#section-6.2 :
235     *
236     * "To increase the speed of the key exchange, both client and server may
237     *  reduce the size of their private exponents.  It should be at least
238     *  twice as long as the key material that is generated from the shared
239     *  secret.  For more details, see the paper by van Oorschot and Wiener
240     *  [VAN-OORSCHOT]."
241     *
242     * $length is in bits
243     *
244     * @param Parameters $params
245     * @param int $length optional
246     * @return DH\PrivateKey
247     */
248    public static function createKey(Parameters $params, $length = 0)
249    {
250        $class = new \ReflectionClass(static::class);
251        if ($class->isFinal()) {
252            throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')');
253        }
254
255        $one = new BigInteger(1);
256        if ($length) {
257            $max = $one->bitwise_leftShift($length);
258            $max = $max->subtract($one);
259        } else {
260            $max = $params->prime->subtract($one);
261        }
262
263        $key = new PrivateKey();
264        $key->prime = $params->prime;
265        $key->base = $params->base;
266        $key->privateKey = BigInteger::randomRange($one, $max);
267        $key->publicKey = $key->base->powMod($key->privateKey, $key->prime);
268        return $key;
269    }
270
271    /**
272     * Compute Shared Secret
273     *
274     * @param PrivateKey|EC $private
275     * @param PublicKey|BigInteger|string $public
276     * @return mixed
277     */
278    public static function computeSecret($private, $public)
279    {
280        if ($private instanceof PrivateKey) { // DH\PrivateKey
281            switch (true) {
282                case $public instanceof PublicKey:
283                    if (!$private->prime->equals($public->prime) || !$private->base->equals($public->base)) {
284                        throw new \InvalidArgumentException('The public and private key do not share the same prime and / or base numbers');
285                    }
286                    return $public->publicKey->powMod($private->privateKey, $private->prime)->toBytes(true);
287                case is_string($public):
288                    $public = new BigInteger($public, -256);
289                    // fall-through
290                case $public instanceof BigInteger:
291                    return $public->powMod($private->privateKey, $private->prime)->toBytes(true);
292                default:
293                    throw new \InvalidArgumentException('$public needs to be an instance of DH\PublicKey, a BigInteger or a string');
294            }
295        }
296
297        if ($private instanceof EC\PrivateKey) {
298            switch (true) {
299                case $public instanceof EC\PublicKey:
300                    $public = $public->getEncodedCoordinates();
301                    // fall-through
302                case is_string($public):
303                    $point = $private->multiply($public);
304                    switch ($private->getCurve()) {
305                        case 'Curve25519':
306                        case 'Curve448':
307                            $secret = $point;
308                            break;
309                        default:
310                            // according to https://www.secg.org/sec1-v2.pdf#page=33 only X is returned
311                            $secret = substr($point, 1, (strlen($point) - 1) >> 1);
312                    }
313                    /*
314                    if (($secret[0] & "\x80") === "\x80") {
315                        $secret = "\0$secret";
316                    }
317                    */
318                    return $secret;
319                default:
320                    throw new \InvalidArgumentException('$public needs to be an instance of EC\PublicKey or a string (an encoded coordinate)');
321            }
322        }
323    }
324
325    /**
326     * Load the key
327     *
328     * @param string $key
329     * @param string $password optional
330     * @return AsymmetricKey
331     */
332    public static function load($key, $password = false)
333    {
334        try {
335            return EC::load($key, $password);
336        } catch (NoKeyLoadedException $e) {
337        }
338
339        return parent::load($key, $password);
340    }
341
342    /**
343     * OnLoad Handler
344     *
345     * @return bool
346     */
347    protected static function onLoad(array $components)
348    {
349        if (!isset($components['privateKey']) && !isset($components['publicKey'])) {
350            $new = new Parameters();
351        } else {
352            $new = isset($components['privateKey']) ?
353                new PrivateKey() :
354                new PublicKey();
355        }
356
357        $new->prime = $components['prime'];
358        $new->base = $components['base'];
359
360        if (isset($components['privateKey'])) {
361            $new->privateKey = $components['privateKey'];
362        }
363        if (isset($components['publicKey'])) {
364            $new->publicKey = $components['publicKey'];
365        }
366
367        return $new;
368    }
369
370    /**
371     * Determines which hashing function should be used
372     *
373     * @param string $hash
374     */
375    public function withHash($hash)
376    {
377        throw new UnsupportedOperationException('DH does not use a hash algorithm');
378    }
379
380    /**
381     * Returns the hash algorithm currently being used
382     *
383     */
384    public function getHash()
385    {
386        throw new UnsupportedOperationException('DH does not use a hash algorithm');
387    }
388
389    /**
390     * Returns the parameters
391     *
392     * A public / private key is only returned if the currently loaded "key" contains an x or y
393     * value.
394     *
395     * @see self::getPublicKey()
396     * @return mixed
397     */
398    public function getParameters()
399    {
400        $type = DH::validatePlugin('Keys', 'PKCS1', 'saveParameters');
401
402        $key = $type::saveParameters($this->prime, $this->base);
403        return DH::load($key, 'PKCS1');
404    }
405}
406