Changeset 46858 for trunk/src/wp-includes/sodium_compat/src/Compat.php
- Timestamp:
- 12/09/2019 04:40:11 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/sodium_compat/src/Compat.php
r46586 r46858 50 50 51 51 // 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; 52 56 const CRYPTO_AEAD_AES256GCM_KEYBYTES = 32; 53 57 const CRYPTO_AEAD_AES256GCM_NSECBYTES = 0; … … 75 79 const CRYPTO_BOX_NONCEBYTES = 24; 76 80 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; 77 85 const CRYPTO_KX_BYTES = 32; 86 const CRYPTO_KX_PRIMITIVE = 'x25519blake2b'; 78 87 const CRYPTO_KX_SEEDBYTES = 32; 88 const CRYPTO_KX_KEYPAIRBYTES = 64; 79 89 const CRYPTO_KX_PUBLICKEYBYTES = 32; 80 90 const CRYPTO_KX_SECRETKEYBYTES = 32; 91 const CRYPTO_KX_SESSIONKEYBYTES = 32; 81 92 const CRYPTO_GENERICHASH_BYTES = 32; 82 93 const CRYPTO_GENERICHASH_BYTES_MIN = 16; … … 86 97 const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64; 87 98 const CRYPTO_PWHASH_SALTBYTES = 16; 88 const CRYPTO_PWHASH_STRPREFIX = '$argon2i $';99 const CRYPTO_PWHASH_STRPREFIX = '$argon2id$'; 89 100 const CRYPTO_PWHASH_ALG_ARGON2I13 = 1; 90 101 const CRYPTO_PWHASH_ALG_ARGON2ID13 = 2; … … 108 119 const CRYPTO_SECRETBOX_MACBYTES = 16; 109 120 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; 110 129 const CRYPTO_SIGN_BYTES = 64; 111 130 const CRYPTO_SIGN_SEEDBYTES = 32; … … 115 134 const CRYPTO_STREAM_KEYBYTES = 32; 116 135 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 } 117 240 118 241 /** … … 1311 1434 * @psalm-suppress MixedArgument 1312 1435 * @psalm-suppress ReferenceConstraintViolation 1436 * @psalm-suppress ConflictingReferenceConstraint 1313 1437 */ 1314 1438 public static function crypto_generichash_final(&$ctx, $length = self::CRYPTO_GENERICHASH_BYTES) … … 1324 1448 $func = '\\Sodium\\crypto_generichash_final'; 1325 1449 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 ''; 1326 1458 } 1327 1459 if (PHP_INT_SIZE === 4) { … … 1381 1513 1382 1514 /** 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 /** 1383 1562 * Update a BLAKE2b hashing context with additional data. 1384 1563 * … … 1423 1602 { 1424 1603 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); 1425 1663 } 1426 1664 … … 1512 1750 1513 1751 /** 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 /** 1514 1895 * @param int $outlen 1515 1896 * @param string $passwd … … 1591 1972 'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP' 1592 1973 ); 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); 1593 2004 } 1594 2005 … … 1989 2400 1990 2401 /** 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 /** 1991 2507 * Calculates a SipHash-2-4 hash of a message for a given key. 1992 2508 * … … 2135 2651 } 2136 2652 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; 2137 2679 } 2138 2680 … … 2625 3167 ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2); 2626 3168 3169 if (self::useNewSodiumAPI()) { 3170 return sodium_memcmp($left, $right); 3171 } 2627 3172 if (self::use_fallback('memcmp')) { 2628 3173 return (int) call_user_func('\\Sodium\\memcmp', $left, $right); … … 2667 3212 'To fix this error, make sure libsodium is installed and the PHP extension is enabled.' 2668 3213 ); 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); 2669 3366 } 2670 3367
Note: See TracChangeset
for help on using the changeset viewer.