diff --git a/.gitignore b/.gitignore index d6ddb7a66e8aa..f448d6ba6997b 100644 --- a/.gitignore +++ b/.gitignore @@ -116,6 +116,12 @@ Desktop.ini /libraries/vendor/paragonie/random_compat/psalm-autoload.php /libraries/vendor/paragonie/random_compat/psalm.xml /libraries/vendor/paragonie/random_compat/tests +/libraries/vendor/paragonie/sodium_compat/.gitignore +/libraries/vendor/paragonie/sodium_compat/composer.json +/libraries/vendor/paragonie/sodium_compat/composer.lock +/libraries/vendor/paragonie/sodium_compat/phpunit.xml.dist +/libraries/vendor/paragonie/sodium_compat/README.md +/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/README.md /libraries/vendor/phpmailer/phpmailer/docs /libraries/vendor/phpmailer/phpmailer/examples /libraries/vendor/phpmailer/phpmailer/language diff --git a/composer.json b/composer.json index d27260fe815ec..04621a0ccad06 100644 --- a/composer.json +++ b/composer.json @@ -34,6 +34,7 @@ "ircmaxell/password-compat": "1.*", "leafo/lessphp": "0.5.0", "paragonie/random_compat": "~1.0", + "paragonie/sodium_compat": "^1.0.1", "phpmailer/phpmailer": "^5.2.20", "symfony/polyfill-php55": "~1.2", "symfony/polyfill-php56": "~1.0", @@ -47,4 +48,4 @@ "squizlabs/php_codesniffer": "~1.5", "pear/cache_lite": "1.7.16" } -} \ No newline at end of file +} diff --git a/composer.lock b/composer.lock index 1cdd5b7158f35..8bba7e8692ad9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "508d04c9f88b696e7a08afbc3959b6ed", + "content-hash": "ff501849de6d0ec4a7790c7f5c42651b", "packages": [ { "name": "ircmaxell/password-compat", @@ -861,6 +861,87 @@ ], "time": "2017-03-13T16:22:52+00:00" }, + { + "name": "paragonie/sodium_compat", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/paragonie/sodium_compat.git", + "reference": "3c6b3b7ffd256df19c39b0f4aa0bb28badd08aaa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/3c6b3b7ffd256df19c39b0f4aa0bb28badd08aaa", + "reference": "3c6b3b7ffd256df19c39b0f4aa0bb28badd08aaa", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "^1|^2", + "php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7" + }, + "require-dev": { + "phpunit/phpunit": "^3|^4|^5" + }, + "suggest": { + "ext-libsodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security." + }, + "type": "library", + "autoload": { + "files": [ + "autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com" + }, + { + "name": "Frank Denis", + "email": "jedisct1@pureftpd.org" + } + ], + "description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists", + "keywords": [ + "Authentication", + "BLAKE2b", + "ChaCha20", + "ChaCha20-Poly1305", + "Chapoly", + "Curve25519", + "Ed25519", + "EdDSA", + "Edwards-curve Digital Signature Algorithm", + "Elliptic Curve Diffie-Hellman", + "Poly1305", + "Pure-PHP cryptography", + "RFC 7748", + "RFC 8032", + "Salpoly", + "Salsa20", + "X25519", + "XChaCha20-Poly1305", + "XSalsa20-Poly1305", + "Xchacha20", + "Xsalsa20", + "aead", + "cryptography", + "ecdh", + "elliptic curve", + "elliptic curve cryptography", + "encryption", + "libsodium", + "php", + "public-key cryptography", + "secret-key cryptography", + "side-channel resistant" + ], + "time": "2017-06-09T22:35:18+00:00" + }, { "name": "phpmailer/phpmailer", "version": "v5.2.23", diff --git a/libraries/joomla/crypt/cipher/sodium.php b/libraries/joomla/crypt/cipher/sodium.php new file mode 100644 index 0000000000000..671ceb2b6564d --- /dev/null +++ b/libraries/joomla/crypt/cipher/sodium.php @@ -0,0 +1,133 @@ +type !== 'sodium') + { + throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected sodium.'); + } + + if (!$this->nonce) + { + throw new RuntimeException('Missing nonce to decrypt data'); + } + + $decrypted = \Sodium\crypto_box_open( + $data, + $this->nonce, + \Sodium\crypto_box_keypair_from_secretkey_and_publickey($key->private, $key->public) + ); + + if ($decrypted === false) + { + throw new RuntimeException('Malformed message or invalid MAC'); + } + + return $decrypted; + } + + /** + * Method to encrypt a data string. + * + * @param string $data The data string to encrypt. + * @param JCryptKey $key The key object to use for encryption. + * + * @return string The encrypted data string. + * + * @since __DEPLOY_VERSION__ + * @throws RuntimeException + */ + public function encrypt($data, JCryptKey $key) + { + // Validate key. + if ($key->type !== 'sodium') + { + throw new InvalidArgumentException('Invalid key of type: ' . $key->type . '. Expected sodium.'); + } + + if (!$this->nonce) + { + throw new RuntimeException('Missing nonce to decrypt data'); + } + + return \Sodium\crypto_box( + $data, + $this->nonce, + \Sodium\crypto_box_keypair_from_secretkey_and_publickey($key->private, $key->public) + ); + } + + /** + * Method to generate a new encryption key object. + * + * @param array $options Key generation options. + * + * @return JCryptKey + * + * @since __DEPLOY_VERSION__ + * @throws RuntimeException + */ + public function generateKey(array $options = array()) + { + // Create the new encryption key object. + $key = new JCryptKey('sodium'); + + // Generate the encryption key. + $pair = \Sodium\crypto_box_keypair(); + + $key->public = \Sodium\crypto_box_publickey($pair); + $key->private = \Sodium\crypto_box_secretkey($pair); + + return $key; + } + + /** + * Set the nonce to use for encrypting/decrypting messages + * + * @param string $nonce The message nonce + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function setNonce($nonce) + { + $this->nonce = $nonce; + } +} diff --git a/libraries/vendor/composer/autoload_classmap.php b/libraries/vendor/composer/autoload_classmap.php index d6330d2166453..5a97e8f9928d9 100644 --- a/libraries/vendor/composer/autoload_classmap.php +++ b/libraries/vendor/composer/autoload_classmap.php @@ -8,12 +8,208 @@ return array( 'CallbackFilterIterator' => $vendorDir . '/joomla/compat/src/CallbackFilterIterator.php', 'EasyPeasyICS' => $vendorDir . '/phpmailer/phpmailer/extras/EasyPeasyICS.php', + 'Joomla\\Application\\AbstractApplication' => $vendorDir . '/joomla/application/src/AbstractApplication.php', + 'Joomla\\Application\\AbstractCliApplication' => $vendorDir . '/joomla/application/src/AbstractCliApplication.php', + 'Joomla\\Application\\AbstractDaemonApplication' => $vendorDir . '/joomla/application/src/AbstractDaemonApplication.php', + 'Joomla\\Application\\AbstractWebApplication' => $vendorDir . '/joomla/application/src/AbstractWebApplication.php', + 'Joomla\\Application\\Cli\\CliInput' => $vendorDir . '/joomla/application/src/Cli/CliInput.php', + 'Joomla\\Application\\Cli\\CliOutput' => $vendorDir . '/joomla/application/src/Cli/CliOutput.php', + 'Joomla\\Application\\Cli\\ColorProcessor' => $vendorDir . '/joomla/application/src/Cli/ColorProcessor.php', + 'Joomla\\Application\\Cli\\ColorStyle' => $vendorDir . '/joomla/application/src/Cli/ColorStyle.php', + 'Joomla\\Application\\Cli\\Output\\Processor\\ColorProcessor' => $vendorDir . '/joomla/application/src/Cli/Output/Processor/ColorProcessor.php', + 'Joomla\\Application\\Cli\\Output\\Processor\\ProcessorInterface' => $vendorDir . '/joomla/application/src/Cli/Output/Processor/ProcessorInterface.php', + 'Joomla\\Application\\Cli\\Output\\Stdout' => $vendorDir . '/joomla/application/src/Cli/Output/Stdout.php', + 'Joomla\\Application\\Cli\\Output\\Xml' => $vendorDir . '/joomla/application/src/Cli/Output/Xml.php', + 'Joomla\\Application\\Web\\WebClient' => $vendorDir . '/joomla/application/src/Web/WebClient.php', + 'Joomla\\Archive\\Archive' => $vendorDir . '/joomla/archive/src/Archive.php', + 'Joomla\\Archive\\Bzip2' => $vendorDir . '/joomla/archive/src/Bzip2.php', + 'Joomla\\Archive\\ExtractableInterface' => $vendorDir . '/joomla/archive/src/ExtractableInterface.php', + 'Joomla\\Archive\\Gzip' => $vendorDir . '/joomla/archive/src/Gzip.php', + 'Joomla\\Archive\\Tar' => $vendorDir . '/joomla/archive/src/Tar.php', + 'Joomla\\Archive\\Zip' => $vendorDir . '/joomla/archive/src/Zip.php', + 'Joomla\\DI\\Container' => $vendorDir . '/joomla/di/src/Container.php', + 'Joomla\\DI\\ContainerAwareInterface' => $vendorDir . '/joomla/di/src/ContainerAwareInterface.php', + 'Joomla\\DI\\ContainerAwareTrait' => $vendorDir . '/joomla/di/src/ContainerAwareTrait.php', + 'Joomla\\DI\\Exception\\DependencyResolutionException' => $vendorDir . '/joomla/di/src/Exception/DependencyResolutionException.php', + 'Joomla\\DI\\ServiceProviderInterface' => $vendorDir . '/joomla/di/src/ServiceProviderInterface.php', + 'Joomla\\DI\\Tests\\AliasingTest' => $vendorDir . '/joomla/di/Tests/AliasingTest.php', + 'Joomla\\DI\\Tests\\ContainerAccessTest' => $vendorDir . '/joomla/di/Tests/ContainerAccessTest.php', + 'Joomla\\DI\\Tests\\ContainerAwareTraitTest' => $vendorDir . '/joomla/di/Tests/ContainerAwareTraitTest.php', + 'Joomla\\DI\\Tests\\ContainerSetupTest' => $vendorDir . '/joomla/di/Tests/ContainerSetupTest.php', + 'Joomla\\DI\\Tests\\HierachicalTest' => $vendorDir . '/joomla/di/Tests/HierachicalTest.php', + 'Joomla\\DI\\Tests\\ObjectBuildingTest' => $vendorDir . '/joomla/di/Tests/ObjectBuildingTest.php', + 'Joomla\\DI\\Tests\\ResourceDecoration' => $vendorDir . '/joomla/di/Tests/ResourceDecorationTest.php', + 'Joomla\\DI\\Tests\\ResourceTest' => $vendorDir . '/joomla/di/Tests/ResourceTest.php', + 'Joomla\\DI\\Tests\\ServiceProviderTest' => $vendorDir . '/joomla/di/Tests/ServiceProviderTest.php', + 'Joomla\\DI\\Tests\\Stub1' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub2' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub3' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub4' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub5' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub6' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub7' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub8' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub9' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\StubInterface' => $vendorDir . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\Data\\DataObject' => $vendorDir . '/joomla/data/src/DataObject.php', + 'Joomla\\Data\\DataSet' => $vendorDir . '/joomla/data/src/DataSet.php', + 'Joomla\\Data\\DumpableInterface' => $vendorDir . '/joomla/data/src/DumpableInterface.php', + 'Joomla\\Data\\Tests\\DataObjectTest' => $vendorDir . '/joomla/data/Tests/DataObjectTest.php', + 'Joomla\\Data\\Tests\\DataSetTest' => $vendorDir . '/joomla/data/Tests/DataSetTest.php', + 'Joomla\\Data\\Tests\\JDataBuran' => $vendorDir . '/joomla/data/Tests/Stubs/buran.php', + 'Joomla\\Data\\Tests\\JDataCapitaliser' => $vendorDir . '/joomla/data/Tests/Stubs/capitaliser.php', + 'Joomla\\Data\\Tests\\JDataVostok' => $vendorDir . '/joomla/data/Tests/Stubs/vostok.php', + 'Joomla\\Event\\AbstractEvent' => $vendorDir . '/joomla/event/src/AbstractEvent.php', + 'Joomla\\Event\\DelegatingDispatcher' => $vendorDir . '/joomla/event/src/DelegatingDispatcher.php', + 'Joomla\\Event\\Dispatcher' => $vendorDir . '/joomla/event/src/Dispatcher.php', + 'Joomla\\Event\\DispatcherAwareInterface' => $vendorDir . '/joomla/event/src/DispatcherAwareInterface.php', + 'Joomla\\Event\\DispatcherAwareTrait' => $vendorDir . '/joomla/event/src/DispatcherAwareTrait.php', + 'Joomla\\Event\\DispatcherInterface' => $vendorDir . '/joomla/event/src/DispatcherInterface.php', + 'Joomla\\Event\\Event' => $vendorDir . '/joomla/event/src/Event.php', + 'Joomla\\Event\\EventImmutable' => $vendorDir . '/joomla/event/src/EventImmutable.php', + 'Joomla\\Event\\EventInterface' => $vendorDir . '/joomla/event/src/EventInterface.php', + 'Joomla\\Event\\ListenersPriorityQueue' => $vendorDir . '/joomla/event/src/ListenersPriorityQueue.php', + 'Joomla\\Event\\Priority' => $vendorDir . '/joomla/event/src/Priority.php', + 'Joomla\\Event\\Tests\\AbstractEventTest' => $vendorDir . '/joomla/event/Tests/AbstractEventTest.php', + 'Joomla\\Event\\Tests\\DelegatingDispatcherTest' => $vendorDir . '/joomla/event/Tests/DelegatingDispatcherTest.php', + 'Joomla\\Event\\Tests\\DispatcherTest' => $vendorDir . '/joomla/event/Tests/DispatcherTest.php', + 'Joomla\\Event\\Tests\\EventImmutableTest' => $vendorDir . '/joomla/event/Tests/EventImmutableTest.php', + 'Joomla\\Event\\Tests\\EventTest' => $vendorDir . '/joomla/event/Tests/EventTest.php', + 'Joomla\\Event\\Tests\\ListenersPriorityQueueTest' => $vendorDir . '/joomla/event/Tests/ListenersPriorityQueueTest.php', + 'Joomla\\Event\\Tests\\Stubs\\EmptyListener' => $vendorDir . '/joomla/event/Tests/Stubs/EmptyListener.php', + 'Joomla\\Event\\Tests\\Stubs\\FirstListener' => $vendorDir . '/joomla/event/Tests/Stubs/FirstListener.php', + 'Joomla\\Event\\Tests\\Stubs\\SecondListener' => $vendorDir . '/joomla/event/Tests/Stubs/SecondListener.php', + 'Joomla\\Event\\Tests\\Stubs\\SomethingListener' => $vendorDir . '/joomla/event/Tests/Stubs/SomethingListener.php', + 'Joomla\\Event\\Tests\\Stubs\\ThirdListener' => $vendorDir . '/joomla/event/Tests/Stubs/ThirdListener.php', + 'Joomla\\Filesystem\\Buffer' => $vendorDir . '/joomla/filesystem/src/Buffer.php', + 'Joomla\\Filesystem\\Clients\\FtpClient' => $vendorDir . '/joomla/filesystem/src/Clients/FtpClient.php', + 'Joomla\\Filesystem\\Exception\\FilesystemException' => $vendorDir . '/joomla/filesystem/src/Exception/FilesystemException.php', + 'Joomla\\Filesystem\\File' => $vendorDir . '/joomla/filesystem/src/File.php', + 'Joomla\\Filesystem\\Folder' => $vendorDir . '/joomla/filesystem/src/Folder.php', + 'Joomla\\Filesystem\\Helper' => $vendorDir . '/joomla/filesystem/src/Helper.php', + 'Joomla\\Filesystem\\Patcher' => $vendorDir . '/joomla/filesystem/src/Patcher.php', + 'Joomla\\Filesystem\\Path' => $vendorDir . '/joomla/filesystem/src/Path.php', + 'Joomla\\Filesystem\\Stream' => $vendorDir . '/joomla/filesystem/src/Stream.php', + 'Joomla\\Filesystem\\Stream\\String' => $vendorDir . '/joomla/filesystem/src/Stream/String.php', + 'Joomla\\Filesystem\\Stream\\StringWrapper' => $vendorDir . '/joomla/filesystem/src/Stream/StringWrapper.php', + 'Joomla\\Filesystem\\Support\\StringController' => $vendorDir . '/joomla/filesystem/src/Support/StringController.php', + 'Joomla\\Filter\\InputFilter' => $vendorDir . '/joomla/filter/src/InputFilter.php', + 'Joomla\\Filter\\OutputFilter' => $vendorDir . '/joomla/filter/src/OutputFilter.php', + 'Joomla\\Input\\Cli' => $vendorDir . '/joomla/input/src/Cli.php', + 'Joomla\\Input\\Cookie' => $vendorDir . '/joomla/input/src/Cookie.php', + 'Joomla\\Input\\Files' => $vendorDir . '/joomla/input/src/Files.php', + 'Joomla\\Input\\Input' => $vendorDir . '/joomla/input/src/Input.php', + 'Joomla\\Input\\Json' => $vendorDir . '/joomla/input/src/Json.php', + 'Joomla\\Ldap\\LdapClient' => $vendorDir . '/joomla/ldap/src/LdapClient.php', + 'Joomla\\Ldap\\Tests\\LdapClientTest' => $vendorDir . '/joomla/ldap/Tests/LdapClientTest.php', + 'Joomla\\Registry\\AbstractRegistryFormat' => $vendorDir . '/joomla/registry/src/AbstractRegistryFormat.php', + 'Joomla\\Registry\\Factory' => $vendorDir . '/joomla/registry/src/Factory.php', + 'Joomla\\Registry\\FormatInterface' => $vendorDir . '/joomla/registry/src/FormatInterface.php', + 'Joomla\\Registry\\Format\\Ini' => $vendorDir . '/joomla/registry/src/Format/Ini.php', + 'Joomla\\Registry\\Format\\Json' => $vendorDir . '/joomla/registry/src/Format/Json.php', + 'Joomla\\Registry\\Format\\Php' => $vendorDir . '/joomla/registry/src/Format/Php.php', + 'Joomla\\Registry\\Format\\Xml' => $vendorDir . '/joomla/registry/src/Format/Xml.php', + 'Joomla\\Registry\\Format\\Yaml' => $vendorDir . '/joomla/registry/src/Format/Yaml.php', + 'Joomla\\Registry\\Registry' => $vendorDir . '/joomla/registry/src/Registry.php', + 'Joomla\\Session\\Session' => $vendorDir . '/joomla/session/Joomla/Session/Session.php', + 'Joomla\\Session\\Storage' => $vendorDir . '/joomla/session/Joomla/Session/Storage.php', + 'Joomla\\Session\\Storage\\Apc' => $vendorDir . '/joomla/session/Joomla/Session/Storage/Apc.php', + 'Joomla\\Session\\Storage\\Database' => $vendorDir . '/joomla/session/Joomla/Session/Storage/Database.php', + 'Joomla\\Session\\Storage\\Memcache' => $vendorDir . '/joomla/session/Joomla/Session/Storage/Memcache.php', + 'Joomla\\Session\\Storage\\Memcached' => $vendorDir . '/joomla/session/Joomla/Session/Storage/Memcached.php', + 'Joomla\\Session\\Storage\\None' => $vendorDir . '/joomla/session/Joomla/Session/Storage/None.php', + 'Joomla\\Session\\Storage\\Wincache' => $vendorDir . '/joomla/session/Joomla/Session/Storage/Wincache.php', + 'Joomla\\Session\\Storage\\Xcache' => $vendorDir . '/joomla/session/Joomla/Session/Storage/Xcache.php', + 'Joomla\\Session\\Tests\\Handler\\ApcHandlerTest' => $vendorDir . '/joomla/session/tests/Handler/ApcHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\ApcuHandlerTest' => $vendorDir . '/joomla/session/tests/Handler/ApcuHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\DatabaseHandlerTest' => $vendorDir . '/joomla/session/tests/Handler/DatabaseHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\FilesystemHandlerTest' => $vendorDir . '/joomla/session/tests/Handler/FilesystemHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\MemcacheHandlerTest' => $vendorDir . '/joomla/session/tests/Handler/MemcacheHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\MemcachedHandlerTest' => $vendorDir . '/joomla/session/tests/Handler/MemcachedHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\NativeStorageTest' => $vendorDir . '/joomla/session/tests/Storage/NativeStorageTest.php', + 'Joomla\\Session\\Tests\\Handler\\RedisHandlerTest' => $vendorDir . '/joomla/session/tests/Handler/RedisHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\WincacheHandlerTest' => $vendorDir . '/joomla/session/tests/Handler/WincacheHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\XCacheHandlerTest' => $vendorDir . '/joomla/session/tests/Handler/XCacheHandlerTest.php', + 'Joomla\\Session\\Tests\\SessionTest' => $vendorDir . '/joomla/session/tests/SessionTest.php', + 'Joomla\\String\\Inflector' => $vendorDir . '/joomla/string/src/Inflector.php', + 'Joomla\\String\\Normalise' => $vendorDir . '/joomla/string/src/Normalise.php', + 'Joomla\\String\\String' => $vendorDir . '/joomla/string/src/String.php', + 'Joomla\\String\\StringHelper' => $vendorDir . '/joomla/string/src/StringHelper.php', + 'Joomla\\Uri\\AbstractUri' => $vendorDir . '/joomla/uri/src/AbstractUri.php', + 'Joomla\\Uri\\Tests\\UriHelperTest' => $vendorDir . '/joomla/uri/Tests/UriHelperTest.php', + 'Joomla\\Uri\\Tests\\UriImmuteableTest' => $vendorDir . '/joomla/uri/Tests/UriImmutableTest.php', + 'Joomla\\Uri\\Tests\\UriTest' => $vendorDir . '/joomla/uri/Tests/UriTest.php', + 'Joomla\\Uri\\Uri' => $vendorDir . '/joomla/uri/src/Uri.php', + 'Joomla\\Uri\\UriHelper' => $vendorDir . '/joomla/uri/src/UriHelper.php', + 'Joomla\\Uri\\UriImmutable' => $vendorDir . '/joomla/uri/src/UriImmutable.php', + 'Joomla\\Uri\\UriInterface' => $vendorDir . '/joomla/uri/src/UriInterface.php', + 'Joomla\\Utilities\\ArrayHelper' => $vendorDir . '/joomla/utilities/src/ArrayHelper.php', 'JsonSerializable' => $vendorDir . '/joomla/compat/src/JsonSerializable.php', 'PHPMailer' => $vendorDir . '/phpmailer/phpmailer/class.phpmailer.php', 'PHPMailerOAuth' => $vendorDir . '/phpmailer/phpmailer/class.phpmaileroauth.php', 'PHPMailerOAuthGoogle' => $vendorDir . '/phpmailer/phpmailer/class.phpmaileroauthgoogle.php', 'POP3' => $vendorDir . '/phpmailer/phpmailer/class.pop3.php', + 'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php', + 'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php', + 'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php', + 'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareInterface.php', + 'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareTrait.php', + 'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php', + 'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php', + 'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php', + 'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', + 'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'SMTP' => $vendorDir . '/phpmailer/phpmailer/class.smtp.php', + 'SimplePie' => $vendorDir . '/simplepie/simplepie/library/SimplePie.php', + 'SimplePie_Author' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Author.php', + 'SimplePie_Cache' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Cache.php', + 'SimplePie_Cache_Base' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Cache/Base.php', + 'SimplePie_Cache_DB' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Cache/DB.php', + 'SimplePie_Cache_File' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Cache/File.php', + 'SimplePie_Cache_Memcache' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Cache/Memcache.php', + 'SimplePie_Cache_MySQL' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Cache/MySQL.php', + 'SimplePie_Caption' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Caption.php', + 'SimplePie_Category' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Category.php', + 'SimplePie_Content_Type_Sniffer' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Content/Type/Sniffer.php', + 'SimplePie_Copyright' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Copyright.php', + 'SimplePie_Core' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Core.php', + 'SimplePie_Credit' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Credit.php', + 'SimplePie_Decode_HTML_Entities' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Decode/HTML/Entities.php', + 'SimplePie_Enclosure' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Enclosure.php', + 'SimplePie_Exception' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Exception.php', + 'SimplePie_File' => $vendorDir . '/simplepie/simplepie/library/SimplePie/File.php', + 'SimplePie_HTTP_Parser' => $vendorDir . '/simplepie/simplepie/library/SimplePie/HTTP/Parser.php', + 'SimplePie_IRI' => $vendorDir . '/simplepie/simplepie/library/SimplePie/IRI.php', + 'SimplePie_Item' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Item.php', + 'SimplePie_Locator' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Locator.php', + 'SimplePie_Misc' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Misc.php', + 'SimplePie_Net_IPv6' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Net/IPv6.php', + 'SimplePie_Parse_Date' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Parse/Date.php', + 'SimplePie_Parser' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Parser.php', + 'SimplePie_Rating' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Rating.php', + 'SimplePie_Registry' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Registry.php', + 'SimplePie_Restriction' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Restriction.php', + 'SimplePie_Sanitize' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Sanitize.php', + 'SimplePie_Source' => $vendorDir . '/simplepie/simplepie/library/SimplePie/Source.php', + 'SimplePie_XML_Declaration_Parser' => $vendorDir . '/simplepie/simplepie/library/SimplePie/XML/Declaration/Parser.php', + 'SimplePie_gzdecode' => $vendorDir . '/simplepie/simplepie/library/SimplePie/gzdecode.php', + 'Symfony\\Component\\Yaml\\Dumper' => $vendorDir . '/symfony/yaml/Dumper.php', + 'Symfony\\Component\\Yaml\\Escaper' => $vendorDir . '/symfony/yaml/Escaper.php', + 'Symfony\\Component\\Yaml\\Exception\\DumpException' => $vendorDir . '/symfony/yaml/Exception/DumpException.php', + 'Symfony\\Component\\Yaml\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/yaml/Exception/ExceptionInterface.php', + 'Symfony\\Component\\Yaml\\Exception\\ParseException' => $vendorDir . '/symfony/yaml/Exception/ParseException.php', + 'Symfony\\Component\\Yaml\\Exception\\RuntimeException' => $vendorDir . '/symfony/yaml/Exception/RuntimeException.php', + 'Symfony\\Component\\Yaml\\Inline' => $vendorDir . '/symfony/yaml/Inline.php', + 'Symfony\\Component\\Yaml\\Parser' => $vendorDir . '/symfony/yaml/Parser.php', + 'Symfony\\Component\\Yaml\\Unescaper' => $vendorDir . '/symfony/yaml/Unescaper.php', + 'Symfony\\Component\\Yaml\\Yaml' => $vendorDir . '/symfony/yaml/Yaml.php', + 'Symfony\\Polyfill\\Php55\\Php55' => $vendorDir . '/symfony/polyfill-php55/Php55.php', + 'Symfony\\Polyfill\\Php55\\Php55ArrayColumn' => $vendorDir . '/symfony/polyfill-php55/Php55ArrayColumn.php', + 'Symfony\\Polyfill\\Php56\\Php56' => $vendorDir . '/symfony/polyfill-php56/Php56.php', + 'Symfony\\Polyfill\\Util\\Binary' => $vendorDir . '/symfony/polyfill-util/Binary.php', + 'Symfony\\Polyfill\\Util\\BinaryNoFuncOverload' => $vendorDir . '/symfony/polyfill-util/BinaryNoFuncOverload.php', + 'Symfony\\Polyfill\\Util\\BinaryOnFuncOverload' => $vendorDir . '/symfony/polyfill-util/BinaryOnFuncOverload.php', + 'Symfony\\Polyfill\\Util\\TestListener' => $vendorDir . '/symfony/polyfill-util/TestListener.php', 'lessc' => $vendorDir . '/leafo/lessphp/lessc.inc.php', 'lessc_formatter_classic' => $vendorDir . '/leafo/lessphp/lessc.inc.php', 'lessc_formatter_compressed' => $vendorDir . '/leafo/lessphp/lessc.inc.php', diff --git a/libraries/vendor/composer/autoload_files.php b/libraries/vendor/composer/autoload_files.php index 3d72446f81c6e..fb46f771b9ea3 100644 --- a/libraries/vendor/composer/autoload_files.php +++ b/libraries/vendor/composer/autoload_files.php @@ -21,8 +21,9 @@ '05d739a990f75f0c44ebe1f032b33148' => $vendorDir . '/joomla/string/src/phputf8/ucwords.php', '4292e2fa66516089e6006723267587b4' => $vendorDir . '/joomla/string/src/phputf8/utils/ascii.php', '87465e33b7551b401bf051928f220e9a' => $vendorDir . '/joomla/string/src/phputf8/utils/validation.php', - 'e40631d46120a9c38ea139981f8dab26' => $vendorDir . '/ircmaxell/password-compat/lib/password.php', '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php', + 'e40631d46120a9c38ea139981f8dab26' => $vendorDir . '/ircmaxell/password-compat/lib/password.php', 'edc6464955a37aa4d5fbf39d40fb6ee7' => $vendorDir . '/symfony/polyfill-php55/bootstrap.php', 'bd9634f2d41831496de0d3dfe4c94881' => $vendorDir . '/symfony/polyfill-php56/bootstrap.php', + '3109cb1a231dcd04bee1f9f620d46975' => $vendorDir . '/paragonie/sodium_compat/autoload.php', ); diff --git a/libraries/vendor/composer/autoload_static.php b/libraries/vendor/composer/autoload_static.php index f51dd15da6a43..fbcc91e744799 100644 --- a/libraries/vendor/composer/autoload_static.php +++ b/libraries/vendor/composer/autoload_static.php @@ -22,10 +22,11 @@ class ComposerStaticInit205c915b9c7d3e718e7c95793ee67ffe '05d739a990f75f0c44ebe1f032b33148' => __DIR__ . '/..' . '/joomla/string/src/phputf8/ucwords.php', '4292e2fa66516089e6006723267587b4' => __DIR__ . '/..' . '/joomla/string/src/phputf8/utils/ascii.php', '87465e33b7551b401bf051928f220e9a' => __DIR__ . '/..' . '/joomla/string/src/phputf8/utils/validation.php', - 'e40631d46120a9c38ea139981f8dab26' => __DIR__ . '/..' . '/ircmaxell/password-compat/lib/password.php', '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', + 'e40631d46120a9c38ea139981f8dab26' => __DIR__ . '/..' . '/ircmaxell/password-compat/lib/password.php', 'edc6464955a37aa4d5fbf39d40fb6ee7' => __DIR__ . '/..' . '/symfony/polyfill-php55/bootstrap.php', 'bd9634f2d41831496de0d3dfe4c94881' => __DIR__ . '/..' . '/symfony/polyfill-php56/bootstrap.php', + '3109cb1a231dcd04bee1f9f620d46975' => __DIR__ . '/..' . '/paragonie/sodium_compat/autoload.php', ); public static $prefixLengthsPsr4 = array ( @@ -183,12 +184,208 @@ class ComposerStaticInit205c915b9c7d3e718e7c95793ee67ffe public static $classMap = array ( 'CallbackFilterIterator' => __DIR__ . '/..' . '/joomla/compat/src/CallbackFilterIterator.php', 'EasyPeasyICS' => __DIR__ . '/..' . '/phpmailer/phpmailer/extras/EasyPeasyICS.php', + 'Joomla\\Application\\AbstractApplication' => __DIR__ . '/..' . '/joomla/application/src/AbstractApplication.php', + 'Joomla\\Application\\AbstractCliApplication' => __DIR__ . '/..' . '/joomla/application/src/AbstractCliApplication.php', + 'Joomla\\Application\\AbstractDaemonApplication' => __DIR__ . '/..' . '/joomla/application/src/AbstractDaemonApplication.php', + 'Joomla\\Application\\AbstractWebApplication' => __DIR__ . '/..' . '/joomla/application/src/AbstractWebApplication.php', + 'Joomla\\Application\\Cli\\CliInput' => __DIR__ . '/..' . '/joomla/application/src/Cli/CliInput.php', + 'Joomla\\Application\\Cli\\CliOutput' => __DIR__ . '/..' . '/joomla/application/src/Cli/CliOutput.php', + 'Joomla\\Application\\Cli\\ColorProcessor' => __DIR__ . '/..' . '/joomla/application/src/Cli/ColorProcessor.php', + 'Joomla\\Application\\Cli\\ColorStyle' => __DIR__ . '/..' . '/joomla/application/src/Cli/ColorStyle.php', + 'Joomla\\Application\\Cli\\Output\\Processor\\ColorProcessor' => __DIR__ . '/..' . '/joomla/application/src/Cli/Output/Processor/ColorProcessor.php', + 'Joomla\\Application\\Cli\\Output\\Processor\\ProcessorInterface' => __DIR__ . '/..' . '/joomla/application/src/Cli/Output/Processor/ProcessorInterface.php', + 'Joomla\\Application\\Cli\\Output\\Stdout' => __DIR__ . '/..' . '/joomla/application/src/Cli/Output/Stdout.php', + 'Joomla\\Application\\Cli\\Output\\Xml' => __DIR__ . '/..' . '/joomla/application/src/Cli/Output/Xml.php', + 'Joomla\\Application\\Web\\WebClient' => __DIR__ . '/..' . '/joomla/application/src/Web/WebClient.php', + 'Joomla\\Archive\\Archive' => __DIR__ . '/..' . '/joomla/archive/src/Archive.php', + 'Joomla\\Archive\\Bzip2' => __DIR__ . '/..' . '/joomla/archive/src/Bzip2.php', + 'Joomla\\Archive\\ExtractableInterface' => __DIR__ . '/..' . '/joomla/archive/src/ExtractableInterface.php', + 'Joomla\\Archive\\Gzip' => __DIR__ . '/..' . '/joomla/archive/src/Gzip.php', + 'Joomla\\Archive\\Tar' => __DIR__ . '/..' . '/joomla/archive/src/Tar.php', + 'Joomla\\Archive\\Zip' => __DIR__ . '/..' . '/joomla/archive/src/Zip.php', + 'Joomla\\DI\\Container' => __DIR__ . '/..' . '/joomla/di/src/Container.php', + 'Joomla\\DI\\ContainerAwareInterface' => __DIR__ . '/..' . '/joomla/di/src/ContainerAwareInterface.php', + 'Joomla\\DI\\ContainerAwareTrait' => __DIR__ . '/..' . '/joomla/di/src/ContainerAwareTrait.php', + 'Joomla\\DI\\Exception\\DependencyResolutionException' => __DIR__ . '/..' . '/joomla/di/src/Exception/DependencyResolutionException.php', + 'Joomla\\DI\\ServiceProviderInterface' => __DIR__ . '/..' . '/joomla/di/src/ServiceProviderInterface.php', + 'Joomla\\DI\\Tests\\AliasingTest' => __DIR__ . '/..' . '/joomla/di/Tests/AliasingTest.php', + 'Joomla\\DI\\Tests\\ContainerAccessTest' => __DIR__ . '/..' . '/joomla/di/Tests/ContainerAccessTest.php', + 'Joomla\\DI\\Tests\\ContainerAwareTraitTest' => __DIR__ . '/..' . '/joomla/di/Tests/ContainerAwareTraitTest.php', + 'Joomla\\DI\\Tests\\ContainerSetupTest' => __DIR__ . '/..' . '/joomla/di/Tests/ContainerSetupTest.php', + 'Joomla\\DI\\Tests\\HierachicalTest' => __DIR__ . '/..' . '/joomla/di/Tests/HierachicalTest.php', + 'Joomla\\DI\\Tests\\ObjectBuildingTest' => __DIR__ . '/..' . '/joomla/di/Tests/ObjectBuildingTest.php', + 'Joomla\\DI\\Tests\\ResourceDecoration' => __DIR__ . '/..' . '/joomla/di/Tests/ResourceDecorationTest.php', + 'Joomla\\DI\\Tests\\ResourceTest' => __DIR__ . '/..' . '/joomla/di/Tests/ResourceTest.php', + 'Joomla\\DI\\Tests\\ServiceProviderTest' => __DIR__ . '/..' . '/joomla/di/Tests/ServiceProviderTest.php', + 'Joomla\\DI\\Tests\\Stub1' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub2' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub3' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub4' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub5' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub6' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub7' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub8' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\Stub9' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\DI\\Tests\\StubInterface' => __DIR__ . '/..' . '/joomla/di/Tests/Stubs/stubs.php', + 'Joomla\\Data\\DataObject' => __DIR__ . '/..' . '/joomla/data/src/DataObject.php', + 'Joomla\\Data\\DataSet' => __DIR__ . '/..' . '/joomla/data/src/DataSet.php', + 'Joomla\\Data\\DumpableInterface' => __DIR__ . '/..' . '/joomla/data/src/DumpableInterface.php', + 'Joomla\\Data\\Tests\\DataObjectTest' => __DIR__ . '/..' . '/joomla/data/Tests/DataObjectTest.php', + 'Joomla\\Data\\Tests\\DataSetTest' => __DIR__ . '/..' . '/joomla/data/Tests/DataSetTest.php', + 'Joomla\\Data\\Tests\\JDataBuran' => __DIR__ . '/..' . '/joomla/data/Tests/Stubs/buran.php', + 'Joomla\\Data\\Tests\\JDataCapitaliser' => __DIR__ . '/..' . '/joomla/data/Tests/Stubs/capitaliser.php', + 'Joomla\\Data\\Tests\\JDataVostok' => __DIR__ . '/..' . '/joomla/data/Tests/Stubs/vostok.php', + 'Joomla\\Event\\AbstractEvent' => __DIR__ . '/..' . '/joomla/event/src/AbstractEvent.php', + 'Joomla\\Event\\DelegatingDispatcher' => __DIR__ . '/..' . '/joomla/event/src/DelegatingDispatcher.php', + 'Joomla\\Event\\Dispatcher' => __DIR__ . '/..' . '/joomla/event/src/Dispatcher.php', + 'Joomla\\Event\\DispatcherAwareInterface' => __DIR__ . '/..' . '/joomla/event/src/DispatcherAwareInterface.php', + 'Joomla\\Event\\DispatcherAwareTrait' => __DIR__ . '/..' . '/joomla/event/src/DispatcherAwareTrait.php', + 'Joomla\\Event\\DispatcherInterface' => __DIR__ . '/..' . '/joomla/event/src/DispatcherInterface.php', + 'Joomla\\Event\\Event' => __DIR__ . '/..' . '/joomla/event/src/Event.php', + 'Joomla\\Event\\EventImmutable' => __DIR__ . '/..' . '/joomla/event/src/EventImmutable.php', + 'Joomla\\Event\\EventInterface' => __DIR__ . '/..' . '/joomla/event/src/EventInterface.php', + 'Joomla\\Event\\ListenersPriorityQueue' => __DIR__ . '/..' . '/joomla/event/src/ListenersPriorityQueue.php', + 'Joomla\\Event\\Priority' => __DIR__ . '/..' . '/joomla/event/src/Priority.php', + 'Joomla\\Event\\Tests\\AbstractEventTest' => __DIR__ . '/..' . '/joomla/event/Tests/AbstractEventTest.php', + 'Joomla\\Event\\Tests\\DelegatingDispatcherTest' => __DIR__ . '/..' . '/joomla/event/Tests/DelegatingDispatcherTest.php', + 'Joomla\\Event\\Tests\\DispatcherTest' => __DIR__ . '/..' . '/joomla/event/Tests/DispatcherTest.php', + 'Joomla\\Event\\Tests\\EventImmutableTest' => __DIR__ . '/..' . '/joomla/event/Tests/EventImmutableTest.php', + 'Joomla\\Event\\Tests\\EventTest' => __DIR__ . '/..' . '/joomla/event/Tests/EventTest.php', + 'Joomla\\Event\\Tests\\ListenersPriorityQueueTest' => __DIR__ . '/..' . '/joomla/event/Tests/ListenersPriorityQueueTest.php', + 'Joomla\\Event\\Tests\\Stubs\\EmptyListener' => __DIR__ . '/..' . '/joomla/event/Tests/Stubs/EmptyListener.php', + 'Joomla\\Event\\Tests\\Stubs\\FirstListener' => __DIR__ . '/..' . '/joomla/event/Tests/Stubs/FirstListener.php', + 'Joomla\\Event\\Tests\\Stubs\\SecondListener' => __DIR__ . '/..' . '/joomla/event/Tests/Stubs/SecondListener.php', + 'Joomla\\Event\\Tests\\Stubs\\SomethingListener' => __DIR__ . '/..' . '/joomla/event/Tests/Stubs/SomethingListener.php', + 'Joomla\\Event\\Tests\\Stubs\\ThirdListener' => __DIR__ . '/..' . '/joomla/event/Tests/Stubs/ThirdListener.php', + 'Joomla\\Filesystem\\Buffer' => __DIR__ . '/..' . '/joomla/filesystem/src/Buffer.php', + 'Joomla\\Filesystem\\Clients\\FtpClient' => __DIR__ . '/..' . '/joomla/filesystem/src/Clients/FtpClient.php', + 'Joomla\\Filesystem\\Exception\\FilesystemException' => __DIR__ . '/..' . '/joomla/filesystem/src/Exception/FilesystemException.php', + 'Joomla\\Filesystem\\File' => __DIR__ . '/..' . '/joomla/filesystem/src/File.php', + 'Joomla\\Filesystem\\Folder' => __DIR__ . '/..' . '/joomla/filesystem/src/Folder.php', + 'Joomla\\Filesystem\\Helper' => __DIR__ . '/..' . '/joomla/filesystem/src/Helper.php', + 'Joomla\\Filesystem\\Patcher' => __DIR__ . '/..' . '/joomla/filesystem/src/Patcher.php', + 'Joomla\\Filesystem\\Path' => __DIR__ . '/..' . '/joomla/filesystem/src/Path.php', + 'Joomla\\Filesystem\\Stream' => __DIR__ . '/..' . '/joomla/filesystem/src/Stream.php', + 'Joomla\\Filesystem\\Stream\\String' => __DIR__ . '/..' . '/joomla/filesystem/src/Stream/String.php', + 'Joomla\\Filesystem\\Stream\\StringWrapper' => __DIR__ . '/..' . '/joomla/filesystem/src/Stream/StringWrapper.php', + 'Joomla\\Filesystem\\Support\\StringController' => __DIR__ . '/..' . '/joomla/filesystem/src/Support/StringController.php', + 'Joomla\\Filter\\InputFilter' => __DIR__ . '/..' . '/joomla/filter/src/InputFilter.php', + 'Joomla\\Filter\\OutputFilter' => __DIR__ . '/..' . '/joomla/filter/src/OutputFilter.php', + 'Joomla\\Input\\Cli' => __DIR__ . '/..' . '/joomla/input/src/Cli.php', + 'Joomla\\Input\\Cookie' => __DIR__ . '/..' . '/joomla/input/src/Cookie.php', + 'Joomla\\Input\\Files' => __DIR__ . '/..' . '/joomla/input/src/Files.php', + 'Joomla\\Input\\Input' => __DIR__ . '/..' . '/joomla/input/src/Input.php', + 'Joomla\\Input\\Json' => __DIR__ . '/..' . '/joomla/input/src/Json.php', + 'Joomla\\Ldap\\LdapClient' => __DIR__ . '/..' . '/joomla/ldap/src/LdapClient.php', + 'Joomla\\Ldap\\Tests\\LdapClientTest' => __DIR__ . '/..' . '/joomla/ldap/Tests/LdapClientTest.php', + 'Joomla\\Registry\\AbstractRegistryFormat' => __DIR__ . '/..' . '/joomla/registry/src/AbstractRegistryFormat.php', + 'Joomla\\Registry\\Factory' => __DIR__ . '/..' . '/joomla/registry/src/Factory.php', + 'Joomla\\Registry\\FormatInterface' => __DIR__ . '/..' . '/joomla/registry/src/FormatInterface.php', + 'Joomla\\Registry\\Format\\Ini' => __DIR__ . '/..' . '/joomla/registry/src/Format/Ini.php', + 'Joomla\\Registry\\Format\\Json' => __DIR__ . '/..' . '/joomla/registry/src/Format/Json.php', + 'Joomla\\Registry\\Format\\Php' => __DIR__ . '/..' . '/joomla/registry/src/Format/Php.php', + 'Joomla\\Registry\\Format\\Xml' => __DIR__ . '/..' . '/joomla/registry/src/Format/Xml.php', + 'Joomla\\Registry\\Format\\Yaml' => __DIR__ . '/..' . '/joomla/registry/src/Format/Yaml.php', + 'Joomla\\Registry\\Registry' => __DIR__ . '/..' . '/joomla/registry/src/Registry.php', + 'Joomla\\Session\\Session' => __DIR__ . '/..' . '/joomla/session/Joomla/Session/Session.php', + 'Joomla\\Session\\Storage' => __DIR__ . '/..' . '/joomla/session/Joomla/Session/Storage.php', + 'Joomla\\Session\\Storage\\Apc' => __DIR__ . '/..' . '/joomla/session/Joomla/Session/Storage/Apc.php', + 'Joomla\\Session\\Storage\\Database' => __DIR__ . '/..' . '/joomla/session/Joomla/Session/Storage/Database.php', + 'Joomla\\Session\\Storage\\Memcache' => __DIR__ . '/..' . '/joomla/session/Joomla/Session/Storage/Memcache.php', + 'Joomla\\Session\\Storage\\Memcached' => __DIR__ . '/..' . '/joomla/session/Joomla/Session/Storage/Memcached.php', + 'Joomla\\Session\\Storage\\None' => __DIR__ . '/..' . '/joomla/session/Joomla/Session/Storage/None.php', + 'Joomla\\Session\\Storage\\Wincache' => __DIR__ . '/..' . '/joomla/session/Joomla/Session/Storage/Wincache.php', + 'Joomla\\Session\\Storage\\Xcache' => __DIR__ . '/..' . '/joomla/session/Joomla/Session/Storage/Xcache.php', + 'Joomla\\Session\\Tests\\Handler\\ApcHandlerTest' => __DIR__ . '/..' . '/joomla/session/tests/Handler/ApcHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\ApcuHandlerTest' => __DIR__ . '/..' . '/joomla/session/tests/Handler/ApcuHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\DatabaseHandlerTest' => __DIR__ . '/..' . '/joomla/session/tests/Handler/DatabaseHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\FilesystemHandlerTest' => __DIR__ . '/..' . '/joomla/session/tests/Handler/FilesystemHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\MemcacheHandlerTest' => __DIR__ . '/..' . '/joomla/session/tests/Handler/MemcacheHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\MemcachedHandlerTest' => __DIR__ . '/..' . '/joomla/session/tests/Handler/MemcachedHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\NativeStorageTest' => __DIR__ . '/..' . '/joomla/session/tests/Storage/NativeStorageTest.php', + 'Joomla\\Session\\Tests\\Handler\\RedisHandlerTest' => __DIR__ . '/..' . '/joomla/session/tests/Handler/RedisHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\WincacheHandlerTest' => __DIR__ . '/..' . '/joomla/session/tests/Handler/WincacheHandlerTest.php', + 'Joomla\\Session\\Tests\\Handler\\XCacheHandlerTest' => __DIR__ . '/..' . '/joomla/session/tests/Handler/XCacheHandlerTest.php', + 'Joomla\\Session\\Tests\\SessionTest' => __DIR__ . '/..' . '/joomla/session/tests/SessionTest.php', + 'Joomla\\String\\Inflector' => __DIR__ . '/..' . '/joomla/string/src/Inflector.php', + 'Joomla\\String\\Normalise' => __DIR__ . '/..' . '/joomla/string/src/Normalise.php', + 'Joomla\\String\\String' => __DIR__ . '/..' . '/joomla/string/src/String.php', + 'Joomla\\String\\StringHelper' => __DIR__ . '/..' . '/joomla/string/src/StringHelper.php', + 'Joomla\\Uri\\AbstractUri' => __DIR__ . '/..' . '/joomla/uri/src/AbstractUri.php', + 'Joomla\\Uri\\Tests\\UriHelperTest' => __DIR__ . '/..' . '/joomla/uri/Tests/UriHelperTest.php', + 'Joomla\\Uri\\Tests\\UriImmuteableTest' => __DIR__ . '/..' . '/joomla/uri/Tests/UriImmutableTest.php', + 'Joomla\\Uri\\Tests\\UriTest' => __DIR__ . '/..' . '/joomla/uri/Tests/UriTest.php', + 'Joomla\\Uri\\Uri' => __DIR__ . '/..' . '/joomla/uri/src/Uri.php', + 'Joomla\\Uri\\UriHelper' => __DIR__ . '/..' . '/joomla/uri/src/UriHelper.php', + 'Joomla\\Uri\\UriImmutable' => __DIR__ . '/..' . '/joomla/uri/src/UriImmutable.php', + 'Joomla\\Uri\\UriInterface' => __DIR__ . '/..' . '/joomla/uri/src/UriInterface.php', + 'Joomla\\Utilities\\ArrayHelper' => __DIR__ . '/..' . '/joomla/utilities/src/ArrayHelper.php', 'JsonSerializable' => __DIR__ . '/..' . '/joomla/compat/src/JsonSerializable.php', 'PHPMailer' => __DIR__ . '/..' . '/phpmailer/phpmailer/class.phpmailer.php', 'PHPMailerOAuth' => __DIR__ . '/..' . '/phpmailer/phpmailer/class.phpmaileroauth.php', 'PHPMailerOAuthGoogle' => __DIR__ . '/..' . '/phpmailer/phpmailer/class.phpmaileroauthgoogle.php', 'POP3' => __DIR__ . '/..' . '/phpmailer/phpmailer/class.pop3.php', + 'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/AbstractLogger.php', + 'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/Psr/Log/InvalidArgumentException.php', + 'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/Psr/Log/LogLevel.php', + 'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareInterface.php', + 'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareTrait.php', + 'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerInterface.php', + 'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerTrait.php', + 'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/NullLogger.php', + 'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', + 'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php', 'SMTP' => __DIR__ . '/..' . '/phpmailer/phpmailer/class.smtp.php', + 'SimplePie' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie.php', + 'SimplePie_Author' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Author.php', + 'SimplePie_Cache' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Cache.php', + 'SimplePie_Cache_Base' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Cache/Base.php', + 'SimplePie_Cache_DB' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Cache/DB.php', + 'SimplePie_Cache_File' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Cache/File.php', + 'SimplePie_Cache_Memcache' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Cache/Memcache.php', + 'SimplePie_Cache_MySQL' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Cache/MySQL.php', + 'SimplePie_Caption' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Caption.php', + 'SimplePie_Category' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Category.php', + 'SimplePie_Content_Type_Sniffer' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Content/Type/Sniffer.php', + 'SimplePie_Copyright' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Copyright.php', + 'SimplePie_Core' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Core.php', + 'SimplePie_Credit' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Credit.php', + 'SimplePie_Decode_HTML_Entities' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Decode/HTML/Entities.php', + 'SimplePie_Enclosure' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Enclosure.php', + 'SimplePie_Exception' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Exception.php', + 'SimplePie_File' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/File.php', + 'SimplePie_HTTP_Parser' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/HTTP/Parser.php', + 'SimplePie_IRI' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/IRI.php', + 'SimplePie_Item' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Item.php', + 'SimplePie_Locator' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Locator.php', + 'SimplePie_Misc' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Misc.php', + 'SimplePie_Net_IPv6' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Net/IPv6.php', + 'SimplePie_Parse_Date' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Parse/Date.php', + 'SimplePie_Parser' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Parser.php', + 'SimplePie_Rating' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Rating.php', + 'SimplePie_Registry' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Registry.php', + 'SimplePie_Restriction' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Restriction.php', + 'SimplePie_Sanitize' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Sanitize.php', + 'SimplePie_Source' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/Source.php', + 'SimplePie_XML_Declaration_Parser' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/XML/Declaration/Parser.php', + 'SimplePie_gzdecode' => __DIR__ . '/..' . '/simplepie/simplepie/library/SimplePie/gzdecode.php', + 'Symfony\\Component\\Yaml\\Dumper' => __DIR__ . '/..' . '/symfony/yaml/Dumper.php', + 'Symfony\\Component\\Yaml\\Escaper' => __DIR__ . '/..' . '/symfony/yaml/Escaper.php', + 'Symfony\\Component\\Yaml\\Exception\\DumpException' => __DIR__ . '/..' . '/symfony/yaml/Exception/DumpException.php', + 'Symfony\\Component\\Yaml\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/yaml/Exception/ExceptionInterface.php', + 'Symfony\\Component\\Yaml\\Exception\\ParseException' => __DIR__ . '/..' . '/symfony/yaml/Exception/ParseException.php', + 'Symfony\\Component\\Yaml\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/yaml/Exception/RuntimeException.php', + 'Symfony\\Component\\Yaml\\Inline' => __DIR__ . '/..' . '/symfony/yaml/Inline.php', + 'Symfony\\Component\\Yaml\\Parser' => __DIR__ . '/..' . '/symfony/yaml/Parser.php', + 'Symfony\\Component\\Yaml\\Unescaper' => __DIR__ . '/..' . '/symfony/yaml/Unescaper.php', + 'Symfony\\Component\\Yaml\\Yaml' => __DIR__ . '/..' . '/symfony/yaml/Yaml.php', + 'Symfony\\Polyfill\\Php55\\Php55' => __DIR__ . '/..' . '/symfony/polyfill-php55/Php55.php', + 'Symfony\\Polyfill\\Php55\\Php55ArrayColumn' => __DIR__ . '/..' . '/symfony/polyfill-php55/Php55ArrayColumn.php', + 'Symfony\\Polyfill\\Php56\\Php56' => __DIR__ . '/..' . '/symfony/polyfill-php56/Php56.php', + 'Symfony\\Polyfill\\Util\\Binary' => __DIR__ . '/..' . '/symfony/polyfill-util/Binary.php', + 'Symfony\\Polyfill\\Util\\BinaryNoFuncOverload' => __DIR__ . '/..' . '/symfony/polyfill-util/BinaryNoFuncOverload.php', + 'Symfony\\Polyfill\\Util\\BinaryOnFuncOverload' => __DIR__ . '/..' . '/symfony/polyfill-util/BinaryOnFuncOverload.php', + 'Symfony\\Polyfill\\Util\\TestListener' => __DIR__ . '/..' . '/symfony/polyfill-util/TestListener.php', 'lessc' => __DIR__ . '/..' . '/leafo/lessphp/lessc.inc.php', 'lessc_formatter_classic' => __DIR__ . '/..' . '/leafo/lessphp/lessc.inc.php', 'lessc_formatter_compressed' => __DIR__ . '/..' . '/leafo/lessphp/lessc.inc.php', diff --git a/libraries/vendor/composer/installed.json b/libraries/vendor/composer/installed.json index 3f400159e3487..935af0d6c9e1c 100644 --- a/libraries/vendor/composer/installed.json +++ b/libraries/vendor/composer/installed.json @@ -1293,5 +1293,88 @@ "framework", "joomla" ] + }, + { + "name": "paragonie/sodium_compat", + "version": "v1.0.1", + "version_normalized": "1.0.1.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/sodium_compat.git", + "reference": "3c6b3b7ffd256df19c39b0f4aa0bb28badd08aaa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/sodium_compat/zipball/3c6b3b7ffd256df19c39b0f4aa0bb28badd08aaa", + "reference": "3c6b3b7ffd256df19c39b0f4aa0bb28badd08aaa", + "shasum": "" + }, + "require": { + "paragonie/random_compat": "^1|^2", + "php": "^5.2.4|^5.3|^5.4|^5.5|^5.6|^7" + }, + "require-dev": { + "phpunit/phpunit": "^3|^4|^5" + }, + "suggest": { + "ext-libsodium": "Better performance, password hashing (Argon2i), secure memory management (memzero), and better security." + }, + "time": "2017-06-09T22:35:18+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "autoload.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com" + }, + { + "name": "Frank Denis", + "email": "jedisct1@pureftpd.org" + } + ], + "description": "Pure PHP implementation of libsodium; uses the PHP extension if it exists", + "keywords": [ + "Authentication", + "BLAKE2b", + "ChaCha20", + "ChaCha20-Poly1305", + "Chapoly", + "Curve25519", + "Ed25519", + "EdDSA", + "Edwards-curve Digital Signature Algorithm", + "Elliptic Curve Diffie-Hellman", + "Poly1305", + "Pure-PHP cryptography", + "RFC 7748", + "RFC 8032", + "Salpoly", + "Salsa20", + "X25519", + "XChaCha20-Poly1305", + "XSalsa20-Poly1305", + "Xchacha20", + "Xsalsa20", + "aead", + "cryptography", + "ecdh", + "elliptic curve", + "elliptic curve cryptography", + "encryption", + "libsodium", + "php", + "public-key cryptography", + "secret-key cryptography", + "side-channel resistant" + ] } ] diff --git a/libraries/vendor/paragonie/sodium_compat/LICENSE b/libraries/vendor/paragonie/sodium_compat/LICENSE new file mode 100644 index 0000000000000..b97a56059df9c --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/LICENSE @@ -0,0 +1,21 @@ +/* + * ISC License + * + * Copyright (c) 2016-2017 + * Paragon Initiative Enterprises + * + * Copyright (c) 2013-2017 + * Frank Denis + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ \ No newline at end of file diff --git a/libraries/vendor/paragonie/sodium_compat/autoload-fast.php b/libraries/vendor/paragonie/sodium_compat/autoload-fast.php new file mode 100644 index 0000000000000..08724d1eddd2c --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/autoload-fast.php @@ -0,0 +1,4 @@ += 50300) { + // Namespaces didn't exist before 5.3.0, so don't even try to use this + // unless PHP >= 5.3.0 + require_once dirname(__FILE__) . '/lib/namespaced.php'; + require_once dirname(__FILE__) . '/lib/sodium_compat.php'; +} +if (PHP_VERSION_ID < 70200) { + require_once dirname(__FILE__) . '/lib/php72compat.php'; +} diff --git a/libraries/vendor/paragonie/sodium_compat/lib/constants.php b/libraries/vendor/paragonie/sodium_compat/lib/constants.php new file mode 100644 index 0000000000000..e60d0f01c1415 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/lib/constants.php @@ -0,0 +1,45 @@ + 0 if the right operand is less than the left + * @throws TypeError + */ + public static function compare($left, $right) + { + /* Type checks: */ + if (!is_string($left)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($left) . ' given.'); + } + if (!is_string($right)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($right) . ' given.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_compare($left, $right); + } + if (self::use_fallback('compare')) { + return call_user_func('\\Sodium\\compare', $left, $right); + } + return ParagonIE_Sodium_Core_Util::compare($left, $right); + } + + /** + * Authenticated Encryption with Associated Data: Decryption + * + * Algorithm: + * ChaCha20-Poly1305 + * + * This mode uses a 64-bit random nonce with a 64-bit counter. + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * + * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string The original plaintext message + * @throws Error + * @throws TypeError + */ + public static function crypto_aead_chacha20poly1305_decrypt( + $ciphertext = '', + $assocData = '', + $nonce = '', + $key = '' + ) { + /* Type checks: */ + if (!is_string($ciphertext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($ciphertext) . ' given.'); + } + if (!is_string($assocData)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($assocData) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { + throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { + throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { + throw new Error('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_aead_chacha20poly1305_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + if (self::use_fallback('crypto_aead_chacha20poly1305_decrypt')) { + return call_user_func( + '\\Sodium\\crypto_aead_chacha20poly1305_decrypt', + $ciphertext, + $assocData, + $nonce, + $key + ); + } + return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + + /** + * Authenticated Encryption with Associated Data + * + * Algorithm: + * ChaCha20-Poly1305 + * + * This mode uses a 64-bit random nonce with a 64-bit counter. + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * + * @param string $plaintext Message to be encrypted + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string Ciphertext with a 16-byte Poly1305 message + * authentication code appended + * @throws Error + * @throws TypeError + */ + public static function crypto_aead_chacha20poly1305_encrypt( + $plaintext = '', + $assocData = '', + $nonce = '', + $key = '' + ) { + /* Type checks: */ + if (!is_string($plaintext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($plaintext) . ' given.'); + } + if (!is_string($assocData)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($assocData) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) { + throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { + throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_aead_chacha20poly1305_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + if (self::use_fallback('crypto_aead_chacha20poly1305_encrypt')) { + return call_user_func( + '\\Sodium\\crypto_aead_chacha20poly1305_encrypt', + $plaintext, + $assocData, + $nonce, + $key + ); + } + return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + + /** + * Authenticated Encryption with Associated Data: Decryption + * + * Algorithm: + * ChaCha20-Poly1305 + * + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * Regular mode uses a 64-bit random nonce with a 64-bit counter. + * + * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 12 bytes + * @param string $key Encryption key + * + * @return string The original plaintext message + * @throws Error + * @throws TypeError + */ + public static function crypto_aead_chacha20poly1305_ietf_decrypt( + $ciphertext = '', + $assocData = '', + $nonce = '', + $key = '' + ) { + /* Type checks: */ + if (!is_string($ciphertext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($ciphertext) . ' given.'); + } + if (!is_string($assocData)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($assocData) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { + throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { + throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) { + throw new Error('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_aead_chacha20poly1305_ietf_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_decrypt')) { + return call_user_func( + '\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt', + $ciphertext, + $assocData, + $nonce, + $key + ); + } + return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + + /** + * Authenticated Encryption with Associated Data + * + * Algorithm: + * ChaCha20-Poly1305 + * + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * Regular mode uses a 64-bit random nonce with a 64-bit counter. + * + * @param string $plaintext Message to be encrypted + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string Ciphertext with a 16-byte Poly1305 message + * authentication code appended + * @throws Error + * @throws TypeError + */ + public static function crypto_aead_chacha20poly1305_ietf_encrypt( + $plaintext = '', + $assocData = '', + $nonce = '', + $key = '' + ) { + /* Type checks: */ + if (!is_string($plaintext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($plaintext) . ' given.'); + } + if (!is_string($assocData)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($assocData) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) { + throw new Error('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) { + throw new Error('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_aead_chacha20poly1305_ietf_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_encrypt')) { + return call_user_func( + '\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt', + $plaintext, + $assocData, + $nonce, + $key + ); + } + return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + + /** + * Authenticated Encryption with Associated Data: Decryption + * + * Algorithm: + * XChaCha20-Poly1305 + * + * This mode uses a 64-bit random nonce with a 64-bit counter. + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * + * @param string $ciphertext Encrypted message (with Poly1305 MAC appended) + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string The original plaintext message + * @throws Error + * @throws TypeError + */ + public static function crypto_aead_xchacha20poly1305_ietf_decrypt( + $ciphertext = '', + $assocData = '', + $nonce = '', + $key = '' + ) { + /* Type checks: */ + if (!is_string($ciphertext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($ciphertext) . ' given.'); + } + if (!is_string($assocData)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($assocData) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { + throw new Error('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { + throw new Error('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES) { + throw new Error('Message must be at least CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES long'); + } + + return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_decrypt( + $ciphertext, + $assocData, + $nonce, + $key + ); + } + + /** + * Authenticated Encryption with Associated Data + * + * Algorithm: + * XChaCha20-Poly1305 + * + * This mode uses a 64-bit random nonce with a 64-bit counter. + * IETF mode uses a 96-bit random nonce with a 32-bit counter. + * + * @param string $plaintext Message to be encrypted + * @param string $assocData Authenticated Associated Data (unencrypted) + * @param string $nonce Number to be used only Once; must be 8 bytes + * @param string $key Encryption key + * + * @return string Ciphertext with a 16-byte Poly1305 message + * authentication code appended + * @throws Error + * @throws TypeError + */ + public static function crypto_aead_xchacha20poly1305_ietf_encrypt( + $plaintext = '', + $assocData = '', + $nonce = '', + $key = '' + ) { + /* Type checks: */ + if (!is_string($plaintext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($plaintext) . ' given.'); + } + if (!is_string($assocData)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($assocData) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) { + throw new Error('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_NPUBBYTES long'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) { + throw new Error('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_KEYBYTES long'); + } + + return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_encrypt( + $plaintext, + $assocData, + $nonce, + $key + ); + } + + /** + * Authenticate a message. Uses symmetric-key cryptography. + * + * Algorithm: + * HMAC-SHA512-256. Which is HMAC-SHA-512 truncated to 256 bits. + * Not to be confused with HMAC-SHA-512/256 which would use the + * SHA-512/256 hash function (uses different initial parameters + * but still truncates to 256 bits to sidestep length-extension + * attacks). + * + * @param string $message Message to be authenticated + * @param string $key Symmetric authentication key + * @return string Message authentication code + * @throws Error + * @throws TypeError + */ + public static function crypto_auth($message, $key) + { + /* Type checks: */ + if (!is_string($message)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($message) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { + throw new Error('Argument 2 must be CRYPTO_AUTH_KEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_auth($message, $key); + } + if (self::use_fallback('crypto_auth')) { + return call_user_func('\\Sodium\\crypto_auth', $message, $key); + } + return ParagonIE_Sodium_Crypto::auth($message, $key); + } + + /** + * Verify the MAC of a message previously authenticated with crypto_auth. + * + * @param string $mac Message authentication code + * @param string $message Message whose authenticity you are attempting to + * verify (with a given MAC and key) + * @param string $key Symmetric authentication key + * @return bool TRUE if authenticated, FALSE otherwise + * @throws Error + * @throws TypeError + */ + public static function crypto_auth_verify($mac, $message, $key) + { + /* Type checks: */ + if (!is_string($mac)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($mac) . ' given.'); + } + if (!is_string($message)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($message) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($mac) !== self::CRYPTO_AUTH_BYTES) { + throw new Error('Argument 1 must be CRYPTO_AUTH_BYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) { + throw new Error('Argument 3 must be CRYPTO_AUTH_KEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_auth_verify($mac, $message, $key); + } + if (self::use_fallback('crypto_auth_verify')) { + return call_user_func('\\Sodium\\crypto_auth_verify', $mac, $message, $key); + } + return ParagonIE_Sodium_Crypto::auth_verify($mac, $message, $key); + } + + /** + * Authenticated asymmetric-key encryption. Both the sender and recipient + * may decrypt messages. + * + * Algorithm: X25519-Xsalsa20-Poly1305. + * X25519: Elliptic-Curve Diffie Hellman over Curve25519. + * Xsalsa20: Extended-nonce variant of salsa20. + * Poyl1305: Polynomial MAC for one-time message authentication. + * + * @param string $plaintext The message to be encrypted + * @param string $nonce A Number to only be used Once; must be 24 bytes + * @param string $keypair Your secret key and your recipient's public key + * @return string Ciphertext with 16-byte Poly1305 MAC + * @throws Error + * @throws TypeError + */ + public static function crypto_box($plaintext, $nonce, $keypair) + { + /* Type checks: */ + if (!is_string($plaintext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($plaintext) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($keypair)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($keypair) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { + throw new Error('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new Error('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_box($plaintext, $nonce, $keypair); + } + if (self::use_fallback('crypto_box')) { + return call_user_func('\\Sodium\\crypto_box', $plaintext, $nonce, $keypair); + } + return ParagonIE_Sodium_Crypto::box($plaintext, $nonce, $keypair); + } + + /** + * Anonymous public-key encryption. Only the recipient may decrypt messages. + * + * Algorithm: X25519-Xsalsa20-Poly1305, as with crypto_box. + * The sender's X25519 keypair is ephemeral. + * Nonce is generated from the BLAKE2b hash of both public keys. + * + * This provides ciphertext integrity. + * + * @param string $plaintext Message to be sealed + * @param string $publicKey Your recipient's public key + * @return string Sealed message that only your recipient can + * decrypt + * @throws Error + * @throws TypeError + */ + public static function crypto_box_seal($plaintext, $publicKey) + { + /* Type checks: */ + if (!is_string($plaintext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($plaintext) . ' given.'); + } + if (!is_string($publicKey)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($publicKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_box_seal($plaintext, $publicKey); + } + if (self::use_fallback('crypto_box_seal')) { + return call_user_func('\\Sodium\\crypto_box_seal', $plaintext, $publicKey); + } + return ParagonIE_Sodium_Crypto::box_seal($plaintext, $publicKey); + } + + /** + * Opens a message encrypted with crypto_box_seal(). Requires + * the recipient's keypair (sk || pk) to decrypt successfully. + * + * This validates ciphertext integrity. + * + * @param string $ciphertext Sealed message to be opened + * @param string $keypair Your crypto_box keypair + * @return string The original plaintext message + * @throws Error + * @throws TypeError + */ + public static function crypto_box_seal_open($ciphertext, $keypair) + { + /* Type checks: */ + if (!is_string($ciphertext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($ciphertext) . ' given.'); + } + if (!is_string($keypair)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($keypair) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new Error('Argument 2 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_box_seal_open($ciphertext, $keypair); + } + if (self::use_fallback('crypto_box_seal_open')) { + return call_user_func('\\Sodium\\crypto_box_seal_open', $ciphertext, $keypair); + } + return ParagonIE_Sodium_Crypto::box_seal_open($ciphertext, $keypair); + } + + /** + * Generate a new random X25519 keypair. + * + * @return string A 64-byte string; the first 32 are your secret key, while + * the last 32 are your public key. crypto_box_secretkey() + * and crypto_box_publickey() exist to separate them so you + * don't accidentally get them mixed up! + */ + public static function crypto_box_keypair() + { + if (self::isPhp72OrGreater()) { + return sodium_crypto_box_keypair(); + } + if (self::use_fallback('crypto_sign_keypair')) { + return call_user_func('\\Sodium\\crypto_box_keypair'); + } + return ParagonIE_Sodium_Crypto::box_keypair(); + } + + /** + * Combine two keys into a keypair for use in library methods that expect + * a keypair. This doesn't necessarily have to be the same person's keys. + * + * @param string $secretKey Secret key + * @param string $publicKey Public key + * @return string Keypair + * @throws Error + * @throws TypeError + */ + public static function crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey) + { + /* Type checks: */ + if (!is_string($secretKey)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($secretKey) . ' given.'); + } + if (!is_string($publicKey)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($publicKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); + } + if (self::use_fallback('box_keypair_from_secretkey_and_publickey')) { + return call_user_func('\\Sodium\\box_keypair_from_secretkey_and_publickey', $secretKey, $publicKey); + } + return ParagonIE_Sodium_Crypto::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey); + } + + /** + * Decrypt a message previously encrypted with crypto_box(). + * + * @param string $ciphertext Encrypted message + * @param string $nonce Number to only be used Once; must be 24 bytes + * @param string $keypair Your secret key and the sender's public key + * @return string The original plaintext message + * @throws Error + * @throws TypeError + */ + public static function crypto_box_open($ciphertext, $nonce, $keypair) + { + /* Type checks: */ + if (!is_string($ciphertext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($ciphertext) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($keypair)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($keypair) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_BOX_MACBYTES) { + throw new Error('Argument 1 must be at least CRYPTO_BOX_MACBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) { + throw new Error('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new Error('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_box_open($ciphertext, $nonce, $keypair); + } + if (self::use_fallback('crypto_box_open')) { + return call_user_func('\\Sodium\\crypto_box_open', $ciphertext, $nonce, $keypair); + } + return ParagonIE_Sodium_Crypto::box_open($ciphertext, $nonce, $keypair); + } + + /** + * Extract the public key from a crypto_box keypair. + * + * @param string $keypair + * @return string Your crypto_box public key + * @throws Error + * @throws TypeError + */ + public static function crypto_box_publickey($keypair) + { + /* Type checks: */ + if (!is_string($keypair)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($keypair) . ' given.'); + } + if (self::isPhp72OrGreater()) { + return sodium_crypto_box_publickey($keypair); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new Error('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::use_fallback('crypto_box_publickey')) { + return call_user_func('\\Sodium\\crypto_box_publickey', $keypair); + } + return ParagonIE_Sodium_Crypto::box_publickey($keypair); + } + + /** + * Calculate the X25519 public key from a given X25519 secret key. + * + * @param string $secretKey Any X25519 secret key + * @return string The corresponding X25519 public key + * @throws Error + * @throws TypeError + */ + public static function crypto_box_publickey_from_secretkey($secretKey) + { + /* Type checks: */ + if (!is_string($secretKey)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($secretKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_box_publickey_from_secretkey($secretKey); + } + if (self::use_fallback('crypto_box_publickey_from_secretkey')) { + return call_user_func('\\Sodium\\crypto_box_publickey_from_secretkey', $secretKey); + } + return ParagonIE_Sodium_Crypto::box_publickey_from_secretkey($secretKey); + } + + /** + * Extract the secret key from a crypto_box keypair. + * + * @param string $keypair + * @return string Your crypto_box secret key + * @throws Error + * @throws TypeError + */ + public static function crypto_box_secretkey($keypair) + { + /* Type checks: */ + if (!is_string($keypair)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($keypair) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) { + throw new Error('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_box_secretkey($keypair); + } + if (self::use_fallback('crypto_box_secretkey')) { + return call_user_func('\\Sodium\\crypto_box_secretkey', $keypair); + } + return ParagonIE_Sodium_Crypto::box_secretkey($keypair); + } + + /** + * Calculates a BLAKE2b hash, with an optional key. + * + * @param string $message The message to be hashed + * @param string $key If specified, must be a string between 16 and 64 + * bytes long + * @param int $length Output length in bytes; must be between 16 and 64 + * (default = 32) + * @return string Raw binary + * @throws Error + * @throws TypeError + */ + public static function crypto_generichash($message, $key = '', $length = self::CRYPTO_GENERICHASH_BYTES) + { + /* Type checks: */ + if (!is_string($message)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($message) . ' given.'); + } + if (!is_string($key)) { + if ($key === null) { + $key = ''; + } else { + throw new TypeError('Argument 2 must be a string, ' . gettype($key) . ' given.'); + } + } + if (!is_int($length)) { + if (is_numeric($length)) { + $length = (int) $length; + } else { + throw new TypeError('Argument 3 must be an integer, ' . gettype($length) . ' given.'); + } + } + + /* Input validation: */ + if (!empty($key)) { + if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { + throw new Error('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { + throw new Error('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); + } + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_generichash($message, $key, $length); + } + if (self::use_fallback('crypto_generichash')) { + return call_user_func('\\Sodium\\crypto_generichash', $message, $key, $length); + } + return ParagonIE_Sodium_Crypto::generichash($message, $key, $length); + } + + /** + * Get the final BLAKE2b hash output for a given context. + * + * @param string &$ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). + * @param int $length Hash output size. + * @return string Final BLAKE2b hash. + * @throws Error + * @throws TypeError + */ + public static function crypto_generichash_final(&$ctx, $length = self::CRYPTO_GENERICHASH_BYTES) + { + /* Type checks: */ + if (!is_string($ctx)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($ctx) . ' given.'); + } + if (!is_int($length)) { + if (is_numeric($length)) { + $length = (int) $length; + } else { + throw new TypeError('Argument 2 must be an integer, ' . gettype($length) . ' given.'); + } + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_generichash_final($ctx, $length); + } + if (self::use_fallback('crypto_generichash_final')) { + $func = '\\Sodium\\crypto_generichash_final'; + return $func($ctx, $length); + } + $result = ParagonIE_Sodium_Crypto::generichash_final($ctx, $length); + try { + self::memzero($ctx); + } catch (Error $ex) { + unset($ctx); + } + return $result; + } + + /** + * Initialize a BLAKE2b hashing context, for use in a streaming interface. + * + * @param string $key If specified must be a string between 16 and 64 bytes + * @param int $length The size of the desired hash output + * @return string A BLAKE2 hashing context, encoded as a string + * (To be 100% compatible with ext/libsodium) + * @throws Error + * @throws TypeError + */ + public static function crypto_generichash_init($key = '', $length = self::CRYPTO_GENERICHASH_BYTES) + { + /* Type checks: */ + if (!is_string($key)) { + if ($key === null) { + $key = ''; + } else { + throw new TypeError('Argument 1 must be a string, ' . gettype($key) . ' given.'); + } + } + if (!is_int($length)) { + if (is_numeric($length)) { + $length = (int) $length; + } else { + throw new TypeError('Argument 2 must be an integer, ' . gettype($length) . ' given.'); + } + } + + /* Input validation: */ + if (!empty($key)) { + if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) { + throw new Error('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) { + throw new Error('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.'); + } + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_generichash_init($key, $length); + } + if (self::use_fallback('crypto_generichash_init')) { + return call_user_func('\\Sodium\\crypto_generichash_init', $key, $length); + } + return ParagonIE_Sodium_Crypto::generichash_init($key, $length); + } + + /** + * Update a BLAKE2b hashing context with additional data. + * + * @param string &$ctx BLAKE2 hashing context. Generated by crypto_generichash_init(). + * $ctx is passed by reference and gets updated in-place. + * @param string $message The message to append to the existing hash state. + * @return void + * @throws TypeError + */ + public static function crypto_generichash_update(&$ctx, $message) + { + /* Type checks: */ + if (!is_string($ctx)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($ctx) . ' given.'); + } + if (!is_string($message)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($message) . ' given.'); + } + + if (self::isPhp72OrGreater()) { + sodium_crypto_generichash_update($ctx, $message); + return; + } + if (self::use_fallback('crypto_generichash_update')) { + $func = '\\Sodium\\crypto_generichash_update'; + $func($ctx, $message); + return; + } + $ctx = ParagonIE_Sodium_Crypto::generichash_update($ctx, $message); + } + + /** + * Perform a key exchange, between a designated client and a server. + * + * Typically, you would designate one machine to be the client and the + * other to be the server. The first two keys are what you'd expect for + * scalarmult() below, but the latter two public keys don't swap places. + * + * | ALICE | BOB | + * | Client | Server | + * |--------------------------------|-------------------------------------| + * | shared = crypto_kx( | shared = crypto_kx( | + * | alice_sk, | bob_sk, | <- contextual + * | bob_pk, | alice_pk, | <- contextual + * | alice_pk, | alice_pk, | <----- static + * | bob_pk | bob_pk | <----- static + * | ) | ) | + * + * They are used along with the scalarmult product to generate a 256-bit + * BLAKE2b hash unique to the client and server keys. + * + * @param string $my_secret + * @param string $their_public + * @param string $client_public + * @param string $server_public + * @return string + * @throws Error + * @throws TypeError + */ + public static function crypto_kx($my_secret, $their_public, $client_public, $server_public) + { + /* Type checks: */ + if (!is_string($my_secret)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($my_secret) . ' given.'); + } + if (!is_string($their_public)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($their_public) . ' given.'); + } + if (!is_string($client_public)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($client_public) . ' given.'); + } + if (!is_string($server_public)) { + throw new TypeError('Argument 4 must be a string, ' . gettype($server_public) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($my_secret) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($their_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($client_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new Error('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($server_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new Error('Argument 4 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_kx( + $my_secret, + $their_public, + $client_public, + $server_public + ); + } + if (self::use_fallback('crypto_kx')) { + return call_user_func( + '\\Sodium\\crypto_kx', + $my_secret, + $their_public, + $client_public, + $server_public + ); + } + return ParagonIE_Sodium_Crypto::keyExchange( + $my_secret, + $their_public, + $client_public, + $server_public + ); + } + + /** + * Calculate the shared secret between your secret key and your + * recipient's public key. + * + * Algorithm: X25519 (ECDH over Curve25519) + * + * @param string $secretKey + * @param string $publicKey + * @return string + * @throws Error + * @throws TypeError + */ + public static function crypto_scalarmult($secretKey, $publicKey) + { + /* Type checks: */ + if (!is_string($secretKey)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($secretKey) . ' given.'); + } + if (!is_string($publicKey)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($publicKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) { + throw new Error('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_scalarmult($secretKey, $publicKey); + } + if (self::use_fallback('crypto_scalarmult')) { + return call_user_func('\\Sodium\\crypto_scalarmult', $secretKey, $publicKey); + } + + /* Output validation: Forbid all-zero keys */ + if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { + throw new Error('Zero secret key is not allowed'); + } + if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey, str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) { + throw new Error('Zero public key is not allowed'); + } + return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey); + } + + /** + * Calculate an X25519 public key from an X25519 secret key. + * + * @param string $secretKey + * @return string + * @throws Error + * @throws TypeError + */ + public static function crypto_scalarmult_base($secretKey) + { + /* Type checks: */ + if (!is_string($secretKey)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($secretKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) { + throw new Error('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_scalarmult_base($secretKey); + } + if (self::use_fallback('crypto_scalarmult_base')) { + return call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey); + } + if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) { + throw new Error('Zero secret key is not allowed'); + } + return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey); + } + + /** + * Authenticated symmetric-key encryption. + * + * Algorithm: Xsalsa20-Poly1305 + * + * @param string $plaintext The message you're encrypting + * @param string $nonce A Number to be used Once; must be 24 bytes + * @param string $key Symmetric encryption key + * @return string Ciphertext with Poly1305 MAC + * @throws Error + * @throws TypeError + */ + public static function crypto_secretbox($plaintext, $nonce, $key) + { + /* Type checks: */ + if (!is_string($plaintext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($plaintext) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { + throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_secretbox($plaintext, $nonce, $key); + } + if (self::use_fallback('crypto_secretbox')) { + return call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce, $key); + } + return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce, $key); + } + + /** + * Decrypts a message previously encrypted with crypto_secretbox(). + * + * @param string $ciphertext Ciphertext with Poly1305 MAC + * @param string $nonce A Number to be used Once; must be 24 bytes + * @param string $key Symmetric encryption key + * @return string Original plaintext message + * @throws Error + * @throws TypeError + */ + public static function crypto_secretbox_open($ciphertext, $nonce, $key) + { + /* Type checks: */ + if (!is_string($ciphertext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($ciphertext) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { + throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_secretbox_open($ciphertext, $nonce, $key); + } + if (self::use_fallback('crypto_secretbox_open')) { + return call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext, $nonce, $key); + } + return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce, $key); + } + + /** + * Authenticated symmetric-key encryption. + * + * Algorithm: XChaCha20-Poly1305 + * + * @param string $plaintext The message you're encrypting + * @param string $nonce A Number to be used Once; must be 24 bytes + * @param string $key Symmetric encryption key + * @return string Ciphertext with Poly1305 MAC + * @throws Error + * @throws TypeError + */ + public static function crypto_secretbox_xchacha20poly1305($plaintext, $nonce, $key) + { + /* Type checks: */ + if (!is_string($plaintext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($plaintext) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { + throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce, $key); + } + /** + * Decrypts a message previously encrypted with crypto_secretbox_xchacha20poly1305(). + * + * @param string $ciphertext Ciphertext with Poly1305 MAC + * @param string $nonce A Number to be used Once; must be 24 bytes + * @param string $key Symmetric encryption key + * @return string Original plaintext message + * @throws Error + * @throws TypeError + */ + public static function crypto_secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) + { + /* Type checks: */ + if (!is_string($ciphertext)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($ciphertext) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) { + throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + + return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key); + } + + /** + * Calculates a SipHash-2-4 hash of a message for a given key. + * + * @param string $message Input message + * @param string $key SipHash-2-4 key + * @return string Hash + * @throws Error + * @throws TypeError + */ + public static function crypto_shorthash($message, $key) + { + /* Type checks: */ + if (!is_string($message)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($message) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SHORTHASH_KEYBYTES) { + throw new Error('Argument 2 must be CRYPTO_SHORTHASH_KEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_shorthash($message, $key); + } + if (self::use_fallback('crypto_shorthash')) { + return call_user_func('\\Sodium\\crypto_shorthash', $message, $key); + } + return ParagonIE_Sodium_Core_SipHash::sipHash24($message, $key); + } + + /** + * Expand a key and nonce into a keystream of pseudorandom bytes. + * + * @param int $len Number of bytes desired + * @param string $nonce Number to be used Once; must be 24 bytes + * @param string $key Xsalsa20 key + * @return string Pseudorandom stream that can be XORed with messages + * to provide encryption (but not authentication; see + * Poly1305 or crypto_auth() for that, which is not + * optional for security) + * @throws Error + * @throws TypeError + */ + public static function crypto_stream($len, $nonce, $key) + { + /* Type checks: */ + if (!is_int($len)) { + if (is_numeric($len)) { + $len = (int) $len; + } else { + throw new TypeError('Argument 1 must be an integer, ' . gettype($len) . ' given.'); + } + } + if (!is_string($nonce)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { + throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { + throw new Error('Argument 3 must be CRYPTO_STREAM_KEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_stream($len, $nonce, $key); + } + if (self::use_fallback('crypto_stream')) { + return call_user_func('\\Sodium\\crypto_stream', $len, $nonce, $key); + } + return ParagonIE_Sodium_Core_Xsalsa20::xsalsa20($len, $nonce, $key); + } + + /** + * DANGER! UNAUTHENTICATED ENCRYPTION! + * + * Unless you are following expert advice, do not used this feature. + * + * Algorithm: Xsalsa20 + * + * This DOES NOT provide ciphertext integrity. + * + * @param string $message Plaintext message + * @param string $nonce Number to be used Once; must be 24 bytes + * @param string $key Encryption key + * @return string Encrypted text which is vulnerable to chosen- + * ciphertext attacks unless you implement some + * other mitigation to the ciphertext (i.e. + * Encrypt then MAC) + * @throws Error + * @throws TypeError + */ + public static function crypto_stream_xor($message, $nonce, $key) + { + /* Type checks: */ + if (!is_string($message)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($message) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) { + throw new Error('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) { + throw new Error('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_stream_xor($message, $nonce, $key); + } + if (self::use_fallback('crypto_stream_xor')) { + return call_user_func('\\Sodium\\crypto_stream_xor', $message, $nonce, $key); + } + return ParagonIE_Sodium_Core_Xsalsa20::xsalsa20_xor($message, $nonce, $key); + } + + /** + * Returns a signed message. You probably want crypto_sign_detached() + * instead, which only returns the signature. + * + * Algorithm: Ed25519 (EdDSA over Curve25519) + * + * @param string $message Message to be signed. + * @param string $secretKey Secret signing key. + * @return string Signed message (signature is prefixed). + * @throws Error + * @throws TypeError + */ + public static function crypto_sign($message, $secretKey) + { + /* Type checks: */ + if (!is_string($message)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($message) . ' given.'); + } + if (!is_string($secretKey)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($secretKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { + throw new Error('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_sign($message, $secretKey); + } + if (self::use_fallback('crypto_sign')) { + return call_user_func('\\Sodium\\crypto_sign', $message, $secretKey); + } + return ParagonIE_Sodium_Crypto::sign($message, $secretKey); + } + + /** + * Validates a signed message then returns the message. + * + * @param string $signedMessage A signed message + * @param string $publicKey A public key + * @return string The original message (if the signature is + * valid for this public key) + * @throws Error + * @throws TypeError + */ + public static function crypto_sign_open($signedMessage, $publicKey) + { + /* Type checks: */ + if (!is_string($signedMessage)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($signedMessage) . ' given.'); + } + if (!is_string($publicKey)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($publicKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($signedMessage) < self::CRYPTO_SIGN_BYTES) { + throw new Error('Argument 1 must be at least CRYPTO_SIGN_BYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { + throw new Error('Argument 2 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_sign_open($signedMessage, $publicKey); + } + if (self::use_fallback('crypto_sign_open')) { + return call_user_func('\\Sodium\\crypto_sign_open', $signedMessage, $publicKey); + } + return ParagonIE_Sodium_Crypto::sign_open($signedMessage, $publicKey); + } + + /** + * Generate a new random Ed25519 keypair. + * + * @return string + */ + public static function crypto_sign_keypair() + { + if (self::isPhp72OrGreater()) { + return sodium_crypto_sign_keypair(); + } + if (self::use_fallback('crypto_sign_keypair')) { + return call_user_func( + '\\Sodium\\crypto_sign_keypair' + ); + } + return ParagonIE_Sodium_Core_Ed25519::keypair(); + } + + /** + * Generate an Ed25519 keypair from a seed. + * + * @param string $seed Input seed + * @return string Keypair + */ + public static function crypto_sign_seed_keypair($seed) + { + if (self::isPhp72OrGreater()) { + return sodium_crypto_sign_seed_keypair($seed); + } + if (self::use_fallback('crypto_sign_keypair')) { + return call_user_func('\\Sodium\\crypto_sign_seed_keypair', $seed); + } + $publicKey = ''; + $secretKey = ''; + ParagonIE_Sodium_Core_Ed25519::seed_keypair($publicKey, $secretKey, $seed); + return $secretKey . $publicKey; + } + + /** + * Extract an Ed25519 public key from an Ed25519 keypair. + * + * @param string $keypair Keypair + * @return string Public key + * @throws Error + * @throws TypeError + */ + public static function crypto_sign_publickey($keypair) + { + /* Type checks: */ + if (!is_string($keypair)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($keypair) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { + throw new Error('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_sign_publickey($keypair); + } + if (self::use_fallback('crypto_sign_publickey')) { + return call_user_func('\\Sodium\\crypto_sign_publickey', $keypair); + } + return ParagonIE_Sodium_Core_Ed25519::publickey($keypair); + } + + /** + * Calculate an Ed25519 public key from an Ed25519 secret key. + * + * @param string $secretKey Your Ed25519 secret key + * @return string The corresponding Ed25519 public key + * @throws Error + * @throws TypeError + */ + public static function crypto_sign_publickey_from_secretkey($secretKey) + { + /* Type checks: */ + if (!is_string($secretKey)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($secretKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { + throw new Error('Argument 1 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_sign_publickey_from_secretkey($secretKey); + } + if (self::use_fallback('crypto_sign_publickey_from_publickey')) { + return call_user_func('\\Sodium\\crypto_sign_publickey_from_publickey', $secretKey); + } + return ParagonIE_Sodium_Core_Ed25519::publickey_from_secretkey($secretKey); + } + + /** + * Extract an Ed25519 secret key from an Ed25519 keypair. + * + * @param string $keypair Keypair + * @return string Secret key + * @throws Error + * @throws TypeError + */ + public static function crypto_sign_secretkey($keypair) + { + /* Type checks: */ + if (!is_string($keypair)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($keypair) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) { + throw new Error('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_sign_secretkey($keypair); + } + if (self::use_fallback('crypto_sign_secretkey')) { + return call_user_func('\\Sodium\\crypto_sign_secretkey', $keypair); + } + return ParagonIE_Sodium_Core_Ed25519::secretkey($keypair); + } + + /** + * Calculate the Ed25519 signature of a message and return ONLY the signature. + * + * Algorithm: Ed25519 (EdDSA over Curve25519) + * + * @param string $message Message to be signed + * @param string $secretKey Secret signing key + * @return string Digital signature + * @throws Error + * @throws TypeError + */ + public static function crypto_sign_detached($message, $secretKey) + { + /* Type checks: */ + if (!is_string($message)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($message) . ' given.'); + } + if (!is_string($secretKey)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($secretKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) { + throw new Error('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_sign_detached($message, $secretKey); + } + if (self::use_fallback('crypto_sign_detached')) { + return call_user_func('\\Sodium\\crypto_sign_detached', $message, $secretKey); + } + return ParagonIE_Sodium_Crypto::sign_detached($message, $secretKey); + } + + /** + * Verify the Ed25519 signature of a message. + * + * @param string $signature Digital sginature + * @param string $message Message to be verified + * @param string $publicKey Public key + * @return bool TRUE if this signature is good for this public key; + * FALSE otherwise + * @throws Error + * @throws TypeError + */ + public static function crypto_sign_verify_detached($signature, $message, $publicKey) + { + /* Type checks: */ + if (!is_string($signature)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($signature) . ' given.'); + } + if (!is_string($message)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($message) . ' given.'); + } + if (!is_string($publicKey)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($publicKey) . ' given.'); + } + + /* Input validation: */ + if (ParagonIE_Sodium_Core_Util::strlen($signature) !== self::CRYPTO_SIGN_BYTES) { + throw new Error('Argument 1 must be CRYPTO_SIGN_BYTES long.'); + } + if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) { + throw new Error('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long.'); + } + + if (self::isPhp72OrGreater()) { + return sodium_crypto_sign_verify_detached($signature, $message, $publicKey); + } + if (self::use_fallback('crypto_sign_verify_detached')) { + return call_user_func('\\Sodium\\crypto_sign_verify_detached', $signature, $message, $publicKey); + } + return ParagonIE_Sodium_Crypto::sign_verify_detached($signature, $message, $publicKey); + } + + /** + * Cache-timing-safe implementation of hex2bin(). + * + * @param string $string Hexadecimal string + * @return string Raw binary string + * @throws TypeError + */ + public static function hex2bin($string) + { + /* Type checks: */ + if (!is_string($string)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.'); + } + + if (self::isPhp72OrGreater()) { + return self::hex2bin($string); + } + if (self::use_fallback('hex2bin')) { + return call_user_func('\\Sodium\\hex2bin', $string); + } + return ParagonIE_Sodium_Core_Util::hex2bin($string); + } + + /** + * The equivalent to the libsodium minor version we aim to be compatible + * with (sans pwhash and memzero). + * + * @return int + */ + public static function library_version_major() + { + if (self::use_fallback('library_version_major')) { + return (int)call_user_func('\\Sodium\\library_version_major'); + } + return self::LIBRARY_VERSION_MAJOR; + } + + /** + * The equivalent to the libsodium minor version we aim to be compatible + * with (sans pwhash and memzero). + * + * @return int + */ + public static function library_version_minor() + { + if (self::use_fallback('library_version_minor')) { + return (int)call_user_func('\\Sodium\\library_version_minor'); + } + return self::LIBRARY_VERSION_MINOR; + } + + /** + * Compare two strings. + * + * @param string $left + * @param string $right + * @return int + * @throws TypeError + */ + public static function memcmp($left, $right) + { + /* Type checks: */ + if (!is_string($left)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($left) . ' given.'); + } + if (!is_string($right)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($right) . ' given.'); + } + + if (self::use_fallback('memcmp')) { + return call_user_func('\\Sodium\\memcmp', $left, $right); + } + return ParagonIE_Sodium_Core_Util::memcmp($left, $right); + } + + /** + * It's actually not possible to zero memory buffers in PHP. You need the + * native library for that. + * + * @param &string $var + * + * @return void + * @throws Error (Unless libsodium is installed) + */ + public static function memzero(&$var) + { + /* Type checks: */ + if (!is_string($var)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($var) . ' given.'); + } + + if (self::isPhp72OrGreater()) { + sodium_memzero($var); + return; + } + if (self::use_fallback('memzero')) { + @call_user_func('\\Sodium\\memzero', $var); + return; + } + // This is the best we can do. + throw new Error( + 'This is not implemented, as it is not possible to securely wipe memory from PHP' + ); + } + + /** + * Generate a string of bytes from the kernel's CSPRNG. + * Proudly uses /dev/urandom (if getrandom(2) is not available). + * + * @param int $numBytes + * @return string + * @throws TypeError + */ + public static function randombytes_buf($numBytes) + { + /* Type checks: */ + if (!is_int($numBytes)) { + if (is_numeric($numBytes)) { + $numBytes = (int)$numBytes; + } else { + throw new TypeError('Argument 1 must be an integer, ' . gettype($numBytes) . ' given.'); + } + } + if (self::use_fallback('randombytes_buf')) { + return call_user_func('\\Sodium\\randombytes_buf', $numBytes); + } + return random_bytes($numBytes); + } + + /** + * Generate an integer between 0 and $range (non-inclusive). + * + * @param int $range + * @return int + * @throws TypeError + */ + public static function randombytes_uniform($range) + { + /* Type checks: */ + if (!is_int($range)) { + if (is_numeric($range)) { + $range = (int)$range; + } else { + throw new TypeError('Argument 1 must be an integer, ' . gettype($range) . ' given.'); + } + } + if (self::use_fallback('randombytes_uniform')) { + return (int)call_user_func('\\Sodium\\randombytes_uniform', $range); + } + return random_int(0, $range - 1); + } + + /** + * Generate a random 16-bit integer. + * + * @return int + */ + public static function randombytes_random16() + { + if (self::use_fallback('randombytes_random16')) { + return (int) call_user_func('\\Sodium\\randombytes_random16'); + } + return random_int(0, 65535); + } + + /** + * This emulates libsodium's version_string() function, except ours is + * prefixed with 'polyfill-'. + * + * @return string + */ + public static function version_string() + { + if (self::use_fallback('version_string')) { + return (string) call_user_func('\\Sodium\\version_string'); + } + return self::VERSION_STRING; + } + + /** + * Should we use the libsodium core function instead? + * This is always a good idea, if it's available. (Unless we're in the + * middle of running our unit test suite.) + * + * If ext/libsodium is available, use it. Return TRUE. + * Otherwise, we have to use the code provided herein. Return FALSE. + * + * @param string $sodium_func_name + * + * @return bool + */ + protected static function use_fallback($sodium_func_name = '') + { + static $res = null; + if ($res === null) { + $res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300; + } + if ($res === false) { + // No libsodium installed + return false; + } + if (self::$disableFallbackForUnitTests) { + // Don't fallback. Use the PHP implementation. + return false; + } + if (!empty($sodium_func_name)) { + return is_callable('\\Sodium\\' . $sodium_func_name); + } + return true; + } + + /** + * Libsodium as implemented in PHP 7.2 + * + * @ref https://wiki.php.net/rfc/libsodium + * @return bool + */ + protected static function isPhp72OrGreater() + { + static $res = null; + if ($res === null) { + $res = PHP_VERSION_ID >= 70200 && extension_loaded('libsodium'); + } + if (self::$disableFallbackForUnitTests) { + // Don't fallback. Use the PHP implementation. + return false; + } + return $res; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/BLAKE2b.php b/libraries/vendor/paragonie/sodium_compat/src/Core/BLAKE2b.php new file mode 100644 index 0000000000000..4c3b58d3695f2 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/BLAKE2b.php @@ -0,0 +1,657 @@ +> (32 - $c)); + $l0 = $x[1] << $c; + } else { + $h0 = $x[1] << ($c - 32); + } + + $h1 = 0; + $c1 = 64 - $c; + + if ($c1 < 32) { + $h1 = $x[0] >> $c1; + $l1 = ($x[1] >> $c1) | ($x[0] & ((1 << $c1) - 1)) << (32 - $c1); + } else { + $l1 = $x[0] >> ($c1 - 32); + } + + return self::new64($h0 | $h1, $l0 | $l1); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @return int + */ + protected static function flatten64($x) + { + return ($x[0] * 4294967296 + $x[1]); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @param int $i + * @return SplFixedArray + */ + protected static function load64(SplFixedArray $x, $i) + { + $l = $x[$i] | ($x[$i+1]<<8) | ($x[$i+2]<<16) | ($x[$i+3]<<24); + $h = $x[$i+4] | ($x[$i+5]<<8) | ($x[$i+6]<<16) | ($x[$i+7]<<24); + return self::new64($h, $l); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $x + * @param int $i + * @param SplFixedArray $u + * @return void + */ + protected static function store64(SplFixedArray $x, $i, SplFixedArray $u) + { + $maxLength = $x->getSize() - 1; + for ($j = 0; $j < 8; ++$j) { + /* + [0, 1, 2, 3, 4, 5, 6, 7] + ... becomes ... + [0, 0, 0, 0, 1, 1, 1, 1] + */ + $uIdx = ((7 - $j) & 4) >> 2; + $x[$i] = ($u[$uIdx] & 0xff); + if (++$i > $maxLength) { + return; + } + $u[$uIdx] >>= 8; + } + } + + /** + * This just sets the $iv static variable. + * + * @internal You should not use this directly from another application + * + * @return void + */ + public static function pseudoConstructor() + { + static $called = false; + if ($called) { + return; + } + self::$iv = new SplFixedArray(8); + self::$iv[0] = self::new64(0x6a09e667, 0xf3bcc908); + self::$iv[1] = self::new64(0xbb67ae85, 0x84caa73b); + self::$iv[2] = self::new64(0x3c6ef372, 0xfe94f82b); + self::$iv[3] = self::new64(0xa54ff53a, 0x5f1d36f1); + self::$iv[4] = self::new64(0x510e527f, 0xade682d1); + self::$iv[5] = self::new64(0x9b05688c, 0x2b3e6c1f); + self::$iv[6] = self::new64(0x1f83d9ab, 0xfb41bd6b); + self::$iv[7] = self::new64(0x5be0cd19, 0x137e2179); + + $called = true; + } + + /** + * Returns a fresh BLAKE2 context. + * + * @internal You should not use this directly from another application + * + * @return SplFixedArray + */ + protected static function context() + { + $ctx = new SplFixedArray(5); + $ctx[0] = new SplFixedArray(8); // h + $ctx[1] = new SplFixedArray(2); // t + $ctx[2] = new SplFixedArray(2); // f + $ctx[3] = new SplFixedArray(256); // buf + $ctx[4] = 0; // buflen + + for ($i = 8; $i--;) { + $ctx[0][$i] = self::$iv[$i]; + } + for ($i = 256; $i--;) { + $ctx[3][$i] = 0; + } + + $zero = self::new64(0, 0); + $ctx[1][0] = $zero; + $ctx[1][1] = $zero; + $ctx[2][0] = $zero; + $ctx[2][1] = $zero; + + return $ctx; + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $ctx + * @param SplFixedArray $buf + * @return void + */ + protected static function compress(SplFixedArray $ctx, SplFixedArray $buf) + { + $m = new SplFixedArray(16); + $v = new SplFixedArray(16); + + for ($i = 16; $i--;) { + $m[$i] = self::load64($buf, $i << 3); + } + + for ($i = 8; $i--;) { + $v[$i] = $ctx[0][$i]; + } + + $v[ 8] = self::$iv[0]; + $v[ 9] = self::$iv[1]; + $v[10] = self::$iv[2]; + $v[11] = self::$iv[3]; + + $v[12] = self::xor64($ctx[1][0], self::$iv[4]); + $v[13] = self::xor64($ctx[1][1], self::$iv[5]); + $v[14] = self::xor64($ctx[2][0], self::$iv[6]); + $v[15] = self::xor64($ctx[2][1], self::$iv[7]); + + for ($r = 0; $r < 12; ++$r) { + $v = self::G($r, 0, 0, 4, 8, 12, $v, $m); + $v = self::G($r, 1, 1, 5, 9, 13, $v, $m); + $v = self::G($r, 2, 2, 6, 10, 14, $v, $m); + $v = self::G($r, 3, 3, 7, 11, 15, $v, $m); + $v = self::G($r, 4, 0, 5, 10, 15, $v, $m); + $v = self::G($r, 5, 1, 6, 11, 12, $v, $m); + $v = self::G($r, 6, 2, 7, 8, 13, $v, $m); + $v = self::G($r, 7, 3, 4, 9, 14, $v, $m); + } + + for ($i = 8; $i--;) { + $ctx[0][$i] = self::xor64( + $ctx[0][$i], self::xor64($v[$i], $v[$i+8]) + ); + } + } + + /** + * @internal You should not use this directly from another application + * + * @param int $r + * @param int $i + * @param int $a + * @param int $b + * @param int $c + * @param int $d + * @param SplFixedArray $v + * @param SplFixedArray $m + * @return SplFixedArray + */ + public static function G($r, $i, $a, $b, $c, $d, SplFixedArray $v, SplFixedArray $m) + { + $v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][$i << 1]]); + $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 32); + $v[$c] = self::add64($v[$c], $v[$d]); + $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 24); + $v[$a] = self::add364($v[$a], $v[$b], $m[self::$sigma[$r][($i << 1) + 1]]); + $v[$d] = self::rotr64(self::xor64($v[$d], $v[$a]), 16); + $v[$c] = self::add64($v[$c], $v[$d]); + $v[$b] = self::rotr64(self::xor64($v[$b], $v[$c]), 63); + return $v; + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $ctx + * @param int $inc + * @return void + * @throws Error + */ + public static function increment_counter($ctx, $inc) + { + if ($inc < 0) { + throw new Error('Increasing by a negative number makes no sense.'); + } + $t = self::to64($inc); + # S->t is $ctx[1] in our implementation + + # S->t[0] = ( uint64_t )( t >> 0 ); + $ctx[1][0] = self::add64($ctx[1][0], $t); + + # S->t[1] += ( S->t[0] < inc ); + if (self::flatten64($ctx[1][0]) < $inc) { + $ctx[1][1] = self::add64($ctx[1][1], self::to64(1)); + } + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $ctx + * @param SplFixedArray $p + * @param int $plen + * @return void + */ + public static function update(SplFixedArray $ctx, SplFixedArray $p, $plen) + { + self::pseudoConstructor(); + + $offset = 0; + while ($plen > 0) { + $left = $ctx[4]; + $fill = 256 - $left; + + if ($plen > $fill) { + # memcpy( S->buf + left, in, fill ); /* Fill buffer */ + for ($i = $fill; $i--;) { + $ctx[3][$i + $left] = $p[$i + $offset]; + } + + # S->buflen += fill; + $ctx[4] += $fill; + + # blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + self::increment_counter($ctx, 128); + + # blake2b_compress( S, S->buf ); /* Compress */ + self::compress($ctx, $ctx[3]); + + # memcpy( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES ); /* Shift buffer left */ + for ($i = 128; $i--;) { + $ctx[3][$i] = $ctx[3][$i + 128]; + } + + # S->buflen -= BLAKE2B_BLOCKBYTES; + $ctx[4] -= 128; + + # in += fill; + $offset += $fill; + + # inlen -= fill; + $plen -= $fill; + } else { + for ($i = $plen; $i--;) { + $ctx[3][$i + $left] = $p[$i + $offset]; + } + $ctx[4] += $plen; + $offset += $plen; + $plen -= $plen; + } + } + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray $ctx + * @param SplFixedArray $out + * @return SplFixedArray + * @throws Error + */ + public static function finish(SplFixedArray $ctx, SplFixedArray $out) + { + self::pseudoConstructor(); + if ($ctx[4] > 128) { + self::increment_counter($ctx, 128); + self::compress($ctx, $ctx[3]); + $ctx[4] -= 128; + if ($ctx[4] > 128) { + throw new Error('Failed to assert that buflen <= 128 bytes'); + } + for ($i = $ctx[4]; $i--;) { + $ctx[3][$i] = $ctx[3][$i + 128]; + } + } + + self::increment_counter($ctx, $ctx[4]); + $ctx[2][0] = self::new64(0xffffffff, 0xffffffff); + + for ($i = 256 - $ctx[4]; $i--;) { + $ctx[3][$i+$ctx[4]] = 0; + } + + self::compress($ctx, $ctx[3]); + + $i = (int) (($out->getSize() - 1) / 8); + for (; $i >= 0; --$i) { + self::store64($out, $i << 3, $ctx[0][$i]); + } + return $out; + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray|null $key + * @param int $outlen + * @return SplFixedArray + * @throws Exception + */ + public static function init($key = null, $outlen = 64) + { + self::pseudoConstructor(); + $klen = 0; + + if ($key !== null) { + if (count($key) > 64) { + throw new Exception('Invalid key size'); + } + $klen = count($key); + } + + if ($outlen > 64) { + throw new Exception('Invalid output size'); + } + + $ctx = self::context(); + + $p = new SplFixedArray(64); + for ($i = 64; --$i;) { + $p[$i] = 0; + } + + $p[0] = $outlen; // digest_length + $p[1] = $klen; // key_length + $p[2] = 1; // fanout + $p[3] = 1; // depth + + $ctx[0][0] = self::xor64( + $ctx[0][0], + self::load64($p, 0) + ); + + if ($klen > 0 && $key instanceof SplFixedArray) { + $block = new SplFixedArray(128); + for ($i = 128; $i--;) { + $block[$i] = 0; + } + for ($i = $klen; $i--;) { + $block[$i] = $key[$i]; + } + self::update($ctx, $block, 128); + } + + return $ctx; + } + + /** + * Convert a string into an SplFixedArray of integers + * + * @internal You should not use this directly from another application + * + * @param string $str + * @return SplFixedArray + */ + public static function stringToSplFixedArray($str = '') + { + $values = unpack('C*', $str); + return SplFixedArray::fromArray(array_values($values)); + } + + /** + * Convert an SplFixedArray of integers into a string + * + * @internal You should not use this directly from another application + * + * @param SplFixedArray $a + * @return string + */ + public static function SplFixedArrayToString(SplFixedArray $a) + { + /** + * @var array + */ + $arr = $a->toArray(); + $c = $a->count(); + array_unshift($arr, str_repeat('C', $c)); + return call_user_func_array('pack', $arr); + } + + /** + * @internal You should not use this directly from another application + * + * @param SplFixedArray[SplFixedArray] $ctx + * @return string + */ + public static function contextToString(SplFixedArray $ctx) + { + $str = ''; + $ctxA = $ctx[0]->toArray(); + + # uint64_t h[8]; + for ($i = 0; $i < 8; ++$i) { + $str .= self::store32_le($ctxA[$i][1]); + $str .= self::store32_le($ctxA[$i][0]); + } + + # uint64_t t[2]; + # uint64_t f[2]; + for ($i = 1; $i < 3; ++$i) { + $ctxA = $ctx[$i]->toArray(); + $str .= self::store32_le($ctxA[0][1]); + $str .= self::store32_le($ctxA[0][0]); + $str .= self::store32_le($ctxA[1][1]); + $str .= self::store32_le($ctxA[1][0]); + } + + # uint8_t buf[2 * 128]; + $str .= self::SplFixedArrayToString($ctx[3]); + + # size_t buflen; + $str .= implode('', array( + self::intToChr($ctx[4] & 0xff), + self::intToChr(($ctx[4] >> 8) & 0xff), + self::intToChr(($ctx[4] >> 16) & 0xff), + self::intToChr(($ctx[4] >> 24) & 0xff), + self::intToChr(($ctx[4] >> 32) & 0xff), + self::intToChr(($ctx[4] >> 40) & 0xff), + self::intToChr(($ctx[4] >> 48) & 0xff), + self::intToChr(($ctx[4] >> 56) & 0xff) + )); + # uint8_t last_node; + return $str . "\x00"; + } + + /** + * Creates an SplFixedArray containing other SplFixedArray elements, from + * a string (compatible with \Sodium\crypto_generichash_{init, update, final}) + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return SplFixedArray + */ + public static function stringToContext($string) + { + $ctx = self::context(); + + # uint64_t h[8]; + for ($i = 0; $i < 8; ++$i) { + $ctx[0][$i] = SplFixedArray::fromArray( + array( + self::load_4( + self::substr($string, (($i << 3) + 4), 4) + ), + self::load_4( + self::substr($string, (($i << 3) + 0), 4) + ) + ) + ); + } + + # uint64_t t[2]; + # uint64_t f[2]; + for ($i = 1; $i < 3; ++$i) { + $ctx[$i][1] = SplFixedArray::fromArray( + array( + self::load_4(self::substr($string, 76 + (($i - 1) << 4), 4)), + self::load_4(self::substr($string, 72 + (($i - 1) << 4), 4)) + ) + ); + $ctx[$i][0] = SplFixedArray::fromArray( + array( + self::load_4(self::substr($string, 68 + (($i - 1) << 4), 4)), + self::load_4(self::substr($string, 64 + (($i - 1) << 4), 4)) + ) + ); + } + + # uint8_t buf[2 * 128]; + $ctx[3] = self::stringToSplFixedArray(self::substr($string, 96, 256)); + + + # uint8_t buf[2 * 128]; + $int = 0; + for ($i = 0; $i < 8; ++$i) { + $int |= self::chrToInt($string[352 + $i]) << ($i << 3); + } + $ctx[4] = $int; + + return $ctx; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/ChaCha20.php b/libraries/vendor/paragonie/sodium_compat/src/Core/ChaCha20.php new file mode 100644 index 0000000000000..cb07e37b2775c --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/ChaCha20.php @@ -0,0 +1,364 @@ +> (32 - $n)) + ); + } + + /** + * The ChaCha20 quarter round function. Works on four 32-bit integers. + * + * @internal You should not use this directly from another application + * + * @param int $a + * @param int $b + * @param int $c + * @param int $d + * @return array + */ + protected static function quarterRound($a, $b, $c, $d) + { + # a = PLUS(a,b); d = ROTATE(XOR(d,a),16); + $a = ($a + $b) & 0xffffffff; + $d = self::rotate($d ^ $a, 16); + + # c = PLUS(c,d); b = ROTATE(XOR(b,c),12); + $c = ($c + $d) & 0xffffffff; + $b = self::rotate($b ^ $c, 12); + + # a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); + $a = ($a + $b) & 0xffffffff; + $d = self::rotate($d ^ $a, 8); + + # c = PLUS(c,d); b = ROTATE(XOR(b,c), 7); + $c = ($c + $d) & 0xffffffff; + $b = self::rotate($b ^ $c, 7); + return array((int) $a, (int) $b, (int) $c, (int) $d); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx + * @param string $message + * + * @return string + * @throws Exception + */ + public static function encryptBytes( + ParagonIE_Sodium_Core_ChaCha20_Ctx $ctx, + $message = '' + ) { + $bytes = self::strlen($message); + + /* + j0 = ctx->input[0]; + j1 = ctx->input[1]; + j2 = ctx->input[2]; + j3 = ctx->input[3]; + j4 = ctx->input[4]; + j5 = ctx->input[5]; + j6 = ctx->input[6]; + j7 = ctx->input[7]; + j8 = ctx->input[8]; + j9 = ctx->input[9]; + j10 = ctx->input[10]; + j11 = ctx->input[11]; + j12 = ctx->input[12]; + j13 = ctx->input[13]; + j14 = ctx->input[14]; + j15 = ctx->input[15]; + */ + $j0 = (int) $ctx[0]; + $j1 = (int) $ctx[1]; + $j2 = (int) $ctx[2]; + $j3 = (int) $ctx[3]; + $j4 = (int) $ctx[4]; + $j5 = (int) $ctx[5]; + $j6 = (int) $ctx[6]; + $j7 = (int) $ctx[7]; + $j8 = (int) $ctx[8]; + $j9 = (int) $ctx[9]; + $j10 = (int) $ctx[10]; + $j11 = (int) $ctx[11]; + $j12 = (int) $ctx[12]; + $j13 = (int) $ctx[13]; + $j14 = (int) $ctx[14]; + $j15 = (int) $ctx[15]; + + $c = ''; + for (;;) { + if ($bytes < 64) { + $message .= str_repeat("\x00", 64 - $bytes); + } + + $x0 = (int) $j0; + $x1 = (int) $j1; + $x2 = (int) $j2; + $x3 = (int) $j3; + $x4 = (int) $j4; + $x5 = (int) $j5; + $x6 = (int) $j6; + $x7 = (int) $j7; + $x8 = (int) $j8; + $x9 = (int) $j9; + $x10 = (int) $j10; + $x11 = (int) $j11; + $x12 = (int) $j12; + $x13 = (int) $j13; + $x14 = (int) $j14; + $x15 = (int) $j15; + + # for (i = 20; i > 0; i -= 2) { + for ($i = 20; $i > 0; $i -= 2) { + # QUARTERROUND( x0, x4, x8, x12) + list($x0, $x4, $x8, $x12) = self::quarterRound($x0, $x4, $x8, $x12); + + # QUARTERROUND( x1, x5, x9, x13) + list($x1, $x5, $x9, $x13) = self::quarterRound($x1, $x5, $x9, $x13); + + # QUARTERROUND( x2, x6, x10, x14) + list($x2, $x6, $x10, $x14) = self::quarterRound($x2, $x6, $x10, $x14); + + # QUARTERROUND( x3, x7, x11, x15) + list($x3, $x7, $x11, $x15) = self::quarterRound($x3, $x7, $x11, $x15); + + # QUARTERROUND( x0, x5, x10, x15) + list($x0, $x5, $x10, $x15) = self::quarterRound($x0, $x5, $x10, $x15); + + # QUARTERROUND( x1, x6, x11, x12) + list($x1, $x6, $x11, $x12) = self::quarterRound($x1, $x6, $x11, $x12); + + # QUARTERROUND( x2, x7, x8, x13) + list($x2, $x7, $x8, $x13) = self::quarterRound($x2, $x7, $x8, $x13); + + # QUARTERROUND( x3, x4, x9, x14) + list($x3, $x4, $x9, $x14) = self::quarterRound($x3, $x4, $x9, $x14); + } + /* + x0 = PLUS(x0, j0); + x1 = PLUS(x1, j1); + x2 = PLUS(x2, j2); + x3 = PLUS(x3, j3); + x4 = PLUS(x4, j4); + x5 = PLUS(x5, j5); + x6 = PLUS(x6, j6); + x7 = PLUS(x7, j7); + x8 = PLUS(x8, j8); + x9 = PLUS(x9, j9); + x10 = PLUS(x10, j10); + x11 = PLUS(x11, j11); + x12 = PLUS(x12, j12); + x13 = PLUS(x13, j13); + x14 = PLUS(x14, j14); + x15 = PLUS(x15, j15); + */ + $x0 = ($x0 & 0xffffffff) + $j0; + $x1 = ($x1 & 0xffffffff) + $j1; + $x2 = ($x2 & 0xffffffff) + $j2; + $x3 = ($x3 & 0xffffffff) + $j3; + $x4 = ($x4 & 0xffffffff) + $j4; + $x5 = ($x5 & 0xffffffff) + $j5; + $x6 = ($x6 & 0xffffffff) + $j6; + $x7 = ($x7 & 0xffffffff) + $j7; + $x8 = ($x8 & 0xffffffff) + $j8; + $x9 = ($x9 & 0xffffffff) + $j9; + $x10 = ($x10 & 0xffffffff) + $j10; + $x11 = ($x11 & 0xffffffff) + $j11; + $x12 = ($x12 & 0xffffffff) + $j12; + $x13 = ($x13 & 0xffffffff) + $j13; + $x14 = ($x14 & 0xffffffff) + $j14; + $x15 = ($x15 & 0xffffffff) + $j15; + + /* + x0 = XOR(x0, LOAD32_LE(m + 0)); + x1 = XOR(x1, LOAD32_LE(m + 4)); + x2 = XOR(x2, LOAD32_LE(m + 8)); + x3 = XOR(x3, LOAD32_LE(m + 12)); + x4 = XOR(x4, LOAD32_LE(m + 16)); + x5 = XOR(x5, LOAD32_LE(m + 20)); + x6 = XOR(x6, LOAD32_LE(m + 24)); + x7 = XOR(x7, LOAD32_LE(m + 28)); + x8 = XOR(x8, LOAD32_LE(m + 32)); + x9 = XOR(x9, LOAD32_LE(m + 36)); + x10 = XOR(x10, LOAD32_LE(m + 40)); + x11 = XOR(x11, LOAD32_LE(m + 44)); + x12 = XOR(x12, LOAD32_LE(m + 48)); + x13 = XOR(x13, LOAD32_LE(m + 52)); + x14 = XOR(x14, LOAD32_LE(m + 56)); + x15 = XOR(x15, LOAD32_LE(m + 60)); + */ + $x0 ^= self::load_4(self::substr($message, 0, 4)); + $x1 ^= self::load_4(self::substr($message, 4, 4)); + $x2 ^= self::load_4(self::substr($message, 8, 4)); + $x3 ^= self::load_4(self::substr($message, 12, 4)); + $x4 ^= self::load_4(self::substr($message, 16, 4)); + $x5 ^= self::load_4(self::substr($message, 20, 4)); + $x6 ^= self::load_4(self::substr($message, 24, 4)); + $x7 ^= self::load_4(self::substr($message, 28, 4)); + $x8 ^= self::load_4(self::substr($message, 32, 4)); + $x9 ^= self::load_4(self::substr($message, 36, 4)); + $x10 ^= self::load_4(self::substr($message, 40, 4)); + $x11 ^= self::load_4(self::substr($message, 44, 4)); + $x12 ^= self::load_4(self::substr($message, 48, 4)); + $x13 ^= self::load_4(self::substr($message, 52, 4)); + $x14 ^= self::load_4(self::substr($message, 56, 4)); + $x15 ^= self::load_4(self::substr($message, 60, 4)); + + /* + j12 = PLUSONE(j12); + if (!j12) { + j13 = PLUSONE(j13); + } + */ + ++$j12; + if ($j12 & 0xf0000000) { + throw new Exception('Overflow'); + } + + /* + STORE32_LE(c + 0, x0); + STORE32_LE(c + 4, x1); + STORE32_LE(c + 8, x2); + STORE32_LE(c + 12, x3); + STORE32_LE(c + 16, x4); + STORE32_LE(c + 20, x5); + STORE32_LE(c + 24, x6); + STORE32_LE(c + 28, x7); + STORE32_LE(c + 32, x8); + STORE32_LE(c + 36, x9); + STORE32_LE(c + 40, x10); + STORE32_LE(c + 44, x11); + STORE32_LE(c + 48, x12); + STORE32_LE(c + 52, x13); + STORE32_LE(c + 56, x14); + STORE32_LE(c + 60, x15); + */ + $block = self::store32_le((int) ($x0 & 0xffffffff)) . + self::store32_le((int) ($x1 & 0xffffffff)) . + self::store32_le((int) ($x2 & 0xffffffff)) . + self::store32_le((int) ($x3 & 0xffffffff)) . + self::store32_le((int) ($x4 & 0xffffffff)) . + self::store32_le((int) ($x5 & 0xffffffff)) . + self::store32_le((int) ($x6 & 0xffffffff)) . + self::store32_le((int) ($x7 & 0xffffffff)) . + self::store32_le((int) ($x8 & 0xffffffff)) . + self::store32_le((int) ($x9 & 0xffffffff)) . + self::store32_le((int) ($x10 & 0xffffffff)) . + self::store32_le((int) ($x11 & 0xffffffff)) . + self::store32_le((int) ($x12 & 0xffffffff)) . + self::store32_le((int) ($x13 & 0xffffffff)) . + self::store32_le((int) ($x14 & 0xffffffff)) . + self::store32_le((int) ($x15 & 0xffffffff)); + + /* Partial block */ + if ($bytes < 64) { + $c .= self::substr($block, 0, $bytes); + break; + } + + /* Full block */ + $c .= $block; + $bytes -= 64; + if ($bytes <= 0) { + break; + } + $message = self::substr($message, 64); + } + /* end for(;;) loop */ + + $ctx[12] = $j12; + $ctx[13] = $j13; + return $c; + } + + /** + * @internal You should not use this directly from another application + * + * @param int $len + * @param string $nonce + * @param string $key + * @return string + */ + public static function stream($len = 64, $nonce = '', $key = '') + { + return self::encryptBytes( + new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce), + str_repeat("\x00", $len) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $len + * @param string $nonce + * @param string $key + * @return string + */ + public static function ietfStream($len, $nonce = '', $key = '') + { + return self::encryptBytes( + new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce), + str_repeat("\x00", $len) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param string $nonce + * @param string $key + * @param string $ic + * @return string + */ + public static function ietfStreamXorIc($message, $nonce = '', $key = '', $ic = '') + { + return self::encryptBytes( + new ParagonIE_Sodium_Core_ChaCha20_IetfCtx($key, $nonce, $ic), + $message + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param string $nonce + * @param string $key + * @param string $ic + * @return string + */ + public static function streamXorIc($message, $nonce = '', $key = '', $ic = '') + { + return self::encryptBytes( + new ParagonIE_Sodium_Core_ChaCha20_Ctx($key, $nonce, $ic), + $message + ); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/ChaCha20/Ctx.php b/libraries/vendor/paragonie/sodium_compat/src/Core/ChaCha20/Ctx.php new file mode 100644 index 0000000000000..bdbbb59998f40 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/ChaCha20/Ctx.php @@ -0,0 +1,115 @@ + + */ + protected $container; + + /** + * ParagonIE_Sodium_Core_ChaCha20_Ctx constructor. + * + * @internal You should not use this directly from another application + * + * @param string $key ChaCha20 key. + * @param string $iv Initialization Vector (a.k.a. nonce). + * @param string $counter The initial counter value. + * Defaults to 8 0x00 bytes. + * @throws InvalidArgumentException + */ + public function __construct($key = '', $iv = '', $counter = '') + { + if (self::strlen($key) !== 32) { + throw new InvalidArgumentException('ChaCha20 expects a 256-bit key.'); + } + if (self::strlen($iv) !== 8) { + throw new InvalidArgumentException('ChaCha20 expects a 64-bit nonce.'); + } + $this->container = new SplFixedArray(16); + + /* "expand 32-byte k" as per ChaCha20 spec */ + $this->container[0] = 0x61707865; + $this->container[1] = 0x3320646e; + $this->container[2] = 0x79622d32; + $this->container[3] = 0x6b206574; + $this->container[4] = self::load_4(self::substr($key, 0, 4)); + $this->container[5] = self::load_4(self::substr($key, 4, 4)); + $this->container[6] = self::load_4(self::substr($key, 8, 4)); + $this->container[7] = self::load_4(self::substr($key, 12, 4)); + $this->container[8] = self::load_4(self::substr($key, 16, 4)); + $this->container[9] = self::load_4(self::substr($key, 20, 4)); + $this->container[10] = self::load_4(self::substr($key, 24, 4)); + $this->container[11] = self::load_4(self::substr($key, 28, 4)); + + if (empty($counter)) { + $this->container[12] = 0; + $this->container[13] = 0; + } else { + $this->container[12] = self::load_4(self::substr($counter, 0, 4)); + $this->container[13] = self::load_4(self::substr($counter, 4, 4)); + } + $this->container[14] = self::load_4(self::substr($iv, 0, 4)); + $this->container[15] = self::load_4(self::substr($iv, 4, 4)); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $offset + * @param int $value + * @return void + */ + public function offsetSet($offset, $value) + { + if (!is_int($offset)) { + throw new InvalidArgumentException('Expected an integer'); + } + if (!is_int($value)) { + throw new InvalidArgumentException('Expected an integer'); + } + $this->container[$offset] = $value; + } + + /** + * @internal You should not use this directly from another application + * + * @param mixed $offset + * @return bool + */ + public function offsetExists($offset) + { + return isset($this->container[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param mixed $offset + * @return void + */ + public function offsetUnset($offset) + { + unset($this->container[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param mixed $offset + * @return mixed|null + */ + public function offsetGet($offset) + { + return isset($this->container[$offset]) + ? $this->container[$offset] + : null; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/ChaCha20/IetfCtx.php b/libraries/vendor/paragonie/sodium_compat/src/Core/ChaCha20/IetfCtx.php new file mode 100644 index 0000000000000..72b7676061b1e --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/ChaCha20/IetfCtx.php @@ -0,0 +1,37 @@ +container[12] = self::load_4(self::substr($counter, 0, 4)); + } + $this->container[13] = self::load_4(self::substr($iv, 0, 4)); + $this->container[14] = self::load_4(self::substr($iv, 4, 4)); + $this->container[15] = self::load_4(self::substr($iv, 8, 4)); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519.php new file mode 100644 index 0000000000000..ebea37acdeadc --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519.php @@ -0,0 +1,2567 @@ +> 25; + $h0 += self::mul($carry9, 19); + $h9 -= self::mul($carry9, 1 << 25); + $carry1 = ($h1 + (1 << 24)) >> 25; + $h2 += $carry1; + $h1 -= self::mul($carry1, 1 << 25); + $carry3 = ($h3 + (1 << 24)) >> 25; + $h4 += $carry3; + $h3 -= self::mul($carry3, 1 << 25); + $carry5 = ($h5 + (1 << 24)) >> 25; + $h6 += $carry5; + $h5 -= self::mul($carry5, 1 << 25); + $carry7 = ($h7 + (1 << 24)) >> 25; + $h8 += $carry7; + $h7 -= self::mul($carry7, 1 << 25); + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= self::mul($carry0, 1 << 26); + $carry2 = ($h2 + (1 << 25)) >> 26; + $h3 += $carry2; + $h2 -= self::mul($carry2, 1 << 26); + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= self::mul($carry4, 1 << 26); + $carry6 = ($h6 + (1 << 25)) >> 26; + $h7 += $carry6; + $h6 -= self::mul($carry6, 1 << 26); + $carry8 = ($h8 + (1 << 25)) >> 26; + $h9 += $carry8; + $h8 -= self::mul($carry8, 1 << 26); + + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + array( + (int) $h0, + (int) $h1, + (int) $h2, + (int) $h3, + (int) $h4, + (int) $h5, + (int) $h6, + (int) $h7, + (int) $h8, + (int) $h9 + ) + ); + } + + /** + * Convert a field element to a byte string. + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $h + * @return string + */ + public static function fe_tobytes(ParagonIE_Sodium_Core_Curve25519_Fe $h) + { + $h[0] = (int) $h[0]; + $h[1] = (int) $h[1]; + $h[2] = (int) $h[2]; + $h[3] = (int) $h[3]; + $h[4] = (int) $h[4]; + $h[5] = (int) $h[5]; + $h[6] = (int) $h[6]; + $h[7] = (int) $h[7]; + $h[8] = (int) $h[8]; + $h[9] = (int) $h[9]; + + $q = (self::mul(19, $h[9]) + (1 << 24)) >> 25; + $q = ($h[0] + $q) >> 26; + $q = ($h[1] + $q) >> 25; + $q = ($h[2] + $q) >> 26; + $q = ($h[3] + $q) >> 25; + $q = ($h[4] + $q) >> 26; + $q = ($h[5] + $q) >> 25; + $q = ($h[6] + $q) >> 26; + $q = ($h[7] + $q) >> 25; + $q = ($h[8] + $q) >> 26; + $q = ($h[9] + $q) >> 25; + + $h[0] += self::mul(19, $q); + + $carry0 = $h[0] >> 26; + $h[1] += $carry0; + $h[0] -= self::mul($carry0, 1 << 26); + $carry1 = $h[1] >> 25; + $h[2] += $carry1; + $h[1] -= self::mul($carry1, 1 << 25); + $carry2 = $h[2] >> 26; + $h[3] += $carry2; + $h[2] -= self::mul($carry2, 1 << 26); + $carry3 = $h[3] >> 25; + $h[4] += $carry3; + $h[3] -= self::mul($carry3, 1 << 25); + $carry4 = $h[4] >> 26; + $h[5] += $carry4; + $h[4] -= self::mul($carry4, 1 << 26); + $carry5 = $h[5] >> 25; + $h[6] += $carry5; + $h[5] -= self::mul($carry5, 1 << 25); + $carry6 = $h[6] >> 26; + $h[7] += $carry6; + $h[6] -= self::mul($carry6, 1 << 26); + $carry7 = $h[7] >> 25; + $h[8] += $carry7; + $h[7] -= self::mul($carry7, 1 << 25); + $carry8 = $h[8] >> 26; + $h[9] += $carry8; + $h[8] -= self::mul($carry8, 1 << 26); + $carry9 = $h[9] >> 25; + $h[9] -= self::mul($carry9, 1 << 25); + + /** + * @var array + */ + $s = array( + (int) (($h[0] >> 0) & 0xff), + (int) (($h[0] >> 8) & 0xff), + (int) (($h[0] >> 16) & 0xff), + (int) ((($h[0] >> 24) | ($h[1] << 2)) & 0xff), + (int) (($h[1] >> 6) & 0xff), + (int) (($h[1] >> 14) & 0xff), + (int) ((($h[1] >> 22) | ($h[2] << 3)) & 0xff), + (int) (($h[2] >> 5) & 0xff), + (int) (($h[2] >> 13) & 0xff), + (int) ((($h[2] >> 21) | ($h[3] << 5)) & 0xff), + (int) (($h[3] >> 3) & 0xff), + (int) (($h[3] >> 11) & 0xff), + (int) ((($h[3] >> 19) | ($h[4] << 6)) & 0xff), + (int) (($h[4] >> 2) & 0xff), + (int) (($h[4] >> 10) & 0xff), + (int) (($h[4] >> 18) & 0xff), + (int) (($h[5] >> 0) & 0xff), + (int) (($h[5] >> 8) & 0xff), + (int) (($h[5] >> 16) & 0xff), + (int) ((($h[5] >> 24) | ($h[6] << 1)) & 0xff), + (int) (($h[6] >> 7) & 0xff), + (int) (($h[6] >> 15) & 0xff), + (int) ((($h[6] >> 23) | ($h[7] << 3)) & 0xff), + (int) (($h[7] >> 5) & 0xff), + (int) (($h[7] >> 13) & 0xff), + (int) ((($h[7] >> 21) | ($h[8] << 4)) & 0xff), + (int) (($h[8] >> 4) & 0xff), + (int) (($h[8] >> 12) & 0xff), + (int) ((($h[8] >> 20) | ($h[9] << 6)) & 0xff), + (int) (($h[9] >> 2) & 0xff), + (int) (($h[9] >> 10) & 0xff), + (int) (($h[9] >> 18) & 0xff) + ); + return self::intArrayToString($s); + } + + /** + * Is a field element negative? (1 = yes, 0 = no. Used in calculations.) + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return int + */ + public static function fe_isnegative(ParagonIE_Sodium_Core_Curve25519_Fe $f) + { + $str = self::fe_tobytes($f); + return self::chrToInt($str[0]) & 1; + } + + /** + * Returns 0 if this field element results in all NUL bytes. + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return bool + */ + public static function fe_isnonzero(ParagonIE_Sodium_Core_Curve25519_Fe $f) + { + static $zero; + if ($zero === null) { + $zero = str_repeat("\x00", 32); + } + $str = self::fe_tobytes($f); + return !self::verify_32($str, $zero); + } + + /** + * Multiply two field elements + * + * h = f * g + * + * @internal You should not use this directly from another application + * + * @security Is multiplication a source of timing leaks? If so, can we do + * anything to prevent that from happening? + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @param ParagonIE_Sodium_Core_Curve25519_Fe $g + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_mul( + ParagonIE_Sodium_Core_Curve25519_Fe $f, + ParagonIE_Sodium_Core_Curve25519_Fe $g + ) { + $f0 = $f[0]; + $f1 = $f[1]; + $f2 = $f[2]; + $f3 = $f[3]; + $f4 = $f[4]; + $f5 = $f[5]; + $f6 = $f[6]; + $f7 = $f[7]; + $f8 = $f[8]; + $f9 = $f[9]; + $g0 = $g[0]; + $g1 = $g[1]; + $g2 = $g[2]; + $g3 = $g[3]; + $g4 = $g[4]; + $g5 = $g[5]; + $g6 = $g[6]; + $g7 = $g[7]; + $g8 = $g[8]; + $g9 = $g[9]; + $g1_19 = self::mul(19, $g1); + $g2_19 = self::mul(19, $g2); + $g3_19 = self::mul(19, $g3); + $g4_19 = self::mul(19, $g4); + $g5_19 = self::mul(19, $g5); + $g6_19 = self::mul(19, $g6); + $g7_19 = self::mul(19, $g7); + $g8_19 = self::mul(19, $g8); + $g9_19 = self::mul(19, $g9); + $f1_2 = $f1 << 1; + $f3_2 = $f3 << 1; + $f5_2 = $f5 << 1; + $f7_2 = $f7 << 1; + $f9_2 = $f9 << 1; + $f0g0 = self::mul($f0, $g0); + $f0g1 = self::mul($f0, $g1); + $f0g2 = self::mul($f0, $g2); + $f0g3 = self::mul($f0, $g3); + $f0g4 = self::mul($f0, $g4); + $f0g5 = self::mul($f0, $g5); + $f0g6 = self::mul($f0, $g6); + $f0g7 = self::mul($f0, $g7); + $f0g8 = self::mul($f0, $g8); + $f0g9 = self::mul($f0, $g9); + $f1g0 = self::mul($f1, $g0); + $f1g1_2 = self::mul($f1_2, $g1); + $f1g2 = self::mul($f1, $g2); + $f1g3_2 = self::mul($f1_2, $g3); + $f1g4 = self::mul($f1, $g4); + $f1g5_2 = self::mul($f1_2, $g5); + $f1g6 = self::mul($f1, $g6); + $f1g7_2 = self::mul($f1_2, $g7); + $f1g8 = self::mul($f1, $g8); + $f1g9_38 = self::mul($f1_2, $g9_19); + $f2g0 = self::mul($f2, $g0); + $f2g1 = self::mul($f2, $g1); + $f2g2 = self::mul($f2, $g2); + $f2g3 = self::mul($f2, $g3); + $f2g4 = self::mul($f2, $g4); + $f2g5 = self::mul($f2, $g5); + $f2g6 = self::mul($f2, $g6); + $f2g7 = self::mul($f2, $g7); + $f2g8_19 = self::mul($f2, $g8_19); + $f2g9_19 = self::mul($f2, $g9_19); + $f3g0 = self::mul($f3, $g0); + $f3g1_2 = self::mul($f3_2, $g1); + $f3g2 = self::mul($f3, $g2); + $f3g3_2 = self::mul($f3_2, $g3); + $f3g4 = self::mul($f3, $g4); + $f3g5_2 = self::mul($f3_2, $g5); + $f3g6 = self::mul($f3, $g6); + $f3g7_38 = self::mul($f3_2, $g7_19); + $f3g8_19 = self::mul($f3, $g8_19); + $f3g9_38 = self::mul($f3_2, $g9_19); + $f4g0 = self::mul($f4, $g0); + $f4g1 = self::mul($f4, $g1); + $f4g2 = self::mul($f4, $g2); + $f4g3 = self::mul($f4, $g3); + $f4g4 = self::mul($f4, $g4); + $f4g5 = self::mul($f4, $g5); + $f4g6_19 = self::mul($f4, $g6_19); + $f4g7_19 = self::mul($f4, $g7_19); + $f4g8_19 = self::mul($f4, $g8_19); + $f4g9_19 = self::mul($f4, $g9_19); + $f5g0 = self::mul($f5, $g0); + $f5g1_2 = self::mul($f5_2, $g1); + $f5g2 = self::mul($f5, $g2); + $f5g3_2 = self::mul($f5_2, $g3); + $f5g4 = self::mul($f5, $g4); + $f5g5_38 = self::mul($f5_2, $g5_19); + $f5g6_19 = self::mul($f5, $g6_19); + $f5g7_38 = self::mul($f5_2, $g7_19); + $f5g8_19 = self::mul($f5, $g8_19); + $f5g9_38 = self::mul($f5_2, $g9_19); + $f6g0 = self::mul($f6, $g0); + $f6g1 = self::mul($f6, $g1); + $f6g2 = self::mul($f6, $g2); + $f6g3 = self::mul($f6, $g3); + $f6g4_19 = self::mul($f6, $g4_19); + $f6g5_19 = self::mul($f6, $g5_19); + $f6g6_19 = self::mul($f6, $g6_19); + $f6g7_19 = self::mul($f6, $g7_19); + $f6g8_19 = self::mul($f6, $g8_19); + $f6g9_19 = self::mul($f6, $g9_19); + $f7g0 = self::mul($f7, $g0); + $f7g1_2 = self::mul($f7_2, $g1); + $f7g2 = self::mul($f7, $g2); + $f7g3_38 = self::mul($f7_2, $g3_19); + $f7g4_19 = self::mul($f7, $g4_19); + $f7g5_38 = self::mul($f7_2, $g5_19); + $f7g6_19 = self::mul($f7, $g6_19); + $f7g7_38 = self::mul($f7_2, $g7_19); + $f7g8_19 = self::mul($f7, $g8_19); + $f7g9_38 = self::mul($f7_2, $g9_19); + $f8g0 = self::mul($f8, $g0); + $f8g1 = self::mul($f8, $g1); + $f8g2_19 = self::mul($f8, $g2_19); + $f8g3_19 = self::mul($f8, $g3_19); + $f8g4_19 = self::mul($f8, $g4_19); + $f8g5_19 = self::mul($f8, $g5_19); + $f8g6_19 = self::mul($f8, $g6_19); + $f8g7_19 = self::mul($f8, $g7_19); + $f8g8_19 = self::mul($f8, $g8_19); + $f8g9_19 = self::mul($f8, $g9_19); + $f9g0 = self::mul($f9, $g0); + $f9g1_38 = self::mul($f9_2, $g1_19); + $f9g2_19 = self::mul($f9, $g2_19); + $f9g3_38 = self::mul($f9_2, $g3_19); + $f9g4_19 = self::mul($f9, $g4_19); + $f9g5_38 = self::mul($f9_2, $g5_19); + $f9g6_19 = self::mul($f9, $g6_19); + $f9g7_38 = self::mul($f9_2, $g7_19); + $f9g8_19 = self::mul($f9, $g8_19); + $f9g9_38 = self::mul($f9_2, $g9_19); + $h0 = $f0g0 + $f1g9_38 + $f2g8_19 + $f3g7_38 + $f4g6_19 + $f5g5_38 + $f6g4_19 + $f7g3_38 + $f8g2_19 + $f9g1_38; + $h1 = $f0g1 + $f1g0 + $f2g9_19 + $f3g8_19 + $f4g7_19 + $f5g6_19 + $f6g5_19 + $f7g4_19 + $f8g3_19 + $f9g2_19; + $h2 = $f0g2 + $f1g1_2 + $f2g0 + $f3g9_38 + $f4g8_19 + $f5g7_38 + $f6g6_19 + $f7g5_38 + $f8g4_19 + $f9g3_38; + $h3 = $f0g3 + $f1g2 + $f2g1 + $f3g0 + $f4g9_19 + $f5g8_19 + $f6g7_19 + $f7g6_19 + $f8g5_19 + $f9g4_19; + $h4 = $f0g4 + $f1g3_2 + $f2g2 + $f3g1_2 + $f4g0 + $f5g9_38 + $f6g8_19 + $f7g7_38 + $f8g6_19 + $f9g5_38; + $h5 = $f0g5 + $f1g4 + $f2g3 + $f3g2 + $f4g1 + $f5g0 + $f6g9_19 + $f7g8_19 + $f8g7_19 + $f9g6_19; + $h6 = $f0g6 + $f1g5_2 + $f2g4 + $f3g3_2 + $f4g2 + $f5g1_2 + $f6g0 + $f7g9_38 + $f8g8_19 + $f9g7_38; + $h7 = $f0g7 + $f1g6 + $f2g5 + $f3g4 + $f4g3 + $f5g2 + $f6g1 + $f7g0 + $f8g9_19 + $f9g8_19; + $h8 = $f0g8 + $f1g7_2 + $f2g6 + $f3g5_2 + $f4g4 + $f5g3_2 + $f6g2 + $f7g1_2 + $f8g0 + $f9g9_38; + $h9 = $f0g9 + $f1g8 + $f2g7 + $f3g6 + $f4g5 + $f5g4 + $f6g3 + $f7g2 + $f8g1 + $f9g0 ; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + + $carry1 = ($h1 + (1 << 24)) >> 25; + $h2 += $carry1; + $h1 -= $carry1 << 25; + $carry5 = ($h5 + (1 << 24)) >> 25; + $h6 += $carry5; + $h5 -= $carry5 << 25; + + $carry2 = ($h2 + (1 << 25)) >> 26; + $h3 += $carry2; + $h2 -= $carry2 << 26; + $carry6 = ($h6 + (1 << 25)) >> 26; + $h7 += $carry6; + $h6 -= $carry6 << 26; + + $carry3 = ($h3 + (1 << 24)) >> 25; + $h4 += $carry3; + $h3 -= $carry3 << 25; + $carry7 = ($h7 + (1 << 24)) >> 25; + $h8 += $carry7; + $h7 -= $carry7 << 25; + + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + $carry8 = ($h8 + (1 << 25)) >> 26; + $h9 += $carry8; + $h8 -= $carry8 << 26; + + $carry9 = ($h9 + (1 << 24)) >> 25; + $h0 += self::mul($carry9, 19); + $h9 -= $carry9 << 25; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + array( + (int) $h0, + (int) $h1, + (int) $h2, + (int) $h3, + (int) $h4, + (int) $h5, + (int) $h6, + (int) $h7, + (int) $h8, + (int) $h9 + ) + ); + } + + /** + * Get the negative values for each piece of the field element. + * + * h = -f + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_neg(ParagonIE_Sodium_Core_Curve25519_Fe $f) + { + $h = new ParagonIE_Sodium_Core_Curve25519_Fe(); + for ($i = 0; $i < 10; ++$i) { + $h[$i] = -$f[$i]; + } + return $h; + } + + /** + * Square a field element + * + * h = f * f + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_sq(ParagonIE_Sodium_Core_Curve25519_Fe $f) + { + $f0 = (int) $f[0]; + $f1 = (int) $f[1]; + $f2 = (int) $f[2]; + $f3 = (int) $f[3]; + $f4 = (int) $f[4]; + $f5 = (int) $f[5]; + $f6 = (int) $f[6]; + $f7 = (int) $f[7]; + $f8 = (int) $f[8]; + $f9 = (int) $f[9]; + + $f0_2 = $f0 << 1; + $f1_2 = $f1 << 1; + $f2_2 = $f2 << 1; + $f3_2 = $f3 << 1; + $f4_2 = $f4 << 1; + $f5_2 = $f5 << 1; + $f6_2 = $f6 << 1; + $f7_2 = $f7 << 1; + $f5_38 = self::mul(38, $f5); + $f6_19 = self::mul(19, $f6); + $f7_38 = self::mul(38, $f7); + $f8_19 = self::mul(19, $f8); + $f9_38 = self::mul(38, $f9); + $f0f0 = self::mul($f0, $f0); + $f0f1_2 = self::mul($f0_2, $f1); + $f0f2_2 = self::mul($f0_2, $f2); + $f0f3_2 = self::mul($f0_2, $f3); + $f0f4_2 = self::mul($f0_2, $f4); + $f0f5_2 = self::mul($f0_2, $f5); + $f0f6_2 = self::mul($f0_2, $f6); + $f0f7_2 = self::mul($f0_2, $f7); + $f0f8_2 = self::mul($f0_2, $f8); + $f0f9_2 = self::mul($f0_2, $f9); + $f1f1_2 = self::mul($f1_2, $f1); + $f1f2_2 = self::mul($f1_2, $f2); + $f1f3_4 = self::mul($f1_2, $f3_2); + $f1f4_2 = self::mul($f1_2, $f4); + $f1f5_4 = self::mul($f1_2, $f5_2); + $f1f6_2 = self::mul($f1_2, $f6); + $f1f7_4 = self::mul($f1_2, $f7_2); + $f1f8_2 = self::mul($f1_2, $f8); + $f1f9_76 = self::mul($f1_2, $f9_38); + $f2f2 = self::mul($f2, $f2); + $f2f3_2 = self::mul($f2_2, $f3); + $f2f4_2 = self::mul($f2_2, $f4); + $f2f5_2 = self::mul($f2_2, $f5); + $f2f6_2 = self::mul($f2_2, $f6); + $f2f7_2 = self::mul($f2_2, $f7); + $f2f8_38 = self::mul($f2_2, $f8_19); + $f2f9_38 = self::mul($f2, $f9_38); + $f3f3_2 = self::mul($f3_2, $f3); + $f3f4_2 = self::mul($f3_2, $f4); + $f3f5_4 = self::mul($f3_2, $f5_2); + $f3f6_2 = self::mul($f3_2, $f6); + $f3f7_76 = self::mul($f3_2, $f7_38); + $f3f8_38 = self::mul($f3_2, $f8_19); + $f3f9_76 = self::mul($f3_2, $f9_38); + $f4f4 = self::mul($f4, $f4); + $f4f5_2 = self::mul($f4_2, $f5); + $f4f6_38 = self::mul($f4_2, $f6_19); + $f4f7_38 = self::mul($f4, $f7_38); + $f4f8_38 = self::mul($f4_2, $f8_19); + $f4f9_38 = self::mul($f4, $f9_38); + $f5f5_38 = self::mul($f5, $f5_38); + $f5f6_38 = self::mul($f5_2, $f6_19); + $f5f7_76 = self::mul($f5_2, $f7_38); + $f5f8_38 = self::mul($f5_2, $f8_19); + $f5f9_76 = self::mul($f5_2, $f9_38); + $f6f6_19 = self::mul($f6, $f6_19); + $f6f7_38 = self::mul($f6, $f7_38); + $f6f8_38 = self::mul($f6_2, $f8_19); + $f6f9_38 = self::mul($f6, $f9_38); + $f7f7_38 = self::mul($f7, $f7_38); + $f7f8_38 = self::mul($f7_2, $f8_19); + $f7f9_76 = self::mul($f7_2, $f9_38); + $f8f8_19 = self::mul($f8, $f8_19); + $f8f9_38 = self::mul($f8, $f9_38); + $f9f9_38 = self::mul($f9, $f9_38); + $h0 = $f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38; + $h1 = $f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38; + $h2 = $f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19; + $h3 = $f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38; + $h4 = $f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38; + $h5 = $f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38; + $h6 = $f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19; + $h7 = $f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38; + $h8 = $f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38; + $h9 = $f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + + $carry1 = ($h1 + (1 << 24)) >> 25; + $h2 += $carry1; + $h1 -= $carry1 << 25; + $carry5 = ($h5 + (1 << 24)) >> 25; + $h6 += $carry5; + $h5 -= $carry5 << 25; + + $carry2 = ($h2 + (1 << 25)) >> 26; + $h3 += $carry2; + $h2 -= $carry2 << 26; + $carry6 = ($h6 + (1 << 25)) >> 26; + $h7 += $carry6; + $h6 -= $carry6 << 26; + + $carry3 = ($h3 + (1 << 24)) >> 25; + $h4 += $carry3; + $h3 -= $carry3 << 25; + $carry7 = ($h7 + (1 << 24)) >> 25; + $h8 += $carry7; + $h7 -= $carry7 << 25; + + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + $carry8 = ($h8 + (1 << 25)) >> 26; + $h9 += $carry8; + $h8 -= $carry8 << 26; + + $carry9 = ($h9 + (1 << 24)) >> 25; + $h0 += self::mul($carry9, 19); + $h9 -= $carry9 << 25; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + array( + (int) $h0, + (int) $h1, + (int) $h2, + (int) $h3, + (int) $h4, + (int) $h5, + (int) $h6, + (int) $h7, + (int) $h8, + (int) $h9 + ) + ); + } + + + /** + * Square and double a field element + * + * h = 2 * f * f + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_sq2(ParagonIE_Sodium_Core_Curve25519_Fe $f) + { + $f0 = (int) $f[0]; + $f1 = (int) $f[1]; + $f2 = (int) $f[2]; + $f3 = (int) $f[3]; + $f4 = (int) $f[4]; + $f5 = (int) $f[5]; + $f6 = (int) $f[6]; + $f7 = (int) $f[7]; + $f8 = (int) $f[8]; + $f9 = (int) $f[9]; + + $f0_2 = $f0 << 1; + $f1_2 = $f1 << 1; + $f2_2 = $f2 << 1; + $f3_2 = $f3 << 1; + $f4_2 = $f4 << 1; + $f5_2 = $f5 << 1; + $f6_2 = $f6 << 1; + $f7_2 = $f7 << 1; + $f5_38 = self::mul(38, $f5); /* 1.959375*2^30 */ + $f6_19 = self::mul(19, $f6); /* 1.959375*2^30 */ + $f7_38 = self::mul(38, $f7); /* 1.959375*2^30 */ + $f8_19 = self::mul(19, $f8); /* 1.959375*2^30 */ + $f9_38 = self::mul(38, $f9); /* 1.959375*2^30 */ + $f0f0 = self::mul($f0, (int) $f0); + $f0f1_2 = self::mul($f0_2, (int) $f1); + $f0f2_2 = self::mul($f0_2, (int) $f2); + $f0f3_2 = self::mul($f0_2, (int) $f3); + $f0f4_2 = self::mul($f0_2, (int) $f4); + $f0f5_2 = self::mul($f0_2, (int) $f5); + $f0f6_2 = self::mul($f0_2, (int) $f6); + $f0f7_2 = self::mul($f0_2, (int) $f7); + $f0f8_2 = self::mul($f0_2, (int) $f8); + $f0f9_2 = self::mul($f0_2, (int) $f9); + $f1f1_2 = self::mul($f1_2, (int) $f1); + $f1f2_2 = self::mul($f1_2, (int) $f2); + $f1f3_4 = self::mul($f1_2, (int) $f3_2); + $f1f4_2 = self::mul($f1_2, (int) $f4); + $f1f5_4 = self::mul($f1_2, (int) $f5_2); + $f1f6_2 = self::mul($f1_2, (int) $f6); + $f1f7_4 = self::mul($f1_2, (int) $f7_2); + $f1f8_2 = self::mul($f1_2, (int) $f8); + $f1f9_76 = self::mul($f1_2, (int) $f9_38); + $f2f2 = self::mul($f2, (int) $f2); + $f2f3_2 = self::mul($f2_2, (int) $f3); + $f2f4_2 = self::mul($f2_2, (int) $f4); + $f2f5_2 = self::mul($f2_2, (int) $f5); + $f2f6_2 = self::mul($f2_2, (int) $f6); + $f2f7_2 = self::mul($f2_2, (int) $f7); + $f2f8_38 = self::mul($f2_2, (int) $f8_19); + $f2f9_38 = self::mul($f2, (int) $f9_38); + $f3f3_2 = self::mul($f3_2, (int) $f3); + $f3f4_2 = self::mul($f3_2, (int) $f4); + $f3f5_4 = self::mul($f3_2, (int) $f5_2); + $f3f6_2 = self::mul($f3_2, (int) $f6); + $f3f7_76 = self::mul($f3_2, (int) $f7_38); + $f3f8_38 = self::mul($f3_2, (int) $f8_19); + $f3f9_76 = self::mul($f3_2, (int) $f9_38); + $f4f4 = self::mul($f4, (int) $f4); + $f4f5_2 = self::mul($f4_2, (int) $f5); + $f4f6_38 = self::mul($f4_2, (int) $f6_19); + $f4f7_38 = self::mul($f4, (int) $f7_38); + $f4f8_38 = self::mul($f4_2, (int) $f8_19); + $f4f9_38 = self::mul($f4, (int) $f9_38); + $f5f5_38 = self::mul($f5, (int) $f5_38); + $f5f6_38 = self::mul($f5_2, (int) $f6_19); + $f5f7_76 = self::mul($f5_2, (int) $f7_38); + $f5f8_38 = self::mul($f5_2, (int) $f8_19); + $f5f9_76 = self::mul($f5_2, (int) $f9_38); + $f6f6_19 = self::mul($f6, (int) $f6_19); + $f6f7_38 = self::mul($f6, (int) $f7_38); + $f6f8_38 = self::mul($f6_2, (int) $f8_19); + $f6f9_38 = self::mul($f6, (int) $f9_38); + $f7f7_38 = self::mul($f7, (int) $f7_38); + $f7f8_38 = self::mul($f7_2, (int) $f8_19); + $f7f9_76 = self::mul($f7_2, (int) $f9_38); + $f8f8_19 = self::mul($f8, (int) $f8_19); + $f8f9_38 = self::mul($f8, (int) $f9_38); + $f9f9_38 = self::mul($f9, (int) $f9_38); + + $h0 = (int) ($f0f0 + $f1f9_76 + $f2f8_38 + $f3f7_76 + $f4f6_38 + $f5f5_38); + $h1 = (int) ($f0f1_2 + $f2f9_38 + $f3f8_38 + $f4f7_38 + $f5f6_38); + $h2 = (int) ($f0f2_2 + $f1f1_2 + $f3f9_76 + $f4f8_38 + $f5f7_76 + $f6f6_19); + $h3 = (int) ($f0f3_2 + $f1f2_2 + $f4f9_38 + $f5f8_38 + $f6f7_38); + $h4 = (int) ($f0f4_2 + $f1f3_4 + $f2f2 + $f5f9_76 + $f6f8_38 + $f7f7_38); + $h5 = (int) ($f0f5_2 + $f1f4_2 + $f2f3_2 + $f6f9_38 + $f7f8_38); + $h6 = (int) ($f0f6_2 + $f1f5_4 + $f2f4_2 + $f3f3_2 + $f7f9_76 + $f8f8_19); + $h7 = (int) ($f0f7_2 + $f1f6_2 + $f2f5_2 + $f3f4_2 + $f8f9_38); + $h8 = (int) ($f0f8_2 + $f1f7_4 + $f2f6_2 + $f3f5_4 + $f4f4 + $f9f9_38); + $h9 = (int) ($f0f9_2 + $f1f8_2 + $f2f7_2 + $f3f6_2 + $f4f5_2); + + $h0 = (int) ($h0 + $h0); + $h1 = (int) ($h1 + $h1); + $h2 = (int) ($h2 + $h2); + $h3 = (int) ($h3 + $h3); + $h4 = (int) ($h4 + $h4); + $h5 = (int) ($h5 + $h5); + $h6 = (int) ($h6 + $h6); + $h7 = (int) ($h7 + $h7); + $h8 = (int) ($h8 + $h8); + $h9 = (int) ($h9 + $h9); + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + + $carry1 = ($h1 + (1 << 24)) >> 25; + $h2 += $carry1; + $h1 -= $carry1 << 25; + $carry5 = ($h5 + (1 << 24)) >> 25; + $h6 += $carry5; + $h5 -= $carry5 << 25; + + $carry2 = ($h2 + (1 << 25)) >> 26; + $h3 += $carry2; + $h2 -= $carry2 << 26; + $carry6 = ($h6 + (1 << 25)) >> 26; + $h7 += $carry6; + $h6 -= $carry6 << 26; + + $carry3 = ($h3 + (1 << 24)) >> 25; + $h4 += $carry3; + $h3 -= $carry3 << 25; + $carry7 = ($h7 + (1 << 24)) >> 25; + $h8 += $carry7; + $h7 -= $carry7 << 25; + + $carry4 = ($h4 + (1 << 25)) >> 26; + $h5 += $carry4; + $h4 -= $carry4 << 26; + $carry8 = ($h8 + (1 << 25)) >> 26; + $h9 += $carry8; + $h8 -= $carry8 << 26; + + $carry9 = ($h9 + (1 << 24)) >> 25; + $h0 += self::mul($carry9, 19); + $h9 -= $carry9 << 25; + + $carry0 = ($h0 + (1 << 25)) >> 26; + $h1 += $carry0; + $h0 -= $carry0 << 26; + + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + array( + (int) $h0, + (int) $h1, + (int) $h2, + (int) $h3, + (int) $h4, + (int) $h5, + (int) $h6, + (int) $h7, + (int) $h8, + (int) $h9 + ) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $Z + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_invert(ParagonIE_Sodium_Core_Curve25519_Fe $Z) + { + $z = clone $Z; + $t0 = self::fe_sq($z); + $t1 = self::fe_sq($t0); + $t1 = self::fe_sq($t1); + $t1 = self::fe_mul($z, $t1); + $t0 = self::fe_mul($t0, $t1); + $t2 = self::fe_sq($t0); + $t1 = self::fe_mul($t1, $t2); + $t2 = self::fe_sq($t1); + for ($i = 1; $i < 5; ++$i) { + $t2 = self::fe_sq($t2); + } + $t1 = self::fe_mul($t2, $t1); + $t2 = self::fe_sq($t1); + for ($i = 1; $i < 10; ++$i) { + $t2 = self::fe_sq($t2); + } + $t2 = self::fe_mul($t2, $t1); + $t3 = self::fe_sq($t2); + for ($i = 1; $i < 20; ++$i) { + $t3 = self::fe_sq($t3); + } + $t2 = self::fe_mul($t3, $t2); + $t2 = self::fe_sq($t2); + for ($i = 1; $i < 10; ++$i) { + $t2 = self::fe_sq($t2); + } + $t1 = self::fe_mul($t2, $t1); + $t2 = self::fe_sq($t1); + for ($i = 1; $i < 50; ++$i) { + $t2 = self::fe_sq($t2); + } + $t2 = self::fe_mul($t2, $t1); + $t3 = self::fe_sq($t2); + for ($i = 1; $i < 100; ++$i) { + $t3 = self::fe_sq($t3); + } + $t2 = self::fe_mul($t3, $t2); + $t2 = self::fe_sq($t2); + for ($i = 1; $i < 50; ++$i) { + $t2 = self::fe_sq($t2); + } + $t1 = self::fe_mul($t2, $t1); + $t1 = self::fe_sq($t1); + for ($i = 1; $i < 5; ++$i) { + $t1 = self::fe_sq($t1); + } + return self::fe_mul($t1, $t0); + } + + /** + * @internal You should not use this directly from another application + * + * @ref https://github.com/jedisct1/libsodium/blob/68564326e1e9dc57ef03746f85734232d20ca6fb/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1054-L1106 + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $z + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_pow22523(ParagonIE_Sodium_Core_Curve25519_Fe $z) + { + # fe_sq(t0, z); + # fe_sq(t1, t0); + # fe_sq(t1, t1); + # fe_mul(t1, z, t1); + # fe_mul(t0, t0, t1); + # fe_sq(t0, t0); + # fe_mul(t0, t1, t0); + # fe_sq(t1, t0); + $t0 = self::fe_sq($z); + $t1 = self::fe_sq($t0); + $t1 = self::fe_sq($t1); + $t1 = self::fe_mul($z, $t1); + $t0 = self::fe_mul($t0, $t1); + $t0 = self::fe_sq($t0); + $t0 = self::fe_mul($t1, $t0); + $t1 = self::fe_sq($t0); + + # for (i = 1; i < 5; ++i) { + # fe_sq(t1, t1); + # } + for ($i = 1; $i < 5; ++$i) { + $t1 = self::fe_sq($t1); + } + + # fe_mul(t0, t1, t0); + # fe_sq(t1, t0); + $t0 = self::fe_mul($t1, $t0); + $t1 = self::fe_sq($t0); + + # for (i = 1; i < 10; ++i) { + # fe_sq(t1, t1); + # } + for ($i = 1; $i < 10; ++$i) { + $t1 = self::fe_sq($t1); + } + + # fe_mul(t1, t1, t0); + # fe_sq(t2, t1); + $t1 = self::fe_mul($t1, $t0); + $t2 = self::fe_sq($t1); + + # for (i = 1; i < 20; ++i) { + # fe_sq(t2, t2); + # } + for ($i = 1; $i < 20; ++$i) { + $t2 = self::fe_sq($t2); + } + + # fe_mul(t1, t2, t1); + # fe_sq(t1, t1); + $t1 = self::fe_mul($t2, $t1); + $t1 = self::fe_sq($t1); + + # for (i = 1; i < 10; ++i) { + # fe_sq(t1, t1); + # } + for ($i = 1; $i < 10; ++$i) { + $t1 = self::fe_sq($t1); + } + + # fe_mul(t0, t1, t0); + # fe_sq(t1, t0); + $t0 = self::fe_mul($t1, $t0); + $t1 = self::fe_sq($t0); + + # for (i = 1; i < 50; ++i) { + # fe_sq(t1, t1); + # } + for ($i = 1; $i < 50; ++$i) { + $t1 = self::fe_sq($t1); + } + + # fe_mul(t1, t1, t0); + # fe_sq(t2, t1); + $t1 = self::fe_mul($t1, $t0); + $t2 = self::fe_sq($t1); + + # for (i = 1; i < 100; ++i) { + # fe_sq(t2, t2); + # } + for ($i = 1; $i < 100; ++$i) { + $t2 = self::fe_sq($t2); + } + + # fe_mul(t1, t2, t1); + # fe_sq(t1, t1); + $t1 = self::fe_mul($t2, $t1); + $t1 = self::fe_sq($t1); + + # for (i = 1; i < 50; ++i) { + # fe_sq(t1, t1); + # } + for ($i = 1; $i < 50; ++$i) { + $t1 = self::fe_sq($t1); + } + + # fe_mul(t0, t1, t0); + # fe_sq(t0, t0); + # fe_sq(t0, t0); + # fe_mul(out, t0, z); + $t0 = self::fe_mul($t1, $t0); + $t0 = self::fe_sq($t0); + $t0 = self::fe_sq($t0); + return self::fe_mul($t0, $z); + } + + /** + * Subtract two field elements. + * + * h = f - g + * + * Preconditions: + * |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc. + * + * Postconditions: + * |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f + * @param ParagonIE_Sodium_Core_Curve25519_Fe $g + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function fe_sub(ParagonIE_Sodium_Core_Curve25519_Fe $f, ParagonIE_Sodium_Core_Curve25519_Fe $g) + { + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray( + array( + (int) ($f[0] - $g[0]), + (int) ($f[1] - $g[1]), + (int) ($f[2] - $g[2]), + (int) ($f[3] - $g[3]), + (int) ($f[4] - $g[4]), + (int) ($f[5] - $g[5]), + (int) ($f[6] - $g[6]), + (int) ($f[7] - $g[7]), + (int) ($f[8] - $g[8]), + (int) ($f[9] - $g[9]) + ) + ); + } + + /** + * Add two group elements. + * + * r = p + q + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_add( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, + ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q + ) { + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); + $r->X = self::fe_add($p->Y, $p->X); + $r->Y = self::fe_sub($p->Y, $p->X); + $r->Z = self::fe_mul($r->X, $q->YplusX); + $r->Y = self::fe_mul($r->Y, $q->YminusX); + $r->T = self::fe_mul($q->T2d, $p->T); + $r->X = self::fe_mul($p->Z, $q->Z); + $t0 = self::fe_add($r->X, $r->X); + $r->X = self::fe_sub($r->Z, $r->Y); + $r->Y = self::fe_add($r->Z, $r->Y); + $r->Z = self::fe_add($t0, $r->T); + $r->T = self::fe_sub($t0, $r->T); + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @ref https://github.com/jedisct1/libsodium/blob/157c4a80c13b117608aeae12178b2d38825f9f8f/src/libsodium/crypto_core/curve25519/ref10/curve25519_ref10.c#L1185-L1215 + * @param string $a + * @return array + */ + public static function slide($a) + { + if (self::strlen($a) < 256) { + if (self::strlen($a) < 16) { + $a = str_pad($a, 256, '0', STR_PAD_RIGHT); + } + } + $r = array(); + for ($i = 0; $i < 256; ++$i) { + $r[$i] = 1 & ( + self::chrToInt($a[$i >> 3]) + >> + ($i & 7) + ); + } + + for ($i = 0;$i < 256;++$i) { + if ($r[$i]) { + for ($b = 1;$b <= 6 && $i + $b < 256;++$b) { + if ($r[$i + $b]) { + if ($r[$i] + ($r[$i + $b] << $b) <= 15) { + $r[$i] += $r[$i + $b] << $b; + $r[$i + $b] = 0; + } elseif ($r[$i] - ($r[$i + $b] << $b) >= -15) { + $r[$i] -= $r[$i + $b] << $b; + for ($k = $i + $b; $k < 256; ++$k) { + if (!$r[$k]) { + $r[$k] = 1; + break; + } + $r[$k] = 0; + } + } else { + break; + } + } + } + } + } + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $s + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + */ + public static function ge_frombytes_negate_vartime($s) + { + static $d = null; + if (!$d) { + $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d); + } + + # fe_frombytes(h->Y,s); + # fe_1(h->Z); + $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3( + self::fe_0(), + self::fe_frombytes($s), + self::fe_1() + ); + + # fe_sq(u,h->Y); + # fe_mul(v,u,d); + # fe_sub(u,u,h->Z); /* u = y^2-1 */ + # fe_add(v,v,h->Z); /* v = dy^2+1 */ + $u = self::fe_sq($h->Y); + $v = self::fe_mul($u, $d); + $u = self::fe_sub($u, $h->Z); /* u = y^2 - 1 */ + $v = self::fe_add($v, $h->Z); /* v = dy^2 + 1 */ + + # fe_sq(v3,v); + # fe_mul(v3,v3,v); /* v3 = v^3 */ + # fe_sq(h->X,v3); + # fe_mul(h->X,h->X,v); + # fe_mul(h->X,h->X,u); /* x = uv^7 */ + $v3 = self::fe_sq($v); + $v3 = self::fe_mul($v3, $v); /* v3 = v^3 */ + $h->X = self::fe_sq($v3); + $h->X = self::fe_mul($h->X, $v); + $h->X = self::fe_mul($h->X, $u); /* x = uv^7 */ + + # fe_pow22523(h->X,h->X); /* x = (uv^7)^((q-5)/8) */ + # fe_mul(h->X,h->X,v3); + # fe_mul(h->X,h->X,u); /* x = uv^3(uv^7)^((q-5)/8) */ + $h->X = self::fe_pow22523($h->X); /* x = (uv^7)^((q-5)/8) */ + $h->X = self::fe_mul($h->X, $v3); + $h->X = self::fe_mul($h->X, $u); /* x = uv^3(uv^7)^((q-5)/8) */ + + # fe_sq(vxx,h->X); + # fe_mul(vxx,vxx,v); + # fe_sub(check,vxx,u); /* vx^2-u */ + $vxx = self::fe_sq($h->X); + $vxx = self::fe_mul($vxx, $v); + $check = self::fe_sub($vxx, $u); /* vx^2 - u */ + + # if (fe_isnonzero(check)) { + # fe_add(check,vxx,u); /* vx^2+u */ + # if (fe_isnonzero(check)) { + # return -1; + # } + # fe_mul(h->X,h->X,sqrtm1); + # } + if (self::fe_isnonzero($check)) { + $check = self::fe_add($vxx, $u); /* vx^2 + u */ + if (self::fe_isnonzero($check)) { + throw new RangeException('Internal check failed.'); + } + $h->X = self::fe_mul( + $h->X, + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1) + ); + } + + # if (fe_isnegative(h->X) == (s[31] >> 7)) { + # fe_neg(h->X,h->X); + # } + $i = self::chrToInt($s[31]); + if (self::fe_isnegative($h->X) === ($i >> 7)) { + $h->X = self::fe_neg($h->X); + } + + # fe_mul(h->T,h->X,h->Y); + $h->T = self::fe_mul($h->X, $h->Y); + return $h; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_madd( + ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R, + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, + ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q + ) { + $r = clone $R; + $r->X = self::fe_add($p->Y, $p->X); + $r->Y = self::fe_sub($p->Y, $p->X); + $r->Z = self::fe_mul($r->X, $q->yplusx); + $r->Y = self::fe_mul($r->Y, $q->yminusx); + $r->T = self::fe_mul($q->xy2d, $p->T); + $t0 = self::fe_add(clone $p->Z, clone $p->Z); + $r->X = self::fe_sub($r->Z, $r->Y); + $r->Y = self::fe_add($r->Z, $r->Y); + $r->Z = self::fe_add($t0, $r->T); + $r->T = self::fe_sub($t0, $r->T); + + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_msub( + ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $R, + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, + ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $q + ) { + $r = clone $R; + + $r->X = self::fe_add($p->Y, $p->X); + $r->Y = self::fe_sub($p->Y, $p->X); + $r->Z = self::fe_mul($r->X, $q->yminusx); + $r->Y = self::fe_mul($r->Y, $q->yplusx); + $r->T = self::fe_mul($q->xy2d, $p->T); + $t0 = self::fe_add($p->Z, $p->Z); + $r->X = self::fe_sub($r->Z, $r->Y); + $r->Y = self::fe_add($r->Z, $r->Y); + $r->Z = self::fe_sub($t0, $r->T); + $r->T = self::fe_add($t0, $r->T); + + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 + */ + public static function ge_p1p1_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p) + { + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P2(); + $r->X = self::fe_mul($p->X, $p->T); + $r->Y = self::fe_mul($p->Y, $p->Z); + $r->Z = self::fe_mul($p->Z, $p->T); + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + */ + public static function ge_p1p1_to_p3(ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 $p) + { + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P3(); + $r->X = self::fe_mul($p->X, $p->T); + $r->Y = self::fe_mul($p->Y, $p->Z); + $r->Z = self::fe_mul($p->Z, $p->T); + $r->T = self::fe_mul($p->X, $p->Y); + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 + */ + public static function ge_p2_0() + { + return new ParagonIE_Sodium_Core_Curve25519_Ge_P2( + self::fe_0(), + self::fe_1(), + self::fe_1() + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_p2_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $p) + { + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); + + $r->X = self::fe_sq($p->X); + $r->Z = self::fe_sq($p->Y); + $r->T = self::fe_sq2($p->Z); + $r->Y = self::fe_add($p->X, $p->Y); + $t0 = self::fe_sq($r->Y); + $r->Y = self::fe_add($r->Z, $r->X); + $r->Z = self::fe_sub($r->Z, $r->X); + $r->X = self::fe_sub($t0, $r->Y); + $r->T = self::fe_sub($r->T, $r->Z); + + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + */ + public static function ge_p3_0() + { + return new ParagonIE_Sodium_Core_Curve25519_Ge_P3( + self::fe_0(), + self::fe_1(), + self::fe_1(), + self::fe_0() + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Cached + */ + public static function ge_p3_to_cached(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) + { + static $d2 = null; + if ($d2 === null) { + $d2 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d2); + } + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached(); + $r->YplusX = self::fe_add($p->Y, $p->X); + $r->YminusX = self::fe_sub($p->Y, $p->X); + $r->Z = self::fe_copy($p->Z); + $r->T2d = self::fe_mul($p->T, $d2); + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 + */ + public static function ge_p3_to_p2(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) + { + return new ParagonIE_Sodium_Core_Curve25519_Ge_P2( + $p->X, + $p->Y, + $p->Z + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h + * @return string + */ + public static function ge_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h) + { + $recip = self::fe_invert($h->Z); + $x = self::fe_mul($h->X, $recip); + $y = self::fe_mul($h->Y, $recip); + $s = self::fe_tobytes($y); + $s[31] = self::intToChr( + self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) + ); + return $s; + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_p3_dbl(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p) + { + $q = self::ge_p3_to_p2($p); + return self::ge_p2_dbl($q); + } + + /** + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp + */ + public static function ge_precomp_0() + { + return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + self::fe_1(), + self::fe_1(), + self::fe_0() + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $b + * @param int $c + * @return int + */ + public static function equal($b, $c) + { + return (($b ^ $c) - 1 & 0xffffffff) >> 31; + } + + /** + * @internal You should not use this directly from another application + * + * @param int $char + * @return int (1 = yes, 0 = no) + */ + public static function negative($char) + { + if (is_int($char)) { + return $char < 0 ? 1 : 0; + } + $x = self::chrToInt(self::substr($char, 0, 1)); + if (PHP_INT_SIZE === 8) { + return $x >> 63; + } + return $x >> 31; + } + + /** + * Conditional move + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u + * @param int $b + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp + */ + public static function cmov( + ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $t, + ParagonIE_Sodium_Core_Curve25519_Ge_Precomp $u, + $b + ) { + if (!is_int($b)) { + throw new InvalidArgumentException('Expected an integer.'); + } + return new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + self::fe_cmov($t->yplusx, $u->yplusx, $b), + self::fe_cmov($t->yminusx, $u->yminusx, $b), + self::fe_cmov($t->xy2d, $u->xy2d, $b) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $pos + * @param int $b + * @return ParagonIE_Sodium_Core_Curve25519_Ge_Precomp + */ + public static function ge_select($pos = 0, $b = 0) + { + static $base = null; + if ($base === null) { + $base = array(); + foreach (self::$base as $i => $bas) { + for ($j = 0; $j < 8; ++$j) { + $base[$i][$j] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][0]), + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][1]), + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($bas[$j][2]) + ); + } + } + } + if (!is_int($pos)) { + throw new InvalidArgumentException('Position must be an integer'); + } + if ($pos < 0 || $pos > 31) { + throw new RangeException('Position is out of range [0, 31]'); + } + + $bnegative = self::negative($b); + $babs = $b - (((-$bnegative) & $b) << 1); + + $t = self::ge_precomp_0(); + for ($i = 0; $i < 8; ++$i) { + $t = self::cmov( + $t, + $base[$pos][$i], + self::equal($babs, $i + 1) + ); + } + $minusT = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + self::fe_copy($t->yminusx), + self::fe_copy($t->yplusx), + self::fe_neg($t->xy2d) + ); + return self::cmov($t, $minusT, $bnegative); + } + + /** + * Subtract two group elements. + * + * r = p - q + * + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p + * @param ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P1p1 + */ + public static function ge_sub( + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $p, + ParagonIE_Sodium_Core_Curve25519_Ge_Cached $q + ) { + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); + + $r->X = self::fe_add($p->Y, $p->X); + $r->Y = self::fe_sub($p->Y, $p->X); + $r->Z = self::fe_mul($r->X, $q->YminusX); + $r->Y = self::fe_mul($r->Y, $q->YplusX); + $r->T = self::fe_mul($q->T2d, $p->T); + $r->X = self::fe_mul($p->Z, $q->Z); + $t0 = self::fe_add($r->X, $r->X); + $r->X = self::fe_sub($r->Z, $r->Y); + $r->Y = self::fe_add($r->Z, $r->Y); + $r->Z = self::fe_sub($t0, $r->T); + $r->T = self::fe_add($t0, $r->T); + + return $r; + } + + /** + * Convert a group element to a byte string. + * + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h + * @return string + */ + public static function ge_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P2 $h) + { + $recip = self::fe_invert($h->Z); + $x = self::fe_mul($h->X, $recip); + $y = self::fe_mul($h->Y, $recip); + $s = self::fe_tobytes($y); + $s[31] = self::intToChr( + self::chrToInt($s[31]) ^ (self::fe_isnegative($x) << 7) + ); + return $s; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $a + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A + * @param string $b + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P2 + */ + public static function ge_double_scalarmult_vartime( + $a, + ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A, + $b + ) { + /** + * @var ParagonIE_Sodium_Core_Curve25519_Ge_Cached[] + */ + $Ai = array(); + + /** + * @var ParagonIE_Sodium_Core_Curve25519_Ge_Precomp[] + */ + static $Bi = array(); + if (!$Bi) { + for ($i = 0; $i < 8; ++$i) { + $Bi[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Precomp( + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][0]), + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][1]), + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$base2[$i][2]) + ); + } + } + for ($i = 0; $i < 8; ++$i) { + $Ai[$i] = new ParagonIE_Sodium_Core_Curve25519_Ge_Cached( + self::fe_0(), + self::fe_0(), + self::fe_0(), + self::fe_0() + ); + } + + # slide(aslide,a); + # slide(bslide,b); + $aslide = self::slide($a); + $bslide = self::slide($b); + + # ge_p3_to_cached(&Ai[0],A); + # ge_p3_dbl(&t,A); ge_p1p1_to_p3(&A2,&t); + $Ai[0] = self::ge_p3_to_cached($A); + $t = self::ge_p3_dbl($A); + $A2 = self::ge_p1p1_to_p3($t); + + # ge_add(&t,&A2,&Ai[0]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[1],&u); + # ge_add(&t,&A2,&Ai[1]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[2],&u); + # ge_add(&t,&A2,&Ai[2]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[3],&u); + # ge_add(&t,&A2,&Ai[3]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[4],&u); + # ge_add(&t,&A2,&Ai[4]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[5],&u); + # ge_add(&t,&A2,&Ai[5]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[6],&u); + # ge_add(&t,&A2,&Ai[6]); ge_p1p1_to_p3(&u,&t); ge_p3_to_cached(&Ai[7],&u); + for ($i = 0; $i < 7; ++$i) { + $t = self::ge_add($A2, $Ai[$i]); + $u = self::ge_p1p1_to_p3($t); + $Ai[$i + 1] = self::ge_p3_to_cached($u); + } + + # ge_p2_0(r); + $r = self::ge_p2_0(); + + # for (i = 255;i >= 0;--i) { + # if (aslide[i] || bslide[i]) break; + # } + $i = 255; + for (; $i >= 0; --$i) { + if ($aslide[$i] || $bslide[$i]) { + break; + } + } + + # for (;i >= 0;--i) { + for (; $i >= 0; --$i) { + # ge_p2_dbl(&t,r); + $t = self::ge_p2_dbl($r); + + # if (aslide[i] > 0) { + if ($aslide[$i] > 0) { + # ge_p1p1_to_p3(&u,&t); + # ge_add(&t,&u,&Ai[aslide[i]/2]); + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_add( + $u, + $Ai[(int) floor($aslide[$i] / 2)] + ); + # } else if (aslide[i] < 0) { + } elseif ($aslide[$i] < 0) { + # ge_p1p1_to_p3(&u,&t); + # ge_sub(&t,&u,&Ai[(-aslide[i])/2]); + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_sub( + $u, + $Ai[(int) floor(-$aslide[$i] / 2)] + ); + } + + # if (bslide[i] > 0) { + if ($bslide[$i] > 0) { + # ge_p1p1_to_p3(&u,&t); + # ge_madd(&t,&u,&Bi[bslide[i]/2]); + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_madd( + $t, + $u, + $Bi[(int) floor($bslide[$i] / 2)] + ); + # } else if (bslide[i] < 0) { + } elseif ($bslide[$i] < 0) { + # ge_p1p1_to_p3(&u,&t); + # ge_msub(&t,&u,&Bi[(-bslide[i])/2]); + $u = self::ge_p1p1_to_p3($t); + $t = self::ge_msub( + $t, + $u, + $Bi[(int) floor(-$bslide[$i] / 2)] + ); + } + # ge_p1p1_to_p2(r,&t); + $r = self::ge_p1p1_to_p2($t); + } + return $r; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $a + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3 + */ + public static function ge_scalarmult_base($a) + { + $e = array(); + $r = new ParagonIE_Sodium_Core_Curve25519_Ge_P1p1(); + + for ($i = 0; $i < 32; ++$i) { + $e[$i << 1] = self::chrToInt($a[$i]) & 15; + $e[($i << 1) + 1] = (self::chrToInt($a[$i]) >> 4) & 15; + } + + $carry = 0; + for ($i = 0; $i < 63; ++$i) { + $e[$i] += $carry; + $carry = $e[$i] + 8; + $carry >>= 4; + $e[$i] -= $carry << 4; + } + $e[63] += $carry; + + $h = self::ge_p3_0(); + + for ($i = 1; $i < 64; $i += 2) { + $t = self::ge_select((int) floor($i / 2), $e[$i]); + $r = self::ge_madd($r, $h, $t); + $h = self::ge_p1p1_to_p3($r); + } + + $r = self::ge_p3_dbl($h); + + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + $s = self::ge_p1p1_to_p2($r); + $r = self::ge_p2_dbl($s); + + $h = self::ge_p1p1_to_p3($r); + + for ($i = 0; $i < 64; $i += 2) { + $t = self::ge_select($i >> 1, $e[$i]); + $r = self::ge_madd($r, $h, $t); + $h = self::ge_p1p1_to_p3($r); + } + return $h; + } + + /** + * Calculates (ab + c) mod l + * where l = 2^252 + 27742317777372353535851937790883648493 + * + * @internal You should not use this directly from another application + * + * @param string $a + * @param string $b + * @param string $c + * @return string + */ + public static function sc_muladd($a, $b, $c) + { + $a0 = 2097151 & self::load_3(self::substr($a, 0, 3)); + $a1 = 2097151 & (self::load_4(self::substr($a, 2, 4)) >> 5); + $a2 = 2097151 & (self::load_3(self::substr($a, 5, 3)) >> 2); + $a3 = 2097151 & (self::load_4(self::substr($a, 7, 4)) >> 7); + $a4 = 2097151 & (self::load_4(self::substr($a, 10, 4)) >> 4); + $a5 = 2097151 & (self::load_3(self::substr($a, 13, 3)) >> 1); + $a6 = 2097151 & (self::load_4(self::substr($a, 15, 4)) >> 6); + $a7 = 2097151 & (self::load_3(self::substr($a, 18, 3)) >> 3); + $a8 = 2097151 & self::load_3(self::substr($a, 21, 3)); + $a9 = 2097151 & (self::load_4(self::substr($a, 23, 4)) >> 5); + $a10 = 2097151 & (self::load_3(self::substr($a, 26, 3)) >> 2); + $a11 = (self::load_4(self::substr($a, 28, 4)) >> 7); + $b0 = 2097151 & self::load_3(self::substr($b, 0, 3)); + $b1 = 2097151 & (self::load_4(self::substr($b, 2, 4)) >> 5); + $b2 = 2097151 & (self::load_3(self::substr($b, 5, 3)) >> 2); + $b3 = 2097151 & (self::load_4(self::substr($b, 7, 4)) >> 7); + $b4 = 2097151 & (self::load_4(self::substr($b, 10, 4)) >> 4); + $b5 = 2097151 & (self::load_3(self::substr($b, 13, 3)) >> 1); + $b6 = 2097151 & (self::load_4(self::substr($b, 15, 4)) >> 6); + $b7 = 2097151 & (self::load_3(self::substr($b, 18, 3)) >> 3); + $b8 = 2097151 & self::load_3(self::substr($b, 21, 3)); + $b9 = 2097151 & (self::load_4(self::substr($b, 23, 4)) >> 5); + $b10 = 2097151 & (self::load_3(self::substr($b, 26, 3)) >> 2); + $b11 = (self::load_4(self::substr($b, 28, 4)) >> 7); + $c0 = 2097151 & self::load_3(self::substr($c, 0, 3)); + $c1 = 2097151 & (self::load_4(self::substr($c, 2, 4)) >> 5); + $c2 = 2097151 & (self::load_3(self::substr($c, 5, 3)) >> 2); + $c3 = 2097151 & (self::load_4(self::substr($c, 7, 4)) >> 7); + $c4 = 2097151 & (self::load_4(self::substr($c, 10, 4)) >> 4); + $c5 = 2097151 & (self::load_3(self::substr($c, 13, 3)) >> 1); + $c6 = 2097151 & (self::load_4(self::substr($c, 15, 4)) >> 6); + $c7 = 2097151 & (self::load_3(self::substr($c, 18, 3)) >> 3); + $c8 = 2097151 & self::load_3(self::substr($c, 21, 3)); + $c9 = 2097151 & (self::load_4(self::substr($c, 23, 4)) >> 5); + $c10 = 2097151 & (self::load_3(self::substr($c, 26, 3)) >> 2); + $c11 = (self::load_4(self::substr($c, 28, 4)) >> 7); + + /* Can't really avoid the pyramid here: */ + $s0 = $c0 + self::mul($a0, $b0); + $s1 = $c1 + self::mul($a0, $b1) + self::mul($a1, $b0); + $s2 = $c2 + self::mul($a0, $b2) + self::mul($a1, $b1) + self::mul($a2, $b0); + $s3 = $c3 + self::mul($a0, $b3) + self::mul($a1, $b2) + self::mul($a2, $b1) + self::mul($a3, $b0); + $s4 = $c4 + self::mul($a0, $b4) + self::mul($a1, $b3) + self::mul($a2, $b2) + self::mul($a3, $b1) + self::mul($a4, $b0); + $s5 = $c5 + self::mul($a0, $b5) + self::mul($a1, $b4) + self::mul($a2, $b3) + self::mul($a3, $b2) + self::mul($a4, $b1) + self::mul($a5, $b0); + $s6 = $c6 + self::mul($a0, $b6) + self::mul($a1, $b5) + self::mul($a2, $b4) + self::mul($a3, $b3) + self::mul($a4, $b2) + self::mul($a5, $b1) + self::mul($a6, $b0); + $s7 = $c7 + self::mul($a0, $b7) + self::mul($a1, $b6) + self::mul($a2, $b5) + self::mul($a3, $b4) + self::mul($a4, $b3) + self::mul($a5, $b2) + self::mul($a6, $b1) + self::mul($a7, $b0); + $s8 = $c8 + self::mul($a0, $b8) + self::mul($a1, $b7) + self::mul($a2, $b6) + self::mul($a3, $b5) + self::mul($a4, $b4) + self::mul($a5, $b3) + self::mul($a6, $b2) + self::mul($a7, $b1) + self::mul($a8, $b0); + $s9 = $c9 + self::mul($a0, $b9) + self::mul($a1, $b8) + self::mul($a2, $b7) + self::mul($a3, $b6) + self::mul($a4, $b5) + self::mul($a5, $b4) + self::mul($a6, $b3) + self::mul($a7, $b2) + self::mul($a8, $b1) + self::mul($a9, $b0); + $s10 = $c10 + self::mul($a0, $b10) + self::mul($a1, $b9) + self::mul($a2, $b8) + self::mul($a3, $b7) + self::mul($a4, $b6) + self::mul($a5, $b5) + self::mul($a6, $b4) + self::mul($a7, $b3) + self::mul($a8, $b2) + self::mul($a9, $b1) + self::mul($a10, $b0); + $s11 = $c11 + self::mul($a0, $b11) + self::mul($a1, $b10) + self::mul($a2, $b9) + self::mul($a3, $b8) + self::mul($a4, $b7) + self::mul($a5, $b6) + self::mul($a6, $b5) + self::mul($a7, $b4) + self::mul($a8, $b3) + self::mul($a9, $b2) + self::mul($a10, $b1) + self::mul($a11, $b0); + $s12 = self::mul($a1, $b11) + self::mul($a2, $b10) + self::mul($a3, $b9) + self::mul($a4, $b8) + self::mul($a5, $b7) + self::mul($a6, $b6) + self::mul($a7, $b5) + self::mul($a8, $b4) + self::mul($a9, $b3) + self::mul($a10, $b2) + self::mul($a11, $b1); + $s13 = self::mul($a2, $b11) + self::mul($a3, $b10) + self::mul($a4, $b9) + self::mul($a5, $b8) + self::mul($a6, $b7) + self::mul($a7, $b6) + self::mul($a8, $b5) + self::mul($a9, $b4) + self::mul($a10, $b3) + self::mul($a11, $b2); + $s14 = self::mul($a3, $b11) + self::mul($a4, $b10) + self::mul($a5, $b9) + self::mul($a6, $b8) + self::mul($a7, $b7) + self::mul($a8, $b6) + self::mul($a9, $b5) + self::mul($a10, $b4) + self::mul($a11, $b3); + $s15 = self::mul($a4, $b11) + self::mul($a5, $b10) + self::mul($a6, $b9) + self::mul($a7, $b8) + self::mul($a8, $b7) + self::mul($a9, $b6) + self::mul($a10, $b5) + self::mul($a11, $b4); + $s16 = self::mul($a5, $b11) + self::mul($a6, $b10) + self::mul($a7, $b9) + self::mul($a8, $b8) + self::mul($a9, $b7) + self::mul($a10, $b6) + self::mul($a11, $b5); + $s17 = self::mul($a6, $b11) + self::mul($a7, $b10) + self::mul($a8, $b9) + self::mul($a9, $b8) + self::mul($a10, $b7) + self::mul($a11, $b6); + $s18 = self::mul($a7, $b11) + self::mul($a8, $b10) + self::mul($a9, $b9) + self::mul($a10, $b8) + self::mul($a11, $b7); + $s19 = self::mul($a8, $b11) + self::mul($a9, $b10) + self::mul($a10, $b9) + self::mul($a11, $b8); + $s20 = self::mul($a9, $b11) + self::mul($a10, $b10) + self::mul($a11, $b9); + $s21 = self::mul($a10, $b11) + self::mul($a11, $b10); + $s22 = self::mul($a11, $b11); + $s23 = 0; + + + $carry0 = ($s0 + (1 << 20)) >> 21; + $s1 += $carry0; + $s0 -= self::mul($carry0, 1 << 21); + $carry2 = ($s2 + (1 << 20)) >> 21; + $s3 += $carry2; + $s2 -= self::mul($carry2, 1 << 21); + $carry4 = ($s4 + (1 << 20)) >> 21; + $s5 += $carry4; + $s4 -= self::mul($carry4, 1 << 21); + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= self::mul($carry6, 1 << 21); + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= self::mul($carry8, 1 << 21); + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= self::mul($carry10, 1 << 21); + $carry12 = ($s12 + (1 << 20)) >> 21; + $s13 += $carry12; + $s12 -= self::mul($carry12, 1 << 21); + $carry14 = ($s14 + (1 << 20)) >> 21; + $s15 += $carry14; + $s14 -= self::mul($carry14, 1 << 21); + $carry16 = ($s16 + (1 << 20)) >> 21; + $s17 += $carry16; + $s16 -= self::mul($carry16, 1 << 21); + $carry18 = ($s18 + (1 << 20)) >> 21; + $s19 += $carry18; + $s18 -= self::mul($carry18, 1 << 21); + $carry20 = ($s20 + (1 << 20)) >> 21; + $s21 += $carry20; + $s20 -= self::mul($carry20, 1 << 21); + $carry22 = ($s22 + (1 << 20)) >> 21; + $s23 += $carry22; + $s22 -= self::mul($carry22, 1 << 21); + + $carry1 = ($s1 + (1 << 20)) >> 21; + $s2 += $carry1; + $s1 -= self::mul($carry1, 1 << 21); + $carry3 = ($s3 + (1 << 20)) >> 21; + $s4 += $carry3; + $s3 -= self::mul($carry3, 1 << 21); + $carry5 = ($s5 + (1 << 20)) >> 21; + $s6 += $carry5; + $s5 -= self::mul($carry5, 1 << 21); + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= self::mul($carry7, 1 << 21); + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= self::mul($carry9, 1 << 21); + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= self::mul($carry11, 1 << 21); + $carry13 = ($s13 + (1 << 20)) >> 21; + $s14 += $carry13; + $s13 -= self::mul($carry13, 1 << 21); + $carry15 = ($s15 + (1 << 20)) >> 21; + $s16 += $carry15; + $s15 -= self::mul($carry15, 1 << 21); + $carry17 = ($s17 + (1 << 20)) >> 21; + $s18 += $carry17; + $s17 -= self::mul($carry17, 1 << 21); + $carry19 = ($s19 + (1 << 20)) >> 21; + $s20 += $carry19; + $s19 -= self::mul($carry19, 1 << 21); + $carry21 = ($s21 + (1 << 20)) >> 21; + $s22 += $carry21; + $s21 -= self::mul($carry21, 1 << 21); + + $s11 += self::mul($s23, 666643); + $s12 += self::mul($s23, 470296); + $s13 += self::mul($s23, 654183); + $s14 -= self::mul($s23, 997805); + $s15 += self::mul($s23, 136657); + $s16 -= self::mul($s23, 683901); + + $s10 += self::mul($s22, 666643); + $s11 += self::mul($s22, 470296); + $s12 += self::mul($s22, 654183); + $s13 -= self::mul($s22, 997805); + $s14 += self::mul($s22, 136657); + $s15 -= self::mul($s22, 683901); + + $s9 += self::mul($s21, 666643); + $s10 += self::mul($s21, 470296); + $s11 += self::mul($s21, 654183); + $s12 -= self::mul($s21, 997805); + $s13 += self::mul($s21, 136657); + $s14 -= self::mul($s21, 683901); + + $s8 += self::mul($s20, 666643); + $s9 += self::mul($s20, 470296); + $s10 += self::mul($s20, 654183); + $s11 -= self::mul($s20, 997805); + $s12 += self::mul($s20, 136657); + $s13 -= self::mul($s20, 683901); + + $s7 += self::mul($s19, 666643); + $s8 += self::mul($s19, 470296); + $s9 += self::mul($s19, 654183); + $s10 -= self::mul($s19, 997805); + $s11 += self::mul($s19, 136657); + $s12 -= self::mul($s19, 683901); + + $s6 += self::mul($s18, 666643); + $s7 += self::mul($s18, 470296); + $s8 += self::mul($s18, 654183); + $s9 -= self::mul($s18, 997805); + $s10 += self::mul($s18, 136657); + $s11 -= self::mul($s18, 683901); + + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= self::mul($carry6, 1 << 21); + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= self::mul($carry8, 1 << 21); + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= self::mul($carry10, 1 << 21); + $carry12 = ($s12 + (1 << 20)) >> 21; + $s13 += $carry12; + $s12 -= self::mul($carry12, 1 << 21); + $carry14 = ($s14 + (1 << 20)) >> 21; + $s15 += $carry14; + $s14 -= self::mul($carry14, 1 << 21); + $carry16 = ($s16 + (1 << 20)) >> 21; + $s17 += $carry16; + $s16 -= self::mul($carry16, 1 << 21); + + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= self::mul($carry7, 1 << 21); + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= self::mul($carry9, 1 << 21); + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= self::mul($carry11, 1 << 21); + $carry13 = ($s13 + (1 << 20)) >> 21; + $s14 += $carry13; + $s13 -= self::mul($carry13, 1 << 21); + $carry15 = ($s15 + (1 << 20)) >> 21; + $s16 += $carry15; + $s15 -= self::mul($carry15, 1 << 21); + + $s5 += self::mul($s17, 666643); + $s6 += self::mul($s17, 470296); + $s7 += self::mul($s17, 654183); + $s8 -= self::mul($s17, 997805); + $s9 += self::mul($s17, 136657); + $s10 -= self::mul($s17, 683901); + + $s4 += self::mul($s16, 666643); + $s5 += self::mul($s16, 470296); + $s6 += self::mul($s16, 654183); + $s7 -= self::mul($s16, 997805); + $s8 += self::mul($s16, 136657); + $s9 -= self::mul($s16, 683901); + + $s3 += self::mul($s15, 666643); + $s4 += self::mul($s15, 470296); + $s5 += self::mul($s15, 654183); + $s6 -= self::mul($s15, 997805); + $s7 += self::mul($s15, 136657); + $s8 -= self::mul($s15, 683901); + + $s2 += self::mul($s14, 666643); + $s3 += self::mul($s14, 470296); + $s4 += self::mul($s14, 654183); + $s5 -= self::mul($s14, 997805); + $s6 += self::mul($s14, 136657); + $s7 -= self::mul($s14, 683901); + + $s1 += self::mul($s13, 666643); + $s2 += self::mul($s13, 470296); + $s3 += self::mul($s13, 654183); + $s4 -= self::mul($s13, 997805); + $s5 += self::mul($s13, 136657); + $s6 -= self::mul($s13, 683901); + + $s0 += self::mul($s12, 666643); + $s1 += self::mul($s12, 470296); + $s2 += self::mul($s12, 654183); + $s3 -= self::mul($s12, 997805); + $s4 += self::mul($s12, 136657); + $s5 -= self::mul($s12, 683901); + $s12 = 0; + + $carry0 = ($s0 + (1 << 20)) >> 21; + $s1 += $carry0; + $s0 -= self::mul($carry0, 1 << 21); + $carry2 = ($s2 + (1 << 20)) >> 21; + $s3 += $carry2; + $s2 -= self::mul($carry2, 1 << 21); + $carry4 = ($s4 + (1 << 20)) >> 21; + $s5 += $carry4; + $s4 -= self::mul($carry4, 1 << 21); + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= self::mul($carry6, 1 << 21); + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= self::mul($carry8, 1 << 21); + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= self::mul($carry10, 1 << 21); + + $carry1 = ($s1 + (1 << 20)) >> 21; + $s2 += $carry1; + $s1 -= self::mul($carry1, 1 << 21); + $carry3 = ($s3 + (1 << 20)) >> 21; + $s4 += $carry3; + $s3 -= self::mul($carry3, 1 << 21); + $carry5 = ($s5 + (1 << 20)) >> 21; + $s6 += $carry5; + $s5 -= self::mul($carry5, 1 << 21); + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= self::mul($carry7, 1 << 21); + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= self::mul($carry9, 1 << 21); + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= self::mul($carry11, 1 << 21); + + $s0 += self::mul($s12, 666643); + $s1 += self::mul($s12, 470296); + $s2 += self::mul($s12, 654183); + $s3 -= self::mul($s12, 997805); + $s4 += self::mul($s12, 136657); + $s5 -= self::mul($s12, 683901); + $s12 = 0; + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= self::mul($carry0, 1 << 21); + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= self::mul($carry1, 1 << 21); + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= self::mul($carry2, 1 << 21); + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= self::mul($carry3, 1 << 21); + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= self::mul($carry4, 1 << 21); + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= self::mul($carry5, 1 << 21); + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= self::mul($carry6, 1 << 21); + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= self::mul($carry7, 1 << 21); + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= self::mul($carry8, 1 << 21); + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= self::mul($carry9, 1 << 21); + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= self::mul($carry10, 1 << 21); + $carry11 = $s11 >> 21; + $s12 += $carry11; + $s11 -= self::mul($carry11, 1 << 21); + + + $s0 += self::mul($s12, 666643); + $s1 += self::mul($s12, 470296); + $s2 += self::mul($s12, 654183); + $s3 -= self::mul($s12, 997805); + $s4 += self::mul($s12, 136657); + $s5 -= self::mul($s12, 683901); + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= self::mul($carry0, 1 << 21); + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= self::mul($carry1, 1 << 21); + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= self::mul($carry2, 1 << 21); + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= self::mul($carry3, 1 << 21); + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= self::mul($carry4, 1 << 21); + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= self::mul($carry5, 1 << 21); + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= self::mul($carry6, 1 << 21); + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= self::mul($carry7, 1 << 21); + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= self::mul($carry8, 1 << 21); + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= self::mul($carry9, 1 << 21); + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= self::mul($carry10, 1 << 21); + + + /** + * @var array + */ + $arr = array( + (int) (0xff & ($s0 >> 0)), + (int) (0xff & ($s0 >> 8)), + (int) (0xff & (($s0 >> 16) | self::mul($s1, 1 << 5))), + (int) (0xff & ($s1 >> 3)), + (int) (0xff & ($s1 >> 11)), + (int) (0xff & (($s1 >> 19) | self::mul($s2, 1 << 2))), + (int) (0xff & ($s2 >> 6)), + (int) (0xff & (($s2 >> 14) | self::mul($s3, 1 << 7))), + (int) (0xff & ($s3 >> 1)), + (int) (0xff & ($s3 >> 9)), + (int) (0xff & (($s3 >> 17) | self::mul($s4, 1 << 4))), + (int) (0xff & ($s4 >> 4)), + (int) (0xff & ($s4 >> 12)), + (int) (0xff & (($s4 >> 20) | self::mul($s5, 1 << 1))), + (int) (0xff & ($s5 >> 7)), + (int) (0xff & (($s5 >> 15) | self::mul($s6, 1 << 6))), + (int) (0xff & ($s6 >> 2)), + (int) (0xff & ($s6 >> 10)), + (int) (0xff & (($s6 >> 18) | self::mul($s7, 1 << 3))), + (int) (0xff & ($s7 >> 5)), + (int) (0xff & ($s7 >> 13)), + (int) (0xff & ($s8 >> 0)), + (int) (0xff & ($s8 >> 8)), + (int) (0xff & (($s8 >> 16) | self::mul($s9, 1 << 5))), + (int) (0xff & ($s9 >> 3)), + (int) (0xff & ($s9 >> 11)), + (int) (0xff & (($s9 >> 19) | self::mul($s10, 1 << 2))), + (int) (0xff & ($s10 >> 6)), + (int) (0xff & (($s10 >> 14) | self::mul($s11, 1 << 7))), + (int) (0xff & ($s11 >> 1)), + (int) (0xff & ($s11 >> 9)), + 0xff & ($s11 >> 17) + ); + return self::intArrayToString($arr); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $s + * @return string + */ + public static function sc_reduce($s) + { + $s0 = 2097151 & self::load_3(self::substr($s, 0, 3)); + $s1 = 2097151 & (self::load_4(self::substr($s, 2, 4)) >> 5); + $s2 = 2097151 & (self::load_3(self::substr($s, 5, 3)) >> 2); + $s3 = 2097151 & (self::load_4(self::substr($s, 7, 4)) >> 7); + $s4 = 2097151 & (self::load_4(self::substr($s, 10, 4)) >> 4); + $s5 = 2097151 & (self::load_3(self::substr($s, 13, 3)) >> 1); + $s6 = 2097151 & (self::load_4(self::substr($s, 15, 4)) >> 6); + $s7 = 2097151 & (self::load_3(self::substr($s, 18, 4)) >> 3); + $s8 = 2097151 & self::load_3(self::substr($s, 21, 3)); + $s9 = 2097151 & (self::load_4(self::substr($s, 23, 4)) >> 5); + $s10 = 2097151 & (self::load_3(self::substr($s, 26, 3)) >> 2); + $s11 = 2097151 & (self::load_4(self::substr($s, 28, 4)) >> 7); + $s12 = 2097151 & (self::load_4(self::substr($s, 31, 4)) >> 4); + $s13 = 2097151 & (self::load_3(self::substr($s, 34, 3)) >> 1); + $s14 = 2097151 & (self::load_4(self::substr($s, 36, 4)) >> 6); + $s15 = 2097151 & (self::load_3(self::substr($s, 39, 4)) >> 3); + $s16 = 2097151 & self::load_3(self::substr($s, 42, 3)); + $s17 = 2097151 & (self::load_4(self::substr($s, 44, 4)) >> 5); + $s18 = 2097151 & (self::load_3(self::substr($s, 47, 3)) >> 2); + $s19 = 2097151 & (self::load_4(self::substr($s, 49, 4)) >> 7); + $s20 = 2097151 & (self::load_4(self::substr($s, 52, 4)) >> 4); + $s21 = 2097151 & (self::load_3(self::substr($s, 55, 3)) >> 1); + $s22 = 2097151 & (self::load_4(self::substr($s, 57, 4)) >> 6); + $s23 = (self::load_4(self::substr($s, 60, 4)) >> 3); + + $s11 += self::mul($s23, 666643); + $s12 += self::mul($s23, 470296); + $s13 += self::mul($s23, 654183); + $s14 -= self::mul($s23, 997805); + $s15 += self::mul($s23, 136657); + $s16 -= self::mul($s23, 683901); + + $s10 += self::mul($s22, 666643); + $s11 += self::mul($s22, 470296); + $s12 += self::mul($s22, 654183); + $s13 -= self::mul($s22, 997805); + $s14 += self::mul($s22, 136657); + $s15 -= self::mul($s22, 683901); + + $s9 += self::mul($s21, 666643); + $s10 += self::mul($s21, 470296); + $s11 += self::mul($s21, 654183); + $s12 -= self::mul($s21, 997805); + $s13 += self::mul($s21, 136657); + $s14 -= self::mul($s21, 683901); + + $s8 += self::mul($s20, 666643); + $s9 += self::mul($s20, 470296); + $s10 += self::mul($s20, 654183); + $s11 -= self::mul($s20, 997805); + $s12 += self::mul($s20, 136657); + $s13 -= self::mul($s20, 683901); + + $s7 += self::mul($s19, 666643); + $s8 += self::mul($s19, 470296); + $s9 += self::mul($s19, 654183); + $s10 -= self::mul($s19, 997805); + $s11 += self::mul($s19, 136657); + $s12 -= self::mul($s19, 683901); + + $s6 += self::mul($s18, 666643); + $s7 += self::mul($s18, 470296); + $s8 += self::mul($s18, 654183); + $s9 -= self::mul($s18, 997805); + $s10 += self::mul($s18, 136657); + $s11 -= self::mul($s18, 683901); + + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= self::mul($carry6, 1 << 21); + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= self::mul($carry8, 1 << 21); + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= self::mul($carry10, 1 << 21); + $carry12 = ($s12 + (1 << 20)) >> 21; + $s13 += $carry12; + $s12 -= self::mul($carry12, 1 << 21); + $carry14 = ($s14 + (1 << 20)) >> 21; + $s15 += $carry14; + $s14 -= self::mul($carry14, 1 << 21); + $carry16 = ($s16 + (1 << 20)) >> 21; + $s17 += $carry16; + $s16 -= self::mul($carry16, 1 << 21); + + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= self::mul($carry7, 1 << 21); + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= self::mul($carry9, 1 << 21); + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= self::mul($carry11, 1 << 21); + $carry13 = ($s13 + (1 << 20)) >> 21; + $s14 += $carry13; + $s13 -= self::mul($carry13, 1 << 21); + $carry15 = ($s15 + (1 << 20)) >> 21; + $s16 += $carry15; + $s15 -= self::mul($carry15, 1 << 21); + + $s5 += self::mul($s17, 666643); + $s6 += self::mul($s17, 470296); + $s7 += self::mul($s17, 654183); + $s8 -= self::mul($s17, 997805); + $s9 += self::mul($s17, 136657); + $s10 -= self::mul($s17, 683901); + + $s4 += self::mul($s16, 666643); + $s5 += self::mul($s16, 470296); + $s6 += self::mul($s16, 654183); + $s7 -= self::mul($s16, 997805); + $s8 += self::mul($s16, 136657); + $s9 -= self::mul($s16, 683901); + + $s3 += self::mul($s15, 666643); + $s4 += self::mul($s15, 470296); + $s5 += self::mul($s15, 654183); + $s6 -= self::mul($s15, 997805); + $s7 += self::mul($s15, 136657); + $s8 -= self::mul($s15, 683901); + + $s2 += self::mul($s14, 666643); + $s3 += self::mul($s14, 470296); + $s4 += self::mul($s14, 654183); + $s5 -= self::mul($s14, 997805); + $s6 += self::mul($s14, 136657); + $s7 -= self::mul($s14, 683901); + + $s1 += self::mul($s13, 666643); + $s2 += self::mul($s13, 470296); + $s3 += self::mul($s13, 654183); + $s4 -= self::mul($s13, 997805); + $s5 += self::mul($s13, 136657); + $s6 -= self::mul($s13, 683901); + + $s0 += self::mul($s12, 666643); + $s1 += self::mul($s12, 470296); + $s2 += self::mul($s12, 654183); + $s3 -= self::mul($s12, 997805); + $s4 += self::mul($s12, 136657); + $s5 -= self::mul($s12, 683901); + $s12 = 0; + + $carry0 = ($s0 + (1 << 20)) >> 21; + $s1 += $carry0; + $s0 -= self::mul($carry0, 1 << 21); + $carry2 = ($s2 + (1 << 20)) >> 21; + $s3 += $carry2; + $s2 -= self::mul($carry2, 1 << 21); + $carry4 = ($s4 + (1 << 20)) >> 21; + $s5 += $carry4; + $s4 -= self::mul($carry4, 1 << 21); + $carry6 = ($s6 + (1 << 20)) >> 21; + $s7 += $carry6; + $s6 -= self::mul($carry6, 1 << 21); + $carry8 = ($s8 + (1 << 20)) >> 21; + $s9 += $carry8; + $s8 -= self::mul($carry8, 1 << 21); + $carry10 = ($s10 + (1 << 20)) >> 21; + $s11 += $carry10; + $s10 -= self::mul($carry10, 1 << 21); + + $carry1 = ($s1 + (1 << 20)) >> 21; + $s2 += $carry1; + $s1 -= self::mul($carry1, 1 << 21); + $carry3 = ($s3 + (1 << 20)) >> 21; + $s4 += $carry3; + $s3 -= self::mul($carry3, 1 << 21); + $carry5 = ($s5 + (1 << 20)) >> 21; + $s6 += $carry5; + $s5 -= self::mul($carry5, 1 << 21); + $carry7 = ($s7 + (1 << 20)) >> 21; + $s8 += $carry7; + $s7 -= self::mul($carry7, 1 << 21); + $carry9 = ($s9 + (1 << 20)) >> 21; + $s10 += $carry9; + $s9 -= self::mul($carry9, 1 << 21); + $carry11 = ($s11 + (1 << 20)) >> 21; + $s12 += $carry11; + $s11 -= self::mul($carry11, 1 << 21); + + $s0 += self::mul($s12, 666643); + $s1 += self::mul($s12, 470296); + $s2 += self::mul($s12, 654183); + $s3 -= self::mul($s12, 997805); + $s4 += self::mul($s12, 136657); + $s5 -= self::mul($s12, 683901); + $s12 = 0; + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= self::mul($carry0, 1 << 21); + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= self::mul($carry1, 1 << 21); + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= self::mul($carry2, 1 << 21); + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= self::mul($carry3, 1 << 21); + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= self::mul($carry4, 1 << 21); + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= self::mul($carry5, 1 << 21); + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= self::mul($carry6, 1 << 21); + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= self::mul($carry7, 1 << 21); + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= self::mul($carry8, 1 << 21); + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= self::mul($carry9, 1 << 21); + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= self::mul($carry10, 1 << 21); + $carry11 = $s11 >> 21; + $s12 += $carry11; + $s11 -= self::mul($carry11, 1 << 21); + + $s0 += self::mul($s12, 666643); + $s1 += self::mul($s12, 470296); + $s2 += self::mul($s12, 654183); + $s3 -= self::mul($s12, 997805); + $s4 += self::mul($s12, 136657); + $s5 -= self::mul($s12, 683901); + + $carry0 = $s0 >> 21; + $s1 += $carry0; + $s0 -= self::mul($carry0, 1 << 21); + $carry1 = $s1 >> 21; + $s2 += $carry1; + $s1 -= self::mul($carry1, 1 << 21); + $carry2 = $s2 >> 21; + $s3 += $carry2; + $s2 -= self::mul($carry2, 1 << 21); + $carry3 = $s3 >> 21; + $s4 += $carry3; + $s3 -= self::mul($carry3, 1 << 21); + $carry4 = $s4 >> 21; + $s5 += $carry4; + $s4 -= self::mul($carry4, 1 << 21); + $carry5 = $s5 >> 21; + $s6 += $carry5; + $s5 -= self::mul($carry5, 1 << 21); + $carry6 = $s6 >> 21; + $s7 += $carry6; + $s6 -= self::mul($carry6, 1 << 21); + $carry7 = $s7 >> 21; + $s8 += $carry7; + $s7 -= self::mul($carry7, 1 << 21); + $carry8 = $s8 >> 21; + $s9 += $carry8; + $s8 -= self::mul($carry8, 1 << 21); + $carry9 = $s9 >> 21; + $s10 += $carry9; + $s9 -= self::mul($carry9, 1 << 21); + $carry10 = $s10 >> 21; + $s11 += $carry10; + $s10 -= self::mul($carry10, 1 << 21); + + /** + * @var array + */ + $arr = array( + (int) ($s0 >> 0), + (int) ($s0 >> 8), + (int) (($s0 >> 16) | self::mul($s1, 1 << 5)), + (int) ($s1 >> 3), + (int) ($s1 >> 11), + (int) (($s1 >> 19) | self::mul($s2, 1 << 2)), + (int) ($s2 >> 6), + (int) (($s2 >> 14) | self::mul($s3, 1 << 7)), + (int) ($s3 >> 1), + (int) ($s3 >> 9), + (int) (($s3 >> 17) | self::mul($s4, 1 << 4)), + (int) ($s4 >> 4), + (int) ($s4 >> 12), + (int) (($s4 >> 20) | self::mul($s5, 1 << 1)), + (int) ($s5 >> 7), + (int) (($s5 >> 15) | self::mul($s6, 1 << 6)), + (int) ($s6 >> 2), + (int) ($s6 >> 10), + (int) (($s6 >> 18) | self::mul($s7, 1 << 3)), + (int) ($s7 >> 5), + (int) ($s7 >> 13), + (int) ($s8 >> 0), + (int) ($s8 >> 8), + (int) (($s8 >> 16) | self::mul($s9, 1 << 5)), + (int) ($s9 >> 3), + (int) ($s9 >> 11), + (int) (($s9 >> 19) | self::mul($s10, 1 << 2)), + (int) ($s10 >> 6), + (int) (($s10 >> 14) | self::mul($s11, 1 << 7)), + (int) ($s11 >> 1), + (int) ($s11 >> 9), + (int) $s11 >> 17 + ); + return self::intArrayToString($arr); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Fe.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Fe.php new file mode 100644 index 0000000000000..fb66315f00f77 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Fe.php @@ -0,0 +1,126 @@ +size = 10; + } + + /** + * @internal You should not use this directly from another application + * + * @param array $array + * @param bool $save_indexes + * @return self + */ + public static function fromArray($array, $save_indexes = null) + { + $count = count($array); + if ($save_indexes) { + $keys = array_keys($array); + } else { + $keys = range(0, $count - 1); + } + $array = array_values($array); + + $obj = new ParagonIE_Sodium_Core_Curve25519_Fe($count); + if ($save_indexes) { + for ($i = 0; $i < $count; ++$i) { + $obj->offsetSet($keys[$i], $array[$i]); + } + } else { + for ($i = 0; $i < $count; ++$i) { + $obj->offsetSet($i, $array[$i]); + } + } + return $obj; + } + + /** + * @internal You should not use this directly from another application + * + * @param mixed $offset + * @param mixed $value + * @return void + */ + public function offsetSet($offset, $value) + { + if (!is_int($value)) { + throw new InvalidArgumentException('Expected an integer'); + } + if (is_null($offset)) { + $this->container[] = $value; + } else { + $this->container[$offset] = $value; + } + } + + /** + * @internal You should not use this directly from another application + * + * @param mixed $offset + * @return bool + */ + public function offsetExists($offset) + { + return isset($this->container[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param mixed $offset + * @return void + */ + public function offsetUnset($offset) + { + unset($this->container[$offset]); + } + + /** + * @internal You should not use this directly from another application + * + * @param mixed $offset + * @return mixed|null + */ + public function offsetGet($offset) + { + return isset($this->container[$offset]) + ? $this->container[$offset] + : null; + } + + /** + * @internal You should not use this directly from another application + * + * @return array + */ + public function __debugInfo() + { + return array(implode(', ', $this->container)); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/Cached.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/Cached.php new file mode 100644 index 0000000000000..39bf8977766c9 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/Cached.php @@ -0,0 +1,65 @@ +YplusX = $YplusX; + if ($YminusX === null) { + $YminusX = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->YminusX = $YminusX; + if ($Z === null) { + $Z = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Z = $Z; + if ($T2d === null) { + $T2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->T2d = $T2d; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/P1p1.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/P1p1.php new file mode 100644 index 0000000000000..a63d6ab232e7c --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/P1p1.php @@ -0,0 +1,64 @@ +X = $x; + if ($y === null) { + $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Y = $y; + if ($z === null) { + $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Z = $z; + if ($t === null) { + $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->T = $t; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/P2.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/P2.php new file mode 100644 index 0000000000000..aee4000d14193 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/P2.php @@ -0,0 +1,54 @@ +X = $x; + if ($y === null) { + $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Y = $y; + if ($z === null) { + $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Z = $z; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/P3.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/P3.php new file mode 100644 index 0000000000000..00f5b27a4b288 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/P3.php @@ -0,0 +1,65 @@ +X = $x; + if ($y === null) { + $y = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Y = $y; + if ($z === null) { + $z = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->Z = $z; + if ($t === null) { + $t = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->T = $t; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/Precomp.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/Precomp.php new file mode 100644 index 0000000000000..59611c103669e --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/Ge/Precomp.php @@ -0,0 +1,54 @@ +yplusx = $yplusx; + if ($yminusx === null) { + $yminusx = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->yminusx = $yminusx; + if ($xy2d === null) { + $xy2d = new ParagonIE_Sodium_Core_Curve25519_Fe(); + } + $this->xy2d = $xy2d; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/H.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/H.php new file mode 100644 index 0000000000000..c371be50255d7 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Curve25519/H.php @@ -0,0 +1,1467 @@ +> 8) & $n + ); + $n &= ( + (($x ^ $L[$i]) - 1) >> 8 + ); + } while ($i !== 0); + + return $c === 0; + } + + /** + * @param string $R + * @return bool + */ + public static function small_order($R) + { + static $blacklist = array( + /* 0 (order 4) */ + array( + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ), + /* 1 (order 1) */ + array( + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ), + /* 2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ + array( + 0x26, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, + 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, + 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, + 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x05 + ), + /* 55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ + array( + 0xc7, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, + 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, + 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, + 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0x7a + ), + /* p-1 (order 2) */ + array( + 0x13, 0xe8, 0x95, 0x8f, 0xc2, 0xb2, 0x27, 0xb0, + 0x45, 0xc3, 0xf4, 0x89, 0xf2, 0xef, 0x98, 0xf0, + 0xd5, 0xdf, 0xac, 0x05, 0xd3, 0xc6, 0x33, 0x39, + 0xb1, 0x38, 0x02, 0x88, 0x6d, 0x53, 0xfc, 0x85 + ), + /* p (order 4) */ + array( + 0xb4, 0x17, 0x6a, 0x70, 0x3d, 0x4d, 0xd8, 0x4f, + 0xba, 0x3c, 0x0b, 0x76, 0x0d, 0x10, 0x67, 0x0f, + 0x2a, 0x20, 0x53, 0xfa, 0x2c, 0x39, 0xcc, 0xc6, + 0x4e, 0xc7, 0xfd, 0x77, 0x92, 0xac, 0x03, 0xfa + ), + /* p+1 (order 1) */ + array( + 0xec, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f + ), + /* p+2707385501144840649318225287225658788936804267575313519463743609750303402022 (order 8) */ + array( + 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f + ), + /* p+55188659117513257062467267217118295137698188065244968500265048394206261417927 (order 8) */ + array( + 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f + ), + /* 2p-1 (order 2) */ + array( + 0xd9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + ), + /* 2p (order 4) */ + array( + 0xda, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + ), + /* 2p+1 (order 1) */ + array( + 0xdb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff + ) + ); + $countBlacklist = count($blacklist); + + for ($i = 0; $i < $countBlacklist; ++$i) { + $c = 0; + for ($j = 0; $j < 32; ++$j) { + $c |= self::chrToInt($R[$j]) ^ $blacklist[$i][$j]; + } + if ($c === 0) { + return true; + } + } + return false; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/HChaCha20.php b/libraries/vendor/paragonie/sodium_compat/src/Core/HChaCha20.php new file mode 100644 index 0000000000000..b6cf92996e65c --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/HChaCha20.php @@ -0,0 +1,106 @@ + 0; $i -= 2) { + $x4 ^= self::rotate($x0 + $x12, 7); + $x8 ^= self::rotate($x4 + $x0, 9); + $x12 ^= self::rotate($x8 + $x4, 13); + $x0 ^= self::rotate($x12 + $x8, 18); + $x9 ^= self::rotate($x5 + $x1, 7); + $x13 ^= self::rotate($x9 + $x5, 9); + $x1 ^= self::rotate($x13 + $x9, 13); + $x5 ^= self::rotate($x1 + $x13, 18); + $x14 ^= self::rotate($x10 + $x6, 7); + $x2 ^= self::rotate($x14 + $x10, 9); + $x6 ^= self::rotate($x2 + $x14, 13); + $x10 ^= self::rotate($x6 + $x2, 18); + $x3 ^= self::rotate($x15 + $x11, 7); + $x7 ^= self::rotate($x3 + $x15, 9); + $x11 ^= self::rotate($x7 + $x3, 13); + $x15 ^= self::rotate($x11 + $x7, 18); + $x1 ^= self::rotate($x0 + $x3, 7); + $x2 ^= self::rotate($x1 + $x0, 9); + $x3 ^= self::rotate($x2 + $x1, 13); + $x0 ^= self::rotate($x3 + $x2, 18); + $x6 ^= self::rotate($x5 + $x4, 7); + $x7 ^= self::rotate($x6 + $x5, 9); + $x4 ^= self::rotate($x7 + $x6, 13); + $x5 ^= self::rotate($x4 + $x7, 18); + $x11 ^= self::rotate($x10 + $x9, 7); + $x8 ^= self::rotate($x11 + $x10, 9); + $x9 ^= self::rotate($x8 + $x11, 13); + $x10 ^= self::rotate($x9 + $x8, 18); + $x12 ^= self::rotate($x15 + $x14, 7); + $x13 ^= self::rotate($x12 + $x15, 9); + $x14 ^= self::rotate($x13 + $x12, 13); + $x15 ^= self::rotate($x14 + $x13, 18); + } + + return self::store32_le($x0) . + self::store32_le($x5) . + self::store32_le($x10) . + self::store32_le($x15) . + self::store32_le($x6) . + self::store32_le($x7) . + self::store32_le($x8) . + self::store32_le($x9); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Poly1305.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Poly1305.php new file mode 100644 index 0000000000000..be3b83da7c7dc --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Poly1305.php @@ -0,0 +1,59 @@ +update($m) + ->finish(); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $mac + * @param string $m + * @param string $key + * @return bool + */ + public static function onetimeauth_verify($mac, $m, $key) + { + if (self::strlen($key) < 32) { + throw new InvalidArgumentException( + 'Key must be 32 bytes long.' + ); + } + $state = new ParagonIE_Sodium_Core_Poly1305_State( + self::substr($key, 0, 32) + ); + $calc = $state + ->update($m) + ->finish(); + return self::verify_16($calc, $mac); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Poly1305/State.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Poly1305/State.php new file mode 100644 index 0000000000000..f03da72947bf0 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Poly1305/State.php @@ -0,0 +1,356 @@ + + */ + protected $buffer = array(); + + /** + * @var bool + */ + protected $final = false; + + /** + * @var array + */ + public $h; + + /** + * @var int + */ + protected $leftover = 0; + + /** + * @var int[] + */ + public $r; + + /** + * @var int[] + */ + public $pad; + + /** + * ParagonIE_Sodium_Core_Poly1305_State constructor. + * + * @internal You should not use this directly from another application + * + * @param string $key + * @throws InvalidArgumentException + */ + public function __construct($key = '') + { + if (self::strlen($key) < 32) { + throw new InvalidArgumentException( + 'Poly1305 requires a 32-byte key' + ); + } + /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ + $this->r = array( + (int) ((self::load_4(self::substr($key, 0, 4))) & 0x3ffffff), + (int) ((self::load_4(self::substr($key, 3, 4)) >> 2) & 0x3ffff03), + (int) ((self::load_4(self::substr($key, 6, 4)) >> 4) & 0x3ffc0ff), + (int) ((self::load_4(self::substr($key, 9, 4)) >> 6) & 0x3f03fff), + (int) ((self::load_4(self::substr($key, 12, 4)) >> 8) & 0x00fffff) + ); + + /* h = 0 */ + $this->h = array(0, 0, 0, 0, 0); + + /* save pad for later */ + $this->pad = array( + self::load_4(self::substr($key, 16, 4)), + self::load_4(self::substr($key, 20, 4)), + self::load_4(self::substr($key, 24, 4)), + self::load_4(self::substr($key, 28, 4)), + ); + + $this->leftover = 0; + $this->final = false; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @return self + */ + public function update($message = '') + { + $bytes = self::strlen($message); + + /* handle leftover */ + if ($this->leftover) { + $want = ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - $this->leftover; + if ($want > $bytes) { + $want = $bytes; + } + for ($i = 0; $i < $want; ++$i) { + $mi = self::chrToInt($message[$i]); + $this->buffer[$this->leftover + $i] = $mi; + } + // We snip off the leftmost bytes. + $message = self::substr($message, $want); + $bytes = self::strlen($message); + $this->leftover += $want; + if ($this->leftover < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + // We still don't have enough to run $this->blocks() + return $this; + } + + $this->blocks( + static::intArrayToString($this->buffer), + ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE + ); + $this->leftover = 0; + } + + /* process full blocks */ + if ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + $want = $bytes & ~(ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE - 1); + if ($want >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + $block = self::substr($message, 0, $want); + if (self::strlen($block) >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + $this->blocks($block, $want); + $message = self::substr($message, $want); + $bytes = self::strlen($message); + } + } + } + + /* store leftover */ + if ($bytes) { + for ($i = 0; $i < $bytes; ++$i) { + $mi = self::chrToInt($message[$i]); + $this->buffer[$this->leftover + $i] = $mi; + } + $this->leftover = (int) $this->leftover + $bytes; + } + return $this; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param int $bytes + * @return self + */ + public function blocks($message, $bytes) + { + if (self::strlen($message) < 16) { + $message = str_pad($message, 16, "\x00", STR_PAD_RIGHT); + } + $hibit = $this->final ? 0 : 1 << 24; /* 1 << 128 */ + $r0 = (int) $this->r[0]; + $r1 = (int) $this->r[1]; + $r2 = (int) $this->r[2]; + $r3 = (int) $this->r[3]; + $r4 = (int) $this->r[4]; + + $s1 = self::mul($r1, 5); + $s2 = self::mul($r2, 5); + $s3 = self::mul($r3, 5); + $s4 = self::mul($r4, 5); + + $h0 = $this->h[0]; + $h1 = $this->h[1]; + $h2 = $this->h[2]; + $h3 = $this->h[3]; + $h4 = $this->h[4]; + + while ($bytes >= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE) { + /* h += m[i] */ + $h0 += self::load_4(self::substr($message, 0, 4)) & 0x3ffffff; + $h1 += (self::load_4(self::substr($message, 3, 4)) >> 2) & 0x3ffffff; + $h2 += (self::load_4(self::substr($message, 6, 4)) >> 4) & 0x3ffffff; + $h3 += (self::load_4(self::substr($message, 9, 4)) >> 6) & 0x3ffffff; + $h4 += (self::load_4(self::substr($message, 12, 4)) >> 8) | $hibit; + + /* h *= r */ + $d0 = ( + self::mul($h0, $r0) + + self::mul($h1, $s4) + + self::mul($h2, $s3) + + self::mul($h3, $s2) + + self::mul($h4, $s1) + ); + $d1 = ( + self::mul($h0, $r1) + + self::mul($h1, $r0) + + self::mul($h2, $s4) + + self::mul($h3, $s3) + + self::mul($h4, $s2) + ); + + $d2 = ( + self::mul($h0, $r2) + + self::mul($h1, $r1) + + self::mul($h2, $r0) + + self::mul($h3, $s4) + + self::mul($h4, $s3) + ); + + $d3 = ( + self::mul($h0, $r3) + + self::mul($h1, $r2) + + self::mul($h2, $r1) + + self::mul($h3, $r0) + + self::mul($h4, $s4) + ); + + $d4 = ( + self::mul($h0, $r4) + + self::mul($h1, $r3) + + self::mul($h2, $r2) + + self::mul($h3, $r1) + + self::mul($h4, $r0) + ); + + /* (partial) h %= p */ + $c = $d0 >> 26; + $h0 = $d0 & 0x3ffffff; + $d1 += $c; + $c = $d1 >> 26; + $h1 = $d1 & 0x3ffffff; + $d2 += $c; + $c = $d2 >> 26; + $h2 = $d2 & 0x3ffffff; + $d3 += $c; + $c = $d3 >> 26; + $h3 = $d3 & 0x3ffffff; + $d4 += $c; + $c = $d4 >> 26; + $h4 = $d4 & 0x3ffffff; + $h0 += (int) self::mul($c, 5); + $c = $h0 >> 26; + $h0 &= 0x3ffffff; + $h1 += $c; + + // Chop off the left 32 bytes. + $message = self::substr( + $message, + ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE + ); + $bytes -= ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; + } + + $this->h = array( + (int) ($h0 & 0xffffffff), + (int) ($h1 & 0xffffffff), + (int) ($h2 & 0xffffffff), + (int) ($h3 & 0xffffffff), + (int) ($h4 & 0xffffffff) + ); + return $this; + } + + /** + * @internal You should not use this directly from another application + * + * @return string + */ + public function finish() + { + /* process the remaining block */ + if ($this->leftover) { + $i = $this->leftover; + $this->buffer[$i++] = 1; + for (; $i < ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE; ++$i) { + $this->buffer[$i] = 0; + } + $this->final = true; + $this->blocks( + self::substr( + static::intArrayToString($this->buffer), + 0, + ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE + ), + ParagonIE_Sodium_Core_Poly1305::BLOCK_SIZE + ); + } + + $h0 = (int) $this->h[0]; + $h1 = (int) $this->h[1]; + $h2 = (int) $this->h[2]; + $h3 = (int) $this->h[3]; + $h4 = (int) $this->h[4]; + + $c = $h1 >> 26; + $h1 &= 0x3ffffff; + $h2 += $c; + $c = $h2 >> 26; + $h2 &= 0x3ffffff; + $h3 += $c; + $c = $h3 >> 26; + $h3 &= 0x3ffffff; + $h4 += $c; + $c = $h4 >> 26; + $h4 &= 0x3ffffff; + $h0 += self::mul($c, 5); + $c = $h0 >> 26; + $h0 &= 0x3ffffff; + $h1 += $c; + + /* compute h + -p */ + $g0 = $h0 + 5; + $c = $g0 >> 26; + $g0 &= 0x3ffffff; + $g1 = $h1 + $c; + $c = $g1 >> 26; + $g1 &= 0x3ffffff; + $g2 = $h2 + $c; + $c = $g2 >> 26; + $g2 &= 0x3ffffff; + $g3 = $h3 + $c; + $c = $g3 >> 26; + $g3 &= 0x3ffffff; + $g4 = ($h4 + $c - (1 << 26)) & 0xffffffff; + + /* select h if h < p, or h + -p if h >= p */ + $mask = ($g4 >> 31) - 1; + + $g0 &= $mask; + $g1 &= $mask; + $g2 &= $mask; + $g3 &= $mask; + $g4 &= $mask; + + $mask = ~$mask & 0xffffffff; + $h0 = ($h0 & $mask) | $g0; + $h1 = ($h1 & $mask) | $g1; + $h2 = ($h2 & $mask) | $g2; + $h3 = ($h3 & $mask) | $g3; + $h4 = ($h4 & $mask) | $g4; + + /* h = h % (2^128) */ + $h0 = (($h0) | ($h1 << 26)) & 0xffffffff; + $h1 = (($h1 >> 6) | ($h2 << 20)) & 0xffffffff; + $h2 = (($h2 >> 12) | ($h3 << 14)) & 0xffffffff; + $h3 = (($h3 >> 18) | ($h4 << 8)) & 0xffffffff; + + /* mac = (h + pad) % (2^128) */ + $f = ($h0 + $this->pad[0]); + $h0 = (int) $f; + $f = ($h1 + $this->pad[1] + ($f >> 32)); + $h1 = (int) $f; + $f = ($h2 + $this->pad[2] + ($f >> 32)); + $h2 = (int) $f; + $f = ($h3 + $this->pad[3] + ($f >> 32)); + $h3 = (int) $f; + + return self::store32_le($h0 & 0xffffffff) . + self::store32_le($h1 & 0xffffffff) . + self::store32_le($h2 & 0xffffffff) . + self::store32_le($h3 & 0xffffffff); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Salsa20.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Salsa20.php new file mode 100644 index 0000000000000..afb70cf0ddac5 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Salsa20.php @@ -0,0 +1,265 @@ + 0; $i -= 2) { + $x4 ^= self::rotate($x0 + $x12, 7); + $x8 ^= self::rotate($x4 + $x0, 9); + $x12 ^= self::rotate($x8 + $x4, 13); + $x0 ^= self::rotate($x12 + $x8, 18); + + $x9 ^= self::rotate($x5 + $x1, 7); + $x13 ^= self::rotate($x9 + $x5, 9); + $x1 ^= self::rotate($x13 + $x9, 13); + $x5 ^= self::rotate($x1 + $x13, 18); + + $x14 ^= self::rotate($x10 + $x6, 7); + $x2 ^= self::rotate($x14 + $x10, 9); + $x6 ^= self::rotate($x2 + $x14, 13); + $x10 ^= self::rotate($x6 + $x2, 18); + + $x3 ^= self::rotate($x15 + $x11, 7); + $x7 ^= self::rotate($x3 + $x15, 9); + $x11 ^= self::rotate($x7 + $x3, 13); + $x15 ^= self::rotate($x11 + $x7, 18); + + $x1 ^= self::rotate($x0 + $x3, 7); + $x2 ^= self::rotate($x1 + $x0, 9); + $x3 ^= self::rotate($x2 + $x1, 13); + $x0 ^= self::rotate($x3 + $x2, 18); + + $x6 ^= self::rotate($x5 + $x4, 7); + $x7 ^= self::rotate($x6 + $x5, 9); + $x4 ^= self::rotate($x7 + $x6, 13); + $x5 ^= self::rotate($x4 + $x7, 18); + + $x11 ^= self::rotate($x10 + $x9, 7); + $x8 ^= self::rotate($x11 + $x10, 9); + $x9 ^= self::rotate($x8 + $x11, 13); + $x10 ^= self::rotate($x9 + $x8, 18); + + $x12 ^= self::rotate($x15 + $x14, 7); + $x13 ^= self::rotate($x12 + $x15, 9); + $x14 ^= self::rotate($x13 + $x12, 13); + $x15 ^= self::rotate($x14 + $x13, 18); + } + + $x0 += $j0; + $x1 += $j1; + $x2 += $j2; + $x3 += $j3; + $x4 += $j4; + $x5 += $j5; + $x6 += $j6; + $x7 += $j7; + $x8 += $j8; + $x9 += $j9; + $x10 += $j10; + $x11 += $j11; + $x12 += $j12; + $x13 += $j13; + $x14 += $j14; + $x15 += $j15; + + return self::store32_le($x0) . + self::store32_le($x1) . + self::store32_le($x2) . + self::store32_le($x3) . + self::store32_le($x4) . + self::store32_le($x5) . + self::store32_le($x6) . + self::store32_le($x7) . + self::store32_le($x8) . + self::store32_le($x9) . + self::store32_le($x10) . + self::store32_le($x11) . + self::store32_le($x12) . + self::store32_le($x13) . + self::store32_le($x14) . + self::store32_le($x15); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $len + * @param string $nonce + * @param string $key + * @return string + */ + public static function salsa20($len, $nonce, $key) + { + if (self::strlen($key) !== 32) { + throw new RangeException('Key must be 32 bytes long'); + } + $kcopy = '' . $key; + $in = self::substr($nonce, 0, 8) . str_repeat("\0", 8); + $c = ''; + while ($len >= 64) { + $c .= self::core_salsa20($in, $kcopy, null); + $u = 1; + // Internal counter. + for ($i = 8; $i < 16; ++$i) { + $u += self::chrToInt($in[$i]); + $in[$i] = self::intToChr($u & 0xff); + $u >>= 8; + } + $len -= 64; + } + if ($len > 0) { + $c .= self::substr( + self::core_salsa20($in, $kcopy, null), + 0, + $len + ); + } + try { + ParagonIE_Sodium_Compat::memzero($kcopy); + } catch (Error $ex) { + $kcopy = null; + } + return $c; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $m + * @param string $n + * @param int $ic + * @param string $k + * @return string + */ + public static function salsa20_xor_ic($m, $n, $ic, $k) + { + $mlen = self::strlen($m); + if ($mlen < 1) { + return ''; + } + $kcopy = self::substr($k, 0, 32); + $in = self::substr($n, 0, 8); + // Initialize the counter + $in .= ParagonIE_Sodium_Core_Util::store64_le($ic); + + $c = ''; + while ($mlen >= 64) { + $block = self::core_salsa20($in, $kcopy, null); + $c .= self::xorStrings( + self::substr($m, 0, 64), + self::substr($block, 0, 64) + ); + $u = 1; + for ($i = 8; $i < 16; ++$i) { + $u += self::chrToInt($in[$i]); + $in[$i] = self::intToChr($u & 0xff); + $u >>= 8; + } + + $mlen -= 64; + $m = self::substr($m, 64); + } + + if ($mlen) { + $block = self::core_salsa20($in, $kcopy, null); + $c .= self::xorStrings( + self::substr($m, 0, $mlen), + self::substr($block, 0, $mlen) + ); + } + try { + ParagonIE_Sodium_Compat::memzero($block); + ParagonIE_Sodium_Compat::memzero($kcopy); + } catch (Error $ex) { + $block = null; + $kcopy = null; + } + + return $c; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $message + * @param string $nonce + * @param string $key + * @return string + */ + public static function salsa20_xor($message, $nonce, $key) + { + return self::xorStrings( + $message, + self::salsa20( + self::strlen($message), + $nonce, + $key + ) + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $u + * @param int $c + * @return int + */ + public static function rotate($u, $c) + { + $u &= 0xffffffff; + $c %= 32; + return 0xffffffff & ( + ($u << $c) + | + ($u >> (32 - $c)) + ); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/SipHash.php b/libraries/vendor/paragonie/sodium_compat/src/Core/SipHash.php new file mode 100644 index 0000000000000..592ad7a4d521a --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/SipHash.php @@ -0,0 +1,300 @@ + + */ + public static function add(array $a, array $b) + { + $x1 = $a[1] + $b[1]; + $c = $x1 >> 32; // Carry if ($a + $b) > 0xffffffff + $x0 = $a[0] + $b[0] + $c; + return array( + $x0 & 0xffffffff, + $x1 & 0xffffffff + ); + } + + /** + * @internal You should not use this directly from another application + * + * @param int $int0 + * @param int $int1 + * @param int $c + * @return array + */ + public static function rotl_64($int0, $int1, $c) + { + $int0 &= 0xffffffff; + $int1 &= 0xffffffff; + $c &= 63; + if ($c === 32) { + return array($int1, $int0); + } + if ($c > 31) { + $tmp = $int1; + $int1 = $int0; + $int0 = $tmp; + $c &= 31; + } + if ($c === 0) { + return array($int0, $int1); + } + return array( + 0xffffffff & ( + ($int0 << $c) + | + ($int1 >> (32 - $c)) + ), + 0xffffffff & ( + ($int1 << $c) + | + ($int0 >> (32 - $c)) + ), + ); + } + + /** + * Implements Siphash-2-4 using only 32-bit numbers. + * + * When we split an int into two, the higher bits go to the lower index. + * e.g. 0xDEADBEEFAB10C92D becomes [ + * 0 => 0xDEADBEEF, + * 1 => 0xAB10C92D + * ]. + * + * @internal You should not use this directly from another application + * + * @param string $in + * @param string $key + * @return string + */ + public static function sipHash24($in, $key) + { + $inlen = self::strlen($in); + + # /* "somepseudorandomlygeneratedbytes" */ + # u64 v0 = 0x736f6d6570736575ULL; + # u64 v1 = 0x646f72616e646f6dULL; + # u64 v2 = 0x6c7967656e657261ULL; + # u64 v3 = 0x7465646279746573ULL; + $v = array( + 0x736f6d65, // 0 + 0x70736575, // 1 + 0x646f7261, // 2 + 0x6e646f6d, // 3 + 0x6c796765, // 4 + 0x6e657261, // 5 + 0x74656462, // 6 + 0x79746573 // 7 + ); + // v0 => $v[0], $v[1] + // v1 => $v[2], $v[3] + // v2 => $v[4], $v[5] + // v3 => $v[6], $v[7] + + # u64 k0 = LOAD64_LE( k ); + # u64 k1 = LOAD64_LE( k + 8 ); + $k = array( + self::load_4(self::substr($key, 4, 4)), + self::load_4(self::substr($key, 0, 4)), + self::load_4(self::substr($key, 12, 4)), + self::load_4(self::substr($key, 8, 4)) + ); + // k0 => $k[0], $k[1] + // k1 => $k[2], $k[3] + + # b = ( ( u64 )inlen ) << 56; + $b = array( + $inlen << 24, + 0 + ); + // See docblock for why the 0th index gets the higher bits. + + # v3 ^= k1; + $v[6] ^= $k[2]; + $v[7] ^= $k[3]; + # v2 ^= k0; + $v[4] ^= $k[0]; + $v[5] ^= $k[1]; + # v1 ^= k1; + $v[2] ^= $k[2]; + $v[3] ^= $k[3]; + # v0 ^= k0; + $v[0] ^= $k[0]; + $v[1] ^= $k[1]; + + $left = $inlen; + # for ( ; in != end; in += 8 ) + while ($left >= 8) { + # m = LOAD64_LE( in ); + $m = array( + self::load_4(self::substr($in, 4, 4)), + self::load_4(self::substr($in, 0, 4)) + ); + + # v3 ^= m; + $v[6] ^= $m[0]; + $v[7] ^= $m[1]; + + # SIPROUND; + # SIPROUND; + $v = self::sipRound($v); + $v = self::sipRound($v); + + # v0 ^= m; + $v[0] ^= $m[0]; + $v[1] ^= $m[1]; + + $in = self::substr($in, 8); + $left -= 8; + } + + # switch( left ) + # { + # case 7: b |= ( ( u64 )in[ 6] ) << 48; + # case 6: b |= ( ( u64 )in[ 5] ) << 40; + # case 5: b |= ( ( u64 )in[ 4] ) << 32; + # case 4: b |= ( ( u64 )in[ 3] ) << 24; + # case 3: b |= ( ( u64 )in[ 2] ) << 16; + # case 2: b |= ( ( u64 )in[ 1] ) << 8; + # case 1: b |= ( ( u64 )in[ 0] ); break; + # case 0: break; + # } + switch ($left) { + case 7: + $b[0] |= self::chrToInt($in[6]) << 16; + case 6: + $b[0] |= self::chrToInt($in[5]) << 8; + case 5: + $b[0] |= self::chrToInt($in[4]); + case 4: + $b[1] |= self::chrToInt($in[3]) << 24; + case 3: + $b[1] |= self::chrToInt($in[2]) << 16; + case 2: + $b[1] |= self::chrToInt($in[1]) << 8; + case 1: + $b[1] |= self::chrToInt($in[0]); + case 0: + break; + } + // See docblock for why the 0th index gets the higher bits. + + # v3 ^= b; + $v[6] ^= $b[0]; + $v[7] ^= $b[1]; + + # SIPROUND; + # SIPROUND; + $v = self::sipRound($v); + $v = self::sipRound($v); + + # v0 ^= b; + $v[0] ^= $b[0]; + $v[1] ^= $b[1]; + + // Flip the lower 8 bits of v2 which is ($v[4], $v[5]) in our implementation + # v2 ^= 0xff; + $v[5] ^= 0xff; + + # SIPROUND; + # SIPROUND; + # SIPROUND; + # SIPROUND; + $v = self::sipRound($v); + $v = self::sipRound($v); + $v = self::sipRound($v); + $v = self::sipRound($v); + + # b = v0 ^ v1 ^ v2 ^ v3; + # STORE64_LE( out, b ); + return self::store32_le($v[1] ^ $v[3] ^ $v[5] ^ $v[7]) . + self::store32_le($v[0] ^ $v[2] ^ $v[4] ^ $v[6]); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/Util.php b/libraries/vendor/paragonie/sodium_compat/src/Core/Util.php new file mode 100644 index 0000000000000..1cb5612579341 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/Util.php @@ -0,0 +1,767 @@ +> 4; + $hex .= pack( + 'CC', + (87 + $b + ((($b - 10) >> 8) & ~38)), + (87 + $c + ((($c - 10) >> 8) & ~38)) + ); + } + return $hex; + } + + /** + * Convert a binary string into a hexadecimal string without cache-timing + * leaks, returning uppercase letters (as per RFC 4648) + * + * @internal You should not use this directly from another application + * + * @param string $bin_string (raw binary) + * @return string + */ + public static function bin2hexUpper($bin_string) + { + $hex = ''; + $len = self::strlen($bin_string); + for ($i = 0; $i < $len; ++$i) { + $chunk = unpack('C', self::substr($bin_string, $i, 2)); + /** + * Lower 16 bits + * + * @var int + */ + $c = $chunk[1] & 0xf; + + /** + * Upper 16 bits + * @var int + */ + $b = $chunk[1] >> 4; + + /** + * Use pack() and binary operators to turn the two integers + * into hexadecimal characters. We don't use chr() here, because + * it uses a lookup table internally and we want to avoid + * cache-timing side-channels. + */ + $hex .= pack( + 'CC', + (55 + $b + ((($b - 10) >> 8) & ~6)), + (55 + $c + ((($c - 10) >> 8) & ~6)) + ); + } + return $hex; + } + + /** + * Cache-timing-safe variant of ord() + * + * @internal You should not use this directly from another application + * + * @param string $chr + * @return int + * @throws Error + */ + public static function chrToInt($chr) + { + /* Type checks: */ + if (!is_string($chr)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($chr) . ' given.'); + } + if (self::strlen($chr) !== 1) { + throw new Error('chrToInt() expects a string that is exactly 1 character long'); + } + $chunk = unpack('C', $chr); + return $chunk[1]; + } + + /** + * Compares two strings. + * + * @internal You should not use this directly from another application + * + * @param string $left + * @param string $right + * @param int $len + * @return int + */ + public static function compare($left, $right, $len = null) + { + $leftLen = self::strlen($left); + $rightLen = self::strlen($right); + if ($len === null) { + $len = max($leftLen, $rightLen); + $left = str_pad($left, $len, "\x00", STR_PAD_RIGHT); + $right = str_pad($right, $len, "\x00", STR_PAD_RIGHT); + } + + $gt = 0; + $eq = 1; + $i = $len; + while ($i !== 0) { + --$i; + $gt |= ((self::chrToInt($right[$i]) - self::chrToInt($left[$i])) >> 8) & $eq; + $eq &= ((self::chrToInt($right[$i]) ^ self::chrToInt($left[$i])) - 1) >> 8; + } + return ($gt + $gt + $eq) - 1; + } + + /** + * Evaluate whether or not two strings are equal (in constant-time) + * + * @param string $left + * @param string $right + * @return bool + * @throws TypeError + */ + public static function hashEquals($left, $right) + { + /* Type checks: */ + if (!is_string($left)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($left) . ' given.'); + } + if (!is_string($right)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($right) . ' given.'); + } + + if (is_callable('hash_equals')) { + return hash_equals($left, $right); + } + $d = 0; + $len = self::strlen($left); + if ($len !== self::strlen($right)) { + return false; + } + for ($i = 0; $i < $len; ++$i) { + $d |= self::chrToInt($left[$i]) ^ self::chrToInt($right[$i]); + } + + if ($d !== 0) { + return false; + } + return $left === $right; + } + + /** + * Convert a hexadecimal string into a binary string without cache-timing + * leaks + * + * @internal You should not use this directly from another application + * + * @param string $hexString + * @param bool $strictPadding + * @return string (raw binary) + * @throws RangeException + * @throws TypeError + */ + public static function hex2bin($hexString, $strictPadding = false) + { + /* Type checks: */ + if (!is_string($hexString)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($hexString) . ' given.'); + } + + $hex_pos = 0; + $bin = ''; + $c_acc = 0; + $hex_len = self::strlen($hexString); + $state = 0; + if (($hex_len & 1) !== 0) { + if ($strictPadding) { + throw new RangeException( + 'Expected an even number of hexadecimal characters' + ); + } else { + $hexString = '0' . $hexString; + ++$hex_len; + } + } + + $chunk = unpack('C*', $hexString); + while ($hex_pos < $hex_len) { + ++$hex_pos; + $c = $chunk[$hex_pos]; + $c_num = $c ^ 48; + $c_num0 = ($c_num - 10) >> 8; + $c_alpha = ($c & ~32) - 55; + $c_alpha0 = (($c_alpha - 10) ^ ($c_alpha - 16)) >> 8; + if (($c_num0 | $c_alpha0) === 0) { + throw new RangeException( + 'hex2bin() only expects hexadecimal characters' + ); + } + $c_val = ($c_num0 & $c_num) | ($c_alpha & $c_alpha0); + if ($state === 0) { + $c_acc = $c_val * 16; + } else { + $bin .= pack('C', $c_acc | $c_val); + } + $state ^= 1; + } + return $bin; + } + + /** + * Turn an array of integers into a string + * + * @internal You should not use this directly from another application + * + * @param array $ints + * @return string + */ + public static function intArrayToString(array $ints) + { + $args = $ints; + foreach ($args as $i => $v) { + $args[$i] = $v & 0xff; + } + array_unshift($args, str_repeat('C', count($ints))); + return call_user_func_array('pack', $args); + } + + /** + * Cache-timing-safe variant of ord() + * + * @internal You should not use this directly from another application + * + * @param int $int + * @return string + * @throws TypeError + */ + public static function intToChr($int) + { + return pack('C', $int); + } + + /** + * Load a 3 character substring into an integer + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return int + * @throws RangeException + * @throws TypeError + */ + public static function load_3($string) + { + /* Type checks: */ + if (!is_string($string)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.'); + } + + /* Input validation: */ + if (self::strlen($string) < 3) { + throw new RangeException( + 'String must be 3 bytes or more; ' . self::strlen($string) . ' given.' + ); + } + $result = self::chrToInt($string[0]); + $result |= self::chrToInt($string[1]) << 8; + $result |= self::chrToInt($string[2]) << 16; + return $result & 0xffffff; + } + + /** + * Load a 4 character substring into an integer + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return int + * @throws RangeException + * @throws TypeError + */ + public static function load_4($string) + { + /* Type checks: */ + if (!is_string($string)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.'); + } + + /* Input validation: */ + if (self::strlen($string) < 4) { + throw new RangeException( + 'String must be 4 bytes or more; ' . self::strlen($string) . ' given.' + ); + } + $result = (self::chrToInt($string[0]) & 0xff); + $result |= (self::chrToInt($string[1]) & 0xff) << 8; + $result |= (self::chrToInt($string[2]) & 0xff) << 16; + $result |= (self::chrToInt($string[3]) & 0xff) << 24; + return $result & 0xffffffff; + } + + /** + * Load a 8 character substring into an integer + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return int + * @throws RangeException + * @throws TypeError + */ + public static function load64_le($string) + { + /* Type checks: */ + if (!is_string($string)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($string) . ' given.'); + } + + /* Input validation: */ + if (self::strlen($string) < 4) { + throw new RangeException( + 'String must be 4 bytes or more; ' . self::strlen($string) . ' given.' + ); + } + $result = (self::chrToInt($string[0]) & 0xff); + $result |= (self::chrToInt($string[1]) & 0xff) << 8; + $result |= (self::chrToInt($string[2]) & 0xff) << 16; + $result |= (self::chrToInt($string[3]) & 0xff) << 24; + $result |= (self::chrToInt($string[4]) & 0xff) << 32; + $result |= (self::chrToInt($string[5]) & 0xff) << 40; + $result |= (self::chrToInt($string[6]) & 0xff) << 48; + $result |= (self::chrToInt($string[7]) & 0xff) << 56; + return (int) $result; + } + + /** + * @internal You should not use this directly from another application + * + * @param string $left + * @param string $right + * @return int + */ + public static function memcmp($left, $right) + { + if (self::hashEquals($left, $right)) { + return 0; + } + return -1; + } + + /** + * Multiply two integers in constant-time + * + * Micro-architecture timing side-channels caused by how your CPU + * implements multiplication are best prevented by never using the + * multiplication operators and ensuring that our code always takes + * the same number of operations to complete, regardless of the values + * of $a and $b. + * + * @internal You should not use this directly from another application + * + * @param int $a + * @param int $b + * @return int + */ + public static function mul($a, $b) + { + if (ParagonIE_Sodium_Compat::$fastMult) { + return (int) ($a * $b); + } + + static $size = null; + if (!$size) { + $size = (PHP_INT_SIZE << 3) - 1; + } + + $c = 0; + + /** + * Mask is either -1 or 0. + * + * -1 in binary looks like 0x1111 ... 1111 + * 0 in binary looks like 0x0000 ... 0000 + * + * @var int + */ + $mask = -(($b >> $size) & 1); + + /** + * Ensure $b is a positive integer, without creating + * a branching side-channel + */ + $b = ($b & ~$mask) | ($mask & -$b); + + /** + * This loop always runs 32 times when PHP_INT_SIZE is 4. + * This loop always runs 64 times when PHP_INT_SIZE is 8. + */ + for ($i = $size; $i >= 0; --$i) { + $c += (int) ($a & -($b & 1)); + $a <<= 1; + $b >>= 1; + } + + /** + * If $b was negative, we then apply the same value to $c here. + * It doesn't matter much if $a was negative; the $c += above would + * have produced a negative integer to begin with. But a negative $b + * makes $b >>= 1 never return 0, so we would end up with incorrect + * results. + * + * The end result is what we'd expect from integer multiplication. + */ + return (int) (($c & ~$mask) | ($mask & -$c)); + } + + /** + * Convert any arbitrary numbers into two 32-bit integers that represent + * a 64-bit integer. + * + * @internal You should not use this directly from another application + * + * @param int|float $num + * @return array + */ + public static function numericTo64BitInteger($num) + { + $high = 0; + $low = $num & 0xffffffff; + + if ((+(abs($num))) >= 1) { + if ($num > 0) { + $high = min((+(floor($num/4294967296))), 4294967295); + } else { + $high = ~~((+(ceil(($num - (+((~~($num)))))/4294967296)))); + } + } + return array((int) $high, (int) $low); + } + + /** + * Store a 24-bit integer into a string, treating it as big-endian. + * + * @internal You should not use this directly from another application + * + * @param int $int + * @return string + * @throws TypeError + */ + public static function store_3($int) + { + /* Type checks: */ + if (!is_int($int)) { + if (is_numeric($int)) { + $int = (int) $int; + } else { + throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.'); + } + } + + return self::intToChr(($int >> 16) & 0xff) . + self::intToChr(($int >> 8) & 0xff) . + self::intToChr($int & 0xff); + } + + /** + * Store a 32-bit integer into a string, treating it as little-endian. + * + * @internal You should not use this directly from another application + * + * @param int $int + * @return string + * @throws TypeError + */ + public static function store32_le($int) + { + /* Type checks: */ + if (!is_int($int)) { + if (is_numeric($int)) { + $int = (int) $int; + } else { + throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.'); + } + } + + return self::intToChr($int & 0xff) . + self::intToChr(($int >> 8) & 0xff) . + self::intToChr(($int >> 16) & 0xff) . + self::intToChr(($int >> 24) & 0xff); + } + + /** + * Store a 32-bit integer into a string, treating it as big-endian. + * + * @internal You should not use this directly from another application + * + * @param int $int + * @return string + * @throws TypeError + */ + public static function store_4($int) + { + /* Type checks: */ + if (!is_int($int)) { + if (is_numeric($int)) { + $int = (int) $int; + } else { + throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.'); + } + } + + return self::intToChr(($int >> 24) & 0xff) . + self::intToChr(($int >> 16) & 0xff) . + self::intToChr(($int >> 8) & 0xff) . + self::intToChr($int & 0xff); + } + + /** + * Stores a 64-bit integer as an string, treating it as little-endian. + * + * @internal You should not use this directly from another application + * + * @param int $int + * @return string + * @throws TypeError + */ + public static function store64_le($int) + { + /* Type checks: */ + if (!is_int($int)) { + if (is_numeric($int)) { + $int = (int) $int; + } else { + throw new TypeError('Argument 1 must be an integer, ' . gettype($int) . ' given.'); + } + } + + if (PHP_INT_SIZE === 8) { + return self::intToChr($int & 0xff) . + self::intToChr(($int >> 8) & 0xff) . + self::intToChr(($int >> 16) & 0xff) . + self::intToChr(($int >> 24) & 0xff) . + self::intToChr(($int >> 32) & 0xff) . + self::intToChr(($int >> 40) & 0xff) . + self::intToChr(($int >> 48) & 0xff) . + self::intToChr(($int >> 56) & 0xff); + } + if ($int > PHP_INT_MAX) { + list($hiB, $int) = self::numericTo64BitInteger($int); + } else { + $hiB = 0; + } + return self::intToChr($hiB & 0xff) . + self::intToChr(($hiB >> 8) & 0xff) . + self::intToChr(($hiB >> 16) & 0xff) . + self::intToChr(($hiB >> 24) & 0xff) . + self::intToChr(($int ) & 0xff) . + self::intToChr(($int >> 8) & 0xff) . + self::intToChr(($int >> 16) & 0xff) . + self::intToChr(($int >> 24) & 0xff); + } + + /** + * Safe string length + * + * @internal You should not use this directly from another application + * + * @ref mbstring.func_overload + * + * @param string $str + * @return int + * @throws TypeError + */ + public static function strlen($str) + { + /* Type checks: */ + if (!is_string($str)) { + throw new TypeError('String expected'); + } + + return (int) ( + self::isMbStringOverride() + ? mb_strlen($str, '8bit') + : strlen($str) + ); + } + + /** + * Turn a string into an array of integers + * + * @internal You should not use this directly from another application + * + * @param string $string + * @return array + * @throws TypeError + */ + public static function stringToIntArray($string) + { + if (!is_string($string)) { + throw new TypeError('String expected'); + } + /** + * @var array + */ + $values = array_values( + unpack('C*', $string) + ); + return $values; + } + + /** + * Safe substring + * + * @internal You should not use this directly from another application + * + * @ref mbstring.func_overload + * + * @param string $str + * @param int $start + * @param int $length + * @return string + * @throws TypeError + */ + public static function substr($str, $start = 0, $length = null) + { + /* Type checks: */ + if (!is_string($str)) { + throw new TypeError('String expected'); + } + + if ($length === 0) { + return ''; + } + + if (self::isMbStringOverride()) { + if (PHP_VERSION_ID < 50400 && $length === null) { + $length = self::strlen($str); + } + $sub = (string) mb_substr($str, $start, $length, '8bit'); + } elseif ($length === null) { + $sub = (string) substr($str, $start); + } else { + $sub = (string) substr($str, $start, $length); + } + if (isset($sub)) { + return $sub; + } + return ''; + } + + /** + * Compare a 16-character byte string in constant time. + * + * @internal You should not use this directly from another application + * + * @param string $a + * @param string $b + * @return bool + * @throws TypeError + */ + public static function verify_16($a, $b) + { + /* Type checks: */ + if (!is_string($a)) { + throw new TypeError('String expected'); + } + if (!is_string($b)) { + throw new TypeError('String expected'); + } + return self::hashEquals( + self::substr($a, 0, 16), + self::substr($b, 0, 16) + ); + } + + /** + * Compare a 32-character byte string in constant time. + * + * @internal You should not use this directly from another application + * + * @param string $a + * @param string $b + * @return bool + * @throws TypeError + */ + public static function verify_32($a, $b) + { + /* Type checks: */ + if (!is_string($a)) { + throw new TypeError('String expected'); + } + if (!is_string($b)) { + throw new TypeError('String expected'); + } + return self::hashEquals( + self::substr($a, 0, 32), + self::substr($b, 0, 32) + ); + } + + /** + * Calculate $a ^ $b for two strings. + * + * @internal You should not use this directly from another application + * + * @param string $a + * @param string $b + * @return string + * @throws TypeError + */ + public static function xorStrings($a, $b) + { + /* Type checks: */ + if (!is_string($a)) { + throw new TypeError('Argument 1 must be a string'); + } + if (!is_string($b)) { + throw new TypeError('Argument 2 must be a string'); + } + + return $a ^ $b; + } + + /** + * Returns whether or not mbstring.func_overload is in effect. + * + * @internal You should not use this directly from another application + * + * @return bool + */ + protected static function isMbStringOverride() + { + static $mbstring = null; + + if ($mbstring === null) { + $mbstring = extension_loaded('mbstring') + && + (ini_get('mbstring.func_overload') & MB_OVERLOAD_STRING); + } + + return $mbstring; + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/X25519.php b/libraries/vendor/paragonie/sodium_compat/src/Core/X25519.php new file mode 100644 index 0000000000000..c33f15d4037fa --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/X25519.php @@ -0,0 +1,311 @@ +> 25; + $h[0] += self::mul($carry9, 19); + $h[9] -= $carry9 << 25; + $carry1 = ($h[1] + (1 << 24)) >> 25; + $h[2] += $carry1; + $h[1] -= $carry1 << 25; + $carry3 = ($h[3] + (1 << 24)) >> 25; + $h[4] += $carry3; + $h[3] -= $carry3 << 25; + $carry5 = ($h[5] + (1 << 24)) >> 25; + $h[6] += $carry5; + $h[5] -= $carry5 << 25; + $carry7 = ($h[7] + (1 << 24)) >> 25; + $h[8] += $carry7; + $h[7] -= $carry7 << 25; + + $carry0 = ($h[0] + (1 << 25)) >> 26; + $h[1] += $carry0; + $h[0] -= $carry0 << 26; + $carry2 = ($h[2] + (1 << 25)) >> 26; + $h[3] += $carry2; + $h[2] -= $carry2 << 26; + $carry4 = ($h[4] + (1 << 25)) >> 26; + $h[5] += $carry4; + $h[4] -= $carry4 << 26; + $carry6 = ($h[6] + (1 << 25)) >> 26; + $h[7] += $carry6; + $h[6] -= $carry6 << 26; + $carry8 = ($h[8] + (1 << 25)) >> 26; + $h[9] += $carry8; + $h[8] -= $carry8 << 26; + + foreach ($h as $i => $value) { + $h[$i] = (int) $value; + } + return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h); + } + + /** + * @internal You should not use this directly from another application + * + * Inline comments preceded by # are from libsodium's ref10 code. + * + * @param string $n + * @param string $p + * @return string + */ + public static function crypto_scalarmult_curve25519_ref10($n, $p) + { + # for (i = 0;i < 32;++i) e[i] = n[i]; + $e = '' . $n; + # e[0] &= 248; + $e[0] = self::intToChr( + self::chrToInt($e[0]) & 248 + ); + # e[31] &= 127; + # e[31] |= 64; + $e[31] = self::intToChr( + (self::chrToInt($e[31]) & 127) | 64 + ); + # fe_frombytes(x1,p); + $x1 = self::fe_frombytes($p); + # fe_1(x2); + $x2 = self::fe_1(); + # fe_0(z2); + $z2 = self::fe_0(); + # fe_copy(x3,x1); + $x3 = self::fe_copy($x1); + # fe_1(z3); + $z3 = self::fe_1(); + + # swap = 0; + $swap = 0; + + # for (pos = 254;pos >= 0;--pos) { + for ($pos = 254; $pos >= 0; --$pos) { + # b = e[pos / 8] >> (pos & 7); + $b = self::chrToInt( + $e[(int) floor($pos / 8)] + ) >> ($pos & 7); + # b &= 1; + $b &= 1; + # swap ^= b; + $swap ^= $b; + # fe_cswap(x2,x3,swap); + self::fe_cswap($x2, $x3, $swap); + # fe_cswap(z2,z3,swap); + self::fe_cswap($z2, $z3, $swap); + # swap = b; + $swap = $b; + # fe_sub(tmp0,x3,z3); + $tmp0 = self::fe_sub($x3, $z3); + # fe_sub(tmp1,x2,z2); + $tmp1 = self::fe_sub($x2, $z2); + + # fe_add(x2,x2,z2); + $x2 = self::fe_add($x2, $z2); + + # fe_add(z2,x3,z3); + $z2 = self::fe_add($x3, $z3); + + # fe_mul(z3,tmp0,x2); + $z3 = self::fe_mul($tmp0, $x2); + + # fe_mul(z2,z2,tmp1); + $z2 = self::fe_mul($z2, $tmp1); + + # fe_sq(tmp0,tmp1); + $tmp0 = self::fe_sq($tmp1); + + # fe_sq(tmp1,x2); + $tmp1 = self::fe_sq($x2); + + # fe_add(x3,z3,z2); + $x3 = self::fe_add($z3, $z2); + + # fe_sub(z2,z3,z2); + $z2 = self::fe_sub($z3, $z2); + + # fe_mul(x2,tmp1,tmp0); + $x2 = self::fe_mul($tmp1, $tmp0); + + # fe_sub(tmp1,tmp1,tmp0); + $tmp1 = self::fe_sub($tmp1, $tmp0); + + # fe_sq(z2,z2); + $z2 = self::fe_sq($z2); + + # fe_mul121666(z3,tmp1); + $z3 = self::fe_mul121666($tmp1); + + # fe_sq(x3,x3); + $x3 = self::fe_sq($x3); + + # fe_add(tmp0,tmp0,z3); + $tmp0 = self::fe_add($tmp0, $z3); + + # fe_mul(z3,x1,z2); + $z3 = self::fe_mul($x1, $z2); + + # fe_mul(z2,tmp1,tmp0); + $z2 = self::fe_mul($tmp1, $tmp0); + } + + # fe_cswap(x2,x3,swap); + self::fe_cswap($x2, $x3, $swap); + + # fe_cswap(z2,z3,swap); + self::fe_cswap($z2, $z3, $swap); + + # fe_invert(z2,z2); + $z2 = self::fe_invert($z2); + + # fe_mul(x2,x2,z2); + $x2 = self::fe_mul($x2, $z2); + # fe_tobytes(q,x2); + return self::fe_tobytes($x2); + } + + /** + * @internal You should not use this directly from another application + * + * @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY + * @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ + * @return ParagonIE_Sodium_Core_Curve25519_Fe + */ + public static function edwards_to_montgomery( + ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY, + ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ + ) { + $tempX = self::fe_add($edwardsZ, $edwardsY); + $tempZ = self::fe_sub($edwardsZ, $edwardsY); + $tempZ = self::fe_invert($tempZ); + return self::fe_mul($tempX, $tempZ); + } + + /** + * @internal You should not use this directly from another application + * + * @param string $n + * @return string + * @throws TypeError + */ + public static function crypto_scalarmult_curve25519_ref10_base($n) + { + # for (i = 0;i < 32;++i) e[i] = n[i]; + $e = '' . $n; + + # e[0] &= 248; + $e[0] = self::intToChr( + self::chrToInt($e[0]) & 248 + ); + + # e[31] &= 127; + # e[31] |= 64; + $e[31] = self::intToChr( + (self::chrToInt($e[31]) & 127) | 64 + ); + + $A = self::ge_scalarmult_base($e); + if ( + !($A->Y instanceof ParagonIE_Sodium_Core_Curve25519_Fe) + || + !($A->Z instanceof ParagonIE_Sodium_Core_Curve25519_Fe) + ) { + throw new TypeError('Null points encountered'); + } + $pk = self::edwards_to_montgomery($A->Y, $A->Z); + return self::fe_tobytes($pk); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/Core/XChaCha20.php b/libraries/vendor/paragonie/sodium_compat/src/Core/XChaCha20.php new file mode 100644 index 0000000000000..e7a25337bcb15 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/Core/XChaCha20.php @@ -0,0 +1,62 @@ +update($ad); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); + $state->update($ciphertext); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen)); + $computed_mac = $state->finish(); + + /* Compare the given MAC with the recalculated MAC: */ + if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) { + throw new Error('Invalid MAC'); + } + + // Here, we know that the MAC is valid, so we decrypt and return the plaintext + return ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + $ciphertext, + $nonce, + $key, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + } + + /** + * AEAD Encryption with ChaCha20-Poly1305 + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + */ + public static function aead_chacha20poly1305_encrypt( + $message = '', + $ad = '', + $nonce = '', + $key = '' + ) { + /** @var int $len - Length of the plaintext message */ + $len = ParagonIE_Sodium_Core_Util::strlen($message); + + /** @var int $adlen - Length of the associated data */ + $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); + + /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::stream( + 32, + $nonce, + $key + ); + $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); + try { + ParagonIE_Sodium_Compat::memzero($block0); + } catch (Error $ex) { + $block0 = null; + } + + /** @var string $ciphertext - Raw encrypted data */ + $ciphertext = ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + $message, + $nonce, + $key, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + + $state->update($ad); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); + $state->update($ciphertext); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($len)); + return $ciphertext . $state->finish(); + } + + /** + * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + * @throws Error + */ + public static function aead_chacha20poly1305_ietf_decrypt( + $message = '', + $ad = '', + $nonce = '', + $key = '' + ) { + /** @var int $adlen - Length of associated data */ + $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); + + /** @var int $len - Length of message (ciphertext + MAC) */ + $len = ParagonIE_Sodium_Core_Util::strlen($message); + + /** @var int $clen - Length of ciphertext */ + $clen = $len - self::aead_chacha20poly1305_IETF_ABYTES; + + /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream( + 32, + $nonce, + $key + ); + + /** @var string $mac - Message authentication code */ + $mac = ParagonIE_Sodium_Core_Util::substr( + $message, + $len - self::aead_chacha20poly1305_IETF_ABYTES, + self::aead_chacha20poly1305_IETF_ABYTES + ); + + /** @var string $ciphertext - The encrypted message (sans MAC) */ + $ciphertext = ParagonIE_Sodium_Core_Util::substr( + $message, + 0, + $len - self::aead_chacha20poly1305_IETF_ABYTES + ); + + /* Recalculate the Poly1305 authentication tag (MAC): */ + $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); + try { + ParagonIE_Sodium_Compat::memzero($block0); + } catch (Error $ex) { + $block0 = null; + } + $state->update($ad); + $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); + $state->update($ciphertext); + $state->update(str_repeat("\x00", (0x10 - $clen) & 0xf)); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($clen)); + $computed_mac = $state->finish(); + + /* Compare the given MAC with the recalculated MAC: */ + if (!ParagonIE_Sodium_Core_Util::verify_16($computed_mac, $mac)) { + throw new Error('Invalid MAC'); + } + + // Here, we know that the MAC is valid, so we decrypt and return the plaintext + return ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + $ciphertext, + $nonce, + $key, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + } + + /** + * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + */ + public static function aead_chacha20poly1305_ietf_encrypt( + $message = '', + $ad = '', + $nonce = '', + $key = '' + ) { + /** @var int $len - Length of the plaintext message */ + $len = ParagonIE_Sodium_Core_Util::strlen($message); + + /** @var int $adlen - Length of the associated data */ + $adlen = ParagonIE_Sodium_Core_Util::strlen($ad); + + /** @var string The first block of the chacha20 keystream, used as a poly1305 key */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::ietfStream( + 32, + $nonce, + $key + ); + $state = new ParagonIE_Sodium_Core_Poly1305_State($block0); + try { + ParagonIE_Sodium_Compat::memzero($block0); + } catch (Error $ex) { + $block0 = null; + } + + /** @var string $ciphertext - Raw encrypted data */ + $ciphertext = ParagonIE_Sodium_Core_ChaCha20::ietfStreamXorIc( + $message, + $nonce, + $key, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + + $state->update($ad); + $state->update(str_repeat("\x00", ((0x10 - $adlen) & 0xf))); + $state->update($ciphertext); + $state->update(str_repeat("\x00", ((0x10 - $len) & 0xf))); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($adlen)); + $state->update(ParagonIE_Sodium_Core_Util::store64_le($len)); + return $ciphertext . $state->finish(); + } + + /** + * AEAD Decryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + * @throws Error + */ + public static function aead_xchacha20poly1305_ietf_decrypt( + $message = '', + $ad = '', + $nonce = '', + $key = '' + ) { + $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( + ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16), + $key + ); + $nonceLast = "\x00\x00\x00\x00" . + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + + return self::aead_chacha20poly1305_ietf_decrypt($message, $ad, $nonceLast, $subkey); + } + + /** + * AEAD Encryption with ChaCha20-Poly1305, IETF mode (96-bit nonce) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $ad + * @param string $nonce + * @param string $key + * @return string + */ + public static function aead_xchacha20poly1305_ietf_encrypt( + $message = '', + $ad = '', + $nonce = '', + $key = '' + ) { + $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( + ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16), + $key + ); + $nonceLast = "\x00\x00\x00\x00" . + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + + return self::aead_chacha20poly1305_ietf_encrypt($message, $ad, $nonceLast, $subkey); + } + + /** + * HMAC-SHA-512-256 (a.k.a. the leftmost 256 bits of HMAC-SHA-512) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $key + * @return string + */ + public static function auth($message, $key) + { + return ParagonIE_Sodium_Core_Util::substr( + hash_hmac('sha512', $message, $key, true), + 0, + 32 + ); + } + + /** + * HMAC-SHA-512-256 validation. Constant-time via hash_equals(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $mac + * @param string $message + * @param string $key + * @return bool + */ + public static function auth_verify($mac, $message, $key) + { + return ParagonIE_Sodium_Core_Util::hashEquals( + $mac, + self::auth($message, $key) + ); + } + + /** + * X25519 key exchange followed by Xsalsa20Poly1305 symmetric encryption + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $plaintext + * @param string $nonce + * @param string $keypair + * @return string + */ + public static function box($plaintext, $nonce, $keypair) + { + $c = self::secretbox( + $plaintext, + $nonce, + self::box_beforenm( + self::box_secretkey($keypair), + self::box_publickey($keypair) + ) + ); + return $c; + } + + /** + * X25519-Xsalsa20-Poly1305 with one ephemeral X25519 keypair. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $publicKey + * @return string + */ + public static function box_seal($message, $publicKey) + { + /** @var string $ephemeralKeypair */ + $ephemeralKeypair = self::box_keypair(); + + /** @var string $ephemeralSK */ + $ephemeralSK = self::box_secretkey($ephemeralKeypair); + + /** @var string $ephemeralPK */ + $ephemeralPK = self::box_publickey($ephemeralKeypair); + + /** @var string $nonce */ + $nonce = self::generichash( + $ephemeralPK . $publicKey, + '', + 24 + ); + + /** @var string $keypair - The combined keypair used in crypto_box() */ + $keypair = self::box_keypair_from_secretkey_and_publickey($ephemeralSK, $publicKey); + + /** @var string $ciphertext Ciphertext + MAC from crypto_box */ + $ciphertext = self::box($message, $nonce, $keypair); + try { + ParagonIE_Sodium_Compat::memzero($ephemeralKeypair); + ParagonIE_Sodium_Compat::memzero($ephemeralSK); + ParagonIE_Sodium_Compat::memzero($nonce); + } catch (Error $ex) { + $ephemeralKeypair = null; + $ephemeralSK = null; + $nonce = null; + } + return $ephemeralPK . $ciphertext; + } + + /** + * Opens a message encrypted via box_seal(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $keypair + * @return string + */ + public static function box_seal_open($message, $keypair) + { + /** @var string $ephemeralPK */ + $ephemeralPK = ParagonIE_Sodium_Core_Util::substr($message, 0, 32); + + /** @var string $ciphertext (ciphertext + MAC) */ + $ciphertext = ParagonIE_Sodium_Core_Util::substr($message, 32); + + /** @var string $secretKey */ + $secretKey = self::box_secretkey($keypair); + + /** @var string $publicKey */ + $publicKey = self::box_publickey($keypair); + + /** @var string $nonce */ + $nonce = self::generichash( + $ephemeralPK . $publicKey, + '', + 24 + ); + + /** @var string $keypair */ + $keypair = self::box_keypair_from_secretkey_and_publickey($secretKey, $ephemeralPK); + + /** @var string $m */ + $m = self::box_open($ciphertext, $nonce, $keypair); + try { + ParagonIE_Sodium_Compat::memzero($secretKey); + ParagonIE_Sodium_Compat::memzero($ephemeralPK); + ParagonIE_Sodium_Compat::memzero($nonce); + } catch (Error $ex) { + $secretKey = null; + $ephemeralPK = null; + $nonce = null; + } + return $m; + } + + /** + * Used by crypto_box() to get the crypto_secretbox() key. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $sk + * @param string $pk + * @return string + */ + public static function box_beforenm($sk, $pk) + { + return ParagonIE_Sodium_Core_HSalsa20::hsalsa20( + str_repeat("\x00", 16), + self::scalarmult($sk, $pk) + ); + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @return string + */ + public static function box_keypair() + { + $sKey = random_bytes(32); + $pKey = self::scalarmult_base($sKey); + return $sKey . $pKey; + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $sKey + * @param string $pKey + * @return string + */ + public static function box_keypair_from_secretkey_and_publickey($sKey, $pKey) + { + return ParagonIE_Sodium_Core_Util::substr($sKey, 0, 32) . + ParagonIE_Sodium_Core_Util::substr($pKey, 0, 32); + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $keypair + * @return string + * @throws RangeException + */ + public static function box_secretkey($keypair) + { + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== 64) { + throw new RangeException('Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'); + } + return ParagonIE_Sodium_Core_Util::substr($keypair, 0, 32); + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $keypair + * @return string + * @throws RangeException + */ + public static function box_publickey($keypair) + { + if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES) { + throw new RangeException('Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_KEYPAIRBYTES bytes long.'); + } + return ParagonIE_Sodium_Core_Util::substr($keypair, 32, 32); + } + + /** + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $sKey + * @return string + * @throws RangeException + */ + public static function box_publickey_from_secretkey($sKey) + { + if (ParagonIE_Sodium_Core_Util::strlen($sKey) !== ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES) { + throw new RangeException('Must be ParagonIE_Sodium_Compat::CRYPTO_BOX_SECRETKEYBYTES bytes long.'); + } + return self::scalarmult_base($sKey); + } + + /** + * Decrypt a message encrypted with box(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ciphertext + * @param string $nonce + * @param string $nonce + * @param string $keypair + * @return string + */ + public static function box_open($ciphertext, $nonce, $keypair) + { + return self::secretbox_open( + $ciphertext, + $nonce, + self::box_beforenm( + self::box_secretkey($keypair), + self::box_publickey($keypair) + ) + ); + } + + /** + * Calculate a BLAKE2b hash. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string|null $key + * @param int $outlen + * @return string + * @throws RangeException + */ + public static function generichash($message, $key = '', $outlen = 32) + { + // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized + ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); + + $k = null; + if (!empty($key)) { + /** @var SplFixedArray $k */ + $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key); + if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) { + throw new RangeException('Invalid key size'); + } + } + + /** @var SplFixedArray $in */ + $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message); + + /** @var SplFixedArray $ctx */ + $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outlen); + ParagonIE_Sodium_Core_BLAKE2b::update($ctx, $in, $in->count()); + + /** @var SplFixedArray $out */ + $out = new SplFixedArray($outlen); + $out = ParagonIE_Sodium_Core_BLAKE2b::finish($ctx, $out); + + /** @var array */ + $outArray = $out->toArray(); + return ParagonIE_Sodium_Core_Util::intArrayToString($outArray); + } + + /** + * Finalize a BLAKE2b hashing context, returning the hash. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ctx + * @param int $outlen + * @return string + * @throws TypeError + */ + public static function generichash_final($ctx, $outlen = 32) + { + if (!is_string($ctx)) { + throw new TypeError('Context must be a string'); + } + $out = new SplFixedArray($outlen); + + /** @var SplFixedArray $context */ + $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx); + + /** @var SplFixedArray $out */ + $out = ParagonIE_Sodium_Core_BLAKE2b::finish($context, $out); + + /** @var array */ + $outArray = $out->toArray(); + return ParagonIE_Sodium_Core_Util::intArrayToString($outArray); + } + + /** + * Initialize a hashing context for BLAKE2b. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $key + * @param int $outputLength + * @return string + * @throws RangeException + */ + public static function generichash_init($key = '', $outputLength = 32) + { + // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized + ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); + + $k = null; + if (!empty($key)) { + $k = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($key); + if ($k->count() > ParagonIE_Sodium_Core_BLAKE2b::KEYBYTES) { + throw new RangeException('Invalid key size'); + } + } + + /** @var SplFixedArray $ctx */ + $ctx = ParagonIE_Sodium_Core_BLAKE2b::init($k, $outputLength); + + return ParagonIE_Sodium_Core_BLAKE2b::contextToString($ctx); + } + + /** + * Update a hashing context for BLAKE2b with $message + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ctx + * @param string $message + * @return string + */ + public static function generichash_update($ctx, $message) + { + // This ensures that ParagonIE_Sodium_Core_BLAKE2b::$iv is initialized + ParagonIE_Sodium_Core_BLAKE2b::pseudoConstructor(); + + /** @var SplFixedArray $context */ + $context = ParagonIE_Sodium_Core_BLAKE2b::stringToContext($ctx); + + /** @var SplFixedArray $in */ + $in = ParagonIE_Sodium_Core_BLAKE2b::stringToSplFixedArray($message); + + ParagonIE_Sodium_Core_BLAKE2b::update($context, $in, $in->count()); + + return ParagonIE_Sodium_Core_BLAKE2b::contextToString($context); + } + + /** + * Libsodium's crypto_kx(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $my_sk + * @param string $their_pk + * @param string $client_pk + * @param string $server_pk + * @return string + */ + public static function keyExchange($my_sk, $their_pk, $client_pk, $server_pk) + { + return self::generichash( + self::scalarmult($my_sk, $their_pk) . + $client_pk . + $server_pk + ); + } + + /** + * ECDH over Curve25519 + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $sKey + * @param string $pKey + * @return string + * + * @throws Error + */ + public static function scalarmult($sKey, $pKey) + { + $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10($sKey, $pKey); + self::scalarmult_throw_if_zero($q); + return $q; + } + + /** + * ECDH over Curve25519, using the basepoint. + * Used to get a secret key from a public key. + * + * @param string $secret + * @return string + * + * @throws Error + */ + public static function scalarmult_base($secret) + { + $q = ParagonIE_Sodium_Core_X25519::crypto_scalarmult_curve25519_ref10_base($secret); + self::scalarmult_throw_if_zero($q); + return $q; + } + + /** + * This throws an Error if a zero public key was passed to the function. + * + * @param string $q + * @return void + * @throws Error + */ + protected static function scalarmult_throw_if_zero($q) + { + $d = 0; + for ($i = 0; $i < self::box_curve25519xsalsa20poly1305_SECRETKEYBYTES; ++$i) { + $d |= ParagonIE_Sodium_Core_Util::chrToInt($q[$i]); + } + + /* branch-free variant of === 0 */ + if (-(1 & (($d - 1) >> 8))) { + throw new Error('Zero public key is not allowed'); + } + } + + /** + * Xsalsa20-Poly1305 authenticated symmetric-key encryption. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $plaintext + * @param string $nonce + * @param string $key + * @return string + */ + public static function secretbox($plaintext, $nonce, $key) + { + /** @var string $subkey */ + $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); + + /** @var string $block0 */ + $block0 = str_repeat("\x00", 32); + + /** @var int $mlen - Length of the plaintext message */ + $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext); + $mlen0 = $mlen; + if ($mlen0 > 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES) { + $mlen0 = 64 - self::secretbox_xsalsa20poly1305_ZEROBYTES; + } + $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor( + $block0, + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey + ); + + /** @var string $c */ + $c = ParagonIE_Sodium_Core_Util::substr( + $block0, + self::secretbox_xsalsa20poly1305_ZEROBYTES + ); + if ($mlen > $mlen0) { + $c .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( + ParagonIE_Sodium_Core_Util::substr( + $plaintext, + self::secretbox_xsalsa20poly1305_ZEROBYTES + ), + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + 1, + $subkey + ); + } + $state = new ParagonIE_Sodium_Core_Poly1305_State( + ParagonIE_Sodium_Core_Util::substr( + $block0, + 0, + self::onetimeauth_poly1305_KEYBYTES + ) + ); + try { + ParagonIE_Sodium_Compat::memzero($block0); + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (Error $ex) { + $block0 = null; + $subkey = null; + } + + $state->update($c); + + /** @var string $c - MAC || ciphertext */ + $c = $state->finish() . $c; + unset($state); + + return $c; + } + + /** + * Decrypt a ciphertext generated via secretbox(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ciphertext + * @param string $nonce + * @param string $key + * @return string + * @throws Error + */ + public static function secretbox_open($ciphertext, $nonce, $key) + { + /** @var string $mac */ + $mac = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + 0, + self::secretbox_xsalsa20poly1305_MACBYTES + ); + + /** @var string $c */ + $c = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + self::secretbox_xsalsa20poly1305_MACBYTES + ); + + /** @var int $clen */ + $clen = ParagonIE_Sodium_Core_Util::strlen($c); + + /** @var string $subkey */ + $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20( + 64, + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey + ); + $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify( + $mac, + $c, + ParagonIE_Sodium_Core_Util::substr($block0, 0, 32) + ); + if (!$verified) { + try { + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (Error $ex) { + $subkey = null; + } + throw new Error('Invalid MAC'); + } + + /** @var string $m - Decrypted message */ + $m = ParagonIE_Sodium_Core_Util::xorStrings( + ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xsalsa20poly1305_ZEROBYTES), + ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xsalsa20poly1305_ZEROBYTES) + ); + if ($clen > self::secretbox_xsalsa20poly1305_ZEROBYTES) { + // We had more than 1 block, so let's continue to decrypt the rest. + $m .= ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( + ParagonIE_Sodium_Core_Util::substr( + $c, + self::secretbox_xsalsa20poly1305_ZEROBYTES + ), + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + 1, + $subkey + ); + } + return $m; + } + + /** + * XChaCha20-Poly1305 authenticated symmetric-key encryption. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $plaintext + * @param string $nonce + * @param string $key + * @return string + */ + public static function secretbox_xchacha20poly1305($plaintext, $nonce, $key) + { + /** @var string $subkey */ + $subkey = ParagonIE_Sodium_Core_HChaCha20::hChaCha20( + ParagonIE_Sodium_Core_Util::substr($nonce, 0, 16), + $key + ); + $nonceLast = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + + /** @var string $block0 */ + $block0 = str_repeat("\x00", 32); + + /** @var int $mlen - Length of the plaintext message */ + $mlen = ParagonIE_Sodium_Core_Util::strlen($plaintext); + $mlen0 = $mlen; + if ($mlen0 > 64 - self::secretbox_xchacha20poly1305_ZEROBYTES) { + $mlen0 = 64 - self::secretbox_xchacha20poly1305_ZEROBYTES; + } + $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + $block0, + $nonceLast, + $subkey + ); + + /** @var string $c */ + $c = ParagonIE_Sodium_Core_Util::substr( + $block0, + self::secretbox_xchacha20poly1305_ZEROBYTES + ); + if ($mlen > $mlen0) { + $c .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + ParagonIE_Sodium_Core_Util::substr( + $plaintext, + self::secretbox_xchacha20poly1305_ZEROBYTES + ), + $nonceLast, + $subkey, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + } + $state = new ParagonIE_Sodium_Core_Poly1305_State( + ParagonIE_Sodium_Core_Util::substr( + $block0, + 0, + self::onetimeauth_poly1305_KEYBYTES + ) + ); + try { + ParagonIE_Sodium_Compat::memzero($block0); + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (Error $ex) { + $block0 = null; + $subkey = null; + } + + $state->update($c); + + /** @var string $c - MAC || ciphertext */ + $c = $state->finish() . $c; + unset($state); + + return $c; + } + + /** + * Decrypt a ciphertext generated via secretbox_xchacha20poly1305(). + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $ciphertext + * @param string $nonce + * @param string $key + * @return string + * @throws Error + */ + public static function secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key) + { + /** @var string $mac */ + $mac = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + 0, + self::secretbox_xchacha20poly1305_MACBYTES + ); + + /** @var string $c */ + $c = ParagonIE_Sodium_Core_Util::substr( + $ciphertext, + self::secretbox_xchacha20poly1305_MACBYTES + ); + + /** @var int $clen */ + $clen = ParagonIE_Sodium_Core_Util::strlen($c); + + /** @var string $subkey */ + $subkey = ParagonIE_Sodium_Core_HChaCha20::hchacha20($nonce, $key); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_ChaCha20::stream( + 64, + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey + ); + $verified = ParagonIE_Sodium_Core_Poly1305::onetimeauth_verify( + $mac, + $c, + ParagonIE_Sodium_Core_Util::substr($block0, 0, 32) + ); + + if (!$verified) { + try { + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (Error $ex) { + $subkey = null; + } + throw new Error('Invalid MAC'); + } + + /** @var string $m - Decrypted message */ + $m = ParagonIE_Sodium_Core_Util::xorStrings( + ParagonIE_Sodium_Core_Util::substr($block0, self::secretbox_xchacha20poly1305_ZEROBYTES), + ParagonIE_Sodium_Core_Util::substr($c, 0, self::secretbox_xchacha20poly1305_ZEROBYTES) + ); + + if ($clen > self::secretbox_xchacha20poly1305_ZEROBYTES) { + // We had more than 1 block, so let's continue to decrypt the rest. + $m .= ParagonIE_Sodium_Core_ChaCha20::streamXorIc( + ParagonIE_Sodium_Core_Util::substr( + $c, + self::secretbox_xchacha20poly1305_ZEROBYTES + ), + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey, + ParagonIE_Sodium_Core_Util::store64_le(1) + ); + } + return $m; + } + + /** + * Detached Ed25519 signature. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $sk + * @return string + */ + public static function sign_detached($message, $sk) + { + return ParagonIE_Sodium_Core_Ed25519::sign_detached($message, $sk); + } + + /** + * Attached Ed25519 signature. (Returns a signed message.) + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $message + * @param string $sk + * @return string + */ + public static function sign($message, $sk) + { + return ParagonIE_Sodium_Core_Ed25519::sign($message, $sk); + } + + /** + * Opens a signed message. If valid, returns the message. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $signedMessage + * @param string $pk + * @return string + */ + public static function sign_open($signedMessage, $pk) + { + return ParagonIE_Sodium_Core_Ed25519::sign_open($signedMessage, $pk); + } + + /** + * Verify a detached signature of a given message and public key. + * + * @internal Do not use this directly. Use ParagonIE_Sodium_Compat. + * + * @param string $signature + * @param string $message + * @param string $pk + * @return bool + */ + public static function sign_verify_detached($signature, $message, $pk) + { + return ParagonIE_Sodium_Core_Ed25519::verify_detached($signature, $message, $pk); + } +} diff --git a/libraries/vendor/paragonie/sodium_compat/src/File.php b/libraries/vendor/paragonie/sodium_compat/src/File.php new file mode 100644 index 0000000000000..f787662890091 --- /dev/null +++ b/libraries/vendor/paragonie/sodium_compat/src/File.php @@ -0,0 +1,1041 @@ + ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_KEYBYTES_MAX) { + throw new TypeError('Argument 2 must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes'); + } + } + if ($outputLength < ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MIN) { + throw new Error('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MIN'); + } + if ($outputLength > ParagonIE_Sodium_Compat::CRYPTO_GENERICHASH_BYTES_MAX) { + throw new Error('Argument 3 must be at least CRYPTO_GENERICHASH_BYTES_MAX'); + } + + /** @var int $size */ + $size = filesize($filePath); + if (!is_int($size)) { + throw new Error('Could not obtain the file size'); + } + + /** @var resource $fp */ + $fp = fopen($filePath, 'rb'); + if (!is_resource($fp)) { + throw new Error('Could not open input file for reading'); + } + $ctx = ParagonIE_Sodium_Compat::crypto_generichash_init($key, $outputLength); + while ($size > 0) { + $blockSize = $size > 64 + ? 64 + : $size; + ParagonIE_Sodium_Compat::crypto_generichash_update($ctx, fread($fp, $blockSize)); + $size -= $blockSize; + } + + fclose($fp); + return ParagonIE_Sodium_Compat::crypto_generichash_final($ctx, $outputLength); + } + + /** + * Encrypt a file (rather than a string). Uses less memory than + * ParagonIE_Sodium_Compat::crypto_secretbox(), but produces + * the same result. + * + * @param string $inputFile Absolute path to a file on the filesystem + * @param string $outputFile Absolute path to a file on the filesystem + * @param string $nonce Number to be used only once + * @param string $key Encryption key + * + * @return bool + * @throws Error + * @throws TypeError + */ + public static function secretbox($inputFile, $outputFile, $nonce, $key) + { + /* Type checks: */ + if (!is_string($inputFile)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given..'); + } + if (!is_string($outputFile)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); + } + + /* Input validation: */ + if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new TypeError('Argument 3 must be CRYPTO_SECRETBOX_NONCEBYTES bytes'); + } + if (!is_string($key)) { + throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); + } + if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) { + throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_KEYBYTES bytes'); + } + + /** @var int $size */ + $size = filesize($inputFile); + if (!is_int($size)) { + throw new Error('Could not obtain the file size'); + } + + /** @var resource $ifp */ + $ifp = fopen($inputFile, 'rb'); + if (!is_resource($ifp)) { + throw new Error('Could not open input file for reading'); + } + + /** @var resource $ofp */ + $ofp = fopen($outputFile, 'wb'); + if (!is_resource($ofp)) { + fclose($ifp); + throw new Error('Could not open output file for writing'); + } + + $res = self::secretbox_encrypt($ifp, $ofp, $size, $nonce, $key); + fclose($ifp); + fclose($ofp); + return $res; + } + /** + * Seal a file (rather than a string). Uses less memory than + * ParagonIE_Sodium_Compat::crypto_secretbox_open(), but produces + * the same result. + * + * Warning: Does not protect against TOCTOU attacks. You should + * just load the file into memory and use crypto_secretbox_open() if + * you are worried about those. + * + * @param string $inputFile + * @param string $outputFile + * @param string $nonce + * @param string $key + * @return bool + * @throws Error + * @throws TypeError + */ + public static function secretbox_open($inputFile, $outputFile, $nonce, $key) + { + /* Type checks: */ + if (!is_string($inputFile)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($inputFile) . ' given.'); + } + if (!is_string($outputFile)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($outputFile) . ' given.'); + } + if (!is_string($nonce)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($nonce) . ' given.'); + } + if (!is_string($key)) { + throw new TypeError('Argument 4 must be a string, ' . gettype($key) . ' given.'); + } + + /* Input validation: */ + if (self::strlen($nonce) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_NONCEBYTES) { + throw new TypeError('Argument 4 must be CRYPTO_SECRETBOX_NONCEBYTES bytes'); + } + if (self::strlen($key) !== ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_KEYBYTES) { + throw new TypeError('Argument 4 must be CRYPTO_SECRETBOXBOX_KEYBYTES bytes'); + } + + /** @var int $size */ + $size = filesize($inputFile); + if (!is_int($size)) { + throw new Error('Could not obtain the file size'); + } + + /** @var resource $ifp */ + $ifp = fopen($inputFile, 'rb'); + if (!is_resource($ifp)) { + throw new Error('Could not open input file for reading'); + } + + /** @var resource $ofp */ + $ofp = fopen($outputFile, 'wb'); + if (!is_resource($ofp)) { + fclose($ifp); + throw new Error('Could not open output file for writing'); + } + + $res = self::secretbox_decrypt($ifp, $ofp, $size, $nonce, $key); + fclose($ifp); + fclose($ofp); + try { + ParagonIE_Sodium_Compat::memzero($key); + } catch (Error $ex) { + unset($key); + } + return $res; + } + + /** + * Sign a file (rather than a string). Uses less memory than + * ParagonIE_Sodium_Compat::crypto_sign_detached(), but produces + * the same result. + * + * @param string $filePath Absolute path to a file on the filesystem + * @param string $secretKey Secret signing key + * + * @return string Ed25519 signature + * @throws Error + * @throws TypeError + */ + public static function sign($filePath, $secretKey) + { + /* Type checks: */ + if (!is_string($filePath)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($filePath) . ' given.'); + } + if (!is_string($secretKey)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($secretKey) . ' given.'); + } + + /* Input validation: */ + if (self::strlen($secretKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_SECRETKEYBYTES) { + throw new TypeError('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES bytes'); + } + + /** @var int $size */ + $size = filesize($filePath); + if (!is_int($size)) { + throw new Error('Could not obtain the file size'); + } + + /** @var resource $fp */ + $fp = fopen($filePath, 'rb'); + if (!is_resource($fp)) { + throw new Error('Could not open input file for reading'); + } + + /** @var string $az */ + $az = hash('sha512', self::substr($secretKey, 0, 32), true); + + $az[0] = self::intToChr(self::chrToInt($az[0]) & 248); + $az[31] = self::intToChr((self::chrToInt($az[31]) & 63) | 64); + + /** @var resource $hs */ + $hs = hash_init('sha512'); + hash_update($hs, self::substr($az, 32, 32)); + $hs = self::updateHashWithFile($hs, $fp, $size); + + /** @var string $nonceHash */ + $nonceHash = hash_final($hs, true); + + /** @var string $pk */ + $pk = self::substr($secretKey, 32, 32); + + /** @var string $nonce */ + $nonce = ParagonIE_Sodium_Core_Ed25519::sc_reduce($nonceHash) . self::substr($nonceHash, 32); + + /** @var string $sig */ + $sig = ParagonIE_Sodium_Core_Ed25519::ge_p3_tobytes( + ParagonIE_Sodium_Core_Ed25519::ge_scalarmult_base($nonce) + ); + + /** @var resource $hs */ + $hs = hash_init('sha512'); + hash_update($hs, self::substr($sig, 0, 32)); + hash_update($hs, self::substr($pk, 0, 32)); + $hs = self::updateHashWithFile($hs, $fp, $size); + + /** @var string $hramHash */ + $hramHash = hash_final($hs, true); + + /** @var string $hram */ + $hram = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hramHash); + + /** @var string $sigAfter */ + $sigAfter = ParagonIE_Sodium_Core_Ed25519::sc_muladd($hram, $az, $nonce); + + /** @var string $sig */ + $sig = self::substr($sig, 0, 32) . self::substr($sigAfter, 0, 32); + + try { + ParagonIE_Sodium_Compat::memzero($az); + } catch (Error $ex) { + $az = null; + } + fclose($fp); + return $sig; + } + + /** + * Verify a file (rather than a string). Uses less memory than + * ParagonIE_Sodium_Compat::crypto_sign_verify_detached(), but + * produces the same result. + * + * @param string $sig Ed25519 signature + * @param string $filePath Absolute path to a file on the filesystem + * @param string $publicKey Signing public key + * + * @return bool + * @throws Error + * @throws Exception + */ + public static function verify($sig, $filePath, $publicKey) + { + /* Type checks: */ + if (!is_string($sig)) { + throw new TypeError('Argument 1 must be a string, ' . gettype($sig) . ' given.'); + } + if (!is_string($filePath)) { + throw new TypeError('Argument 2 must be a string, ' . gettype($filePath) . ' given.'); + } + if (!is_string($publicKey)) { + throw new TypeError('Argument 3 must be a string, ' . gettype($publicKey) . ' given.'); + } + + /* Input validation: */ + if (self::strlen($sig) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_BYTES) { + throw new TypeError('Argument 1 must be CRYPTO_SIGN_BYTES bytes'); + } + if (self::strlen($publicKey) !== ParagonIE_Sodium_Compat::CRYPTO_SIGN_PUBLICKEYBYTES) { + throw new TypeError('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES bytes'); + } + if (self::strlen($sig) < 64) { + throw new Exception('Signature is too short'); + } + + /* Security checks */ + if (ParagonIE_Sodium_Core_Ed25519::check_S_lt_L(self::substr($sig, 32, 32))) { + throw new Exception('S < L - Invalid signature'); + } + if (ParagonIE_Sodium_Core_Ed25519::small_order($sig)) { + throw new Exception('Signature is on too small of an order'); + } + if ((self::chrToInt($sig[63]) & 224) !== 0) { + throw new Exception('Invalid signature'); + } + $d = 0; + for ($i = 0; $i < 32; ++$i) { + $d |= self::chrToInt($publicKey[$i]); + } + if ($d === 0) { + throw new Exception('All zero public key'); + } + + /** @var int $size */ + $size = filesize($filePath); + if (!is_int($size)) { + throw new Error('Could not obtain the file size'); + } + + /** @var resource $fp */ + $fp = fopen($filePath, 'rb'); + if (!is_resource($fp)) { + throw new Error('Could not open input file for reading'); + } + + /** @var bool The original value of ParagonIE_Sodium_Compat::$fastMult */ + $orig = ParagonIE_Sodium_Compat::$fastMult; + + // Set ParagonIE_Sodium_Compat::$fastMult to true to speed up verification. + ParagonIE_Sodium_Compat::$fastMult = true; + + /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P3 $A */ + $A = ParagonIE_Sodium_Core_Ed25519::ge_frombytes_negate_vartime($publicKey); + + /** @var resource $hs */ + $hs = hash_init('sha512'); + hash_update($hs, self::substr($sig, 0, 32)); + hash_update($hs, self::substr($publicKey, 0, 32)); + $hs = self::updateHashWithFile($hs, $fp, $size); + /** @var string $hDigest */ + $hDigest = hash_final($hs, true); + + /** @var string $h */ + $h = ParagonIE_Sodium_Core_Ed25519::sc_reduce($hDigest) . self::substr($hDigest, 32); + + /** @var ParagonIE_Sodium_Core_Curve25519_Ge_P2 $R */ + $R = ParagonIE_Sodium_Core_Ed25519::ge_double_scalarmult_vartime( + $h, + $A, + self::substr($sig, 32) + ); + + /** @var string $rcheck */ + $rcheck = ParagonIE_Sodium_Core_Ed25519::ge_tobytes($R); + + // Close the file handle + fclose($fp); + + // Reset ParagonIE_Sodium_Compat::$fastMult to what it was before. + ParagonIE_Sodium_Compat::$fastMult = $orig; + return self::verify_32($rcheck, self::substr($sig, 0, 32)); + } + + /** + * @param resource $ifp + * @param resource $ofp + * @param int $mlen + * @param string $nonce + * @param string $boxKeypair + * @return bool + */ + protected static function box_encrypt($ifp, $ofp, $mlen, $nonce, $boxKeypair) + { + return self::secretbox_encrypt( + $ifp, + $ofp, + $mlen, + $nonce, + ParagonIE_Sodium_Crypto::box_beforenm( + ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair), + ParagonIE_Sodium_Crypto::box_publickey($boxKeypair) + ) + ); + } + + + /** + * @param resource $ifp + * @param resource $ofp + * @param int $mlen + * @param string $nonce + * @param string $boxKeypair + * @return bool + */ + protected static function box_decrypt($ifp, $ofp, $mlen, $nonce, $boxKeypair) + { + return self::secretbox_decrypt( + $ifp, + $ofp, + $mlen, + $nonce, + ParagonIE_Sodium_Crypto::box_beforenm( + ParagonIE_Sodium_Crypto::box_secretkey($boxKeypair), + ParagonIE_Sodium_Crypto::box_publickey($boxKeypair) + ) + ); + } + + /** + * Encrypt a file + * + * @param resource $ifp + * @param resource $ofp + * @param int $mlen + * @param string $nonce + * @param string $key + * @return bool + */ + protected static function secretbox_encrypt($ifp, $ofp, $mlen, $nonce, $key) + { + $plaintext = fread($ifp, 32); + $first32 = ftell($ifp); + + /** @var string $subkey */ + $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); + + /** @var string $realNonce */ + $realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + + /** @var string $block0 */ + $block0 = str_repeat("\x00", 32); + + /** @var int $mlen - Length of the plaintext message */ + $mlen0 = $mlen; + if ($mlen0 > 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES) { + $mlen0 = 64 - ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES; + } + $block0 .= ParagonIE_Sodium_Core_Util::substr($plaintext, 0, $mlen0); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20_xor( + $block0, + $realNonce, + $subkey + ); + + $state = new ParagonIE_Sodium_Core_Poly1305_State( + ParagonIE_Sodium_Core_Util::substr( + $block0, + 0, + ParagonIE_Sodium_Crypto::onetimeauth_poly1305_KEYBYTES + ) + ); + + // Pre-write 16 blank bytes for the Poly1305 tag + $start = ftell($ofp); + fwrite($ofp, str_repeat("\x00", 16)); + + /** @var string $c */ + $cBlock = ParagonIE_Sodium_Core_Util::substr( + $block0, + ParagonIE_Sodium_Crypto::secretbox_xsalsa20poly1305_ZEROBYTES + ); + $state->update($cBlock); + fwrite($ofp, $cBlock); + $mlen -= 32; + + /** @var int $iter */ + $iter = 1; + + /** @var int $incr */ + $incr = self::BUFFER_SIZE >> 6; + + /* + * Set the cursor to the end of the first half-block. All future bytes will + * generated from salsa20_xor_ic, starting from 1 (second block). + */ + fseek($ifp, $first32, SEEK_SET); + + while ($mlen > 0) { + $blockSize = $mlen > self::BUFFER_SIZE + ? self::BUFFER_SIZE + : $mlen; + $plaintext = fread($ifp, $blockSize); + $cBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( + $plaintext, + $realNonce, + $iter, + $subkey + ); + fwrite($ofp, $cBlock, $blockSize); + $state->update($cBlock); + + $mlen -= $blockSize; + $iter += $incr; + } + try { + ParagonIE_Sodium_Compat::memzero($block0); + ParagonIE_Sodium_Compat::memzero($subkey); + } catch (Error $ex) { + $block0 = null; + $subkey = null; + } + $end = ftell($ofp); + + /* + * Write the Poly1305 authentication tag that provides integrity + * over the ciphertext (encrypt-then-MAC) + */ + fseek($ofp, $start, SEEK_SET); + fwrite($ofp, $state->finish(), ParagonIE_Sodium_Compat::CRYPTO_SECRETBOX_MACBYTES); + fseek($ofp, $end, SEEK_SET); + unset($state); + + return true; + } + + /** + * Decrypt a file + * + * @param resource $ifp + * @param resource $ofp + * @param int $mlen + * @param string $nonce + * @param string $key + * @return bool + * @throws Exception + */ + protected static function secretbox_decrypt($ifp, $ofp, $mlen, $nonce, $key) + { + $tag = fread($ifp, 16); + + /** @var string $subkey */ + $subkey = ParagonIE_Sodium_Core_HSalsa20::hsalsa20($nonce, $key); + + /** @var string $realNonce */ + $realNonce = ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8); + + /** @var string $block0 */ + $block0 = ParagonIE_Sodium_Core_Salsa20::salsa20( + 64, + ParagonIE_Sodium_Core_Util::substr($nonce, 16, 8), + $subkey + ); + + /* Verify the Poly1305 MAC -before- attempting to decrypt! */ + $state = new ParagonIE_Sodium_Core_Poly1305_State(self::substr($block0, 0, 32)); + if (!self::onetimeauth_verify($state, $ifp, $tag, $mlen)) { + throw new Exception('Invalid MAC'); + } + + /* + * Set the cursor to the end of the first half-block. All future bytes will + * generated from salsa20_xor_ic, starting from 1 (second block). + */ + $first32 = fread($ifp, 32); + $first32len = self::strlen($first32); + fwrite( + $ofp, + self::xorStrings( + self::substr($block0, 32, $first32len), + self::substr($first32, 0, $first32len) + ) + ); + $mlen -= 32; + + /** @var int $iter */ + $iter = 1; + + /** @var int $incr */ + $incr = self::BUFFER_SIZE >> 6; + + /* Decrypts ciphertext, writes to output file. */ + while ($mlen > 0) { + $blockSize = $mlen > self::BUFFER_SIZE + ? self::BUFFER_SIZE + : $mlen; + $ciphertext = fread($ifp, $blockSize); + $pBlock = ParagonIE_Sodium_Core_Salsa20::salsa20_xor_ic( + $ciphertext, + $realNonce, + $iter, + $subkey + ); + fwrite($ofp, $pBlock, $blockSize); + $mlen -= $blockSize; + $iter += $incr; + } + return true; + } + + /** + * @param ParagonIE_Sodium_Core_Poly1305_State $state + * @param resource $ifp + * @param string $tag + * @param int $mlen + * @return bool + */ + protected static function onetimeauth_verify(ParagonIE_Sodium_Core_Poly1305_State $state, $ifp, $tag = '', $mlen = 0) + { + /** @var int $pos */ + $pos = ftell($ifp); + + /** @var int $iter */ + $iter = 1; + + /** @var int $incr */ + $incr = self::BUFFER_SIZE >> 6; + + while ($mlen > 0) { + $blockSize = $mlen > self::BUFFER_SIZE + ? self::BUFFER_SIZE + : $mlen; + $ciphertext = fread($ifp, $blockSize); + $state->update($ciphertext); + $mlen -= $blockSize; + $iter += $incr; + } + $res = ParagonIE_Sodium_Core_Util::verify_16($tag, $state->finish()); + + fseek($ifp, $pos, SEEK_SET); + return $res; + } + + /** + * Update a hash context with the contents of a file, without + * loading the entire file into memory. + * + * @param resource $hash + * @param resource $fp + * @param int $size + * @return resource + * @throws Error + * @throws TypeError + */ + public static function updateHashWithFile($hash, $fp, $size = 0) + { + /* Type checks: */ + if (!is_resource($hash)) { + throw new TypeError('Argument 1 must be a resource, ' . gettype($hash) . ' given.'); + } + if (!is_resource($fp)) { + throw new TypeError('Argument 2 must be a resource, ' . gettype($fp) . ' given.'); + } + if (!is_int($size)) { + throw new TypeError('Argument 3 must be an integer, ' . gettype($size) . ' given.'); + } + + /** @var int $originalPosition */ + $originalPosition = ftell($fp); + + // Move file pointer to beginning of file + fseek($fp, 0, SEEK_SET); + for ($i = 0; $i < $size; $i += self::BUFFER_SIZE) { + /** @var string $message */ + $message = fread( + $fp, + ($size - $i) > self::BUFFER_SIZE + ? $size - $i + : self::BUFFER_SIZE + ); + if (!is_string($message)) { + throw new Error('Unexpected error reading from file.'); + } + hash_update($hash, $message); + } + // Reset file pointer's position + fseek($fp, $originalPosition, SEEK_SET); + return $hash; + } +} diff --git a/tests/unit/suites/libraries/joomla/crypt/cipher/JCryptCipherSodiumTest.php b/tests/unit/suites/libraries/joomla/crypt/cipher/JCryptCipherSodiumTest.php new file mode 100644 index 0000000000000..ebc0b7a4a85c0 --- /dev/null +++ b/tests/unit/suites/libraries/joomla/crypt/cipher/JCryptCipherSodiumTest.php @@ -0,0 +1,81 @@ +{DJzOHMCv_<#yKuN/G`/Us{GkgicWG$M|HW;kI0BVZ^|FY/"Obt53?PNaWwhmRtH;lWkWE4vlG5CIFA!abu&F=Xo#Qw}gAp3;GL\'k])%D}C+W&ne6_F$3P5'), + array('Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ' . + 'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor ' . + 'in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt ' . + 'in culpa qui officia deserunt mollit anim id est laborum.'), + array('لا أحد يحب الألم بذاته، يسعى ورائه أو يبتغيه، ببساطة لأنه الألم...'), + array('Широкая электрификация южных губерний даст мощный толчок подъёму сельского хозяйства'), + array('The quick brown fox jumps over the lazy dog.') + ); + } + + /** + * @testdox Validates data is encrypted and decrypted correctly + * + * @param string $data The decrypted data to validate + * + * @covers JCryptCipherSodium::decrypt + * @covers JCryptCipherSodium::encrypt + * @dataProvider dataStrings + */ + public function testDataEncryptionAndDecryption($data) + { + $cipher = new JCryptCipherSodium; + $key = $cipher->generateKey(); + + $cipher->setNonce(\Sodium\randombytes_buf(\Sodium\CRYPTO_BOX_NONCEBYTES)); + + $encrypted = $cipher->encrypt($data, $key); + + // Assert that the encrypted value is not the same as the clear text value. + $this->assertNotSame($data, $encrypted); + + $decrypted = $cipher->decrypt($encrypted, $key); + + // Assert the decrypted string is the same value we started with + $this->assertSame($data, $decrypted); + } + + /** + * @testdox Validates keys are correctly generated + * + * @covers JCryptCipherSodium::generateKey + */ + public function testGenerateKey() + { + $cipher = new JCryptCipherSodium; + $key = $cipher->generateKey(); + + // Assert that the key is the correct type. + $this->assertInstanceOf('JCryptKey', $key); + + // Assert the keys pass validation + $this->assertSame(JCrypt::safeStrlen($key->private), 32); + $this->assertSame(JCrypt::safeStrlen($key->public), 32); + + // Assert the key is of the correct type. + $this->assertAttributeEquals('sodium', 'type', $key); + } +}