WordPress.org

Make WordPress Core


Ignore:
Timestamp:
12/09/2019 04:44:58 PM (15 months 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.
Merges [46858] to the 5.3 branch.
Fixes #48371.

Location:
branches/5.3
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/5.3

  • branches/5.3/src/wp-includes/sodium_compat/src/Compat.php

    r45344 r46859  
    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
Note: See TracChangeset for help on using the changeset viewer.