[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 if (class_exists('ParagonIE_Sodium_Core_Ed25519', false)) { 4 return; 5 } 6 if (!class_exists('ParagonIE_Sodium_Core_Curve25519', false)) { 7 require_once dirname(__FILE__) . '/Curve25519.php'; 8 } 9 10 /** 11 * Class ParagonIE_Sodium_Core_Ed25519 12 */ 13 abstract class ParagonIE_Sodium_Core_Ed25519 extends ParagonIE_Sodium_Core_Curve25519 14 { 15 const KEYPAIR_BYTES = 96; 16 const SEED_BYTES = 32; 17 const SCALAR_BYTES = 32; 18 19 /** 20 * @internal You should not use this directly from another application 21 * 22 * @return string (96 bytes) 23 * @throws Exception 24 * @throws SodiumException 25 * @throws TypeError 26 */ 27 public static function keypair() 28 { 29 $seed = random_bytes(self::SEED_BYTES); 30 $pk = ''; 31 $sk = ''; 32 self::seed_keypair($pk, $sk, $seed); 33 return $sk . $pk; 34 } 35 36 /** 37 * @internal You should not use this directly from another application 38 * 39 * @param string $pk 40 * @param string $sk 41 * @param string $seed 42 * @return string 43 * @throws SodiumException 44 * @throws TypeError 45 */ 46 public static function seed_keypair(&$pk, &$sk, $seed) 47 { 48 if (self::strlen($seed) !== self::SEED_BYTES) { 49 throw new RangeException('crypto_sign keypair seed must be 32 bytes long'); 50 } 51 52 /** @var string $pk */ 53 $pk = self::publickey_from_secretkey($seed); 54 $sk = $seed . $pk; 55 return $sk; 56 } 57 58 /** 59 * @internal You should not use this directly from another application 60 * 61 * @param string $keypair 62 * @return string 63 * @throws TypeError 64 */ 65 public static function secretkey($keypair) 66 { 67 if (self::strlen($keypair) !== self::KEYPAIR_BYTES) { 68 throw new RangeException('crypto_sign keypair must be 96 bytes long'); 69 } 70 return self::substr($keypair, 0, 64); 71 } 72 73 /** 74 * @internal You should not use this directly from another application 75 * 76 * @param string $keypair 77 * @return string 78 * @throws TypeError 79 */ 80 public static function publickey($keypair) 81 { 82 if (self::strlen($keypair) !== self::KEYPAIR_BYTES) { 83 throw new RangeException('crypto_sign keypair must be 96 bytes long'); 84 } 85 return self::substr($keypair, 64, 32); 86 } 87 88 /** 89 * @internal You should not use this directly from another application 90 * 91 * @param string $sk 92 * @return string 93 * @throws SodiumException 94 * @throws TypeError 95 */ 96 public static function publickey_from_secretkey($sk) 97 { 98 /** @var string $sk */ 99 $sk = hash('sha512', self::substr($sk, 0, 32), true); 100 $sk[0] = self::intToChr( 101 self::chrToInt($sk[0]) & 248 102 ); 103 $sk[31] = self::intToChr( 104 (self::chrToInt($sk[31]) & 63) | 64 105 ); 106 return self::sk_to_pk($sk); 107 } 108 109 /** 110 * @param string $pk 111 * @return string 112 * @throws SodiumException 113 * @throws TypeError 114 */ 115 public static function pk_to_curve25519($pk) 116 { 117 if (self::small_order($pk)) { 118 throw new SodiumException('Public key is on a small order'); 119 } 120 $A = self::ge_frombytes_negate_vartime(self::substr($pk, 0, 32)); 121 $p1 = self::ge_mul_l($A); 122 if (!self::fe_isnonzero($p1->X)) { 123 throw new SodiumException('Unexpected zero result'); 124 } 125 126 # fe_1(one_minus_y); 127 # fe_sub(one_minus_y, one_minus_y, A.Y); 128 # fe_invert(one_minus_y, one_minus_y); 129 $one_minux_y = self::fe_invert( 130 self::fe_sub( 131 self::fe_1(), 132 $A->Y 133 ) 134 ); 135 136 # fe_1(x); 137 # fe_add(x, x, A.Y); 138 # fe_mul(x, x, one_minus_y); 139 $x = self::fe_mul( 140 self::fe_add(self::fe_1(), $A->Y), 141 $one_minux_y 142 ); 143 144 # fe_tobytes(curve25519_pk, x); 145 return self::fe_tobytes($x); 146 } 147 148 /** 149 * @internal You should not use this directly from another application 150 * 151 * @param string $sk 152 * @return string 153 * @throws SodiumException 154 * @throws TypeError 155 */ 156 public static function sk_to_pk($sk) 157 { 158 return self::ge_p3_tobytes( 159 self::ge_scalarmult_base( 160 self::substr($sk, 0, 32) 161 ) 162 ); 163 } 164 165 /** 166 * @internal You should not use this directly from another application 167 * 168 * @param string $message 169 * @param string $sk 170 * @return string 171 * @throws SodiumException 172 * @throws TypeError 173 */ 174 public static function sign($message, $sk) 175 { 176 /** @var string $signature */ 177 $signature = self::sign_detached($message, $sk); 178 return $signature . $message; 179 } 180 181 /** 182 * @internal You should not use this directly from another application 183 * 184 * @param string $message A signed message 185 * @param string $pk Public key 186 * @return string Message (without signature) 187 * @throws SodiumException 188 * @throws TypeError 189 */ 190 public static function sign_open($message, $pk) 191 { 192 /** @var string $signature */ 193 $signature = self::substr($message, 0, 64); 194 195 /** @var string $message */ 196 $message = self::substr($message, 64); 197 198 if (self::verify_detached($signature, $message, $pk)) { 199 return $message; 200 } 201 throw new SodiumException('Invalid signature'); 202 } 203 204 /** 205 * @internal You should not use this directly from another application 206 * 207 * @param string $message 208 * @param string $sk 209 * @return string 210 * @throws SodiumException 211 * @throws TypeError 212 */ 213 public static function sign_detached($message, $sk) 214 { 215 # crypto_hash_sha512(az, sk, 32); 216 $az = hash('sha512', self::substr($sk, 0, 32), true); 217 218 # az[0] &= 248; 219 # az[31] &= 63; 220 # az[31] |= 64; 221 $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); 222 $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); 223 224 # crypto_hash_sha512_init(&hs); 225 # crypto_hash_sha512_update(&hs, az + 32, 32); 226 # crypto_hash_sha512_update(&hs, m, mlen); 227 # crypto_hash_sha512_final(&hs, nonce); 228 $hs = hash_init('sha512'); 229 hash_update($hs, self::substr($az, 32, 32)); 230 hash_update($hs, $message); 231 $nonceHash = hash_final($hs, true); 232 233 # memmove(sig + 32, sk + 32, 32); 234 $pk = self::substr($sk, 32, 32); 235 236 # sc_reduce(nonce); 237 # ge_scalarmult_base(&R, nonce); 238 # ge_p3_tobytes(sig, &R); 239 $nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32); 240 $sig = self::ge_p3_tobytes( 241 self::ge_scalarmult_base($nonce) 242 ); 243 244 # crypto_hash_sha512_init(&hs); 245 # crypto_hash_sha512_update(&hs, sig, 64); 246 # crypto_hash_sha512_update(&hs, m, mlen); 247 # crypto_hash_sha512_final(&hs, hram); 248 $hs = hash_init('sha512'); 249 hash_update($hs, self::substr($sig, 0, 32)); 250 hash_update($hs, self::substr($pk, 0, 32)); 251 hash_update($hs, $message); 252 $hramHash = hash_final($hs, true); 253 254 # sc_reduce(hram); 255 # sc_muladd(sig + 32, hram, az, nonce); 256 $hram = self::sc_reduce($hramHash); 257 $sigAfter = self::sc_muladd($hram, $az, $nonce); 258 $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); 259 260 try { 261 ParagonIE_Sodium_Compat::memzero($az); 262 } catch (SodiumException $ex) { 263 $az = null; 264 } 265 return $sig; 266 } 267 268 /** 269 * @internal You should not use this directly from another application 270 * 271 * @param string $sig 272 * @param string $message 273 * @param string $pk 274 * @return bool 275 * @throws SodiumException 276 * @throws TypeError 277 */ 278 public static function verify_detached($sig, $message, $pk) 279 { 280 if (self::strlen($sig) < 64) { 281 throw new SodiumException('Signature is too short'); 282 } 283 if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) { 284 throw new SodiumException('S < L - Invalid signature'); 285 } 286 if (self::small_order($sig)) { 287 throw new SodiumException('Signature is on too small of an order'); 288 } 289 if ((self::chrToInt($sig[63]) & 224) !== 0) { 290 throw new SodiumException('Invalid signature'); 291 } 292 $d = 0; 293 for ($i = 0; $i < 32; ++$i) { 294 $d |= self::chrToInt($pk[$i]); 295 } 296 if ($d === 0) { 297 throw new SodiumException('All zero public key'); 298 } 299 300 /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ 301 $orig = ParagonIE_Sodium_Compat::$fastMult; 302 303 // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. 304 ParagonIE_Sodium_Compat::$fastMult = true; 305 306 /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */ 307 $A = self::ge_frombytes_negate_vartime($pk); 308 309 /** @var string $hDigest */ 310 $hDigest = hash( 311 'sha512', 312 self::substr($sig, 0, 32) . 313 self::substr($pk, 0, 32) . 314 $message, 315 true 316 ); 317 318 /** @var string $h */ 319 $h = self::sc_reduce($hDigest) . self::substr($hDigest, 32); 320 321 /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */ 322 $R = self::ge_double_scalarmult_vartime( 323 $h, 324 $A, 325 self::substr($sig, 32) 326 ); 327 328 /** @var string $rcheck */ 329 $rcheck = self::ge_tobytes($R); 330 331 // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. 332 ParagonIE_Sodium_Compat::$fastMult = $orig; 333 334 return self::verify_32($rcheck, self::substr($sig, 0, 32)); 335 } 336 337 /** 338 * @internal You should not use this directly from another application 339 * 340 * @param string $S 341 * @return bool 342 * @throws SodiumException 343 * @throws TypeError 344 */ 345 public static function check_S_lt_L($S) 346 { 347 if (self::strlen($S) < 32) { 348 throw new SodiumException('Signature must be 32 bytes'); 349 } 350 $L = array( 351 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 352 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 353 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 354 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 355 ); 356 $c = 0; 357 $n = 1; 358 $i = 32; 359 360 /** @var array<int, int> $L */ 361 do { 362 --$i; 363 $x = self::chrToInt($S[$i]); 364 $c |= ( 365 (($x - $L[$i]) >> 8) & $n 366 ); 367 $n &= ( 368 (($x ^ $L[$i]) - 1) >> 8 369 ); 370 } while ($i !== 0); 371 372 return $c === 0; 373 } 374 375 /** 376 * @param string $R 377 * @return bool 378 * @throws SodiumException 379 * @throws TypeError 380 */ 381 public static function small_order($R) 382 { 383 /** @var array<int, array<int, int>> $blocklist */ 384 $blocklist = array( 385 /* 0 (order 4) */ 386 array( 387 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 388 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 389 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 390 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 391 ), 392 /* 1 (order 1) */ 393 array( 394 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 395 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 396 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 397 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 398 ), 399 /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 400 array( 401 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 402 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 403 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 404 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 405 ), 406 /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 407 array( 408 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 409 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 410 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 411 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a 412 ), 413 /* p-1 (order 2) */ 414 array( 415 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 416 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 417 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 418 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85 419 ), 420 /* p (order 4) */ 421 array( 422 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 423 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 424 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 425 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa 426 ), 427 /* p+1 (order 1) */ 428 array( 429 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 430 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 431 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 432 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 433 ), 434 /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 435 array( 436 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 437 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 438 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 439 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 440 ), 441 /* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 442 array( 443 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 444 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 445 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 446 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 447 ), 448 /* 2p-1 (order 2) */ 449 array( 450 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 451 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 452 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 453 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 454 ), 455 /* 2p (order 4) */ 456 array( 457 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 458 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 459 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 460 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 461 ), 462 /* 2p+1 (order 1) */ 463 array( 464 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 465 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 466 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 467 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 468 ) 469 ); 470 /** @var int $countBlocklist */ 471 $countBlocklist = count($blocklist); 472 473 for ($i = 0; $i < $countBlocklist; ++$i) { 474 $c = 0; 475 for ($j = 0; $j < 32; ++$j) { 476 $c |= self::chrToInt($R[$j]) ^ (int) $blocklist[$i][$j]; 477 } 478 if ($c === 0) { 479 return true; 480 } 481 } 482 return false; 483 } 484 485 /** 486 * @param string $s 487 * @return string 488 * @throws SodiumException 489 */ 490 public static function scalar_complement($s) 491 { 492 $t_ = self::L . str_repeat("\x00", 32); 493 sodium_increment($t_); 494 $s_ = $s . str_repeat("\x00", 32); 495 ParagonIE_Sodium_Compat::sub($t_, $s_); 496 return self::sc_reduce($t_); 497 } 498 499 /** 500 * @return string 501 * @throws SodiumException 502 */ 503 public static function scalar_random() 504 { 505 do { 506 $r = ParagonIE_Sodium_Compat::randombytes_buf(self::SCALAR_BYTES); 507 $r[self::SCALAR_BYTES - 1] = self::intToChr( 508 self::chrToInt($r[self::SCALAR_BYTES - 1]) & 0x1f 509 ); 510 } while ( 511 !self::check_S_lt_L($r) || ParagonIE_Sodium_Compat::is_zero($r) 512 ); 513 return $r; 514 } 515 516 /** 517 * @param string $s 518 * @return string 519 * @throws SodiumException 520 */ 521 public static function scalar_negate($s) 522 { 523 $t_ = self::L . str_repeat("\x00", 32) ; 524 $s_ = $s . str_repeat("\x00", 32) ; 525 ParagonIE_Sodium_Compat::sub($t_, $s_); 526 return self::sc_reduce($t_); 527 } 528 529 /** 530 * @param string $a 531 * @param string $b 532 * @return string 533 * @throws SodiumException 534 */ 535 public static function scalar_add($a, $b) 536 { 537 $a_ = $a . str_repeat("\x00", 32); 538 $b_ = $b . str_repeat("\x00", 32); 539 ParagonIE_Sodium_Compat::add($a_, $b_); 540 return self::sc_reduce($a_); 541 } 542 543 /** 544 * @param string $x 545 * @param string $y 546 * @return string 547 * @throws SodiumException 548 */ 549 public static function scalar_sub($x, $y) 550 { 551 $yn = self::scalar_negate($y); 552 return self::scalar_add($x, $yn); 553 } 554 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Wed Dec 25 08:20:01 2024 | Cross-referenced by PHPXref |