[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 * Initialize a hashing context for BLAKE2b. 781 * 782 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 783 * 784 * @param string $key 785 * @param int $outputLength 786 * @param string $salt 787 * @param string $personal 788 * @return string 789 * @throws RangeException 790 * @throws SodiumException 791 * @throws TypeError 792 */ 793 public static function generichash_init_salt_personal( 794 $key = '', 795 $outputLength = 32, 796 $salt = '', 797 $personal = '' 798 ) { 799 // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized 800 ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); 801 802 $k = null; 803 if (!empty($key)) { 804 $k = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($key); 805 if ($k->count() > ParagonIE_Sodium_Core32_BLAKE2b::KEYBYTES) { 806 throw new RangeException('Invalid key size'); 807 } 808 } 809 if (!empty($salt)) { 810 $s = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($salt); 811 } else { 812 $s = null; 813 } 814 if (!empty($salt)) { 815 $p = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($personal); 816 } else { 817 $p = null; 818 } 819 820 /** @var SplFixedArray $ctx */ 821 $ctx = ParagonIE_Sodium_Core32_BLAKE2b::init($k, $outputLength, $s, $p); 822 823 return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($ctx); 824 } 825 826 /** 827 * Update a hashing context for BLAKE2b with $message 828 * 829 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 830 * 831 * @param string $ctx 832 * @param string $message 833 * @return string 834 * @throws SodiumException 835 * @throws TypeError 836 */ 837 public static function generichash_update($ctx, $message) 838 { 839 // This ensures that ParagonIE_Sodium_Core32_BLAKE2b::$iv is initialized 840 ParagonIE_Sodium_Core32_BLAKE2b::pseudoConstructor(); 841 842 /** @var SplFixedArray $context */ 843 $context = ParagonIE_Sodium_Core32_BLAKE2b::stringToContext($ctx); 844 845 /** @var SplFixedArray $in */ 846 $in = ParagonIE_Sodium_Core32_BLAKE2b::stringToSplFixedArray($message); 847 848 ParagonIE_Sodium_Core32_BLAKE2b::update($context, $in, $in->count()); 849 850 return ParagonIE_Sodium_Core32_BLAKE2b::contextToString($context); 851 } 852 853 /** 854 * Libsodium's crypto_kx(). 855 * 856 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 857 * 858 * @param string $my_sk 859 * @param string $their_pk 860 * @param string $client_pk 861 * @param string $server_pk 862 * @return string 863 * @throws SodiumException 864 * @throws TypeError 865 */ 866 public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk) 867 { 868 return self::generichash( 869 self::scalarmult($my_sk, $their_pk) . 870 $client_pk . 871 $server_pk 872 ); 873 } 874 875 /** 876 * ECDH over Curve25519 877 * 878 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 879 * 880 * @param string $sKey 881 * @param string $pKey 882 * @return string 883 * 884 * @throws SodiumException 885 * @throws TypeError 886 */ 887 public static function scalarmult($sKey, $pKey) 888 { 889 $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey); 890 self::scalarmult_throw_if_zero($q); 891 return $q; 892 } 893 894 /** 895 * ECDH over Curve25519, using the basepoint. 896 * Used to get a secret key from a public key. 897 * 898 * @param string $secret 899 * @return string 900 * 901 * @throws SodiumException 902 * @throws TypeError 903 */ 904 public static function scalarmult_base($secret) 905 { 906 $q = ParagonIE_Sodium_Core32_X25519::crypto_scalarmult_curve25519_ref10_base($secret); 907 self::scalarmult_throw_if_zero($q); 908 return $q; 909 } 910 911 /** 912 * This throws an Error if a zero public key was passed to the function. 913 * 914 * @param string $q 915 * @return void 916 * @throws SodiumException 917 * @throws TypeError 918 */ 919 protected static function scalarmult_throw_if_zero($q) 920 { 921 $d = 0; 922 for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) { 923 $d |= ParagonIE_Sodium_Core32_Util::chrToInt($q[$i]); 924 } 925 926 /* branch-free variant of === 0 */ 927 if (-(1 & (($d - 1) >> 8))) { 928 throw new SodiumException('Zero public key is not allowed'); 929 } 930 } 931 932 /** 933 * XSalsa20-Poly1305 authenticated symmetric-key encryption. 934 * 935 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 936 * 937 * @param string $plaintext 938 * @param string $nonce 939 * @param string $key 940 * @return string 941 * @throws SodiumException 942 * @throws TypeError 943 */ 944 public static function secretbox($plaintext, $nonce, $key) 945 { 946 /** @var string $subkey */ 947 $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); 948 949 /** @var string $block0 */ 950 $block0 = str_repeat("\x00", 32); 951 952 /** @var int $mlen - Length of the plaintext message */ 953 $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext); 954 $mlen0 = $mlen; 955 if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) { 956 $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES; 957 } 958 $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); 959 960 /** @var string $block0 */ 961 $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20_xor( 962 $block0, 963 ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 964 $subkey 965 ); 966 967 /** @var string $c */ 968 $c = ParagonIE_Sodium_Core32_Util::substr( 969 $block0, 970 self::secretbox_xsalsa20poly1305_ZEROBYTES 971 ); 972 if ($mlen > $mlen0) { 973 $c .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( 974 ParagonIE_Sodium_Core32_Util::substr( 975 $plaintext, 976 self::secretbox_xsalsa20poly1305_ZEROBYTES 977 ), 978 ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 979 1, 980 $subkey 981 ); 982 } 983 $state = new ParagonIE_Sodium_Core32_Poly1305_State( 984 ParagonIE_Sodium_Core32_Util::substr( 985 $block0, 986 0, 987 self::onetimeauth_poly1305_KEYBYTES 988 ) 989 ); 990 try { 991 ParagonIE_Sodium_Compat::memzero($block0); 992 ParagonIE_Sodium_Compat::memzero($subkey); 993 } catch (SodiumException $ex) { 994 $block0 = null; 995 $subkey = null; 996 } 997 998 $state->update($c); 999 1000 /** @var string $c - MAC || ciphertext */ 1001 $c = $state->finish() . $c; 1002 unset($state); 1003 1004 return $c; 1005 } 1006 1007 /** 1008 * Decrypt a ciphertext generated via secretbox(). 1009 * 1010 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 1011 * 1012 * @param string $ciphertext 1013 * @param string $nonce 1014 * @param string $key 1015 * @return string 1016 * @throws SodiumException 1017 * @throws TypeError 1018 */ 1019 public static function secretbox_open($ciphertext, $nonce, $key) 1020 { 1021 /** @var string $mac */ 1022 $mac = ParagonIE_Sodium_Core32_Util::substr( 1023 $ciphertext, 1024 0, 1025 self::secretbox_xsalsa20poly1305_MACBYTES 1026 ); 1027 1028 /** @var string $c */ 1029 $c = ParagonIE_Sodium_Core32_Util::substr( 1030 $ciphertext, 1031 self::secretbox_xsalsa20poly1305_MACBYTES 1032 ); 1033 1034 /** @var int $clen */ 1035 $clen = ParagonIE_Sodium_Core32_Util::strlen($c); 1036 1037 /** @var string $subkey */ 1038 $subkey = ParagonIE_Sodium_Core32_HSalsa20::hsalsa20($nonce, $key); 1039 1040 /** @var string $block0 */ 1041 $block0 = ParagonIE_Sodium_Core32_Salsa20::salsa20( 1042 64, 1043 ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 1044 $subkey 1045 ); 1046 $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify( 1047 $mac, 1048 $c, 1049 ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32) 1050 ); 1051 if (!$verified) { 1052 try { 1053 ParagonIE_Sodium_Compat::memzero($subkey); 1054 } catch (SodiumException $ex) { 1055 $subkey = null; 1056 } 1057 throw new SodiumException('Invalid MAC'); 1058 } 1059 1060 /** @var string $m - Decrypted message */ 1061 $m = ParagonIE_Sodium_Core32_Util::xorStrings( 1062 ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES), 1063 ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES) 1064 ); 1065 if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) { 1066 // We had more than 1 block, so let's continue to decrypt the rest. 1067 $m .= ParagonIE_Sodium_Core32_Salsa20::salsa20_xor_ic( 1068 ParagonIE_Sodium_Core32_Util::substr( 1069 $c, 1070 self::secretbox_xsalsa20poly1305_ZEROBYTES 1071 ), 1072 ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 1073 1, 1074 (string) $subkey 1075 ); 1076 } 1077 return $m; 1078 } 1079 1080 /** 1081 * XChaCha20-Poly1305 authenticated symmetric-key encryption. 1082 * 1083 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 1084 * 1085 * @param string $plaintext 1086 * @param string $nonce 1087 * @param string $key 1088 * @return string 1089 * @throws SodiumException 1090 * @throws TypeError 1091 */ 1092 public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key) 1093 { 1094 /** @var string $subkey */ 1095 $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( 1096 ParagonIE_Sodium_Core32_Util::substr($nonce, 0, 16), 1097 $key 1098 ); 1099 $nonceLast = ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8); 1100 1101 /** @var string $block0 */ 1102 $block0 = str_repeat("\x00", 32); 1103 1104 /** @var int $mlen - Length of the plaintext message */ 1105 $mlen = ParagonIE_Sodium_Core32_Util::strlen($plaintext); 1106 $mlen0 = $mlen; 1107 if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) { 1108 $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES; 1109 } 1110 $block0 .= ParagonIE_Sodium_Core32_Util::substr($plaintext, 0, $mlen0); 1111 1112 /** @var string $block0 */ 1113 $block0 = ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( 1114 $block0, 1115 $nonceLast, 1116 $subkey 1117 ); 1118 1119 /** @var string $c */ 1120 $c = ParagonIE_Sodium_Core32_Util::substr( 1121 $block0, 1122 self::secretbox_xchacha20poly1305_ZEROBYTES 1123 ); 1124 if ($mlen > $mlen0) { 1125 $c .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( 1126 ParagonIE_Sodium_Core32_Util::substr( 1127 $plaintext, 1128 self::secretbox_xchacha20poly1305_ZEROBYTES 1129 ), 1130 $nonceLast, 1131 $subkey, 1132 ParagonIE_Sodium_Core32_Util::store64_le(1) 1133 ); 1134 } 1135 $state = new ParagonIE_Sodium_Core32_Poly1305_State( 1136 ParagonIE_Sodium_Core32_Util::substr( 1137 $block0, 1138 0, 1139 self::onetimeauth_poly1305_KEYBYTES 1140 ) 1141 ); 1142 try { 1143 ParagonIE_Sodium_Compat::memzero($block0); 1144 ParagonIE_Sodium_Compat::memzero($subkey); 1145 } catch (SodiumException $ex) { 1146 $block0 = null; 1147 $subkey = null; 1148 } 1149 1150 $state->update($c); 1151 1152 /** @var string $c - MAC || ciphertext */ 1153 $c = $state->finish() . $c; 1154 unset($state); 1155 1156 return $c; 1157 } 1158 1159 /** 1160 * Decrypt a ciphertext generated via secretbox_xchacha20poly1305(). 1161 * 1162 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 1163 * 1164 * @param string $ciphertext 1165 * @param string $nonce 1166 * @param string $key 1167 * @return string 1168 * @throws SodiumException 1169 * @throws TypeError 1170 */ 1171 public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) 1172 { 1173 /** @var string $mac */ 1174 $mac = ParagonIE_Sodium_Core32_Util::substr( 1175 $ciphertext, 1176 0, 1177 self::secretbox_xchacha20poly1305_MACBYTES 1178 ); 1179 1180 /** @var string $c */ 1181 $c = ParagonIE_Sodium_Core32_Util::substr( 1182 $ciphertext, 1183 self::secretbox_xchacha20poly1305_MACBYTES 1184 ); 1185 1186 /** @var int $clen */ 1187 $clen = ParagonIE_Sodium_Core32_Util::strlen($c); 1188 1189 /** @var string $subkey */ 1190 $subkey = ParagonIE_Sodium_Core32_HChaCha20::hchacha20($nonce, $key); 1191 1192 /** @var string $block0 */ 1193 $block0 = ParagonIE_Sodium_Core32_ChaCha20::stream( 1194 64, 1195 ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 1196 $subkey 1197 ); 1198 $verified = ParagonIE_Sodium_Core32_Poly1305::onetimeauth_verify( 1199 $mac, 1200 $c, 1201 ParagonIE_Sodium_Core32_Util::substr($block0, 0, 32) 1202 ); 1203 1204 if (!$verified) { 1205 try { 1206 ParagonIE_Sodium_Compat::memzero($subkey); 1207 } catch (SodiumException $ex) { 1208 $subkey = null; 1209 } 1210 throw new SodiumException('Invalid MAC'); 1211 } 1212 1213 /** @var string $m - Decrypted message */ 1214 $m = ParagonIE_Sodium_Core32_Util::xorStrings( 1215 ParagonIE_Sodium_Core32_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES), 1216 ParagonIE_Sodium_Core32_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES) 1217 ); 1218 1219 if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) { 1220 // We had more than 1 block, so let's continue to decrypt the rest. 1221 $m .= ParagonIE_Sodium_Core32_ChaCha20::streamXorIc( 1222 ParagonIE_Sodium_Core32_Util::substr( 1223 $c, 1224 self::secretbox_xchacha20poly1305_ZEROBYTES 1225 ), 1226 ParagonIE_Sodium_Core32_Util::substr($nonce, 16, 8), 1227 (string) $subkey, 1228 ParagonIE_Sodium_Core32_Util::store64_le(1) 1229 ); 1230 } 1231 return $m; 1232 } 1233 1234 /** 1235 * @param string $key 1236 * @return array<int, string> Returns a state and a header. 1237 * @throws Exception 1238 * @throws SodiumException 1239 */ 1240 public static function secretstream_xchacha20poly1305_init_push($key) 1241 { 1242 # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES); 1243 $out = random_bytes(24); 1244 1245 # crypto_core_hchacha20(state->k, out, k, NULL); 1246 $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20($out, $key); 1247 $state = new ParagonIE_Sodium_Core32_SecretStream_State( 1248 $subkey, 1249 ParagonIE_Sodium_Core32_Util::substr($out, 16, 8) . str_repeat("\0", 4) 1250 ); 1251 1252 # _crypto_secretstream_xchacha20poly1305_counter_reset(state); 1253 $state->counterReset(); 1254 1255 # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES, 1256 # crypto_secretstream_xchacha20poly1305_INONCEBYTES); 1257 # memset(state->_pad, 0, sizeof state->_pad); 1258 return array( 1259 $state->toString(), 1260 $out 1261 ); 1262 } 1263 1264 /** 1265 * @param string $key 1266 * @param string $header 1267 * @return string Returns a state. 1268 * @throws Exception 1269 */ 1270 public static function secretstream_xchacha20poly1305_init_pull($key, $header) 1271 { 1272 # crypto_core_hchacha20(state->k, in, k, NULL); 1273 $subkey = ParagonIE_Sodium_Core32_HChaCha20::hChaCha20( 1274 ParagonIE_Sodium_Core32_Util::substr($header, 0, 16), 1275 $key 1276 ); 1277 $state = new ParagonIE_Sodium_Core32_SecretStream_State( 1278 $subkey, 1279 ParagonIE_Sodium_Core32_Util::substr($header, 16) 1280 ); 1281 $state->counterReset(); 1282 # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES, 1283 # crypto_secretstream_xchacha20poly1305_INONCEBYTES); 1284 # memset(state->_pad, 0, sizeof state->_pad); 1285 # return 0; 1286 return $state->toString(); 1287 } 1288 1289 /** 1290 * @param string $state 1291 * @param string $msg 1292 * @param string $aad 1293 * @param int $tag 1294 * @return string 1295 * @throws SodiumException 1296 */ 1297 public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0) 1298 { 1299 $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); 1300 # crypto_onetimeauth_poly1305_state poly1305_state; 1301 # unsigned char block[64U]; 1302 # unsigned char slen[8U]; 1303 # unsigned char *c; 1304 # unsigned char *mac; 1305 1306 $msglen = ParagonIE_Sodium_Core32_Util::strlen($msg); 1307 $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad); 1308 1309 if ((($msglen + 63) >> 6) > 0xfffffffe) { 1310 throw new SodiumException( 1311 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' 1312 ); 1313 } 1314 1315 # if (outlen_p != NULL) { 1316 # *outlen_p = 0U; 1317 # } 1318 # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { 1319 # sodium_misuse(); 1320 # } 1321 1322 # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); 1323 # crypto_onetimeauth_poly1305_init(&poly1305_state, block); 1324 # sodium_memzero(block, sizeof block); 1325 $auth = new ParagonIE_Sodium_Core32_Poly1305_State( 1326 ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) 1327 ); 1328 1329 # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); 1330 $auth->update($aad); 1331 1332 # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, 1333 # (0x10 - adlen) & 0xf); 1334 $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); 1335 1336 # memset(block, 0, sizeof block); 1337 # block[0] = tag; 1338 # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, 1339 # state->nonce, 1U, state->k); 1340 $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( 1341 ParagonIE_Sodium_Core32_Util::intToChr($tag) . str_repeat("\0", 63), 1342 $st->getCombinedNonce(), 1343 $st->getKey(), 1344 ParagonIE_Sodium_Core32_Util::store64_le(1) 1345 ); 1346 1347 # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); 1348 $auth->update($block); 1349 1350 # out[0] = block[0]; 1351 $out = $block[0]; 1352 # c = out + (sizeof tag); 1353 # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k); 1354 $cipher = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( 1355 $msg, 1356 $st->getCombinedNonce(), 1357 $st->getKey(), 1358 ParagonIE_Sodium_Core32_Util::store64_le(2) 1359 ); 1360 1361 # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); 1362 $auth->update($cipher); 1363 1364 $out .= $cipher; 1365 unset($cipher); 1366 1367 # crypto_onetimeauth_poly1305_update 1368 # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); 1369 $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); 1370 1371 # STORE64_LE(slen, (uint64_t) adlen); 1372 $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen); 1373 1374 # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); 1375 $auth->update($slen); 1376 1377 # STORE64_LE(slen, (sizeof block) + mlen); 1378 $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen); 1379 1380 # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); 1381 $auth->update($slen); 1382 1383 # mac = c + mlen; 1384 # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); 1385 $mac = $auth->finish(); 1386 $out .= $mac; 1387 1388 # sodium_memzero(&poly1305_state, sizeof poly1305_state); 1389 unset($auth); 1390 1391 1392 # XOR_BUF(STATE_INONCE(state), mac, 1393 # crypto_secretstream_xchacha20poly1305_INONCEBYTES); 1394 $st->xorNonce($mac); 1395 1396 # sodium_increment(STATE_COUNTER(state), 1397 # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); 1398 $st->incrementCounter(); 1399 // Overwrite by reference: 1400 $state = $st->toString(); 1401 1402 /** @var bool $rekey */ 1403 $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; 1404 # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || 1405 # sodium_is_zero(STATE_COUNTER(state), 1406 # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { 1407 # crypto_secretstream_xchacha20poly1305_rekey(state); 1408 # } 1409 if ($rekey || $st->needsRekey()) { 1410 // DO REKEY 1411 self::secretstream_xchacha20poly1305_rekey($state); 1412 } 1413 # if (outlen_p != NULL) { 1414 # *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen; 1415 # } 1416 return $out; 1417 } 1418 1419 /** 1420 * @param string $state 1421 * @param string $cipher 1422 * @param string $aad 1423 * @return bool|array{0: string, 1: int} 1424 * @throws SodiumException 1425 */ 1426 public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '') 1427 { 1428 $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); 1429 1430 $cipherlen = ParagonIE_Sodium_Core32_Util::strlen($cipher); 1431 # mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES; 1432 $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES; 1433 $aadlen = ParagonIE_Sodium_Core32_Util::strlen($aad); 1434 1435 # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) { 1436 # sodium_misuse(); 1437 # } 1438 if ((($msglen + 63) >> 6) > 0xfffffffe) { 1439 throw new SodiumException( 1440 'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes' 1441 ); 1442 } 1443 1444 # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k); 1445 # crypto_onetimeauth_poly1305_init(&poly1305_state, block); 1446 # sodium_memzero(block, sizeof block); 1447 $auth = new ParagonIE_Sodium_Core32_Poly1305_State( 1448 ParagonIE_Sodium_Core32_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey()) 1449 ); 1450 1451 # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen); 1452 $auth->update($aad); 1453 1454 # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0, 1455 # (0x10 - adlen) & 0xf); 1456 $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf))); 1457 1458 1459 # memset(block, 0, sizeof block); 1460 # block[0] = in[0]; 1461 # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block, 1462 # state->nonce, 1U, state->k); 1463 $block = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( 1464 $cipher[0] . str_repeat("\0", 63), 1465 $st->getCombinedNonce(), 1466 $st->getKey(), 1467 ParagonIE_Sodium_Core32_Util::store64_le(1) 1468 ); 1469 # tag = block[0]; 1470 # block[0] = in[0]; 1471 # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block); 1472 $tag = ParagonIE_Sodium_Core32_Util::chrToInt($block[0]); 1473 $block[0] = $cipher[0]; 1474 $auth->update($block); 1475 1476 1477 # c = in + (sizeof tag); 1478 # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen); 1479 $auth->update(ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen)); 1480 1481 # crypto_onetimeauth_poly1305_update 1482 # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf); 1483 $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf))); 1484 1485 # STORE64_LE(slen, (uint64_t) adlen); 1486 # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); 1487 $slen = ParagonIE_Sodium_Core32_Util::store64_le($aadlen); 1488 $auth->update($slen); 1489 1490 # STORE64_LE(slen, (sizeof block) + mlen); 1491 # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen); 1492 $slen = ParagonIE_Sodium_Core32_Util::store64_le(64 + $msglen); 1493 $auth->update($slen); 1494 1495 # crypto_onetimeauth_poly1305_final(&poly1305_state, mac); 1496 # sodium_memzero(&poly1305_state, sizeof poly1305_state); 1497 $mac = $auth->finish(); 1498 1499 # stored_mac = c + mlen; 1500 # if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) { 1501 # sodium_memzero(mac, sizeof mac); 1502 # return -1; 1503 # } 1504 1505 $stored = ParagonIE_Sodium_Core32_Util::substr($cipher, $msglen + 1, 16); 1506 if (!ParagonIE_Sodium_Core32_Util::hashEquals($mac, $stored)) { 1507 return false; 1508 } 1509 1510 # crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k); 1511 $out = ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( 1512 ParagonIE_Sodium_Core32_Util::substr($cipher, 1, $msglen), 1513 $st->getCombinedNonce(), 1514 $st->getKey(), 1515 ParagonIE_Sodium_Core32_Util::store64_le(2) 1516 ); 1517 1518 # XOR_BUF(STATE_INONCE(state), mac, 1519 # crypto_secretstream_xchacha20poly1305_INONCEBYTES); 1520 $st->xorNonce($mac); 1521 1522 # sodium_increment(STATE_COUNTER(state), 1523 # crypto_secretstream_xchacha20poly1305_COUNTERBYTES); 1524 $st->incrementCounter(); 1525 1526 # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 || 1527 # sodium_is_zero(STATE_COUNTER(state), 1528 # crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) { 1529 # crypto_secretstream_xchacha20poly1305_rekey(state); 1530 # } 1531 1532 // Overwrite by reference: 1533 $state = $st->toString(); 1534 1535 /** @var bool $rekey */ 1536 $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0; 1537 if ($rekey || $st->needsRekey()) { 1538 // DO REKEY 1539 self::secretstream_xchacha20poly1305_rekey($state); 1540 } 1541 return array($out, $tag); 1542 } 1543 1544 /** 1545 * @param string $state 1546 * @return void 1547 * @throws SodiumException 1548 */ 1549 public static function secretstream_xchacha20poly1305_rekey(&$state) 1550 { 1551 $st = ParagonIE_Sodium_Core32_SecretStream_State::fromString($state); 1552 # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + 1553 # crypto_secretstream_xchacha20poly1305_INONCEBYTES]; 1554 # size_t i; 1555 # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { 1556 # new_key_and_inonce[i] = state->k[i]; 1557 # } 1558 $new_key_and_inonce = $st->getKey(); 1559 1560 # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { 1561 # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] = 1562 # STATE_INONCE(state)[i]; 1563 # } 1564 $new_key_and_inonce .= ParagonIE_Sodium_Core32_Util::substR($st->getNonce(), 0, 8); 1565 1566 # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce, 1567 # sizeof new_key_and_inonce, 1568 # state->nonce, state->k); 1569 1570 $st->rekey(ParagonIE_Sodium_Core32_ChaCha20::ietfStreamXorIc( 1571 $new_key_and_inonce, 1572 $st->getCombinedNonce(), 1573 $st->getKey(), 1574 ParagonIE_Sodium_Core32_Util::store64_le(0) 1575 )); 1576 1577 # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) { 1578 # state->k[i] = new_key_and_inonce[i]; 1579 # } 1580 # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) { 1581 # STATE_INONCE(state)[i] = 1582 # new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i]; 1583 # } 1584 # _crypto_secretstream_xchacha20poly1305_counter_reset(state); 1585 $st->counterReset(); 1586 1587 $state = $st->toString(); 1588 } 1589 1590 /** 1591 * Detached Ed25519 signature. 1592 * 1593 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 1594 * 1595 * @param string $message 1596 * @param string $sk 1597 * @return string 1598 * @throws SodiumException 1599 * @throws TypeError 1600 */ 1601 public static function sign_detached($message, $sk) 1602 { 1603 return ParagonIE_Sodium_Core32_Ed25519::sign_detached($message, $sk); 1604 } 1605 1606 /** 1607 * Attached Ed25519 signature. (Returns a signed message.) 1608 * 1609 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 1610 * 1611 * @param string $message 1612 * @param string $sk 1613 * @return string 1614 * @throws SodiumException 1615 * @throws TypeError 1616 */ 1617 public static function sign($message, $sk) 1618 { 1619 return ParagonIE_Sodium_Core32_Ed25519::sign($message, $sk); 1620 } 1621 1622 /** 1623 * Opens a signed message. If valid, returns the message. 1624 * 1625 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 1626 * 1627 * @param string $signedMessage 1628 * @param string $pk 1629 * @return string 1630 * @throws SodiumException 1631 * @throws TypeError 1632 */ 1633 public static function sign_open($signedMessage, $pk) 1634 { 1635 return ParagonIE_Sodium_Core32_Ed25519::sign_open($signedMessage, $pk); 1636 } 1637 1638 /** 1639 * Verify a detached signature of a given message and public key. 1640 * 1641 * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. 1642 * 1643 * @param string $signature 1644 * @param string $message 1645 * @param string $pk 1646 * @return bool 1647 * @throws SodiumException 1648 * @throws TypeError 1649 */ 1650 public static function sign_verify_detached($signature, $message, $pk) 1651 { 1652 return ParagonIE_Sodium_Core32_Ed25519::verify_detached($signature, $message, $pk); 1653 } 1654 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Nov 21 08:20:01 2024 | Cross-referenced by PHPXref |