Make WordPress Core

Changeset 46858


Ignore:
Timestamp:
12/09/2019 04:40:11 PM (5 years ago)
Author:
SergeyBiryukov
Message:

Upgrade/Install: Update sodium_compat to v1.12.1.

This includes a speedup for signature verification on most platforms and bugfixes for 32-bit platforms.

Props paragoninitiativeenterprises, lukaswaudentio.
Fixes #48371.

Location:
trunk/src/wp-includes/sodium_compat
Files:
11 added
19 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/sodium_compat/LICENSE

    r45344 r46858  
    22 * ISC License
    33 *
    4  * Copyright (c) 2016-2018
     4 * Copyright (c) 2016-2019
    55 * Paragon Initiative Enterprises <security at paragonie dot com>
    66 *
    7  * Copyright (c) 2013-2018
     7 * Copyright (c) 2013-2019
    88 * Frank Denis <j at pureftpd dot org>
    99 *
  • trunk/src/wp-includes/sodium_compat/autoload.php

    r46586 r46858  
    4444    require_once dirname(__FILE__) . '/lib/namespaced.php';
    4545    require_once dirname(__FILE__) . '/lib/sodium_compat.php';
     46} else {
     47    require_once dirname(__FILE__) . '/src/PHP52/SplFixedArray.php';
    4648}
    4749if (PHP_VERSION_ID < 70200 || !extension_loaded('sodium')) {
    48     require_once dirname(__FILE__) . '/lib/php72compat.php';
     50    if (PHP_VERSION_ID >= 50300 && !defined('SODIUM_CRYPTO_SCALARMULT_BYTES')) {
     51        require_once dirname(__FILE__) . '/lib/php72compat_const.php';
     52    }
     53    if (PHP_VERSION_ID >= 70000) {
     54        assert(class_exists('ParagonIE_Sodium_Compat'), 'Possible filesystem/autoloader bug?');
     55    } else {
     56        assert(class_exists('ParagonIE_Sodium_Compat'));
     57    }
     58    require_once (dirname(__FILE__) . '/lib/php72compat.php');
    4959}
  • trunk/src/wp-includes/sodium_compat/composer.json

    r46587 r46858  
    5555  },
    5656  "require-dev": {
    57     "phpunit/phpunit": "^3|^4|^5"
     57    "phpunit/phpunit": "^3|^4|^5|^6|^7"
    5858  },
    5959  "suggest": {
  • trunk/src/wp-includes/sodium_compat/lib/constants.php

    r46586 r46858  
    11<?php
    22namespace Sodium;
     3
     4require_once dirname(dirname(__FILE__)) . '/autoload.php';
    35
    46use ParagonIE_Sodium_Compat;
  • trunk/src/wp-includes/sodium_compat/lib/namespaced.php

    r46586 r46858  
    11<?php
     2
     3require_once dirname(dirname(__FILE__)) . '/autoload.php';
    24
    35if (PHP_VERSION_ID < 50300) {
     
    3739    // separators with directory separators in the relative class name, append
    3840    // with .php
    39     $file = dirname(__DIR__) . '/namespaced/' . str_replace('\\', '/', $relative_class) . '.php';
     41    $file = dirname(dirname(__FILE__)) . '/namespaced/' . str_replace('\\', '/', $relative_class) . '.php';
    4042    // if the file exists, require it
    4143    if (file_exists($file)) {
  • trunk/src/wp-includes/sodium_compat/lib/php72compat.php

    r46586 r46858  
    11<?php
     2
     3require_once dirname(dirname(__FILE__)) . '/autoload.php';
    24
    35/**
     
    911 */
    1012foreach (array(
     13    'BASE64_VARIANT_ORIGINAL',
     14    'BASE64_VARIANT_ORIGINAL_NO_PADDING',
     15    'BASE64_VARIANT_URLSAFE',
     16    'BASE64_VARIANT_URLSAFE_NO_PADDING',
    1117    'CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES',
    1218    'CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES',
     
    3036    'CRYPTO_BOX_NONCEBYTES',
    3137    'CRYPTO_BOX_SEEDBYTES',
     38    'CRYPTO_KDF_BYTES_MIN',
     39    'CRYPTO_KDF_BYTES_MAX',
     40    'CRYPTO_KDF_CONTEXTBYTES',
     41    'CRYPTO_KDF_KEYBYTES',
    3242    'CRYPTO_KX_BYTES',
     43    'CRYPTO_KX_KEYPAIRBYTES',
     44    'CRYPTO_KX_PRIMITIVE',
    3345    'CRYPTO_KX_SEEDBYTES',
    3446    'CRYPTO_KX_PUBLICKEYBYTES',
    3547    'CRYPTO_KX_SECRETKEYBYTES',
     48    'CRYPTO_KX_SESSIONKEYBYTES',
    3649    'CRYPTO_GENERICHASH_BYTES',
    3750    'CRYPTO_GENERICHASH_BYTES_MIN',
     
    5770    'CRYPTO_SECRETBOX_MACBYTES',
    5871    'CRYPTO_SECRETBOX_NONCEBYTES',
     72    'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES',
     73    'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES',
     74    'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES',
     75    'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH',
     76    'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL',
     77    'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY',
     78    'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL',
     79    'CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX',
    5980    'CRYPTO_SIGN_BYTES',
    6081    'CRYPTO_SIGN_SEEDBYTES',
     
    6990    ) as $constant
    7091) {
    71     if (!defined("SODIUM_$constant")) {
     92    if (!defined("SODIUM_$constant") && defined("ParagonIE_Sodium_Compat::$constant")) {
    7293        define("SODIUM_$constant", constant("ParagonIE_Sodium_Compat::$constant"));
    7394    }
    7495}
    75 
     96if (!is_callable('sodium_add')) {
     97    /**
     98     * @see ParagonIE_Sodium_Compat::add()
     99     * @param string $val
     100     * @param string $addv
     101     * @return void
     102     * @throws SodiumException
     103     */
     104    function sodium_add(&$val, $addv)
     105    {
     106        ParagonIE_Sodium_Compat::add($val, $addv);
     107    }
     108}
     109if (!is_callable('sodium_base642bin')) {
     110    /**
     111     * @see ParagonIE_Sodium_Compat::bin2base64()
     112     * @param string $string
     113     * @param int $variant
     114     * @param string $ignore
     115     * @return string
     116     * @throws SodiumException
     117     * @throws TypeError
     118     */
     119    function sodium_base642bin($string, $variant, $ignore ='')
     120    {
     121        return ParagonIE_Sodium_Compat::base642bin($string, $variant, $ignore);
     122    }
     123}
     124if (!is_callable('sodium_bin2base64')) {
     125    /**
     126     * @see ParagonIE_Sodium_Compat::bin2base64()
     127     * @param string $string
     128     * @param int $variant
     129     * @return string
     130     * @throws SodiumException
     131     * @throws TypeError
     132     */
     133    function sodium_bin2base64($string, $variant)
     134    {
     135        return ParagonIE_Sodium_Compat::bin2base64($string, $variant);
     136    }
     137}
    76138if (!is_callable('sodium_bin2hex')) {
    77139    /**
     
    187249     * @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_keygen()
    188250     * @return string
     251     * @throws Exception
    189252     */
    190253    function sodium_crypto_aead_chacha20poly1305_keygen()
     
    233296     * @see ParagonIE_Sodium_Compat::crypto_aead_chacha20poly1305_ietf_keygen()
    234297     * @return string
     298     * @throws Exception
    235299     */
    236300    function sodium_crypto_aead_chacha20poly1305_ietf_keygen()
     
    279343     * @see ParagonIE_Sodium_Compat::crypto_aead_xchacha20poly1305_ietf_keygen()
    280344     * @return string
     345     * @throws Exception
    281346     */
    282347    function sodium_crypto_aead_xchacha20poly1305_ietf_keygen()
     
    303368     * @see ParagonIE_Sodium_Compat::crypto_auth_keygen()
    304369     * @return string
     370     * @throws Exception
    305371     */
    306372    function sodium_crypto_auth_keygen()
     
    517583     * @see ParagonIE_Sodium_Compat::crypto_generichash_keygen()
    518584     * @return string
     585     * @throws Exception
    519586     */
    520587    function sodium_crypto_generichash_keygen()
     
    535602    {
    536603        ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, $message);
     604    }
     605}
     606if (!is_callable('sodium_crypto_kdf_keygen')) {
     607    /**
     608     * @see ParagonIE_Sodium_Compat::crypto_kdf_keygen()
     609     * @return string
     610     * @throws Exception
     611     */
     612    function sodium_crypto_kdf_keygen()
     613    {
     614        return ParagonIE_Sodium_Compat::crypto_kdf_keygen();
     615    }
     616}
     617if (!is_callable('sodium_crypto_kdf_derive_from_key')) {
     618    /**
     619     * @see ParagonIE_Sodium_Compat::crypto_kdf_derive_from_key()
     620     * @param int $subkey_len
     621     * @param int $subkey_id
     622     * @param string $context
     623     * @param string $key
     624     * @return string
     625     * @throws Exception
     626     */
     627    function sodium_crypto_kdf_derive_from_key($subkey_len, $subkey_id, $context, $key)
     628    {
     629        return ParagonIE_Sodium_Compat::crypto_kdf_derive_from_key(
     630            $subkey_len,
     631            $subkey_id,
     632            $context,
     633            $key
     634        );
    537635    }
    538636}
     
    556654            $server_public
    557655        );
     656    }
     657}
     658if (!is_callable('sodium_crypto_kx_seed_keypair')) {
     659    /**
     660     * @param string $seed
     661     * @return string
     662     * @throws Exception
     663     */
     664    function sodium_crypto_kx_seed_keypair($seed)
     665    {
     666        return ParagonIE_Sodium_Compat::crypto_kx_seed_keypair($seed);
     667    }
     668}
     669if (!is_callable('sodium_crypto_kx_keypair')) {
     670    /**
     671     * @return string
     672     * @throws Exception
     673     */
     674    function sodium_crypto_kx_keypair()
     675    {
     676        return ParagonIE_Sodium_Compat::crypto_kx_keypair();
     677    }
     678}
     679if (!is_callable('sodium_crypto_kx_client_session_keys')) {
     680    /**
     681     * @param string $keypair
     682     * @param string $serverPublicKey
     683     * @return array{0: string, 1: string}
     684     * @throws SodiumException
     685     */
     686    function sodium_crypto_kx_client_session_keys($keypair, $serverPublicKey)
     687    {
     688        return ParagonIE_Sodium_Compat::crypto_kx_client_session_keys($keypair, $serverPublicKey);
     689    }
     690}
     691if (!is_callable('sodium_crypto_kx_server_session_keys')) {
     692    /**
     693     * @param string $keypair
     694     * @param string $clientPublicKey
     695     * @return array{0: string, 1: string}
     696     * @throws SodiumException
     697     */
     698    function sodium_crypto_kx_server_session_keys($keypair, $clientPublicKey)
     699    {
     700        return ParagonIE_Sodium_Compat::crypto_kx_server_session_keys($keypair, $clientPublicKey);
     701    }
     702}
     703if (!is_callable('sodium_crypto_kx_secretkey')) {
     704    /**
     705     * @param string $keypair
     706     * @return string
     707     * @throws Exception
     708     */
     709    function sodium_crypto_kx_secretkey($keypair)
     710    {
     711        return ParagonIE_Sodium_Compat::crypto_kx_secretkey($keypair);
     712    }
     713}
     714if (!is_callable('sodium_crypto_kx_publickey')) {
     715    /**
     716     * @param string $keypair
     717     * @return string
     718     * @throws Exception
     719     */
     720    function sodium_crypto_kx_publickey($keypair)
     721    {
     722        return ParagonIE_Sodium_Compat::crypto_kx_publickey($keypair);
    558723    }
    559724}
     
    591756    }
    592757}
     758if (!is_callable('sodium_crypto_pwhash_str_needs_rehash')) {
     759    /**
     760     * @see ParagonIE_Sodium_Compat::crypto_pwhash_str_needs_rehash()
     761     * @param string $hash
     762     * @param int $opslimit
     763     * @param int $memlimit
     764     * @return bool
     765     *
     766     * @throws SodiumException
     767     */
     768    function sodium_crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit)
     769    {
     770        return ParagonIE_Sodium_Compat::crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit);
     771    }
     772}
    593773if (!is_callable('sodium_crypto_pwhash_str_verify')) {
    594774    /**
     
    697877     * @see ParagonIE_Sodium_Compat::crypto_secretbox_keygen()
    698878     * @return string
     879     * @throws Exception
    699880     */
    700881    function sodium_crypto_secretbox_keygen()
     
    722903    }
    723904}
     905if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_init_push')) {
     906    /**
     907     * @param string $key
     908     * @return array<int, string>
     909     * @throws SodiumException
     910     */
     911    function sodium_crypto_secretstream_xchacha20poly1305_init_push($key)
     912    {
     913        return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_push($key);
     914    }
     915}
     916if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_push')) {
     917    /**
     918     * @param string $state
     919     * @param string $msg
     920     * @param string $aad
     921     * @param int $tag
     922     * @return string
     923     * @throws SodiumException
     924     */
     925    function sodium_crypto_secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
     926    {
     927        return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_push($state, $msg, $aad, $tag);
     928    }
     929}
     930if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_init_pull')) {
     931    /**
     932     * @param string $header
     933     * @param string $key
     934     * @return string
     935     * @throws Exception
     936     */
     937    function sodium_crypto_secretstream_xchacha20poly1305_init_pull($header, $key)
     938    {
     939        return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_init_pull($header, $key);
     940    }
     941}
     942if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_pull')) {
     943    /**
     944     * @param string $state
     945     * @param string $cipher
     946     * @param string $aad
     947     * @return bool|array{0: string, 1: int}
     948     * @throws SodiumException
     949     */
     950    function sodium_crypto_secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
     951    {
     952        return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_pull($state, $cipher, $aad);
     953    }
     954}
     955if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_rekey')) {
     956    /**
     957     * @param string $state
     958     * @return void
     959     * @throws SodiumException
     960     */
     961    function sodium_crypto_secretstream_xchacha20poly1305_rekey(&$state)
     962    {
     963        ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_rekey($state);
     964    }
     965}
     966if (!is_callable('sodium_crypto_secretstream_xchacha20poly1305_keygen')) {
     967    /**
     968     * @return string
     969     * @throws Exception
     970     */
     971    function sodium_crypto_secretstream_xchacha20poly1305_keygen()
     972    {
     973        return ParagonIE_Sodium_Compat::crypto_secretstream_xchacha20poly1305_keygen();
     974    }
     975}
    724976if (!is_callable('sodium_crypto_shorthash')) {
    725977    /**
     
    740992     * @see ParagonIE_Sodium_Compat::crypto_shorthash_keygen()
    741993     * @return string
     994     * @throws Exception
    742995     */
    743996    function sodium_crypto_shorthash_keygen()
     
    7721025    {
    7731026        return ParagonIE_Sodium_Compat::crypto_sign_detached($message, $sk);
     1027    }
     1028}
     1029if (!is_callable('sodium_crypto_sign_keypair_from_secretkey_and_publickey')) {
     1030    /**
     1031     * @see ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey()
     1032     * @param string $sk
     1033     * @param string $pk
     1034     * @return string
     1035     * @throws SodiumException
     1036     * @throws TypeError
     1037     */
     1038    function sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk)
     1039    {
     1040        return ParagonIE_Sodium_Compat::crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk);
    7741041    }
    7751042}
     
    9161183     * @see ParagonIE_Sodium_Compat::crypto_stream_keygen()
    9171184     * @return string
     1185     * @throws Exception
    9181186     */
    9191187    function sodium_crypto_stream_keygen()
     
    10201288    }
    10211289}
     1290if (!is_callable('sodium_pad')) {
     1291    /**
     1292     * @see ParagonIE_Sodium_Compat::pad()
     1293     * @param string $unpadded
     1294     * @param int $blockSize
     1295     * @return int
     1296     * @throws SodiumException
     1297     * @throws TypeError
     1298     */
     1299    function sodium_pad($unpadded, $blockSize)
     1300    {
     1301        return ParagonIE_Sodium_Compat::pad($unpadded, $blockSize, true);
     1302    }
     1303}
     1304if (!is_callable('sodium_unpad')) {
     1305    /**
     1306     * @see ParagonIE_Sodium_Compat::pad()
     1307     * @param string $padded
     1308     * @param int $blockSize
     1309     * @return int
     1310     * @throws SodiumException
     1311     * @throws TypeError
     1312     */
     1313    function sodium_unpad($padded, $blockSize)
     1314    {
     1315        return ParagonIE_Sodium_Compat::unpad($padded, $blockSize, true);
     1316    }
     1317}
    10221318if (!is_callable('sodium_randombytes_buf')) {
    10231319    /**
     
    10501346     * @see ParagonIE_Sodium_Compat::randombytes_random16()
    10511347     * @return int
     1348     * @throws Exception
    10521349     */
    10531350    function sodium_randombytes_random16()
  • trunk/src/wp-includes/sodium_compat/lib/sodium_compat.php

    r46586 r46858  
    11<?php
    22namespace Sodium;
     3
     4require_once dirname(dirname(__FILE__)) . '/autoload.php';
    35
    46use ParagonIE_Sodium_Compat;
  • trunk/src/wp-includes/sodium_compat/src/Compat.php

    r46586 r46858  
    5050
    5151    // From libsodium
     52    const BASE64_VARIANT_ORIGINAL = 1;
     53    const BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
     54    const BASE64_VARIANT_URLSAFE = 5;
     55    const BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
    5256    const CRYPTO_AEAD_AES256GCM_KEYBYTES = 32;
    5357    const CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
     
    7579    const CRYPTO_BOX_NONCEBYTES = 24;
    7680    const CRYPTO_BOX_SEEDBYTES = 32;
     81    const CRYPTO_KDF_BYTES_MIN = 16;
     82    const CRYPTO_KDF_BYTES_MAX = 64;
     83    const CRYPTO_KDF_CONTEXTBYTES = 8;
     84    const CRYPTO_KDF_KEYBYTES = 32;
    7785    const CRYPTO_KX_BYTES = 32;
     86    const CRYPTO_KX_PRIMITIVE = 'x25519blake2b';
    7887    const CRYPTO_KX_SEEDBYTES = 32;
     88    const CRYPTO_KX_KEYPAIRBYTES = 64;
    7989    const CRYPTO_KX_PUBLICKEYBYTES = 32;
    8090    const CRYPTO_KX_SECRETKEYBYTES = 32;
     91    const CRYPTO_KX_SESSIONKEYBYTES = 32;
    8192    const CRYPTO_GENERICHASH_BYTES = 32;
    8293    const CRYPTO_GENERICHASH_BYTES_MIN = 16;
     
    8697    const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
    8798    const CRYPTO_PWHASH_SALTBYTES = 16;
    88     const CRYPTO_PWHASH_STRPREFIX = '$argon2i$';
     99    const CRYPTO_PWHASH_STRPREFIX = '$argon2id$';
    89100    const CRYPTO_PWHASH_ALG_ARGON2I13 = 1;
    90101    const CRYPTO_PWHASH_ALG_ARGON2ID13 = 2;
     
    108119    const CRYPTO_SECRETBOX_MACBYTES = 16;
    109120    const CRYPTO_SECRETBOX_NONCEBYTES = 24;
     121    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17;
     122    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24;
     123    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32;
     124    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0;
     125    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1;
     126    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2;
     127    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3;
     128    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80;
    110129    const CRYPTO_SIGN_BYTES = 64;
    111130    const CRYPTO_SIGN_SEEDBYTES = 32;
     
    115134    const CRYPTO_STREAM_KEYBYTES = 32;
    116135    const CRYPTO_STREAM_NONCEBYTES = 24;
     136
     137    /**
     138     * Add two numbers (little-endian unsigned), storing the value in the first
     139     * parameter.
     140     *
     141     * This mutates $val.
     142     *
     143     * @param string $val
     144     * @param string $addv
     145     * @return void
     146     * @throws SodiumException
     147     */
     148    public static function add(&$val, $addv)
     149    {
     150        $val_len = ParagonIE_Sodium_Core_Util::strlen($val);
     151        $addv_len = ParagonIE_Sodium_Core_Util::strlen($addv);
     152        if ($val_len !== $addv_len) {
     153            throw new SodiumException('values must have the same length');
     154        }
     155        $A = ParagonIE_Sodium_Core_Util::stringToIntArray($val);
     156        $B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv);
     157
     158        $c = 0;
     159        for ($i = 0; $i < $val_len; $i++) {
     160            $c += ($A[$i] + $B[$i]);
     161            $A[$i] = ($c & 0xff);
     162            $c >>= 8;
     163        }
     164        $val = ParagonIE_Sodium_Core_Util::intArrayToString($A);
     165    }
     166
     167    /**
     168     * @param string $encoded
     169     * @param int $variant
     170     * @param string $ignore
     171     * @return string
     172     * @throws SodiumException
     173     */
     174    public static function base642bin($encoded, $variant, $ignore = '')
     175    {
     176        /* Type checks: */
     177        ParagonIE_Sodium_Core_Util::declareScalarType($encoded, 'string', 1);
     178
     179        /** @var string $encoded */
     180        $encoded = (string) $encoded;
     181        if (ParagonIE_Sodium_Core_Util::strlen($encoded) === 0) {
     182            return '';
     183        }
     184
     185        // Just strip before decoding
     186        if (!empty($ignore)) {
     187            $encoded = str_replace($ignore, '', $encoded);
     188        }
     189
     190        try {
     191            switch ($variant) {
     192                case self::BASE64_VARIANT_ORIGINAL:
     193                    return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, true);
     194                case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
     195                    return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, false);
     196                case self::BASE64_VARIANT_URLSAFE:
     197                    return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, true);
     198                case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
     199                    return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, false);
     200                default:
     201                    throw new SodiumException('invalid base64 variant identifier');
     202            }
     203        } catch (Exception $ex) {
     204            if ($ex instanceof SodiumException) {
     205                throw $ex;
     206            }
     207            throw new SodiumException('invalid base64 string');
     208        }
     209    }
     210
     211    /**
     212     * @param string $decoded
     213     * @param int $variant
     214     * @return string
     215     * @throws SodiumException
     216     */
     217    public static function bin2base64($decoded, $variant)
     218    {
     219        /* Type checks: */
     220        ParagonIE_Sodium_Core_Util::declareScalarType($decoded, 'string', 1);
     221        /** @var string $decoded */
     222        $decoded = (string) $decoded;
     223        if (ParagonIE_Sodium_Core_Util::strlen($decoded) === 0) {
     224            return '';
     225        }
     226
     227        switch ($variant) {
     228            case self::BASE64_VARIANT_ORIGINAL:
     229                return ParagonIE_Sodium_Core_Base64_Original::encode($decoded);
     230            case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
     231                return ParagonIE_Sodium_Core_Base64_Original::encodeUnpadded($decoded);
     232            case self::BASE64_VARIANT_URLSAFE:
     233                return ParagonIE_Sodium_Core_Base64_UrlSafe::encode($decoded);
     234            case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
     235                return ParagonIE_Sodium_Core_Base64_UrlSafe::encodeUnpadded($decoded);
     236            default:
     237                throw new SodiumException('invalid base64 variant identifier');
     238        }
     239    }
    117240
    118241    /**
     
    13111434     * @psalm-suppress MixedArgument
    13121435     * @psalm-suppress ReferenceConstraintViolation
     1436     * @psalm-suppress ConflictingReferenceConstraint
    13131437     */
    13141438    public static function crypto_generichash_final(&$ctx, $length = self::CRYPTO_GENERICHASH_BYTES)
     
    13241448            $func = '\\Sodium\\crypto_generichash_final';
    13251449            return (string) $func($ctx, $length);
     1450        }
     1451        if ($length < 1) {
     1452            try {
     1453                self::memzero($ctx);
     1454            } catch (SodiumException $ex) {
     1455                unset($ctx);
     1456            }
     1457            return '';
    13261458        }
    13271459        if (PHP_INT_SIZE === 4) {
     
    13811513
    13821514    /**
     1515     * Initialize a BLAKE2b hashing context, for use in a streaming interface.
     1516     *
     1517     * @param string|null $key If specified must be a string between 16 and 64 bytes
     1518     * @param int $length      The size of the desired hash output
     1519     * @param string $salt     Salt (up to 16 bytes)
     1520     * @param string $personal Personalization string (up to 16 bytes)
     1521     * @return string          A BLAKE2 hashing context, encoded as a string
     1522     *                         (To be 100% compatible with ext/libsodium)
     1523     * @throws SodiumException
     1524     * @throws TypeError
     1525     * @psalm-suppress MixedArgument
     1526     */
     1527    public static function crypto_generichash_init_salt_personal(
     1528        $key = '',
     1529        $length = self::CRYPTO_GENERICHASH_BYTES,
     1530        $salt = '',
     1531        $personal = ''
     1532    ) {
     1533        /* Type checks: */
     1534        if (is_null($key)) {
     1535            $key = '';
     1536        }
     1537        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1);
     1538        ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
     1539        ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3);
     1540        ParagonIE_Sodium_Core_Util::declareScalarType($personal, 'string', 4);
     1541        $salt = str_pad($salt, 16, "\0", STR_PAD_RIGHT);
     1542        $personal = str_pad($personal, 16, "\0", STR_PAD_RIGHT);
     1543
     1544        /* Input validation: */
     1545        if (!empty($key)) {
     1546            /*
     1547            if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
     1548                throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
     1549            }
     1550            */
     1551            if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
     1552                throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
     1553            }
     1554        }
     1555        if (PHP_INT_SIZE === 4) {
     1556            return ParagonIE_Sodium_Crypto32::generichash_init_salt_personal($key, $length, $salt, $personal);
     1557        }
     1558        return ParagonIE_Sodium_Crypto::generichash_init_salt_personal($key, $length, $salt, $personal);
     1559    }
     1560
     1561    /**
    13831562     * Update a BLAKE2b hashing context with additional data.
    13841563     *
     
    14231602    {
    14241603        return random_bytes(self::CRYPTO_GENERICHASH_KEYBYTES);
     1604    }
     1605
     1606    /**
     1607     * @param int $subkey_len
     1608     * @param int $subkey_id
     1609     * @param string $context
     1610     * @param string $key
     1611     * @return string
     1612     * @throws SodiumException
     1613     */
     1614    public static function crypto_kdf_derive_from_key(
     1615        $subkey_len,
     1616        $subkey_id,
     1617        $context,
     1618        $key
     1619    ) {
     1620        ParagonIE_Sodium_Core_Util::declareScalarType($subkey_len, 'int', 1);
     1621        ParagonIE_Sodium_Core_Util::declareScalarType($subkey_id, 'int', 2);
     1622        ParagonIE_Sodium_Core_Util::declareScalarType($context, 'string', 3);
     1623        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
     1624        $subkey_id = (int) $subkey_id;
     1625        $subkey_len = (int) $subkey_len;
     1626        $context = (string) $context;
     1627        $key = (string) $key;
     1628
     1629        if ($subkey_len < self::CRYPTO_KDF_BYTES_MIN) {
     1630            throw new SodiumException('subkey cannot be smaller than SODIUM_CRYPTO_KDF_BYTES_MIN');
     1631        }
     1632        if ($subkey_len > self::CRYPTO_KDF_BYTES_MAX) {
     1633            throw new SodiumException('subkey cannot be larger than SODIUM_CRYPTO_KDF_BYTES_MAX');
     1634        }
     1635        if ($subkey_id < 0) {
     1636            throw new SodiumException('subkey_id cannot be negative');
     1637        }
     1638        if (ParagonIE_Sodium_Core_Util::strlen($context) !== self::CRYPTO_KDF_CONTEXTBYTES) {
     1639            throw new SodiumException('context should be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes');
     1640        }
     1641        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_KDF_KEYBYTES) {
     1642            throw new SodiumException('key should be SODIUM_CRYPTO_KDF_KEYBYTES bytes');
     1643        }
     1644
     1645        $salt = ParagonIE_Sodium_Core_Util::store64_le($subkey_id);
     1646        $state = self::crypto_generichash_init_salt_personal(
     1647            $key,
     1648            $subkey_len,
     1649            $salt,
     1650            $context
     1651        );
     1652        return self::crypto_generichash_final($state, $subkey_len);
     1653    }
     1654
     1655    /**
     1656     * @return string
     1657     * @throws Exception
     1658     * @throws Error
     1659     */
     1660    public static function crypto_kdf_keygen()
     1661    {
     1662        return random_bytes(self::CRYPTO_KDF_KEYBYTES);
    14251663    }
    14261664
     
    15121750
    15131751    /**
     1752     * @param string $seed
     1753     * @return string
     1754     * @throws SodiumException
     1755     */
     1756    public static function crypto_kx_seed_keypair($seed)
     1757    {
     1758        ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
     1759
     1760        $seed = (string) $seed;
     1761
     1762        if (ParagonIE_Sodium_Core_Util::strlen($seed) !== self::CRYPTO_KX_SEEDBYTES) {
     1763            throw new SodiumException('seed must be SODIUM_CRYPTO_KX_SEEDBYTES bytes');
     1764        }
     1765
     1766        $sk = self::crypto_generichash($seed, '', self::CRYPTO_KX_SECRETKEYBYTES);
     1767        $pk = self::crypto_scalarmult_base($sk);
     1768        return $sk . $pk;
     1769    }
     1770
     1771    /**
     1772     * @return string
     1773     * @throws Exception
     1774     */
     1775    public static function crypto_kx_keypair()
     1776    {
     1777        $sk = self::randombytes_buf(self::CRYPTO_KX_SECRETKEYBYTES);
     1778        $pk = self::crypto_scalarmult_base($sk);
     1779        return $sk . $pk;
     1780    }
     1781
     1782    /**
     1783     * @param string $keypair
     1784     * @param string $serverPublicKey
     1785     * @return array{0: string, 1: string}
     1786     * @throws SodiumException
     1787     */
     1788    public static function crypto_kx_client_session_keys($keypair, $serverPublicKey)
     1789    {
     1790        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
     1791        ParagonIE_Sodium_Core_Util::declareScalarType($serverPublicKey, 'string', 2);
     1792
     1793        $keypair = (string) $keypair;
     1794        $serverPublicKey = (string) $serverPublicKey;
     1795
     1796        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) {
     1797            throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
     1798        }
     1799        if (ParagonIE_Sodium_Core_Util::strlen($serverPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) {
     1800            throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
     1801        }
     1802
     1803        $sk = self::crypto_kx_secretkey($keypair);
     1804        $pk = self::crypto_kx_publickey($keypair);
     1805        $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
     1806        self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $serverPublicKey));
     1807        self::crypto_generichash_update($h, $pk);
     1808        self::crypto_generichash_update($h, $serverPublicKey);
     1809        $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
     1810        return array(
     1811            ParagonIE_Sodium_Core_Util::substr(
     1812                $sessionKeys,
     1813                0,
     1814                self::CRYPTO_KX_SESSIONKEYBYTES
     1815            ),
     1816            ParagonIE_Sodium_Core_Util::substr(
     1817                $sessionKeys,
     1818                self::CRYPTO_KX_SESSIONKEYBYTES,
     1819                self::CRYPTO_KX_SESSIONKEYBYTES
     1820            )
     1821        );
     1822    }
     1823
     1824    /**
     1825     * @param string $keypair
     1826     * @param string $clientPublicKey
     1827     * @return array{0: string, 1: string}
     1828     * @throws SodiumException
     1829     */
     1830    public static function crypto_kx_server_session_keys($keypair, $clientPublicKey)
     1831    {
     1832        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
     1833        ParagonIE_Sodium_Core_Util::declareScalarType($clientPublicKey, 'string', 2);
     1834
     1835        $keypair = (string) $keypair;
     1836        $clientPublicKey = (string) $clientPublicKey;
     1837
     1838        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) {
     1839            throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
     1840        }
     1841        if (ParagonIE_Sodium_Core_Util::strlen($clientPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) {
     1842            throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
     1843        }
     1844
     1845        $sk = self::crypto_kx_secretkey($keypair);
     1846        $pk = self::crypto_kx_publickey($keypair);
     1847        $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
     1848        self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $clientPublicKey));
     1849        self::crypto_generichash_update($h, $clientPublicKey);
     1850        self::crypto_generichash_update($h, $pk);
     1851        $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
     1852        return array(
     1853            ParagonIE_Sodium_Core_Util::substr(
     1854                $sessionKeys,
     1855                self::CRYPTO_KX_SESSIONKEYBYTES,
     1856                self::CRYPTO_KX_SESSIONKEYBYTES
     1857            ),
     1858            ParagonIE_Sodium_Core_Util::substr(
     1859                $sessionKeys,
     1860                0,
     1861                self::CRYPTO_KX_SESSIONKEYBYTES
     1862            )
     1863        );
     1864    }
     1865
     1866    /**
     1867     * @param string $kp
     1868     * @return string
     1869     * @throws SodiumException
     1870     */
     1871    public static function crypto_kx_secretkey($kp)
     1872    {
     1873        return ParagonIE_Sodium_Core_Util::substr(
     1874            $kp,
     1875            0,
     1876            self::CRYPTO_KX_SECRETKEYBYTES
     1877        );
     1878    }
     1879
     1880    /**
     1881     * @param string $kp
     1882     * @return string
     1883     * @throws SodiumException
     1884     */
     1885    public static function crypto_kx_publickey($kp)
     1886    {
     1887        return ParagonIE_Sodium_Core_Util::substr(
     1888            $kp,
     1889            self::CRYPTO_KX_SECRETKEYBYTES,
     1890            self::CRYPTO_KX_PUBLICKEYBYTES
     1891        );
     1892    }
     1893
     1894    /**
    15141895     * @param int $outlen
    15151896     * @param string $passwd
     
    15911972            'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
    15921973        );
     1974    }
     1975
     1976    /**
     1977     * Do we need to rehash this password?
     1978     *
     1979     * @param string $hash
     1980     * @param int $opslimit
     1981     * @param int $memlimit
     1982     * @return bool
     1983     * @throws SodiumException
     1984     */
     1985    public static function crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit)
     1986    {
     1987        ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 1);
     1988        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
     1989        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
     1990
     1991        // Just grab the first 4 pieces.
     1992        $pieces = explode('$', (string) $hash);
     1993        $prefix = implode('$', array_slice($pieces, 0, 4));
     1994
     1995        // Rebuild the expected header.
     1996        /** @var int $ops */
     1997        $ops = (int) $opslimit;
     1998        /** @var int $mem */
     1999        $mem = (int) $memlimit >> 10;
     2000        $encoded = self::CRYPTO_PWHASH_STRPREFIX . 'v=19$m=' . $mem . ',t=' . $ops . ',p=1';
     2001
     2002        // Do they match? If so, we don't need to rehash, so return false.
     2003        return !ParagonIE_Sodium_Core_Util::hashEquals($encoded, $prefix);
    15932004    }
    15942005
     
    19892400
    19902401    /**
     2402     * @param string $key
     2403     * @return array<int, string> Returns a state and a header.
     2404     * @throws Exception
     2405     * @throws SodiumException
     2406     */
     2407    public static function crypto_secretstream_xchacha20poly1305_init_push($key)
     2408    {
     2409        if (PHP_INT_SIZE === 4) {
     2410            return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_push($key);
     2411        }
     2412        return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_push($key);
     2413    }
     2414
     2415    /**
     2416     * @param string $header
     2417     * @param string $key
     2418     * @return string Returns a state.
     2419     * @throws Exception
     2420     */
     2421    public static function crypto_secretstream_xchacha20poly1305_init_pull($header, $key)
     2422    {
     2423        if (ParagonIE_Sodium_Core_Util::strlen($header) < self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) {
     2424            throw new SodiumException(
     2425                'header size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes'
     2426            );
     2427        }
     2428        if (PHP_INT_SIZE === 4) {
     2429            return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_pull($key, $header);
     2430        }
     2431        return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_pull($key, $header);
     2432    }
     2433
     2434    /**
     2435     * @param string $state
     2436     * @param string $msg
     2437     * @param string $aad
     2438     * @param int $tag
     2439     * @return string
     2440     * @throws SodiumException
     2441     */
     2442    public static function crypto_secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
     2443    {
     2444        if (PHP_INT_SIZE === 4) {
     2445            return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_push(
     2446                $state,
     2447                $msg,
     2448                $aad,
     2449                $tag
     2450            );
     2451        }
     2452        return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_push(
     2453            $state,
     2454            $msg,
     2455            $aad,
     2456            $tag
     2457        );
     2458    }
     2459
     2460    /**
     2461     * @param string $state
     2462     * @param string $msg
     2463     * @param string $aad
     2464     * @return bool|array{0: string, 1: int}
     2465     * @throws SodiumException
     2466     */
     2467    public static function crypto_secretstream_xchacha20poly1305_pull(&$state, $msg, $aad = '')
     2468    {
     2469        if (PHP_INT_SIZE === 4) {
     2470            return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_pull(
     2471                $state,
     2472                $msg,
     2473                $aad
     2474            );
     2475        }
     2476        return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_pull(
     2477            $state,
     2478            $msg,
     2479            $aad
     2480        );
     2481    }
     2482
     2483    /**
     2484     * @return string
     2485     * @throws Exception
     2486     */
     2487    public static function crypto_secretstream_xchacha20poly1305_keygen()
     2488    {
     2489        return random_bytes(self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES);
     2490    }
     2491
     2492    /**
     2493     * @param string $state
     2494     * @return void
     2495     * @throws SodiumException
     2496     */
     2497    public static function crypto_secretstream_xchacha20poly1305_rekey(&$state)
     2498    {
     2499        if (PHP_INT_SIZE === 4) {
     2500            ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_rekey($state);
     2501        } else {
     2502            ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_rekey($state);
     2503        }
     2504    }
     2505
     2506    /**
    19912507     * Calculates a SipHash-2-4 hash of a message for a given key.
    19922508     *
     
    21352651        }
    21362652        return ParagonIE_Sodium_Core_Ed25519::keypair();
     2653    }
     2654
     2655    /**
     2656     * @param string $sk
     2657     * @param string $pk
     2658     * @return string
     2659     * @throws SodiumException
     2660     */
     2661    public static function crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk)
     2662    {
     2663        ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1);
     2664        ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1);
     2665        $sk = (string) $sk;
     2666        $pk = (string) $pk;
     2667
     2668        if (ParagonIE_Sodium_Core_Util::strlen($sk) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
     2669            throw new SodiumException('secretkey should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes');
     2670        }
     2671        if (ParagonIE_Sodium_Core_Util::strlen($pk) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
     2672            throw new SodiumException('publickey should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes');
     2673        }
     2674
     2675        if (self::useNewSodiumAPI()) {
     2676            return sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk);
     2677        }
     2678        return $sk . $pk;
    21372679    }
    21382680
     
    26253167        ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2);
    26263168
     3169        if (self::useNewSodiumAPI()) {
     3170            return sodium_memcmp($left, $right);
     3171        }
    26273172        if (self::use_fallback('memcmp')) {
    26283173            return (int) call_user_func('\\Sodium\\memcmp', $left, $right);
     
    26673212            'To fix this error, make sure libsodium is installed and the PHP extension is enabled.'
    26683213        );
     3214    }
     3215
     3216    /**
     3217     * @param string $unpadded
     3218     * @param int $blockSize
     3219     * @param bool $dontFallback
     3220     * @return string
     3221     * @throws SodiumException
     3222     */
     3223    public static function pad($unpadded, $blockSize, $dontFallback = false)
     3224    {
     3225        /* Type checks: */
     3226        ParagonIE_Sodium_Core_Util::declareScalarType($unpadded, 'string', 1);
     3227        ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2);
     3228
     3229        $unpadded = (string) $unpadded;
     3230        $blockSize = (int) $blockSize;
     3231
     3232        if (self::useNewSodiumAPI() && !$dontFallback) {
     3233            return (string) sodium_pad($unpadded, $blockSize);
     3234        }
     3235
     3236        if ($blockSize <= 0) {
     3237            throw new SodiumException(
     3238                'block size cannot be less than 1'
     3239            );
     3240        }
     3241        $unpadded_len = ParagonIE_Sodium_Core_Util::strlen($unpadded);
     3242        $xpadlen = ($blockSize - 1);
     3243        if (($blockSize & ($blockSize - 1)) === 0) {
     3244            $xpadlen -= $unpadded_len & ($blockSize - 1);
     3245        } else {
     3246            $xpadlen -= $unpadded_len % $blockSize;
     3247        }
     3248
     3249        $xpadded_len = $unpadded_len + $xpadlen;
     3250        $padded = str_repeat("\0", $xpadded_len - 1);
     3251        if ($unpadded_len > 0) {
     3252            $st = 1;
     3253            $i = 0;
     3254            $k = $unpadded_len;
     3255            for ($j = 0; $j <= $xpadded_len; ++$j) {
     3256                $i = (int) $i;
     3257                $k = (int) $k;
     3258                $st = (int) $st;
     3259                if ($j >= $unpadded_len) {
     3260                    $padded[$j] = "\0";
     3261                } else {
     3262                    $padded[$j] = $unpadded[$j];
     3263                }
     3264                /** @var int $k */
     3265                $k -= $st;
     3266                $st = (int) (~(
     3267                            (
     3268                                (
     3269                                    ($k >> 48)
     3270                                        |
     3271                                    ($k >> 32)
     3272                                        |
     3273                                    ($k >> 16)
     3274                                        |
     3275                                    $k
     3276                                ) - 1
     3277                            ) >> 16
     3278                        )
     3279                    ) & 1;
     3280                $i += $st;
     3281            }
     3282        }
     3283
     3284        $mask = 0;
     3285        $tail = $xpadded_len;
     3286        for ($i = 0; $i < $blockSize; ++$i) {
     3287            # barrier_mask = (unsigned char)
     3288            #     (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT));
     3289            $barrier_mask = (($i ^ $xpadlen) -1) >> ((PHP_INT_SIZE << 3) - 1);
     3290            # tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
     3291            $padded[$tail - $i] = ParagonIE_Sodium_Core_Util::intToChr(
     3292                (ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]) & $mask)
     3293                    |
     3294                (0x80 & $barrier_mask)
     3295            );
     3296            # mask |= barrier_mask;
     3297            $mask |= $barrier_mask;
     3298        }
     3299        return $padded;
     3300    }
     3301
     3302    /**
     3303     * @param string $padded
     3304     * @param int $blockSize
     3305     * @param bool $dontFallback
     3306     * @return string
     3307     * @throws SodiumException
     3308     */
     3309    public static function unpad($padded, $blockSize, $dontFallback = false)
     3310    {
     3311        /* Type checks: */
     3312        ParagonIE_Sodium_Core_Util::declareScalarType($padded, 'string', 1);
     3313        ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2);
     3314
     3315        $padded = (string) $padded;
     3316        $blockSize = (int) $blockSize;
     3317
     3318        if (self::useNewSodiumAPI() && !$dontFallback) {
     3319            return (string) sodium_unpad($padded, $blockSize);
     3320        }
     3321        if ($blockSize <= 0) {
     3322            throw new SodiumException('block size cannot be less than 1');
     3323        }
     3324        $padded_len = ParagonIE_Sodium_Core_Util::strlen($padded);
     3325        if ($padded_len < $blockSize) {
     3326            throw new SodiumException('invalid padding');
     3327        }
     3328
     3329        # tail = &padded[padded_len - 1U];
     3330        $tail = $padded_len - 1;
     3331
     3332        $acc = 0;
     3333        $valid = 0;
     3334        $pad_len = 0;
     3335
     3336        $found = 0;
     3337        for ($i = 0; $i < $blockSize; ++$i) {
     3338            # c = tail[-i];
     3339            $c = ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]);
     3340
     3341            # is_barrier =
     3342            #     (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
     3343            $is_barrier = (
     3344                (
     3345                    ($acc - 1) & ($pad_len - 1) & (($c ^ 80) - 1)
     3346                ) >> 7
     3347            ) & 1;
     3348            $is_barrier &= ~$found;
     3349            $found |= $is_barrier;
     3350
     3351            # acc |= c;
     3352            $acc |= $c;
     3353
     3354            # pad_len |= i & (1U + ~is_barrier);
     3355            $pad_len |= $i & (1 + ~$is_barrier);
     3356
     3357            # valid |= (unsigned char) is_barrier;
     3358            $valid |= ($is_barrier & 0xff);
     3359        }
     3360        # unpadded_len = padded_len - 1U - pad_len;
     3361        $unpadded_len = $padded_len - 1 - $pad_len;
     3362        if ($valid !== 1) {
     3363            throw new SodiumException('invalid padding');
     3364        }
     3365        return ParagonIE_Sodium_Core_Util::substr($padded, 0, $unpadded_len);
    26693366    }
    26703367
  • trunk/src/wp-includes/sodium_compat/src/Core/BLAKE2b.php

    r46586 r46858  
    8989        $l = ($x[1] + $y[1]) & 0xffffffff;
    9090        return self::new64(
    91             $x[0] + $y[0] + (
     91            (int) ($x[0] + $y[0] + (
    9292                ($l < $x[1]) ? 1 : 0
    93             ),
    94             $l
     93            )),
     94            (int) $l
    9595        );
    9696    }
     
    133133        }
    134134        return self::new64(
    135             (int) ($x[0] ^ $y[0]),
    136             (int) ($x[1] ^ $y[1])
     135            (int) (($x[0] ^ $y[0]) & 0xffffffff),
     136            (int) (($x[1] ^ $y[1]) & 0xffffffff)
    137137        );
    138138    }
     
    300300    protected static function context()
    301301    {
    302         $ctx    = new SplFixedArray(5);
     302        $ctx    = new SplFixedArray(6);
    303303        $ctx[0] = new SplFixedArray(8);   // h
    304304        $ctx[1] = new SplFixedArray(2);   // t
     
    306306        $ctx[3] = new SplFixedArray(256); // buf
    307307        $ctx[4] = 0;                      // buflen
     308        $ctx[5] = 0;                      // last_node (uint8_t)
    308309
    309310        for ($i = 8; $i--;) {
     
    551552     * @param SplFixedArray|null $key
    552553     * @param int $outlen
     554     * @param SplFixedArray|null $salt
     555     * @param SplFixedArray|null $personal
    553556     * @return SplFixedArray
    554557     * @throws SodiumException
     
    560563     * @psalm-suppress MixedArrayOffset
    561564     */
    562     public static function init($key = null, $outlen = 64)
    563     {
     565    public static function init(
     566        $key = null,
     567        $outlen = 64,
     568        $salt = null,
     569        $personal = null
     570    ) {
    564571        self::pseudoConstructor();
    565572        $klen = 0;
     
    579586
    580587        $p = new SplFixedArray(64);
     588        // Zero our param buffer...
    581589        for ($i = 64; --$i;) {
    582590            $p[$i] = 0;
     
    588596        $p[3] = 1;       // depth
    589597
     598        if ($salt instanceof SplFixedArray) {
     599            // salt: [32] through [47]
     600            for ($i = 0; $i < 16; ++$i) {
     601                $p[32 + $i] = (int) $salt[$i];
     602            }
     603        }
     604        if ($personal instanceof SplFixedArray) {
     605            // personal: [48] through [63]
     606            for ($i = 0; $i < 16; ++$i) {
     607                $p[48 + $i] = (int) $personal[$i];
     608            }
     609        }
     610
    590611        $ctx[0][0] = self::xor64(
    591612            $ctx[0][0],
    592613            self::load64($p, 0)
    593614        );
     615        if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) {
     616            // We need to do what blake2b_init_param() does:
     617            for ($i = 1; $i < 8; ++$i) {
     618                $ctx[0][$i] = self::xor64(
     619                    $ctx[0][$i],
     620                    self::load64($p, $i << 3)
     621                );
     622            }
     623        }
    594624
    595625        if ($klen > 0 && $key instanceof SplFixedArray) {
     
    602632            }
    603633            self::update($ctx, $block, 128);
     634            $ctx[4] = 128;
    604635        }
    605636
     
    694725        ));
    695726        # uint8_t last_node;
    696         return $str . "\x00";
     727        return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23);
    697728    }
    698729
     
    747778        $ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256));
    748779
    749 
    750780        # uint8_t buf[2 * 128];
    751781        $int = 0;
  • trunk/src/wp-includes/sodium_compat/src/Core/Ed25519.php

    r46586 r46858  
    277277            throw new SodiumException('Signature is too short');
    278278        }
    279         if (self::check_S_lt_L(self::substr($sig, 32, 32))) {
     279        if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) {
    280280            throw new SodiumException('S < L - Invalid signature');
    281281        }
  • trunk/src/wp-includes/sodium_compat/src/Core/Poly1305/State.php

    r46586 r46858  
    8181
    8282    /**
     83     * Zero internal buffer upon destruction
     84     */
     85    public function __destruct()
     86    {
     87        $this->r[0] ^= $this->r[0];
     88        $this->r[1] ^= $this->r[1];
     89        $this->r[2] ^= $this->r[2];
     90        $this->r[3] ^= $this->r[3];
     91        $this->r[4] ^= $this->r[4];
     92        $this->h[0] ^= $this->h[0];
     93        $this->h[1] ^= $this->h[1];
     94        $this->h[2] ^= $this->h[2];
     95        $this->h[3] ^= $this->h[3];
     96        $this->h[4] ^= $this->h[4];
     97        $this->pad[0] ^= $this->pad[0];
     98        $this->pad[1] ^= $this->pad[1];
     99        $this->pad[2] ^= $this->pad[2];
     100        $this->pad[3] ^= $this->pad[3];
     101        $this->leftover = 0;
     102        $this->final = true;
     103    }
     104
     105    /**
    83106     * @internal You should not use this directly from another application
    84107     *
     
    91114    {
    92115        $bytes = self::strlen($message);
     116        if ($bytes < 1) {
     117            return $this;
     118        }
    93119
    94120        /* handle leftover */
     
    112138
    113139            $this->blocks(
    114                 static::intArrayToString($this->buffer),
     140                self::intArrayToString($this->buffer),
    115141                ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
    116142            );
     
    297323            $this->blocks(
    298324                self::substr(
    299                     static::intArrayToString($this->buffer),
     325                    self::intArrayToString($this->buffer),
    300326                    0,
    301327                    ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE
  • trunk/src/wp-includes/sodium_compat/src/Core/XChaCha20.php

    r46586 r46858  
    4040     * @internal You should not use this directly from another application
    4141     *
     42     * @param int $len
     43     * @param string $nonce
     44     * @param string $key
     45     * @return string
     46     * @throws SodiumException
     47     * @throws TypeError
     48     */
     49    public static function ietfStream($len = 64, $nonce = '', $key = '')
     50    {
     51        if (self::strlen($nonce) !== 24) {
     52            throw new SodiumException('Nonce must be 24 bytes long');
     53        }
     54        return self::encryptBytes(
     55            new ParagonIE_Sodium_Core_ChaCha20_IetfCtx(
     56                self::hChaCha20(
     57                    self::substr($nonce, 0, 16),
     58                    $key
     59                ),
     60                "\x00\x00\x00\x00" . self::substr($nonce, 16, 8)
     61            ),
     62            str_repeat("\x00", $len)
     63        );
     64    }
     65
     66    /**
     67     * @internal You should not use this directly from another application
     68     *
    4269     * @param string $message
    4370     * @param string $nonce
     
    6289        );
    6390    }
     91
     92    /**
     93     * @internal You should not use this directly from another application
     94     *
     95     * @param string $message
     96     * @param string $nonce
     97     * @param string $key
     98     * @param string $ic
     99     * @return string
     100     * @throws SodiumException
     101     * @throws TypeError
     102     */
     103    public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '')
     104    {
     105        if (self::strlen($nonce) !== 24) {
     106            throw new SodiumException('Nonce must be 24 bytes long');
     107        }
     108        return self::encryptBytes(
     109            new ParagonIE_Sodium_Core_ChaCha20_IetfCtx(
     110                self::hChaCha20(self::substr($nonce, 0, 16), $key),
     111                "\x00\x00\x00\x00" . self::substr($nonce, 16, 8),
     112                $ic
     113            ),
     114            $message
     115        );
     116    }
    64117}
  • trunk/src/wp-includes/sodium_compat/src/Core32/BLAKE2b.php

    r46586 r46858  
    224224    protected static function context()
    225225    {
    226         $ctx    = new SplFixedArray(5);
     226        $ctx    = new SplFixedArray(6);
    227227        $ctx[0] = new SplFixedArray(8);   // h
    228228        $ctx[1] = new SplFixedArray(2);   // t
     
    230230        $ctx[3] = new SplFixedArray(256); // buf
    231231        $ctx[4] = 0;                      // buflen
     232        $ctx[5] = 0;                      // last_node (uint8_t)
    232233
    233234        for ($i = 8; $i--;) {
     
    483484     * @param SplFixedArray|null $key
    484485     * @param int $outlen
     486     * @param SplFixedArray|null $salt
     487     * @param SplFixedArray|null $personal
    485488     * @return SplFixedArray
    486489     * @throws SodiumException
     
    492495     * @psalm-suppress MixedMethodCall
    493496     */
    494     public static function init($key = null, $outlen = 64)
    495     {
     497    public static function init(
     498        $key = null,
     499        $outlen = 64,
     500        $salt = null,
     501        $personal = null
     502    ) {
    496503        self::pseudoConstructor();
    497504        $klen = 0;
     
    511518
    512519        $p = new SplFixedArray(64);
     520        // Zero our param buffer...
    513521        for ($i = 64; --$i;) {
    514522            $p[$i] = 0;
     
    520528        $p[3] = 1;       // depth
    521529
     530        if ($salt instanceof SplFixedArray) {
     531            // salt: [32] through [47]
     532            for ($i = 0; $i < 16; ++$i) {
     533                $p[32 + $i] = (int) $salt[$i];
     534            }
     535        }
     536        if ($personal instanceof SplFixedArray) {
     537            // personal: [48] through [63]
     538            for ($i = 0; $i < 16; ++$i) {
     539                $p[48 + $i] = (int) $personal[$i];
     540            }
     541        }
     542
    522543        $ctx[0][0] = self::xor64(
    523544            $ctx[0][0],
     
    525546        );
    526547
     548        if ($salt instanceof SplFixedArray || $personal instanceof SplFixedArray) {
     549            // We need to do what blake2b_init_param() does:
     550            for ($i = 1; $i < 8; ++$i) {
     551                $ctx[0][$i] = self::xor64(
     552                    $ctx[0][$i],
     553                    self::load64($p, $i << 3)
     554                );
     555            }
     556        }
     557
    527558        if ($klen > 0 && $key instanceof SplFixedArray) {
    528559            $block = new SplFixedArray(128);
     
    534565            }
    535566            self::update($ctx, $block, 128);
     567            $ctx[4] = 128;
    536568        }
    537569
     
    596628            /** @var ParagonIE_Sodium_Core32_Int64 $ctxAi */
    597629            $ctxAi = $ctxA[$i];
    598             $str .= $ctxAi->toString();
     630            $str .= $ctxAi->toReverseString();
    599631        }
    600632
     
    609641            $ctxA2 = $ctxA[1];
    610642
    611             $str .= $ctxA1->toString();
    612             $str .= $ctxA2->toString();
     643            $str .= $ctxA1->toReverseString();
     644            $str .= $ctxA2->toReverseString();
    613645        }
    614646
     
    625657            self::intToChr(($ctx4 >> 16) & 0xff),
    626658            self::intToChr(($ctx4 >> 24) & 0xff),
     659            "\x00\x00\x00\x00"
     660            /*
    627661            self::intToChr(($ctx4 >> 32) & 0xff),
    628662            self::intToChr(($ctx4 >> 40) & 0xff),
    629663            self::intToChr(($ctx4 >> 48) & 0xff),
    630664            self::intToChr(($ctx4 >> 56) & 0xff)
     665            */
    631666        ));
    632667        # uint8_t last_node;
    633         return $str . "\x00";
     668        return $str . self::intToChr($ctx[5]) . str_repeat("\x00", 23);
    634669    }
    635670
     
    653688        # uint64_t h[8];
    654689        for ($i = 0; $i < 8; ++$i) {
    655             $ctx[0][$i] = ParagonIE_Sodium_Core32_Int64::fromString(
     690            $ctx[0][$i] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
    656691                self::substr($string, (($i << 3) + 0), 8)
    657692            );
     
    661696        # uint64_t f[2];
    662697        for ($i = 1; $i < 3; ++$i) {
    663             $ctx[$i][1] = ParagonIE_Sodium_Core32_Int64::fromString(
     698            $ctx[$i][1] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
    664699                self::substr($string, 72 + (($i - 1) << 4), 8)
    665700            );
    666             $ctx[$i][0] = ParagonIE_Sodium_Core32_Int64::fromString(
     701            $ctx[$i][0] = ParagonIE_Sodium_Core32_Int64::fromReverseString(
    667702                self::substr($string, 64 + (($i - 1) << 4), 8)
    668703            );
     
    671706        # uint8_t buf[2 * 128];
    672707        $ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256));
    673 
    674708
    675709        # uint8_t buf[2 * 128];
  • trunk/src/wp-includes/sodium_compat/src/Core32/Ed25519.php

    r46586 r46858  
    279279            throw new SodiumException('Signature is too short');
    280280        }
    281         if (self::check_S_lt_L(self::substr($sig, 32, 32))) {
     281        if ((self::chrToInt($sig[63]) & 240) && self::check_S_lt_L(self::substr($sig, 32, 32))) {
    282282            throw new SodiumException('S < L - Invalid signature');
    283283        }
  • trunk/src/wp-includes/sodium_compat/src/Core32/Poly1305/State.php

    r46586 r46858  
    143143
    144144            $this->blocks(
    145                 static::intArrayToString($this->buffer),
     145                self::intArrayToString($this->buffer),
    146146                ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
    147147            );
     
    347347            $this->blocks(
    348348                self::substr(
    349                     static::intArrayToString($this->buffer),
     349                    self::intArrayToString($this->buffer),
    350350                    0,
    351351                    ParagonIE_Sodium_Core32_Poly1305::BLOCK_SIZE
  • trunk/src/wp-includes/sodium_compat/src/Core32/X25519.php

    r46586 r46858  
    152152            $h[$i] = $h[$i]->toInt32();
    153153        }
    154         /** @var array<int, ParagonIE_Sodium_Core32_Int32> $h */
    155         return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h);
     154        /** @var array<int, ParagonIE_Sodium_Core32_Int32> $h2 */
     155        $h2 = $h;
     156        return ParagonIE_Sodium_Core32_Curve25519_Fe::fromArray($h2);
    156157    }
    157158
  • trunk/src/wp-includes/sodium_compat/src/Crypto.php

    r46586 r46858  
    779779
    780780    /**
     781     * Initialize a hashing context for BLAKE2b.
     782     *
     783     * @internal Do not use this directly. Use ParagonIE_Sodium_Compat.
     784     *
     785     * @param string $key
     786     * @param int $outputLength
     787     * @param string $salt
     788     * @param string $personal
     789     * @return string
     790     * @throws RangeException
     791     * @throws SodiumException
     792     * @throws TypeError
     793     */
     794    public static function generichash_init_salt_personal(
     795        $key = '',
     796        $outputLength = 32,
     797        $salt = '',
     798        $personal = ''
     799    ) {
     800        // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized
     801        ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor();
     802
     803        $k = null;
     804        if (!empty($key)) {
     805            $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key);
     806            if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) {
     807                throw new RangeException('Invalid key size');
     808            }
     809        }
     810        if (!empty($salt)) {
     811            $s = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($salt);
     812        } else {
     813            $s = null;
     814        }
     815        if (!empty($salt)) {
     816            $p = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($personal);
     817        } else {
     818            $p = null;
     819        }
     820
     821        /** @var SplFixedArray $ctx */
     822        $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength, $s, $p);
     823
     824        return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx);
     825    }
     826
     827    /**
    781828     * Update a hashing context for BLAKE2b with $message
    782829     *
     
    11871234
    11881235    /**
     1236     * @param string $key
     1237     * @return array<int, string> Returns a state and a header.
     1238     * @throws Exception
     1239     * @throws SodiumException
     1240     */
     1241    public static function secretstream_xchacha20poly1305_init_push($key)
     1242    {
     1243        # randombytes_buf(out, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
     1244        $out = random_bytes(24);
     1245
     1246        # crypto_core_hchacha20(state->k, out, k, NULL);
     1247        $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20($out, $key);
     1248        $state = new ParagonIE_Sodium_Core_SecretStream_State(
     1249            $subkey,
     1250            ParagonIE_Sodium_Core_Util::substr($out, 16, 8) . str_repeat("\0", 4)
     1251        );
     1252
     1253        # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
     1254        $state->counterReset();
     1255
     1256        # memcpy(STATE_INONCE(state), out + crypto_core_hchacha20_INPUTBYTES,
     1257        #        crypto_secretstream_xchacha20poly1305_INONCEBYTES);
     1258        # memset(state->_pad, 0, sizeof state->_pad);
     1259        return array(
     1260            $state->toString(),
     1261            $out
     1262        );
     1263    }
     1264
     1265    /**
     1266     * @param string $key
     1267     * @param string $header
     1268     * @return string Returns a state.
     1269     * @throws Exception
     1270     */
     1271    public static function secretstream_xchacha20poly1305_init_pull($key, $header)
     1272    {
     1273        # crypto_core_hchacha20(state->k, in, k, NULL);
     1274        $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20(
     1275            ParagonIE_Sodium_Core_Util::substr($header, 0, 16),
     1276            $key
     1277        );
     1278        $state = new ParagonIE_Sodium_Core_SecretStream_State(
     1279            $subkey,
     1280            ParagonIE_Sodium_Core_Util::substr($header, 16)
     1281        );
     1282        $state->counterReset();
     1283        # memcpy(STATE_INONCE(state), in + crypto_core_hchacha20_INPUTBYTES,
     1284        #     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
     1285        # memset(state->_pad, 0, sizeof state->_pad);
     1286        # return 0;
     1287        return $state->toString();
     1288    }
     1289
     1290    /**
     1291     * @param string $state
     1292     * @param string $msg
     1293     * @param string $aad
     1294     * @param int $tag
     1295     * @return string
     1296     * @throws SodiumException
     1297     */
     1298    public static function secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
     1299    {
     1300        $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
     1301        # crypto_onetimeauth_poly1305_state poly1305_state;
     1302        # unsigned char                     block[64U];
     1303        # unsigned char                     slen[8U];
     1304        # unsigned char                    *c;
     1305        # unsigned char                    *mac;
     1306
     1307        $msglen = ParagonIE_Sodium_Core_Util::strlen($msg);
     1308        $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
     1309
     1310        if ((($msglen + 63) >> 6) > 0xfffffffe) {
     1311            throw new SodiumException(
     1312                'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
     1313            );
     1314        }
     1315
     1316        # if (outlen_p != NULL) {
     1317        #     *outlen_p = 0U;
     1318        # }
     1319        # if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
     1320        #     sodium_misuse();
     1321        # }
     1322
     1323        # crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
     1324        # crypto_onetimeauth_poly1305_init(&poly1305_state, block);
     1325        # sodium_memzero(block, sizeof block);
     1326        $auth = new ParagonIE_Sodium_Core_Poly1305_State(
     1327            ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
     1328        );
     1329
     1330        # crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
     1331        $auth->update($aad);
     1332
     1333        # crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
     1334        #     (0x10 - adlen) & 0xf);
     1335        $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
     1336
     1337        # memset(block, 0, sizeof block);
     1338        # block[0] = tag;
     1339        # crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
     1340        #                                    state->nonce, 1U, state->k);
     1341        $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
     1342            ParagonIE_Sodium_Core_Util::intToChr($tag) . str_repeat("\0", 63),
     1343            $st->getCombinedNonce(),
     1344            $st->getKey(),
     1345            ParagonIE_Sodium_Core_Util::store64_le(1)
     1346        );
     1347
     1348        # crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
     1349        $auth->update($block);
     1350
     1351        # out[0] = block[0];
     1352        $out = $block[0];
     1353        # c = out + (sizeof tag);
     1354        # crypto_stream_chacha20_ietf_xor_ic(c, m, mlen, state->nonce, 2U, state->k);
     1355        $cipher = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
     1356            $msg,
     1357            $st->getCombinedNonce(),
     1358            $st->getKey(),
     1359            ParagonIE_Sodium_Core_Util::store64_le(2)
     1360        );
     1361
     1362        # crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
     1363        $auth->update($cipher);
     1364
     1365        $out .= $cipher;
     1366        unset($cipher);
     1367
     1368        # crypto_onetimeauth_poly1305_update
     1369        # (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
     1370        $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
     1371
     1372        # STORE64_LE(slen, (uint64_t) adlen);
     1373        $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
     1374
     1375        # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
     1376        $auth->update($slen);
     1377
     1378        # STORE64_LE(slen, (sizeof block) + mlen);
     1379        $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
     1380
     1381        # crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
     1382        $auth->update($slen);
     1383
     1384        # mac = c + mlen;
     1385        # crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
     1386        $mac = $auth->finish();
     1387        $out .= $mac;
     1388
     1389        # sodium_memzero(&poly1305_state, sizeof poly1305_state);
     1390        unset($auth);
     1391
     1392
     1393        # XOR_BUF(STATE_INONCE(state), mac,
     1394        #     crypto_secretstream_xchacha20poly1305_INONCEBYTES);
     1395        $st->xorNonce($mac);
     1396
     1397        # sodium_increment(STATE_COUNTER(state),
     1398        #     crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
     1399        $st->incrementCounter();
     1400        // Overwrite by reference:
     1401        $state = $st->toString();
     1402
     1403        /** @var bool $rekey */
     1404        $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
     1405        # if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
     1406        #     sodium_is_zero(STATE_COUNTER(state),
     1407        #         crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
     1408        #     crypto_secretstream_xchacha20poly1305_rekey(state);
     1409        # }
     1410        if ($rekey || $st->needsRekey()) {
     1411            // DO REKEY
     1412            self::secretstream_xchacha20poly1305_rekey($state);
     1413        }
     1414        # if (outlen_p != NULL) {
     1415        #     *outlen_p = crypto_secretstream_xchacha20poly1305_ABYTES + mlen;
     1416        # }
     1417        return $out;
     1418    }
     1419
     1420    /**
     1421     * @param string $state
     1422     * @param string $cipher
     1423     * @param string $aad
     1424     * @return bool|array{0: string, 1: int}
     1425     * @throws SodiumException
     1426     */
     1427    public static function secretstream_xchacha20poly1305_pull(&$state, $cipher, $aad = '')
     1428    {
     1429        $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
     1430
     1431        $cipherlen = ParagonIE_Sodium_Core_Util::strlen($cipher);
     1432        #     mlen = inlen - crypto_secretstream_xchacha20poly1305_ABYTES;
     1433        $msglen = $cipherlen - ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES;
     1434        $aadlen = ParagonIE_Sodium_Core_Util::strlen($aad);
     1435
     1436        #     if (mlen > crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX) {
     1437        #         sodium_misuse();
     1438        #     }
     1439        if ((($msglen + 63) >> 6) > 0xfffffffe) {
     1440            throw new SodiumException(
     1441                'message cannot be larger than SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX bytes'
     1442            );
     1443        }
     1444
     1445        #     crypto_stream_chacha20_ietf(block, sizeof block, state->nonce, state->k);
     1446        #     crypto_onetimeauth_poly1305_init(&poly1305_state, block);
     1447        #     sodium_memzero(block, sizeof block);
     1448        $auth = new ParagonIE_Sodium_Core_Poly1305_State(
     1449            ParagonIE_Sodium_Core_ChaCha20::ietfStream(32, $st->getCombinedNonce(), $st->getKey())
     1450        );
     1451
     1452        #     crypto_onetimeauth_poly1305_update(&poly1305_state, ad, adlen);
     1453        $auth->update($aad);
     1454
     1455        #     crypto_onetimeauth_poly1305_update(&poly1305_state, _pad0,
     1456        #         (0x10 - adlen) & 0xf);
     1457        $auth->update(str_repeat("\0", ((0x10 - $aadlen) & 0xf)));
     1458
     1459
     1460        #     memset(block, 0, sizeof block);
     1461        #     block[0] = in[0];
     1462        #     crypto_stream_chacha20_ietf_xor_ic(block, block, sizeof block,
     1463        #                                        state->nonce, 1U, state->k);
     1464        $block = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
     1465            $cipher[0] . str_repeat("\0", 63),
     1466            $st->getCombinedNonce(),
     1467            $st->getKey(),
     1468            ParagonIE_Sodium_Core_Util::store64_le(1)
     1469        );
     1470        #     tag = block[0];
     1471        #     block[0] = in[0];
     1472        #     crypto_onetimeauth_poly1305_update(&poly1305_state, block, sizeof block);
     1473        $tag = ParagonIE_Sodium_Core_Util::chrToInt($block[0]);
     1474        $block[0] = $cipher[0];
     1475        $auth->update($block);
     1476
     1477
     1478        #     c = in + (sizeof tag);
     1479        #     crypto_onetimeauth_poly1305_update(&poly1305_state, c, mlen);
     1480        $auth->update(ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen));
     1481
     1482        #     crypto_onetimeauth_poly1305_update
     1483        #     (&poly1305_state, _pad0, (0x10 - (sizeof block) + mlen) & 0xf);
     1484        $auth->update(str_repeat("\0", ((0x10 - 64 + $msglen) & 0xf)));
     1485
     1486        #     STORE64_LE(slen, (uint64_t) adlen);
     1487        #     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
     1488        $slen = ParagonIE_Sodium_Core_Util::store64_le($aadlen);
     1489        $auth->update($slen);
     1490
     1491        #     STORE64_LE(slen, (sizeof block) + mlen);
     1492        #     crypto_onetimeauth_poly1305_update(&poly1305_state, slen, sizeof slen);
     1493        $slen = ParagonIE_Sodium_Core_Util::store64_le(64 + $msglen);
     1494        $auth->update($slen);
     1495
     1496        #     crypto_onetimeauth_poly1305_final(&poly1305_state, mac);
     1497        #     sodium_memzero(&poly1305_state, sizeof poly1305_state);
     1498        $mac = $auth->finish();
     1499
     1500        #     stored_mac = c + mlen;
     1501        #     if (sodium_memcmp(mac, stored_mac, sizeof mac) != 0) {
     1502        #     sodium_memzero(mac, sizeof mac);
     1503        #         return -1;
     1504        #     }
     1505
     1506        $stored = ParagonIE_Sodium_Core_Util::substr($cipher, $msglen + 1, 16);
     1507        if (!ParagonIE_Sodium_Core_Util::hashEquals($mac, $stored)) {
     1508            return false;
     1509        }
     1510
     1511        #     crypto_stream_chacha20_ietf_xor_ic(m, c, mlen, state->nonce, 2U, state->k);
     1512        $out = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
     1513            ParagonIE_Sodium_Core_Util::substr($cipher, 1, $msglen),
     1514            $st->getCombinedNonce(),
     1515            $st->getKey(),
     1516            ParagonIE_Sodium_Core_Util::store64_le(2)
     1517        );
     1518
     1519        #     XOR_BUF(STATE_INONCE(state), mac,
     1520        #         crypto_secretstream_xchacha20poly1305_INONCEBYTES);
     1521        $st->xorNonce($mac);
     1522
     1523        #     sodium_increment(STATE_COUNTER(state),
     1524        #         crypto_secretstream_xchacha20poly1305_COUNTERBYTES);
     1525        $st->incrementCounter();
     1526
     1527        #     if ((tag & crypto_secretstream_xchacha20poly1305_TAG_REKEY) != 0 ||
     1528        #         sodium_is_zero(STATE_COUNTER(state),
     1529        #             crypto_secretstream_xchacha20poly1305_COUNTERBYTES)) {
     1530        #         crypto_secretstream_xchacha20poly1305_rekey(state);
     1531        #     }
     1532
     1533        // Overwrite by reference:
     1534        $state = $st->toString();
     1535
     1536        /** @var bool $rekey */
     1537        $rekey = ($tag & ParagonIE_Sodium_Compat::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY) !== 0;
     1538        if ($rekey || $st->needsRekey()) {
     1539            // DO REKEY
     1540            self::secretstream_xchacha20poly1305_rekey($state);
     1541        }
     1542        return array($out, $tag);
     1543    }
     1544
     1545    /**
     1546     * @param string $state
     1547     * @return void
     1548     * @throws SodiumException
     1549     */
     1550    public static function secretstream_xchacha20poly1305_rekey(&$state)
     1551    {
     1552        $st = ParagonIE_Sodium_Core_SecretStream_State::fromString($state);
     1553        # unsigned char new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES +
     1554        # crypto_secretstream_xchacha20poly1305_INONCEBYTES];
     1555        # size_t        i;
     1556        # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
     1557        #     new_key_and_inonce[i] = state->k[i];
     1558        # }
     1559        $new_key_and_inonce = $st->getKey();
     1560
     1561        # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
     1562        #     new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i] =
     1563        #         STATE_INONCE(state)[i];
     1564        # }
     1565        $new_key_and_inonce .= ParagonIE_Sodium_Core_Util::substR($st->getNonce(), 0, 8);
     1566
     1567        # crypto_stream_chacha20_ietf_xor(new_key_and_inonce, new_key_and_inonce,
     1568        #                                 sizeof new_key_and_inonce,
     1569        #                                 state->nonce, state->k);
     1570
     1571        $st->rekey(ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc(
     1572            $new_key_and_inonce,
     1573            $st->getCombinedNonce(),
     1574            $st->getKey(),
     1575            ParagonIE_Sodium_Core_Util::store64_le(0)
     1576        ));
     1577
     1578        # for (i = 0U; i < crypto_stream_chacha20_ietf_KEYBYTES; i++) {
     1579        #     state->k[i] = new_key_and_inonce[i];
     1580        # }
     1581        # for (i = 0U; i < crypto_secretstream_xchacha20poly1305_INONCEBYTES; i++) {
     1582        #     STATE_INONCE(state)[i] =
     1583        #          new_key_and_inonce[crypto_stream_chacha20_ietf_KEYBYTES + i];
     1584        # }
     1585        # _crypto_secretstream_xchacha20poly1305_counter_reset(state);
     1586        $st->counterReset();
     1587
     1588        $state = $st->toString();
     1589    }
     1590
     1591    /**
    11891592     * Detached Ed25519 signature.
    11901593     *
  • trunk/src/wp-includes/sodium_compat/src/Crypto32.php

    r46586 r46858  
    778778
    779779    /**
     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    /**
    780827     * Update a hashing context for BLAKE2b with $message
    781828     *
     
    11861233
    11871234    /**
     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    /**
    11881591     * Detached Ed25519 signature.
    11891592     *
  • trunk/src/wp-includes/sodium_compat/src/File.php

    r46586 r46858  
    680680
    681681        /* Security checks */
    682         if (ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig, 32, 32))) {
     682        if (
     683            (ParagonIE_Sodium_Core_Ed25519::chrToInt($sig[63]) & 240)
     684                &&
     685            ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig, 32, 32))
     686        ) {
    683687            throw new SodiumException('S < L - Invalid signature');
    684688        }
     
    842846            throw new SodiumException('Could not read input file');
    843847        }
    844         $first32 = ftell($ifp);
     848        $first32 = self::ftell($ifp);
    845849
    846850        /** @var string $subkey */
     
    876880
    877881        // Pre-write 16 blank bytes for the Poly1305 tag
    878         $start = ftell($ofp);
     882        $start = self::ftell($ofp);
    879883        fwrite($ofp, str_repeat("\x00", 16));
    880884
     
    927931            $subkey = null;
    928932        }
    929         $end = ftell($ofp);
     933        $end = self::ftell($ofp);
    930934
    931935        /*
     
    10441048    ) {
    10451049        /** @var int $pos */
    1046         $pos = ftell($ifp);
     1050        $pos = self::ftell($ifp);
    10471051
    10481052        /** @var int $iter */
     
    11071111
    11081112        /** @var int $originalPosition */
    1109         $originalPosition = ftell($fp);
     1113        $originalPosition = self::ftell($fp);
    11101114
    11111115        // Move file pointer to beginning of file
     
    13151319            throw new SodiumException('Could not read input file');
    13161320        }
    1317         $first32 = ftell($ifp);
     1321        $first32 = self::ftell($ifp);
    13181322
    13191323        /** @var string $subkey */
     
    13491353
    13501354        // Pre-write 16 blank bytes for the Poly1305 tag
    1351         $start = ftell($ofp);
     1355        $start = self::ftell($ofp);
    13521356        fwrite($ofp, str_repeat("\x00", 16));
    13531357
     
    14001404            $subkey = null;
    14011405        }
    1402         $end = ftell($ofp);
     1406        $end = self::ftell($ofp);
    14031407
    14041408        /*
     
    15161520    ) {
    15171521        /** @var int $pos */
    1518         $pos = ftell($ifp);
     1522        $pos = self::ftell($ifp);
    15191523
    15201524        /** @var int $iter */
     
    15411545        return $res;
    15421546    }
     1547
     1548    /**
     1549     * @param resource $resource
     1550     * @return int
     1551     * @throws SodiumException
     1552     */
     1553    private static function ftell($resource)
     1554    {
     1555        $return = ftell($resource);
     1556        if (!is_int($return)) {
     1557            throw new SodiumException('ftell() returned false');
     1558        }
     1559        return (int) $return;
     1560    }
    15431561}
Note: See TracChangeset for help on using the changeset viewer.