[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

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

   1  <?php
   2  
   3  if (class_exists('ParagonIE_Sodium_Crypto32', false)) {
   4      return;
   5  }
   6  
   7  /**
   8   * Class ParagonIE_Sodium_Crypto
   9   *
  10   * ATTENTION!
  11   *
  12   * If you are using this library, you should be using
  13   * ParagonIE_Sodium_Compat in your code, not this class.
  14   */
  15  abstract class ParagonIE_Sodium_Crypto32
  16  {
  17      const aead_chacha20poly1305_KEYBYTES = 32;
  18      const aead_chacha20poly1305_NSECBYTES = 0;
  19      const aead_chacha20poly1305_NPUBBYTES = 8;
  20      const aead_chacha20poly1305_ABYTES = 16;
  21  
  22      const aead_chacha20poly1305_IETF_KEYBYTES = 32;
  23      const aead_chacha20poly1305_IETF_NSECBYTES = 0;
  24      const aead_chacha20poly1305_IETF_NPUBBYTES = 12;
  25      const aead_chacha20poly1305_IETF_ABYTES = 16;
  26  
  27      const aead_xchacha20poly1305_IETF_KEYBYTES = 32;
  28      const aead_xchacha20poly1305_IETF_NSECBYTES = 0;
  29      const aead_xchacha20poly1305_IETF_NPUBBYTES = 24;
  30      const aead_xchacha20poly1305_IETF_ABYTES = 16;
  31  
  32      const box_curve25519xsalsa20poly1305_SEEDBYTES = 32;
  33      const box_curve25519xsalsa20poly1305_PUBLICKEYBYTES = 32;
  34      const box_curve25519xsalsa20poly1305_SECRETKEYBYTES = 32;
  35      const box_curve25519xsalsa20poly1305_BEFORENMBYTES = 32;
  36      const box_curve25519xsalsa20poly1305_NONCEBYTES = 24;
  37      const box_curve25519xsalsa20poly1305_MACBYTES = 16;
  38      const box_curve25519xsalsa20poly1305_BOXZEROBYTES = 16;
  39      const box_curve25519xsalsa20poly1305_ZEROBYTES = 32;
  40  
  41      const onetimeauth_poly1305_BYTES = 16;
  42      const onetimeauth_poly1305_KEYBYTES = 32;
  43  
  44      const secretbox_xsalsa20poly1305_KEYBYTES = 32;
  45      const secretbox_xsalsa20poly1305_NONCEBYTES = 24;
  46      const secretbox_xsalsa20poly1305_MACBYTES = 16;
  47      const secretbox_xsalsa20poly1305_BOXZEROBYTES = 16;
  48      const secretbox_xsalsa20poly1305_ZEROBYTES = 32;
  49  
  50      const secretbox_xchacha20poly1305_KEYBYTES = 32;
  51      const secretbox_xchacha20poly1305_NONCEBYTES = 24;
  52      const secretbox_xchacha20poly1305_MACBYTES = 16;
  53      const secretbox_xchacha20poly1305_BOXZEROBYTES = 16;
  54      const secretbox_xchacha20poly1305_ZEROBYTES = 32;
  55  
  56      const stream_salsa20_KEYBYTES = 32;
  57  
  58      /**
  59       * AEAD Decryption with ChaCha20-Poly1305
  60       *
  61       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
  62       *
  63       * @param string $message
  64       * @param string $ad
  65       * @param string $nonce
  66       * @param string $key
  67       * @return string
  68       * @throws SodiumException
  69       * @throws TypeError
  70       */
  71      public static function aead_chacha20poly1305_decrypt(
  72          $message = '',
  73          $ad = '',
  74          $nonce = '',
  75          $key = ''
  76      ) {
  77          /** @var int $len - Length of message (ciphertext + MAC) */
  78          $len = ParagonIE_Sodium_Core32_Util::strlen($message);
  79  
  80          /** @var int  $clen - Length of ciphertext */
  81          $clen = $len - self::aead_chacha20poly1305_ABYTES;
  82  
  83          /** @var int $adlen - Length of associated data */
  84          $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
  85  
  86          /** @var string $mac - Message authentication code */
  87          $mac = ParagonIE_Sodium_Core32_Util::substr(
  88              $message,
  89              $clen,
  90              self::aead_chacha20poly1305_ABYTES
  91          );
  92  
  93          /** @var string $ciphertext - The encrypted message (sans MAC) */
  94          $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 0, $clen);
  95  
  96          /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
  97          $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
  98              32,
  99              $nonce,
 100              $key
 101          );
 102  
 103          /* Recalculate the Poly1305 authentication tag (MAC): */
 104          $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
 105          try {
 106              ParagonIE_Sodium_Compat::memzero($block0);
 107          } catch (SodiumException $ex) {
 108              $block0 = null;
 109          }
 110          $state->update($ad);
 111          $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
 112          $state->update($ciphertext);
 113          $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
 114          $computed_mac = $state->finish();
 115  
 116          /* Compare the given MAC with the recalculated MAC: */
 117          if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
 118              throw new SodiumException('Invalid MAC');
 119          }
 120  
 121          // Here, we know that the MAC is valid, so we decrypt and return the plaintext
 122          return ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
 123              $ciphertext,
 124              $nonce,
 125              $key,
 126              ParagonIE_Sodium_Core32_Util::store64_le(1)
 127          );
 128      }
 129  
 130      /**
 131       * AEAD Encryption with ChaCha20-Poly1305
 132       *
 133       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 134       *
 135       * @param string $message
 136       * @param string $ad
 137       * @param string $nonce
 138       * @param string $key
 139       * @return string
 140       * @throws SodiumException
 141       * @throws TypeError
 142       */
 143      public static function aead_chacha20poly1305_encrypt(
 144          $message = '',
 145          $ad = '',
 146          $nonce = '',
 147          $key = ''
 148      ) {
 149          /** @var int $len - Length of the plaintext message */
 150          $len = ParagonIE_Sodium_Core32_Util::strlen($message);
 151  
 152          /** @var int $adlen - Length of the associated data */
 153          $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
 154  
 155          /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
 156          $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
 157              32,
 158              $nonce,
 159              $key
 160          );
 161          $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
 162          try {
 163              ParagonIE_Sodium_Compat::memzero($block0);
 164          } catch (SodiumException $ex) {
 165              $block0 = null;
 166          }
 167  
 168          /** @var string $ciphertext - Raw encrypted data */
 169          $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
 170              $message,
 171              $nonce,
 172              $key,
 173              ParagonIE_Sodium_Core32_Util::store64_le(1)
 174          );
 175  
 176          $state->update($ad);
 177          $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
 178          $state->update($ciphertext);
 179          $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
 180          return $ciphertext . $state->finish();
 181      }
 182  
 183      /**
 184       * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
 185       *
 186       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 187       *
 188       * @param string $message
 189       * @param string $ad
 190       * @param string $nonce
 191       * @param string $key
 192       * @return string
 193       * @throws SodiumException
 194       * @throws TypeError
 195       */
 196      public static function aead_chacha20poly1305_ietf_decrypt(
 197          $message = '',
 198          $ad = '',
 199          $nonce = '',
 200          $key = ''
 201      ) {
 202          /** @var int $adlen - Length of associated data */
 203          $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
 204  
 205          /** @var int $len - Length of message (ciphertext + MAC) */
 206          $len = ParagonIE_Sodium_Core32_Util::strlen($message);
 207  
 208          /** @var int  $clen - Length of ciphertext */
 209          $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES;
 210  
 211          /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
 212          $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(
 213              32,
 214              $nonce,
 215              $key
 216          );
 217  
 218          /** @var string $mac - Message authentication code */
 219          $mac = ParagonIE_Sodium_Core32_Util::substr(
 220              $message,
 221              $len - self::aead_chacha20poly1305_IETF_ABYTES,
 222              self::aead_chacha20poly1305_IETF_ABYTES
 223          );
 224  
 225          /** @var string $ciphertext - The encrypted message (sans MAC) */
 226          $ciphertext = ParagonIE_Sodium_Core32_Util::substr(
 227              $message,
 228              0,
 229              $len - self::aead_chacha20poly1305_IETF_ABYTES
 230          );
 231  
 232          /* Recalculate the Poly1305 authentication tag (MAC): */
 233          $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
 234          try {
 235              ParagonIE_Sodium_Compat::memzero($block0);
 236          } catch (SodiumException $ex) {
 237              $block0 = null;
 238          }
 239          $state->update($ad);
 240          $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
 241          $state->update($ciphertext);
 242          $state->update(str_repeat("\x00", (0x10 - $clen) & 0xf));
 243          $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
 244          $state->update(ParagonIE_Sodium_Core32_Util::store64_le($clen));
 245          $computed_mac = $state->finish();
 246  
 247          /* Compare the given MAC with the recalculated MAC: */
 248          if (!ParagonIE_Sodium_Core32_Util::verify_16($computed_mac, $mac)) {
 249              throw new SodiumException('Invalid MAC');
 250          }
 251  
 252          // Here, we know that the MAC is valid, so we decrypt and return the plaintext
 253          return ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
 254              $ciphertext,
 255              $nonce,
 256              $key,
 257              ParagonIE_Sodium_Core32_Util::store64_le(1)
 258          );
 259      }
 260  
 261      /**
 262       * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
 263       *
 264       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 265       *
 266       * @param string $message
 267       * @param string $ad
 268       * @param string $nonce
 269       * @param string $key
 270       * @return string
 271       * @throws SodiumException
 272       * @throws TypeError
 273       */
 274      public static function aead_chacha20poly1305_ietf_encrypt(
 275          $message = '',
 276          $ad = '',
 277          $nonce = '',
 278          $key = ''
 279      ) {
 280          /** @var int $len - Length of the plaintext message */
 281          $len = ParagonIE_Sodium_Core32_Util::strlen($message);
 282  
 283          /** @var int $adlen - Length of the associated data */
 284          $adlen = ParagonIE_Sodium_Core32_Util::strlen($ad);
 285  
 286          /** @var string The first block of the chacha20 keystream, used as a poly1305 key */
 287          $block0 = ParagonIE_Sodium_Core32_ChaCha20::ietfStream(
 288              32,
 289              $nonce,
 290              $key
 291          );
 292          $state = new ParagonIE_Sodium_Core32_Poly1305_State($block0);
 293          try {
 294              ParagonIE_Sodium_Compat::memzero($block0);
 295          } catch (SodiumException $ex) {
 296              $block0 = null;
 297          }
 298  
 299          /** @var string $ciphertext - Raw encrypted data */
 300          $ciphertext = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc(
 301              $message,
 302              $nonce,
 303              $key,
 304              ParagonIE_Sodium_Core32_Util::store64_le(1)
 305          );
 306  
 307          $state->update($ad);
 308          $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf)));
 309          $state->update($ciphertext);
 310          $state->update(str_repeat("\x00", ((0x10 - $len) & 0xf)));
 311          $state->update(ParagonIE_Sodium_Core32_Util::store64_le($adlen));
 312          $state->update(ParagonIE_Sodium_Core32_Util::store64_le($len));
 313          return $ciphertext . $state->finish();
 314      }
 315  
 316      /**
 317       * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
 318       *
 319       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 320       *
 321       * @param string $message
 322       * @param string $ad
 323       * @param string $nonce
 324       * @param string $key
 325       * @return string
 326       * @throws SodiumException
 327       * @throws TypeError
 328       */
 329      public static function aead_xchacha20poly1305_ietf_decrypt(
 330          $message = '',
 331          $ad = '',
 332          $nonce = '',
 333          $key = ''
 334      ) {
 335          $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
 336              ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
 337              $key
 338          );
 339          $nonceLast = "\x00\x00\x00\x00" .
 340              ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
 341  
 342          return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey);
 343      }
 344  
 345      /**
 346       * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce)
 347       *
 348       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 349       *
 350       * @param string $message
 351       * @param string $ad
 352       * @param string $nonce
 353       * @param string $key
 354       * @return string
 355       * @throws SodiumException
 356       * @throws TypeError
 357       */
 358      public static function aead_xchacha20poly1305_ietf_encrypt(
 359          $message = '',
 360          $ad = '',
 361          $nonce = '',
 362          $key = ''
 363      ) {
 364          $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
 365              ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
 366              $key
 367          );
 368          $nonceLast = "\x00\x00\x00\x00" .
 369              ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
 370  
 371          return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey);
 372      }
 373  
 374      /**
 375       * HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512)
 376       *
 377       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 378       *
 379       * @param string $message
 380       * @param string $key
 381       * @return string
 382       * @throws TypeError
 383       */
 384      public static function auth($message, $key)
 385      {
 386          return ParagonIE_Sodium_Core32_Util::substr(
 387              hash_hmac('sha512', $message, $key, true),
 388              0,
 389              32
 390          );
 391      }
 392  
 393      /**
 394       * HMAC-SHA-512-256 validation. Constant-time via hash_equals().
 395       *
 396       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 397       *
 398       * @param string $mac
 399       * @param string $message
 400       * @param string $key
 401       * @return bool
 402       * @throws SodiumException
 403       * @throws TypeError
 404       */
 405      public static function auth_verify($mac, $message, $key)
 406      {
 407          return ParagonIE_Sodium_Core32_Util::hashEquals(
 408              $mac,
 409              self::auth($message, $key)
 410          );
 411      }
 412  
 413      /**
 414       * X25519 key exchange followed by XSalsa20Poly1305 symmetric encryption
 415       *
 416       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 417       *
 418       * @param string $plaintext
 419       * @param string $nonce
 420       * @param string $keypair
 421       * @return string
 422       * @throws SodiumException
 423       * @throws TypeError
 424       */
 425      public static function box($plaintext, $nonce, $keypair)
 426      {
 427          return self::secretbox(
 428              $plaintext,
 429              $nonce,
 430              self::box_beforenm(
 431                  self::box_secretkey($keypair),
 432                  self::box_publickey($keypair)
 433              )
 434          );
 435      }
 436  
 437      /**
 438       * X25519-XSalsa20-Poly1305 with one ephemeral X25519 keypair.
 439       *
 440       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 441       *
 442       * @param string $message
 443       * @param string $publicKey
 444       * @return string
 445       * @throws SodiumException
 446       * @throws TypeError
 447       */
 448      public static function box_seal($message, $publicKey)
 449      {
 450          /** @var string $ephemeralKeypair */
 451          $ephemeralKeypair = self::box_keypair();
 452  
 453          /** @var string $ephemeralSK */
 454          $ephemeralSK = self::box_secretkey($ephemeralKeypair);
 455  
 456          /** @var string $ephemeralPK */
 457          $ephemeralPK = self::box_publickey($ephemeralKeypair);
 458  
 459          /** @var string $nonce */
 460          $nonce = self::generichash(
 461              $ephemeralPK . $publicKey,
 462              '',
 463              24
 464          );
 465  
 466          /** @var string $keypair - The combined keypair used in crypto_box() */
 467          $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey);
 468  
 469          /** @var string $ciphertext Ciphertext + MAC from crypto_box */
 470          $ciphertext = self::box($message, $nonce, $keypair);
 471          try {
 472              ParagonIE_Sodium_Compat::memzero($ephemeralKeypair);
 473              ParagonIE_Sodium_Compat::memzero($ephemeralSK);
 474              ParagonIE_Sodium_Compat::memzero($nonce);
 475          } catch (SodiumException $ex) {
 476              $ephemeralKeypair = null;
 477              $ephemeralSK = null;
 478              $nonce = null;
 479          }
 480          return $ephemeralPK . $ciphertext;
 481      }
 482  
 483      /**
 484       * Opens a message encrypted via box_seal().
 485       *
 486       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 487       *
 488       * @param string $message
 489       * @param string $keypair
 490       * @return string
 491       * @throws SodiumException
 492       * @throws TypeError
 493       */
 494      public static function box_seal_open($message, $keypair)
 495      {
 496          /** @var string $ephemeralPK */
 497          $ephemeralPK = ParagonIE_Sodium_Core32_Util::substr($message, 0, 32);
 498  
 499          /** @var string $ciphertext (ciphertext + MAC) */
 500          $ciphertext = ParagonIE_Sodium_Core32_Util::substr($message, 32);
 501  
 502          /** @var string $secretKey */
 503          $secretKey = self::box_secretkey($keypair);
 504  
 505          /** @var string $publicKey */
 506          $publicKey = self::box_publickey($keypair);
 507  
 508          /** @var string $nonce */
 509          $nonce = self::generichash(
 510              $ephemeralPK . $publicKey,
 511              '',
 512              24
 513          );
 514  
 515          /** @var string $keypair */
 516          $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK);
 517  
 518          /** @var string $m */
 519          $m = self::box_open($ciphertext, $nonce, $keypair);
 520          try {
 521              ParagonIE_Sodium_Compat::memzero($secretKey);
 522              ParagonIE_Sodium_Compat::memzero($ephemeralPK);
 523              ParagonIE_Sodium_Compat::memzero($nonce);
 524          } catch (SodiumException $ex) {
 525              $secretKey = null;
 526              $ephemeralPK = null;
 527              $nonce = null;
 528          }
 529          return $m;
 530      }
 531  
 532      /**
 533       * Used by crypto_box() to get the crypto_secretbox() key.
 534       *
 535       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 536       *
 537       * @param string $sk
 538       * @param string $pk
 539       * @return string
 540       * @throws SodiumException
 541       * @throws TypeError
 542       */
 543      public static function box_beforenm($sk, $pk)
 544      {
 545          return ParagonIE_Sodium_Core32_HSalsa20::hsalsa20(
 546              str_repeat("\x00", 16),
 547              self::scalarmult($sk, $pk)
 548          );
 549      }
 550  
 551      /**
 552       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 553       *
 554       * @return string
 555       * @throws Exception
 556       * @throws SodiumException
 557       * @throws TypeError
 558       */
 559      public static function box_keypair()
 560      {
 561          $sKey = random_bytes(32);
 562          $pKey = self::scalarmult_base($sKey);
 563          return $sKey . $pKey;
 564      }
 565  
 566      /**
 567       * @param string $seed
 568       * @return string
 569       * @throws SodiumException
 570       * @throws TypeError
 571       */
 572      public static function box_seed_keypair($seed)
 573      {
 574          $sKey = ParagonIE_Sodium_Core32_Util::substr(
 575              hash('sha512', $seed, true),
 576              0,
 577              32
 578          );
 579          $pKey = self::scalarmult_base($sKey);
 580          return $sKey . $pKey;
 581      }
 582  
 583      /**
 584       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 585       *
 586       * @param string $sKey
 587       * @param string $pKey
 588       * @return string
 589       * @throws TypeError
 590       */
 591      public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey)
 592      {
 593          return ParagonIE_Sodium_Core32_Util::substr($sKey, 0, 32) .
 594              ParagonIE_Sodium_Core32_Util::substr($pKey, 0, 32);
 595      }
 596  
 597      /**
 598       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 599       *
 600       * @param string $keypair
 601       * @return string
 602       * @throws RangeException
 603       * @throws TypeError
 604       */
 605      public static function box_secretkey($keypair)
 606      {
 607          if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== 64) {
 608              throw new RangeException(
 609                  'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
 610              );
 611          }
 612          return ParagonIE_Sodium_Core32_Util::substr($keypair, 0, 32);
 613      }
 614  
 615      /**
 616       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 617       *
 618       * @param string $keypair
 619       * @return string
 620       * @throws RangeException
 621       * @throws TypeError
 622       */
 623      public static function box_publickey($keypair)
 624      {
 625          if (ParagonIE_Sodium_Core32_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) {
 626              throw new RangeException(
 627                  'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'
 628              );
 629          }
 630          return ParagonIE_Sodium_Core32_Util::substr($keypair, 32, 32);
 631      }
 632  
 633      /**
 634       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 635       *
 636       * @param string $sKey
 637       * @return string
 638       * @throws RangeException
 639       * @throws SodiumException
 640       * @throws TypeError
 641       */
 642      public static function box_publickey_from_secretkey($sKey)
 643      {
 644          if (ParagonIE_Sodium_Core32_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) {
 645              throw new RangeException(
 646                  'Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.'
 647              );
 648          }
 649          return self::scalarmult_base($sKey);
 650      }
 651  
 652      /**
 653       * Decrypt a message encrypted with box().
 654       *
 655       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 656       *
 657       * @param string $ciphertext
 658       * @param string $nonce
 659       * @param string $keypair
 660       * @return string
 661       * @throws SodiumException
 662       * @throws TypeError
 663       */
 664      public static function box_open($ciphertext, $nonce, $keypair)
 665      {
 666          return self::secretbox_open(
 667              $ciphertext,
 668              $nonce,
 669              self::box_beforenm(
 670                  self::box_secretkey($keypair),
 671                  self::box_publickey($keypair)
 672              )
 673          );
 674      }
 675  
 676      /**
 677       * Calculate a BLAKE2b hash.
 678       *
 679       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 680       *
 681       * @param string $message
 682       * @param string|null $key
 683       * @param int $outlen
 684       * @return string
 685       * @throws RangeException
 686       * @throws SodiumException
 687       * @throws TypeError
 688       */
 689      public static function generichash($message, $key = '', $outlen = 32)
 690      {
 691          // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
 692          ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
 693  
 694          $k = null;
 695          if (!empty($key)) {
 696              /** @var SplFixedArray $k */
 697              $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
 698              if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
 699                  throw new RangeException('Invalid key size');
 700              }
 701          }
 702  
 703          /** @var SplFixedArray $in */
 704          $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
 705  
 706          /** @var SplFixedArray $ctx */
 707          $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outlen);
 708          ParagonIE_Sodium_Core32_BLAKE2b::update($ctx, $in, $in->count());
 709  
 710          /** @var SplFixedArray $out */
 711          $out = new SplFixedArray($outlen);
 712          $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($ctx, $out);
 713  
 714          /** @var array<int, int> */
 715          $outArray = $out->toArray();
 716          return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
 717      }
 718  
 719      /**
 720       * Finalize a BLAKE2b hashing context, returning the hash.
 721       *
 722       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 723       *
 724       * @param string $ctx
 725       * @param int $outlen
 726       * @return string
 727       * @throws SodiumException
 728       * @throws TypeError
 729       */
 730      public static function generichash_final($ctx, $outlen = 32)
 731      {
 732          if (!is_string($ctx)) {
 733              throw new TypeError('Context must be a string');
 734          }
 735          $out = new SplFixedArray($outlen);
 736  
 737          /** @var SplFixedArray $context */
 738          $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
 739  
 740          /** @var SplFixedArray $out */
 741          $out = ParagonIE_Sodium_Core32_BLAKE2b::finish($context, $out);
 742  
 743          /** @var array<int, int> */
 744          $outArray = $out->toArray();
 745          return ParagonIE_Sodium_Core32_Util::intArrayToString($outArray);
 746      }
 747  
 748      /**
 749       * Initialize a hashing context for BLAKE2b.
 750       *
 751       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 752       *
 753       * @param string $key
 754       * @param int $outputLength
 755       * @return string
 756       * @throws RangeException
 757       * @throws SodiumException
 758       * @throws TypeError
 759       */
 760      public static function generichash_init($key = '', $outputLength = 32)
 761      {
 762          // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
 763          ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
 764  
 765          $k = null;
 766          if (!empty($key)) {
 767              $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key);
 768              if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) {
 769                  throw new RangeException('Invalid key size');
 770              }
 771          }
 772  
 773          /** @var SplFixedArray $ctx */
 774          $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength);
 775  
 776          return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx);
 777      }
 778  
 779      /**
 780       * Update a hashing context for BLAKE2b with $message
 781       *
 782       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 783       *
 784       * @param string $ctx
 785       * @param string $message
 786       * @return string
 787       * @throws SodiumException
 788       * @throws TypeError
 789       */
 790      public static function generichash_update($ctx, $message)
 791      {
 792          // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized
 793          ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor();
 794  
 795          /** @var SplFixedArray $context */
 796          $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx);
 797  
 798          /** @var SplFixedArray $in */
 799          $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message);
 800  
 801          ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in, $in->count());
 802  
 803          return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context);
 804      }
 805  
 806      /**
 807       * Libsodium's crypto_kx().
 808       *
 809       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 810       *
 811       * @param string $my_sk
 812       * @param string $their_pk
 813       * @param string $client_pk
 814       * @param string $server_pk
 815       * @return string
 816       * @throws SodiumException
 817       * @throws TypeError
 818       */
 819      public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk)
 820      {
 821          return self::generichash(
 822              self::scalarmult($my_sk, $their_pk) .
 823              $client_pk .
 824              $server_pk
 825          );
 826      }
 827  
 828      /**
 829       * ECDH over Curve25519
 830       *
 831       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 832       *
 833       * @param string $sKey
 834       * @param string $pKey
 835       * @return string
 836       *
 837       * @throws SodiumException
 838       * @throws TypeError
 839       */
 840      public static function scalarmult($sKey, $pKey)
 841      {
 842          $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey);
 843          self::scalarmult_throw_if_zero($q);
 844          return $q;
 845      }
 846  
 847      /**
 848       * ECDH over Curve25519, using the basepoint.
 849       * Used to get a secret key from a public key.
 850       *
 851       * @param string $secret
 852       * @return string
 853       *
 854       * @throws SodiumException
 855       * @throws TypeError
 856       */
 857      public static function scalarmult_base($secret)
 858      {
 859          $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10_base($secret);
 860          self::scalarmult_throw_if_zero($q);
 861          return $q;
 862      }
 863  
 864      /**
 865       * This throws an Error if a zero public key was passed to the function.
 866       *
 867       * @param string $q
 868       * @return void
 869       * @throws SodiumException
 870       * @throws TypeError
 871       */
 872      protected static function scalarmult_throw_if_zero($q)
 873      {
 874          $d = 0;
 875          for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) {
 876              $d |= ParagonIE_Sodium_Core32_Util::chrToInt($q[$i]);
 877          }
 878  
 879          /* branch-free variant of === 0 */
 880          if (-(1 & (($d - 1) >> 8))) {
 881              throw new SodiumException('Zero public key is not allowed');
 882          }
 883      }
 884  
 885      /**
 886       * XSalsa20-Poly1305 authenticated symmetric-key encryption.
 887       *
 888       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 889       *
 890       * @param string $plaintext
 891       * @param string $nonce
 892       * @param string $key
 893       * @return string
 894       * @throws SodiumException
 895       * @throws TypeError
 896       */
 897      public static function secretbox($plaintext, $nonce, $key)
 898      {
 899          /** @var string $subkey */
 900          $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
 901  
 902          /** @var string $block0 */
 903          $block0 = str_repeat("\x00", 32);
 904  
 905          /** @var int $mlen - Length of the plaintext message */
 906          $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
 907          $mlen0 = $mlen;
 908          if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) {
 909              $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES;
 910          }
 911          $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0);
 912  
 913          /** @var string $block0 */
 914          $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor(
 915              $block0,
 916              ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
 917              $subkey
 918          );
 919  
 920          /** @var string $c */
 921          $c = ParagonIE_Sodium_Core32_Util::substr(
 922              $block0,
 923              self::secretbox_xsalsa20poly1305_ZEROBYTES
 924          );
 925          if ($mlen > $mlen0) {
 926              $c .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
 927                  ParagonIE_Sodium_Core32_Util::substr(
 928                      $plaintext,
 929                      self::secretbox_xsalsa20poly1305_ZEROBYTES
 930                  ),
 931                  ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
 932                  1,
 933                  $subkey
 934              );
 935          }
 936          $state = new ParagonIE_Sodium_Core32_Poly1305_State(
 937              ParagonIE_Sodium_Core32_Util::substr(
 938                  $block0,
 939                  0,
 940                  self::onetimeauth_poly1305_KEYBYTES
 941              )
 942          );
 943          try {
 944              ParagonIE_Sodium_Compat::memzero($block0);
 945              ParagonIE_Sodium_Compat::memzero($subkey);
 946          } catch (SodiumException $ex) {
 947              $block0 = null;
 948              $subkey = null;
 949          }
 950  
 951          $state->update($c);
 952  
 953          /** @var string $c - MAC || ciphertext */
 954          $c = $state->finish() . $c;
 955          unset($state);
 956  
 957          return $c;
 958      }
 959  
 960      /**
 961       * Decrypt a ciphertext generated via secretbox().
 962       *
 963       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
 964       *
 965       * @param string $ciphertext
 966       * @param string $nonce
 967       * @param string $key
 968       * @return string
 969       * @throws SodiumException
 970       * @throws TypeError
 971       */
 972      public static function secretbox_open($ciphertext, $nonce, $key)
 973      {
 974          /** @var string $mac */
 975          $mac = ParagonIE_Sodium_Core32_Util::substr(
 976              $ciphertext,
 977              0,
 978              self::secretbox_xsalsa20poly1305_MACBYTES
 979          );
 980  
 981          /** @var string $c */
 982          $c = ParagonIE_Sodium_Core32_Util::substr(
 983              $ciphertext,
 984              self::secretbox_xsalsa20poly1305_MACBYTES
 985          );
 986  
 987          /** @var int $clen */
 988          $clen = ParagonIE_Sodium_Core32_Util::strlen($c);
 989  
 990          /** @var string $subkey */
 991          $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key);
 992  
 993          /** @var string $block0 */
 994          $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20(
 995              64,
 996              ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
 997              $subkey
 998          );
 999          $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify(
1000              $mac,
1001              $c,
1002              ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32)
1003          );
1004          if (!$verified) {
1005              try {
1006                  ParagonIE_Sodium_Compat::memzero($subkey);
1007              } catch (SodiumException $ex) {
1008                  $subkey = null;
1009              }
1010              throw new SodiumException('Invalid MAC');
1011          }
1012  
1013          /** @var string $m - Decrypted message */
1014          $m = ParagonIE_Sodium_Core32_Util::xorStrings(
1015              ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES),
1016              ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES)
1017          );
1018          if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) {
1019              // We had more than 1 block, so let's continue to decrypt the rest.
1020              $m .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic(
1021                  ParagonIE_Sodium_Core32_Util::substr(
1022                      $c,
1023                      self::secretbox_xsalsa20poly1305_ZEROBYTES
1024                  ),
1025                  ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1026                  1,
1027                  (string) $subkey
1028              );
1029          }
1030          return $m;
1031      }
1032  
1033      /**
1034       * XChaCha20-Poly1305 authenticated symmetric-key encryption.
1035       *
1036       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1037       *
1038       * @param string $plaintext
1039       * @param string $nonce
1040       * @param string $key
1041       * @return string
1042       * @throws SodiumException
1043       * @throws TypeError
1044       */
1045      public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key)
1046      {
1047          /** @var string $subkey */
1048          $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20(
1049              ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16),
1050              $key
1051          );
1052          $nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8);
1053  
1054          /** @var string $block0 */
1055          $block0 = str_repeat("\x00", 32);
1056  
1057          /** @var int $mlen - Length of the plaintext message */
1058          $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext);
1059          $mlen0 = $mlen;
1060          if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) {
1061              $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES;
1062          }
1063          $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0);
1064  
1065          /** @var string $block0 */
1066          $block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
1067              $block0,
1068              $nonceLast,
1069              $subkey
1070          );
1071  
1072          /** @var string $c */
1073          $c = ParagonIE_Sodium_Core32_Util::substr(
1074              $block0,
1075              self::secretbox_xchacha20poly1305_ZEROBYTES
1076          );
1077          if ($mlen > $mlen0) {
1078              $c .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
1079                  ParagonIE_Sodium_Core32_Util::substr(
1080                      $plaintext,
1081                      self::secretbox_xchacha20poly1305_ZEROBYTES
1082                  ),
1083                  $nonceLast,
1084                  $subkey,
1085                  ParagonIE_Sodium_Core32_Util::store64_le(1)
1086              );
1087          }
1088          $state = new ParagonIE_Sodium_Core32_Poly1305_State(
1089              ParagonIE_Sodium_Core32_Util::substr(
1090                  $block0,
1091                  0,
1092                  self::onetimeauth_poly1305_KEYBYTES
1093              )
1094          );
1095          try {
1096              ParagonIE_Sodium_Compat::memzero($block0);
1097              ParagonIE_Sodium_Compat::memzero($subkey);
1098          } catch (SodiumException $ex) {
1099              $block0 = null;
1100              $subkey = null;
1101          }
1102  
1103          $state->update($c);
1104  
1105          /** @var string $c - MAC || ciphertext */
1106          $c = $state->finish() . $c;
1107          unset($state);
1108  
1109          return $c;
1110      }
1111  
1112      /**
1113       * Decrypt a ciphertext generated via secretbox_xchacha20poly1305().
1114       *
1115       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1116       *
1117       * @param string $ciphertext
1118       * @param string $nonce
1119       * @param string $key
1120       * @return string
1121       * @throws SodiumException
1122       * @throws TypeError
1123       */
1124      public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
1125      {
1126          /** @var string $mac */
1127          $mac = ParagonIE_Sodium_Core32_Util::substr(
1128              $ciphertext,
1129              0,
1130              self::secretbox_xchacha20poly1305_MACBYTES
1131          );
1132  
1133          /** @var string $c */
1134          $c = ParagonIE_Sodium_Core32_Util::substr(
1135              $ciphertext,
1136              self::secretbox_xchacha20poly1305_MACBYTES
1137          );
1138  
1139          /** @var int $clen */
1140          $clen = ParagonIE_Sodium_Core32_Util::strlen($c);
1141  
1142          /** @var string $subkey */
1143          $subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce, $key);
1144  
1145          /** @var string $block0 */
1146          $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream(
1147              64,
1148              ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1149              $subkey
1150          );
1151          $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify(
1152              $mac,
1153              $c,
1154              ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32)
1155          );
1156  
1157          if (!$verified) {
1158              try {
1159                  ParagonIE_Sodium_Compat::memzero($subkey);
1160              } catch (SodiumException $ex) {
1161                  $subkey = null;
1162              }
1163              throw new SodiumException('Invalid MAC');
1164          }
1165  
1166          /** @var string $m - Decrypted message */
1167          $m = ParagonIE_Sodium_Core32_Util::xorStrings(
1168              ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES),
1169              ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES)
1170          );
1171  
1172          if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) {
1173              // We had more than 1 block, so let's continue to decrypt the rest.
1174              $m .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc(
1175                  ParagonIE_Sodium_Core32_Util::substr(
1176                      $c,
1177                      self::secretbox_xchacha20poly1305_ZEROBYTES
1178                  ),
1179                  ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8),
1180                  (string) $subkey,
1181                  ParagonIE_Sodium_Core32_Util::store64_le(1)
1182              );
1183          }
1184          return $m;
1185      }
1186  
1187      /**
1188       * Detached Ed25519 signature.
1189       *
1190       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1191       *
1192       * @param string $message
1193       * @param string $sk
1194       * @return string
1195       * @throws SodiumException
1196       * @throws TypeError
1197       */
1198      public static function sign_detached($message, $sk)
1199      {
1200          return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message, $sk);
1201      }
1202  
1203      /**
1204       * Attached Ed25519 signature. (Returns a signed message.)
1205       *
1206       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1207       *
1208       * @param string $message
1209       * @param string $sk
1210       * @return string
1211       * @throws SodiumException
1212       * @throws TypeError
1213       */
1214      public static function sign($message, $sk)
1215      {
1216          return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk);
1217      }
1218  
1219      /**
1220       * Opens a signed message. If valid, returns the message.
1221       *
1222       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1223       *
1224       * @param string $signedMessage
1225       * @param string $pk
1226       * @return string
1227       * @throws SodiumException
1228       * @throws TypeError
1229       */
1230      public static function sign_open($signedMessage, $pk)
1231      {
1232          return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage, $pk);
1233      }
1234  
1235      /**
1236       * Verify a detached signature of a given message and public key.
1237       *
1238       * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
1239       *
1240       * @param string $signature
1241       * @param string $message
1242       * @param string $pk
1243       * @return bool
1244       * @throws SodiumException
1245       * @throws TypeError
1246       */
1247      public static function sign_verify_detached($signature, $message, $pk)
1248      {
1249          return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature, $message, $pk);
1250      }
1251  }


Generated: Tue Nov 19 01:00:03 2019 Cross-referenced by PHPXref 0.7.1