[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
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 25 namespace phpseclib3\Crypt; 26 27 use phpseclib3\Crypt\Common\AsymmetricKey; 28 use phpseclib3\Crypt\DH\Parameters; 29 use phpseclib3\Crypt\DH\PrivateKey; 30 use phpseclib3\Crypt\DH\PublicKey; 31 use phpseclib3\Exception\NoKeyLoadedException; 32 use phpseclib3\Exception\UnsupportedOperationException; 33 use phpseclib3\Math\BigInteger; 34 35 /** 36 * Pure-PHP (EC)DH implementation 37 * 38 * @author Jim Wigginton <terrafrost@php.net> 39 */ 40 abstract 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body