[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 3 if (class_exists('ParagonIE_Sodium_Core32_Ed25519', false)) { 4 return; 5 } 6 if (!class_exists('ParagonIE_Sodium_Core32_Curve25519')) { 7 require_once dirname(__FILE__) . '/Curve25519.php'; 8 } 9 10 /** 11 * Class ParagonIE_Sodium_Core32_Ed25519 12 */ 13 abstract class ParagonIE_Sodium_Core32_Ed25519 extends ParagonIE_Sodium_Core32_Curve25519 14 { 15 const KEYPAIR_BYTES = 96; 16 const SEED_BYTES = 32; 17 18 /** 19 * @internal You should not use this directly from another application 20 * 21 * @return string (96 bytes) 22 * @throws Exception 23 * @throws SodiumException 24 * @throws TypeError 25 */ 26 public static function keypair() 27 { 28 $seed = random_bytes(self::SEED_BYTES); 29 $pk = ''; 30 $sk = ''; 31 self::seed_keypair($pk, $sk, $seed); 32 return $sk . $pk; 33 } 34 35 /** 36 * @internal You should not use this directly from another application 37 * 38 * @param string $pk 39 * @param string $sk 40 * @param string $seed 41 * @return string 42 * @throws SodiumException 43 * @throws TypeError 44 */ 45 public static function seed_keypair(&$pk, &$sk, $seed) 46 { 47 if (self::strlen($seed) !== self::SEED_BYTES) { 48 throw new RangeException('crypto_sign keypair seed must be 32 bytes long'); 49 } 50 51 /** @var string $pk */ 52 $pk = self::publickey_from_secretkey($seed); 53 $sk = $seed . $pk; 54 return $sk; 55 } 56 57 /** 58 * @internal You should not use this directly from another application 59 * 60 * @param string $keypair 61 * @return string 62 * @throws TypeError 63 */ 64 public static function secretkey($keypair) 65 { 66 if (self::strlen($keypair) !== self::KEYPAIR_BYTES) { 67 throw new RangeException('crypto_sign keypair must be 96 bytes long'); 68 } 69 return self::substr($keypair, 0, 64); 70 } 71 72 /** 73 * @internal You should not use this directly from another application 74 * 75 * @param string $keypair 76 * @return string 77 * @throws RangeException 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($pk); 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 137 # fe_1(x); 138 # fe_add(x, x, A.Y); 139 # fe_mul(x, x, one_minus_y); 140 $x = self::fe_mul( 141 self::fe_add(self::fe_1(), $A->Y), 142 $one_minux_y 143 ); 144 145 # fe_tobytes(curve25519_pk, x); 146 return self::fe_tobytes($x); 147 } 148 149 /** 150 * @internal You should not use this directly from another application 151 * 152 * @param string $sk 153 * @return string 154 * @throws SodiumException 155 * @throws TypeError 156 */ 157 public static function sk_to_pk($sk) 158 { 159 return self::ge_p3_tobytes( 160 self::ge_scalarmult_base( 161 self::substr($sk, 0, 32) 162 ) 163 ); 164 } 165 166 /** 167 * @internal You should not use this directly from another application 168 * 169 * @param string $message 170 * @param string $sk 171 * @return string 172 * @throws SodiumException 173 * @throws TypeError 174 */ 175 public static function sign($message, $sk) 176 { 177 /** @var string $signature */ 178 $signature = self::sign_detached($message, $sk); 179 return $signature . $message; 180 } 181 182 /** 183 * @internal You should not use this directly from another application 184 * 185 * @param string $message A signed message 186 * @param string $pk Public key 187 * @return string Message (without signature) 188 * @throws SodiumException 189 * @throws TypeError 190 */ 191 public static function sign_open($message, $pk) 192 { 193 /** @var string $signature */ 194 $signature = self::substr($message, 0, 64); 195 196 /** @var string $message */ 197 $message = self::substr($message, 64); 198 199 if (self::verify_detached($signature, $message, $pk)) { 200 return $message; 201 } 202 throw new SodiumException('Invalid signature'); 203 } 204 205 /** 206 * @internal You should not use this directly from another application 207 * 208 * @param string $message 209 * @param string $sk 210 * @return string 211 * @throws SodiumException 212 * @throws TypeError 213 * @psalm-suppress PossiblyInvalidArgument 214 */ 215 public static function sign_detached($message, $sk) 216 { 217 # crypto_hash_sha512(az, sk, 32); 218 $az = hash('sha512', self::substr($sk, 0, 32), true); 219 220 # az[0] &= 248; 221 # az[31] &= 63; 222 # az[31] |= 64; 223 $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); 224 $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); 225 226 # crypto_hash_sha512_init(&hs); 227 # crypto_hash_sha512_update(&hs, az + 32, 32); 228 # crypto_hash_sha512_update(&hs, m, mlen); 229 # crypto_hash_sha512_final(&hs, nonce); 230 $hs = hash_init('sha512'); 231 self::hash_update($hs, self::substr($az, 32, 32)); 232 self::hash_update($hs, $message); 233 $nonceHash = hash_final($hs, true); 234 235 # memmove(sig + 32, sk + 32, 32); 236 $pk = self::substr($sk, 32, 32); 237 238 # sc_reduce(nonce); 239 # ge_scalarmult_base(&R, nonce); 240 # ge_p3_tobytes(sig, &R); 241 $nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32); 242 $sig = self::ge_p3_tobytes( 243 self::ge_scalarmult_base($nonce) 244 ); 245 246 # crypto_hash_sha512_init(&hs); 247 # crypto_hash_sha512_update(&hs, sig, 64); 248 # crypto_hash_sha512_update(&hs, m, mlen); 249 # crypto_hash_sha512_final(&hs, hram); 250 $hs = hash_init('sha512'); 251 self::hash_update($hs, self::substr($sig, 0, 32)); 252 self::hash_update($hs, self::substr($pk, 0, 32)); 253 self::hash_update($hs, $message); 254 $hramHash = hash_final($hs, true); 255 256 # sc_reduce(hram); 257 # sc_muladd(sig + 32, hram, az, nonce); 258 $hram = self::sc_reduce($hramHash); 259 $sigAfter = self::sc_muladd($hram, $az, $nonce); 260 $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); 261 262 try { 263 ParagonIE_Sodium_Compat::memzero($az); 264 } catch (SodiumException $ex) { 265 $az = null; 266 } 267 return $sig; 268 } 269 270 /** 271 * @internal You should not use this directly from another application 272 * 273 * @param string $sig 274 * @param string $message 275 * @param string $pk 276 * @return bool 277 * @throws SodiumException 278 * @throws TypeError 279 */ 280 public static function verify_detached($sig, $message, $pk) 281 { 282 if (self::strlen($sig) < 64) { 283 throw new SodiumException('Signature is too short'); 284 } 285 if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) { 286 throw new SodiumException('S < L - Invalid signature'); 287 } 288 if (self::small_order($sig)) { 289 throw new SodiumException('Signature is on too small of an order'); 290 } 291 if ((self::chrToInt($sig[63]) & 224) !== 0) { 292 throw new SodiumException('Invalid signature'); 293 } 294 $d = 0; 295 for ($i = 0; $i < 32; ++$i) { 296 $d |= self::chrToInt($pk[$i]); 297 } 298 if ($d === 0) { 299 throw new SodiumException('All zero public key'); 300 } 301 302 /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ 303 $orig = ParagonIE_Sodium_Compat::$fastMult; 304 305 // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. 306 ParagonIE_Sodium_Compat::$fastMult = true; 307 308 /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */ 309 $A = self::ge_frombytes_negate_vartime($pk); 310 311 /** @var string $hDigest */ 312 $hDigest = hash( 313 'sha512', 314 self::substr($sig, 0, 32) . 315 self::substr($pk, 0, 32) . 316 $message, 317 true 318 ); 319 320 /** @var string $h */ 321 $h = self::sc_reduce($hDigest) . self::substr($hDigest, 32); 322 323 /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */ 324 $R = self::ge_double_scalarmult_vartime( 325 $h, 326 $A, 327 self::substr($sig, 32) 328 ); 329 330 /** @var string $rcheck */ 331 $rcheck = self::ge_tobytes($R); 332 333 // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. 334 ParagonIE_Sodium_Compat::$fastMult = $orig; 335 336 return self::verify_32($rcheck, self::substr($sig, 0, 32)); 337 } 338 339 /** 340 * @internal You should not use this directly from another application 341 * 342 * @param string $S 343 * @return bool 344 * @throws SodiumException 345 * @throws TypeError 346 */ 347 public static function check_S_lt_L($S) 348 { 349 if (self::strlen($S) < 32) { 350 throw new SodiumException('Signature must be 32 bytes'); 351 } 352 static $L = array( 353 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 354 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 357 ); 358 /** @var array<int, int> $L */ 359 $c = 0; 360 $n = 1; 361 $i = 32; 362 363 do { 364 --$i; 365 $x = self::chrToInt($S[$i]); 366 $c |= ( 367 (($x - $L[$i]) >> 8) & $n 368 ); 369 $n &= ( 370 (($x ^ $L[$i]) - 1) >> 8 371 ); 372 } while ($i !== 0); 373 374 return $c === 0; 375 } 376 377 /** 378 * @param string $R 379 * @return bool 380 * @throws SodiumException 381 * @throws TypeError 382 */ 383 public static function small_order($R) 384 { 385 static $blocklist = array( 386 /* 0 (order 4) */ 387 array( 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 392 ), 393 /* 1 (order 1) */ 394 array( 395 0x01, 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 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 399 ), 400 /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 401 array( 402 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 403 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 404 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 405 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 406 ), 407 /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 408 array( 409 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 410 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 411 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 412 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a 413 ), 414 /* p-1 (order 2) */ 415 array( 416 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 417 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 418 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 419 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85 420 ), 421 /* p (order 4) */ 422 array( 423 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 424 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 425 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 426 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa 427 ), 428 /* p+1 (order 1) */ 429 array( 430 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 431 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 432 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 433 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 434 ), 435 /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 436 array( 437 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 438 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 439 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 440 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 441 ), 442 /* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 443 array( 444 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 445 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 446 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 447 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 448 ), 449 /* 2p-1 (order 2) */ 450 array( 451 0xd9, 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 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 455 ), 456 /* 2p (order 4) */ 457 array( 458 0xda, 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 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 462 ), 463 /* 2p+1 (order 1) */ 464 array( 465 0xdb, 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 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 469 ) 470 ); 471 /** @var array<int, array<int, int>> $blocklist */ 472 $countBlocklist = count($blocklist); 473 474 for ($i = 0; $i < $countBlocklist; ++$i) { 475 $c = 0; 476 for ($j = 0; $j < 32; ++$j) { 477 $c |= self::chrToInt($R[$j]) ^ $blocklist[$i][$j]; 478 } 479 if ($c === 0) { 480 return true; 481 } 482 } 483 return false; 484 } 485 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Wed Dec 25 08:20:01 2024 | Cross-referenced by PHPXref |