[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

   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  }


Generated: Fri Apr 26 01:00:03 2024 Cross-referenced by PHPXref 0.7.1