[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/sodium_compat/src/Core/ -> Ed25519.php (source)

   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  }


Generated : Thu Apr 25 08:20:02 2024 Cross-referenced by PHPXref