[ 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       */
 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::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 $blacklist = 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>> $blacklist */
 468          $countBlacklist = count($blacklist);
 469  
 470          for ($i = 0; $i < $countBlacklist; ++$i) {
 471              $c = 0;
 472              for ($j = 0; $j < 32; ++$j) {
 473                  $c |= self::chrToInt($R[$j]) ^ $blacklist[$i][$j];
 474              }
 475              if ($c === 0) {
 476                  return true;
 477              }
 478          }
 479          return false;
 480      }
 481  }


Generated: Sun Nov 17 01:00:03 2019 Cross-referenced by PHPXref 0.7.1