[ 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 */ 211 public static function sign_detached($message, $sk) 212 { 213 # crypto_hash_sha512(az, sk, 32); 214 $az = hash('sha512', self::substr($sk, 0, 32), true); 215 216 # az[0] &= 248; 217 # az[31] &= 63; 218 # az[31] |= 64; 219 $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); 220 $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); 221 222 # crypto_hash_sha512_init(&hs); 223 # crypto_hash_sha512_update(&hs, az + 32, 32); 224 # crypto_hash_sha512_update(&hs, m, mlen); 225 # crypto_hash_sha512_final(&hs, nonce); 226 $hs = hash_init('sha512'); 227 hash_update($hs, self::substr($az, 32, 32)); 228 hash_update($hs, $message); 229 $nonceHash = hash_final($hs, true); 230 231 # memmove(sig + 32, sk + 32, 32); 232 $pk = self::substr($sk, 32, 32); 233 234 # sc_reduce(nonce); 235 # ge_scalarmult_base(&R, nonce); 236 # ge_p3_tobytes(sig, &R); 237 $nonce = self::sc_reduce($nonceHash) . self::substr($nonceHash, 32); 238 $sig = self::ge_p3_tobytes( 239 self::ge_scalarmult_base($nonce) 240 ); 241 242 # crypto_hash_sha512_init(&hs); 243 # crypto_hash_sha512_update(&hs, sig, 64); 244 # crypto_hash_sha512_update(&hs, m, mlen); 245 # crypto_hash_sha512_final(&hs, hram); 246 $hs = hash_init('sha512'); 247 hash_update($hs, self::substr($sig, 0, 32)); 248 hash_update($hs, self::substr($pk, 0, 32)); 249 hash_update($hs, $message); 250 $hramHash = hash_final($hs, true); 251 252 # sc_reduce(hram); 253 # sc_muladd(sig + 32, hram, az, nonce); 254 $hram = self::sc_reduce($hramHash); 255 $sigAfter = self::sc_muladd($hram, $az, $nonce); 256 $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); 257 258 try { 259 ParagonIE_Sodium_Compat::memzero($az); 260 } catch (SodiumException $ex) { 261 $az = null; 262 } 263 return $sig; 264 } 265 266 /** 267 * @internal You should not use this directly from another application 268 * 269 * @param string $sig 270 * @param string $message 271 * @param string $pk 272 * @return bool 273 * @throws SodiumException 274 * @throws TypeError 275 */ 276 public static function verify_detached($sig, $message, $pk) 277 { 278 if (self::strlen($sig) < 64) { 279 throw new SodiumException('Signature is too short'); 280 } 281 if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) { 282 throw new SodiumException('S < L - Invalid signature'); 283 } 284 if (self::small_order($sig)) { 285 throw new SodiumException('Signature is on too small of an order'); 286 } 287 if ((self::chrToInt($sig[63]) & 224) !== 0) { 288 throw new SodiumException('Invalid signature'); 289 } 290 $d = 0; 291 for ($i = 0; $i < 32; ++$i) { 292 $d |= self::chrToInt($pk[$i]); 293 } 294 if ($d === 0) { 295 throw new SodiumException('All zero public key'); 296 } 297 298 /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ 299 $orig = ParagonIE_Sodium_Compat::$fastMult; 300 301 // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. 302 ParagonIE_Sodium_Compat::$fastMult = true; 303 304 /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P3 $A */ 305 $A = self::ge_frombytes_negate_vartime($pk); 306 307 /** @var string $hDigest */ 308 $hDigest = hash( 309 'sha512', 310 self::substr($sig, 0, 32) . 311 self::substr($pk, 0, 32) . 312 $message, 313 true 314 ); 315 316 /** @var string $h */ 317 $h = self::sc_reduce($hDigest) . self::substr($hDigest, 32); 318 319 /** @var ParagonIE_Sodium_Core32_Curve25519_Ge_P2 $R */ 320 $R = self::ge_double_scalarmult_vartime( 321 $h, 322 $A, 323 self::substr($sig, 32) 324 ); 325 326 /** @var string $rcheck */ 327 $rcheck = self::ge_tobytes($R); 328 329 // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. 330 ParagonIE_Sodium_Compat::$fastMult = $orig; 331 332 return self::verify_32($rcheck, self::substr($sig, 0, 32)); 333 } 334 335 /** 336 * @internal You should not use this directly from another application 337 * 338 * @param string $S 339 * @return bool 340 * @throws SodiumException 341 * @throws TypeError 342 */ 343 public static function check_S_lt_L($S) 344 { 345 if (self::strlen($S) < 32) { 346 throw new SodiumException('Signature must be 32 bytes'); 347 } 348 static $L = array( 349 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 350 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 351 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 352 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 353 ); 354 /** @var array<int, int> $L */ 355 $c = 0; 356 $n = 1; 357 $i = 32; 358 359 do { 360 --$i; 361 $x = self::chrToInt($S[$i]); 362 $c |= ( 363 (($x - $L[$i]) >> 8) & $n 364 ); 365 $n &= ( 366 (($x ^ $L[$i]) - 1) >> 8 367 ); 368 } while ($i !== 0); 369 370 return $c === 0; 371 } 372 373 /** 374 * @param string $R 375 * @return bool 376 * @throws SodiumException 377 * @throws TypeError 378 */ 379 public static function small_order($R) 380 { 381 static $blocklist = array( 382 /* 0 (order 4) */ 383 array( 384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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 ), 389 /* 1 (order 1) */ 390 array( 391 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 392 0x00, 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 ), 396 /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 397 array( 398 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 399 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 400 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 401 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 402 ), 403 /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 404 array( 405 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 406 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 407 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 408 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a 409 ), 410 /* p-1 (order 2) */ 411 array( 412 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, 413 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, 414 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, 415 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85 416 ), 417 /* p (order 4) */ 418 array( 419 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, 420 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, 421 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, 422 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa 423 ), 424 /* p+1 (order 1) */ 425 array( 426 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 427 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 428 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 429 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 430 ), 431 /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ 432 array( 433 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 434 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 435 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 436 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 437 ), 438 /* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ 439 array( 440 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 441 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 442 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 443 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f 444 ), 445 /* 2p-1 (order 2) */ 446 array( 447 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 448 0xff, 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 ), 452 /* 2p (order 4) */ 453 array( 454 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 455 0xff, 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 ), 459 /* 2p+1 (order 1) */ 460 array( 461 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 462 0xff, 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 ) 466 ); 467 /** @var array<int, array<int, int>> $blocklist */ 468 $countBlocklist = count($blocklist); 469 470 for ($i = 0; $i < $countBlocklist; ++$i) { 471 $c = 0; 472 for ($j = 0; $j < 32; ++$j) { 473 $c |= self::chrToInt($R[$j]) ^ $blocklist[$i][$j]; 474 } 475 if ($c === 0) { 476 return true; 477 } 478 } 479 return false; 480 } 481 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Apr 23 01:00:05 2021 | Cross-referenced by PHPXref 0.7.1 |