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