[ Index ]

PHP Cross Reference of WordPress

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


Generated: Mon Jul 22 01:00:03 2019 Cross-referenced by PHPXref 0.7.1