Subversion Repositories oidplus

Rev

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

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