From ede20ac95a5d53e5407d114548b9b4ac0f20d7de Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 9 Nov 2017 02:11:33 -0500 Subject: [PATCH 1/7] Updated Composer to version 1.5.2 --- util/composer.phar | Bin 1836198 -> 1852323 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/util/composer.phar b/util/composer.phar index 357793176e3b45854af3c8e201bcd3e1b169bbef..508f9cf274be7a7526630f9ef01c183e6b17612f 100755 GIT binary patch delta 31653 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 Uf8YP^Qbip8$F6xAxl#WA0PLWYm;e9( From 3b2cd854837e5df38f75f323aab24e31098812d4 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 9 Nov 2017 02:13:02 -0500 Subject: [PATCH 2/7] Add defuse/php-encryption 2.0 to Composer dependencies --- composer.json | 1 + composer.lock | 113 ++- vendor/bin/generate-defuse-key | 17 + vendor/bin/generate-defuse-key.bat | 4 + vendor/composer/autoload_classmap.php | 19 + vendor/composer/autoload_files.php | 1 + vendor/composer/autoload_psr4.php | 1 + vendor/composer/autoload_static.php | 28 + vendor/composer/installed.json | 115 +++ vendor/defuse/php-encryption/.gitignore | 11 + vendor/defuse/php-encryption/.php_cs | 60 ++ vendor/defuse/php-encryption/LICENSE | 21 + vendor/defuse/php-encryption/README.md | 88 ++ .../php-encryption/bin/generate-defuse-key | 14 + vendor/defuse/php-encryption/composer.json | 35 + vendor/defuse/php-encryption/dist/Makefile | 37 + vendor/defuse/php-encryption/dist/box.json | 25 + .../defuse/php-encryption/dist/signingkey.asc | 52 ++ .../php-encryption/docs/CryptoDetails.md | 64 ++ vendor/defuse/php-encryption/docs/FAQ.md | 39 + .../docs/InstallingAndVerifying.md | 53 ++ .../docs/InternalDeveloperDocs.md | 160 ++++ vendor/defuse/php-encryption/docs/Tutorial.md | 298 +++++++ .../php-encryption/docs/UpgradingFromV1.2.md | 51 ++ .../php-encryption/docs/classes/Crypto.md | 260 ++++++ .../php-encryption/docs/classes/File.md | 446 ++++++++++ .../defuse/php-encryption/docs/classes/Key.md | 117 +++ .../docs/classes/KeyProtectedByPassword.md | 191 +++++ vendor/defuse/php-encryption/psalm.xml | 9 + vendor/defuse/php-encryption/src/Core.php | 446 ++++++++++ vendor/defuse/php-encryption/src/Crypto.php | 393 +++++++++ .../defuse/php-encryption/src/DerivedKeys.php | 50 ++ vendor/defuse/php-encryption/src/Encoding.php | 270 ++++++ .../src/Exception/BadFormatException.php | 7 + .../src/Exception/CryptoException.php | 7 + .../EnvironmentIsBrokenException.php | 7 + .../src/Exception/IOException.php | 7 + .../WrongKeyOrModifiedCiphertextException.php | 7 + vendor/defuse/php-encryption/src/File.php | 784 ++++++++++++++++++ vendor/defuse/php-encryption/src/Key.php | 95 +++ .../php-encryption/src/KeyOrPassword.php | 133 +++ .../src/KeyProtectedByPassword.php | 115 +++ .../php-encryption/src/RuntimeTests.php | 247 ++++++ vendor/paragonie/random_compat/LICENSE | 22 + vendor/paragonie/random_compat/build-phar.sh | 5 + vendor/paragonie/random_compat/composer.json | 37 + .../dist/random_compat.phar.pubkey | 5 + .../dist/random_compat.phar.pubkey.asc | 11 + .../random_compat/lib/byte_safe_strings.php | 181 ++++ .../random_compat/lib/cast_to_int.php | 75 ++ .../random_compat/lib/error_polyfill.php | 49 ++ vendor/paragonie/random_compat/lib/random.php | 223 +++++ .../lib/random_bytes_com_dotnet.php | 88 ++ .../lib/random_bytes_dev_urandom.php | 167 ++++ .../lib/random_bytes_libsodium.php | 88 ++ .../lib/random_bytes_libsodium_legacy.php | 92 ++ .../random_compat/lib/random_bytes_mcrypt.php | 77 ++ .../random_compat/lib/random_int.php | 190 +++++ .../random_compat/other/build_phar.php | 57 ++ .../random_compat/psalm-autoload.php | 9 + vendor/paragonie/random_compat/psalm.xml | 16 + 61 files changed, 6289 insertions(+), 1 deletion(-) create mode 100644 vendor/bin/generate-defuse-key create mode 100644 vendor/bin/generate-defuse-key.bat create mode 100644 vendor/defuse/php-encryption/.gitignore create mode 100644 vendor/defuse/php-encryption/.php_cs create mode 100644 vendor/defuse/php-encryption/LICENSE create mode 100644 vendor/defuse/php-encryption/README.md create mode 100644 vendor/defuse/php-encryption/bin/generate-defuse-key create mode 100644 vendor/defuse/php-encryption/composer.json create mode 100644 vendor/defuse/php-encryption/dist/Makefile create mode 100644 vendor/defuse/php-encryption/dist/box.json create mode 100644 vendor/defuse/php-encryption/dist/signingkey.asc create mode 100644 vendor/defuse/php-encryption/docs/CryptoDetails.md create mode 100644 vendor/defuse/php-encryption/docs/FAQ.md create mode 100644 vendor/defuse/php-encryption/docs/InstallingAndVerifying.md create mode 100644 vendor/defuse/php-encryption/docs/InternalDeveloperDocs.md create mode 100644 vendor/defuse/php-encryption/docs/Tutorial.md create mode 100644 vendor/defuse/php-encryption/docs/UpgradingFromV1.2.md create mode 100644 vendor/defuse/php-encryption/docs/classes/Crypto.md create mode 100644 vendor/defuse/php-encryption/docs/classes/File.md create mode 100644 vendor/defuse/php-encryption/docs/classes/Key.md create mode 100644 vendor/defuse/php-encryption/docs/classes/KeyProtectedByPassword.md create mode 100644 vendor/defuse/php-encryption/psalm.xml create mode 100644 vendor/defuse/php-encryption/src/Core.php create mode 100644 vendor/defuse/php-encryption/src/Crypto.php create mode 100644 vendor/defuse/php-encryption/src/DerivedKeys.php create mode 100644 vendor/defuse/php-encryption/src/Encoding.php create mode 100644 vendor/defuse/php-encryption/src/Exception/BadFormatException.php create mode 100644 vendor/defuse/php-encryption/src/Exception/CryptoException.php create mode 100644 vendor/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php create mode 100644 vendor/defuse/php-encryption/src/Exception/IOException.php create mode 100644 vendor/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php create mode 100644 vendor/defuse/php-encryption/src/File.php create mode 100644 vendor/defuse/php-encryption/src/Key.php create mode 100644 vendor/defuse/php-encryption/src/KeyOrPassword.php create mode 100644 vendor/defuse/php-encryption/src/KeyProtectedByPassword.php create mode 100644 vendor/defuse/php-encryption/src/RuntimeTests.php create mode 100644 vendor/paragonie/random_compat/LICENSE create mode 100644 vendor/paragonie/random_compat/build-phar.sh create mode 100644 vendor/paragonie/random_compat/composer.json create mode 100644 vendor/paragonie/random_compat/dist/random_compat.phar.pubkey create mode 100644 vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc create mode 100644 vendor/paragonie/random_compat/lib/byte_safe_strings.php create mode 100644 vendor/paragonie/random_compat/lib/cast_to_int.php create mode 100644 vendor/paragonie/random_compat/lib/error_polyfill.php create mode 100644 vendor/paragonie/random_compat/lib/random.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php create mode 100644 vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php create mode 100644 vendor/paragonie/random_compat/lib/random_int.php create mode 100644 vendor/paragonie/random_compat/other/build_phar.php create mode 100644 vendor/paragonie/random_compat/psalm-autoload.php create mode 100644 vendor/paragonie/random_compat/psalm.xml diff --git a/composer.json b/composer.json index 0dca48c704..df63226bec 100644 --- a/composer.json +++ b/composer.json @@ -16,6 +16,7 @@ "ezyang/htmlpurifier": "~4.7.0", "mobiledetect/mobiledetectlib": "2.8.*", "league/html-to-markdown": "~4.4.1", + "defuse/php-encryption": "2.*", "pear/Text_LanguageDetect": "1.*", "pear-pear.php.net/Text_Highlighter": "*" }, diff --git a/composer.lock b/composer.lock index 217898dde5..6f2bc8f118 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,71 @@ "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": "a87f82da9a0256ca85c839e83a5c26f0", + "content-hash": "ce088458d9f01920ccee128082ef924a", "packages": [ + { + "name": "defuse/php-encryption", + "version": "v2.1.0", + "source": { + "type": "git", + "url": "https://github.com/defuse/php-encryption.git", + "reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/defuse/php-encryption/zipball/5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", + "reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "paragonie/random_compat": "~2.0", + "php": ">=5.4.0" + }, + "require-dev": { + "nikic/php-parser": "^2.0|^3.0", + "phpunit/phpunit": "^4|^5" + }, + "bin": [ + "bin/generate-defuse-key" + ], + "type": "library", + "autoload": { + "psr-4": { + "Defuse\\Crypto\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Hornby", + "email": "taylor@defuse.ca", + "homepage": "https://defuse.ca/" + }, + { + "name": "Scott Arciszewski", + "email": "info@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "Secure PHP Encryption Library", + "keywords": [ + "aes", + "authenticated encryption", + "cipher", + "crypto", + "cryptography", + "encrypt", + "encryption", + "openssl", + "security", + "symmetric key cryptography" + ], + "time": "2017-05-18T21:28:48+00:00" + }, { "name": "ezyang/htmlpurifier", "version": "v4.7.0", @@ -166,6 +229,54 @@ ], "time": "2017-08-29T18:23:54+00:00" }, + { + "name": "paragonie/random_compat", + "version": "v2.0.11", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8", + "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "type": "library", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ], + "time": "2017-09-27T21:40:39+00:00" + }, { "name": "pear-pear.php.net/Archive_Tar", "version": "1.4.3", diff --git a/vendor/bin/generate-defuse-key b/vendor/bin/generate-defuse-key new file mode 100644 index 0000000000..68ef2cac32 --- /dev/null +++ b/vendor/bin/generate-defuse-key @@ -0,0 +1,17 @@ +#!/usr/bin/env sh + +dir=$(d=${0%[/\\]*}; cd "$d"; cd "../defuse/php-encryption/bin" && pwd) + +# See if we are running in Cygwin by checking for cygpath program +if command -v 'cygpath' >/dev/null 2>&1; then + # Cygwin paths start with /cygdrive/ which will break windows PHP, + # so we need to translate the dir path to windows format. However + # we could be using cygwin PHP which does not require this, so we + # test if the path to PHP starts with /cygdrive/ rather than /usr/bin + if [[ $(which php) == /cygdrive/* ]]; then + dir=$(cygpath -m "$dir"); + fi +fi + +dir=$(echo $dir | sed 's/ /\ /g') +"${dir}/generate-defuse-key" "$@" diff --git a/vendor/bin/generate-defuse-key.bat b/vendor/bin/generate-defuse-key.bat new file mode 100644 index 0000000000..50b5ac6774 --- /dev/null +++ b/vendor/bin/generate-defuse-key.bat @@ -0,0 +1,4 @@ +@ECHO OFF +setlocal DISABLEDELAYEDEXPANSION +SET BIN_TARGET=%~dp0/../defuse/php-encryption/bin/generate-defuse-key +php "%BIN_TARGET%" %* diff --git a/vendor/composer/autoload_classmap.php b/vendor/composer/autoload_classmap.php index 3c21b357b1..b3bd253936 100644 --- a/vendor/composer/autoload_classmap.php +++ b/vendor/composer/autoload_classmap.php @@ -8,13 +8,32 @@ $baseDir = dirname($vendorDir); return array( 'Archive_Tar' => $vendorDir . '/pear-pear.php.net/Archive_Tar/Archive/Tar.php', 'Console_Getopt' => $vendorDir . '/pear-pear.php.net/Console_Getopt/Console/Getopt.php', + 'Defuse\\Crypto\\Core' => $vendorDir . '/defuse/php-encryption/src/Core.php', + 'Defuse\\Crypto\\Crypto' => $vendorDir . '/defuse/php-encryption/src/Crypto.php', + 'Defuse\\Crypto\\DerivedKeys' => $vendorDir . '/defuse/php-encryption/src/DerivedKeys.php', + 'Defuse\\Crypto\\Encoding' => $vendorDir . '/defuse/php-encryption/src/Encoding.php', + 'Defuse\\Crypto\\Exception\\BadFormatException' => $vendorDir . '/defuse/php-encryption/src/Exception/BadFormatException.php', + 'Defuse\\Crypto\\Exception\\CryptoException' => $vendorDir . '/defuse/php-encryption/src/Exception/CryptoException.php', + 'Defuse\\Crypto\\Exception\\EnvironmentIsBrokenException' => $vendorDir . '/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php', + 'Defuse\\Crypto\\Exception\\IOException' => $vendorDir . '/defuse/php-encryption/src/Exception/IOException.php', + 'Defuse\\Crypto\\Exception\\WrongKeyOrModifiedCiphertextException' => $vendorDir . '/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php', + 'Defuse\\Crypto\\File' => $vendorDir . '/defuse/php-encryption/src/File.php', + 'Defuse\\Crypto\\Key' => $vendorDir . '/defuse/php-encryption/src/Key.php', + 'Defuse\\Crypto\\KeyOrPassword' => $vendorDir . '/defuse/php-encryption/src/KeyOrPassword.php', + 'Defuse\\Crypto\\KeyProtectedByPassword' => $vendorDir . '/defuse/php-encryption/src/KeyProtectedByPassword.php', + 'Defuse\\Crypto\\RuntimeTests' => $vendorDir . '/defuse/php-encryption/src/RuntimeTests.php', 'Detection\\MobileDetect' => $vendorDir . '/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php', 'Friendica\\App' => $baseDir . '/src/App.php', 'Friendica\\Core\\Config' => $baseDir . '/src/Core/Config.php', + 'Friendica\\Core\\NotificationsManager' => $baseDir . '/src/Core/NotificationsManager.php', 'Friendica\\Core\\PConfig' => $baseDir . '/src/Core/PConfig.php', 'Friendica\\Core\\System' => $baseDir . '/src/Core/System.php', + 'Friendica\\Core\\Worker' => $baseDir . '/src/Core/Worker.php', + 'Friendica\\Database\\DBM' => $baseDir . '/src/Database/DBM.php', 'Friendica\\Network\\Probe' => $baseDir . '/src/Network/Probe.php', 'Friendica\\ParseUrl' => $baseDir . '/src/ParseUrl.php', + 'Friendica\\Protocol\\DFRN' => $baseDir . '/src/Protocol/DFRN.php', + 'Friendica\\Protocol\\Diaspora' => $baseDir . '/src/Protocol/Diaspora.php', 'Friendica\\Util\\Lock' => $baseDir . '/src/Util/Lock.php', 'HTMLPurifier' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.php', 'HTMLPurifier_Arborize' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php', diff --git a/vendor/composer/autoload_files.php b/vendor/composer/autoload_files.php index c25686b153..f3c197e2be 100644 --- a/vendor/composer/autoload_files.php +++ b/vendor/composer/autoload_files.php @@ -6,5 +6,6 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname($vendorDir); return array( + '5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php', '2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', ); diff --git a/vendor/composer/autoload_psr4.php b/vendor/composer/autoload_psr4.php index 61a440ffdb..9c9cf98802 100644 --- a/vendor/composer/autoload_psr4.php +++ b/vendor/composer/autoload_psr4.php @@ -8,4 +8,5 @@ $baseDir = dirname($vendorDir); return array( 'League\\HTMLToMarkdown\\' => array($vendorDir . '/league/html-to-markdown/src'), 'Friendica\\' => array($baseDir . '/src'), + 'Defuse\\Crypto\\' => array($vendorDir . '/defuse/php-encryption/src'), ); diff --git a/vendor/composer/autoload_static.php b/vendor/composer/autoload_static.php index 2ccc848ef3..f560931d59 100644 --- a/vendor/composer/autoload_static.php +++ b/vendor/composer/autoload_static.php @@ -7,6 +7,7 @@ namespace Composer\Autoload; class ComposerStaticInitFriendica { public static $files = array ( + '5255c38a0faeba867671b61dfda6d864' => __DIR__ . '/..' . '/paragonie/random_compat/lib/random.php', '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php', ); @@ -19,6 +20,10 @@ class ComposerStaticInitFriendica array ( 'Friendica\\' => 10, ), + 'D' => + array ( + 'Defuse\\Crypto\\' => 14, + ), ); public static $prefixDirsPsr4 = array ( @@ -30,6 +35,10 @@ class ComposerStaticInitFriendica array ( 0 => __DIR__ . '/../..' . '/src', ), + 'Defuse\\Crypto\\' => + array ( + 0 => __DIR__ . '/..' . '/defuse/php-encryption/src', + ), ); public static $prefixesPsr0 = array ( @@ -59,13 +68,32 @@ class ComposerStaticInitFriendica public static $classMap = array ( 'Archive_Tar' => __DIR__ . '/..' . '/pear-pear.php.net/Archive_Tar/Archive/Tar.php', 'Console_Getopt' => __DIR__ . '/..' . '/pear-pear.php.net/Console_Getopt/Console/Getopt.php', + 'Defuse\\Crypto\\Core' => __DIR__ . '/..' . '/defuse/php-encryption/src/Core.php', + 'Defuse\\Crypto\\Crypto' => __DIR__ . '/..' . '/defuse/php-encryption/src/Crypto.php', + 'Defuse\\Crypto\\DerivedKeys' => __DIR__ . '/..' . '/defuse/php-encryption/src/DerivedKeys.php', + 'Defuse\\Crypto\\Encoding' => __DIR__ . '/..' . '/defuse/php-encryption/src/Encoding.php', + 'Defuse\\Crypto\\Exception\\BadFormatException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/BadFormatException.php', + 'Defuse\\Crypto\\Exception\\CryptoException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/CryptoException.php', + 'Defuse\\Crypto\\Exception\\EnvironmentIsBrokenException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/EnvironmentIsBrokenException.php', + 'Defuse\\Crypto\\Exception\\IOException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/IOException.php', + 'Defuse\\Crypto\\Exception\\WrongKeyOrModifiedCiphertextException' => __DIR__ . '/..' . '/defuse/php-encryption/src/Exception/WrongKeyOrModifiedCiphertextException.php', + 'Defuse\\Crypto\\File' => __DIR__ . '/..' . '/defuse/php-encryption/src/File.php', + 'Defuse\\Crypto\\Key' => __DIR__ . '/..' . '/defuse/php-encryption/src/Key.php', + 'Defuse\\Crypto\\KeyOrPassword' => __DIR__ . '/..' . '/defuse/php-encryption/src/KeyOrPassword.php', + 'Defuse\\Crypto\\KeyProtectedByPassword' => __DIR__ . '/..' . '/defuse/php-encryption/src/KeyProtectedByPassword.php', + 'Defuse\\Crypto\\RuntimeTests' => __DIR__ . '/..' . '/defuse/php-encryption/src/RuntimeTests.php', 'Detection\\MobileDetect' => __DIR__ . '/..' . '/mobiledetect/mobiledetectlib/namespaced/Detection/MobileDetect.php', 'Friendica\\App' => __DIR__ . '/../..' . '/src/App.php', 'Friendica\\Core\\Config' => __DIR__ . '/../..' . '/src/Core/Config.php', + 'Friendica\\Core\\NotificationsManager' => __DIR__ . '/../..' . '/src/Core/NotificationsManager.php', 'Friendica\\Core\\PConfig' => __DIR__ . '/../..' . '/src/Core/PConfig.php', 'Friendica\\Core\\System' => __DIR__ . '/../..' . '/src/Core/System.php', + 'Friendica\\Core\\Worker' => __DIR__ . '/../..' . '/src/Core/Worker.php', + 'Friendica\\Database\\DBM' => __DIR__ . '/../..' . '/src/Database/DBM.php', 'Friendica\\Network\\Probe' => __DIR__ . '/../..' . '/src/Network/Probe.php', 'Friendica\\ParseUrl' => __DIR__ . '/../..' . '/src/ParseUrl.php', + 'Friendica\\Protocol\\DFRN' => __DIR__ . '/../..' . '/src/Protocol/DFRN.php', + 'Friendica\\Protocol\\Diaspora' => __DIR__ . '/../..' . '/src/Protocol/Diaspora.php', 'Friendica\\Util\\Lock' => __DIR__ . '/../..' . '/src/Util/Lock.php', 'HTMLPurifier' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.php', 'HTMLPurifier_Arborize' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php', diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 2424ae9bec..02d5f612c1 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -442,5 +442,120 @@ ], "description": "Identify human languages from text samples", "homepage": "http://pear.php.net/package/Text_LanguageDetect" + }, + { + "name": "paragonie/random_compat", + "version": "v2.0.11", + "version_normalized": "2.0.11.0", + "source": { + "type": "git", + "url": "https://github.com/paragonie/random_compat.git", + "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/5da4d3c796c275c55f057af5a643ae297d96b4d8", + "reference": "5da4d3c796c275c55f057af5a643ae297d96b4d8", + "shasum": "" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "time": "2017-09-27T21:40:39+00:00", + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "lib/random.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "pseudorandom", + "random" + ] + }, + { + "name": "defuse/php-encryption", + "version": "v2.1.0", + "version_normalized": "2.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/defuse/php-encryption.git", + "reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/defuse/php-encryption/zipball/5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", + "reference": "5176f5abb38d3ea8a6e3ac6cd3bbb54d8185a689", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "paragonie/random_compat": "~2.0", + "php": ">=5.4.0" + }, + "require-dev": { + "nikic/php-parser": "^2.0|^3.0", + "phpunit/phpunit": "^4|^5" + }, + "time": "2017-05-18T21:28:48+00:00", + "bin": [ + "bin/generate-defuse-key" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "Defuse\\Crypto\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Hornby", + "email": "taylor@defuse.ca", + "homepage": "https://defuse.ca/" + }, + { + "name": "Scott Arciszewski", + "email": "info@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "description": "Secure PHP Encryption Library", + "keywords": [ + "aes", + "authenticated encryption", + "cipher", + "crypto", + "cryptography", + "encrypt", + "encryption", + "openssl", + "security", + "symmetric key cryptography" + ] } ] diff --git a/vendor/defuse/php-encryption/.gitignore b/vendor/defuse/php-encryption/.gitignore new file mode 100644 index 0000000000..987c516453 --- /dev/null +++ b/vendor/defuse/php-encryption/.gitignore @@ -0,0 +1,11 @@ +*~ +/test/unit/File/big-generated-file +/composer.lock +/vendor +defuse-crypto.phar +defuse-crypto.phar.sig +composer.phar +box.phar +phpunit.phar +phpunit.phar.asc +test/unit/File/tmp diff --git a/vendor/defuse/php-encryption/.php_cs b/vendor/defuse/php-encryption/.php_cs new file mode 100644 index 0000000000..e317732de4 --- /dev/null +++ b/vendor/defuse/php-encryption/.php_cs @@ -0,0 +1,60 @@ +level(Symfony\CS\FixerInterface::PSR2_LEVEL) + ->fixers([ + 'blankline_after_open_tag', + 'empty_return', + 'extra_empty_lines', + 'function_typehint_space', + 'join_function', + 'method_argument_default_value', + 'multiline_array_trailing_comma', + 'no_blank_lines_after_class_opening', + 'no_empty_lines_after_phpdocs', + 'phpdoc_indent', + 'phpdoc_no_access', + 'phpdoc_no_empty_return', + 'phpdoc_no_package', + 'phpdoc_params', + 'phpdoc_scalar', + 'phpdoc_separation', + 'phpdoc_trim', + 'phpdoc_type_to_var', + 'phpdoc_types', + 'phpdoc_var_without_name', + 'remove_leading_slash_use', + 'remove_lines_between_uses', + 'short_bool_cast', + 'single_quote', + 'spaces_after_semicolon', + 'spaces_before_semicolon', + 'spaces_cast', + 'standardize_not_equal', + 'ternary_spaces', + 'trim_array_spaces', + 'unneeded_control_parentheses', + 'unused_use', + 'whitespacy_lines', + 'align_double_arrow', + 'concat_with_spaces', + 'logical_not_operators_with_successor_space', + 'multiline_spaces_before_semicolon', + 'newline_after_open_tag', + 'ordered_use', + 'php_unit_construct', + 'phpdoc_order', + 'short_array_syntax', + ]); + +if (null === $input->getArgument('path')) { + $config + ->finder( + Symfony\CS\Finder\DefaultFinder::create() + ->in('src') + ->in('test') + ->exclude('vendor') + ); +} + +return $config; diff --git a/vendor/defuse/php-encryption/LICENSE b/vendor/defuse/php-encryption/LICENSE new file mode 100644 index 0000000000..f3e7c8e606 --- /dev/null +++ b/vendor/defuse/php-encryption/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Taylor Hornby and Paragon Initiative +Enterprises . + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/defuse/php-encryption/README.md b/vendor/defuse/php-encryption/README.md new file mode 100644 index 0000000000..a8f29258d3 --- /dev/null +++ b/vendor/defuse/php-encryption/README.md @@ -0,0 +1,88 @@ +php-encryption +=============== + +[![Build Status](https://travis-ci.org/defuse/php-encryption.svg?branch=master)](https://travis-ci.org/defuse/php-encryption) + +This is a library for encrypting data with a key or password in PHP. **It +requires PHP 5.4 or newer.** The current version is v2.0.0, which is expected to +remain stable and supported by its authors with security and bugfixes until at +least January 1st, 2019. + +The library is a joint effort between [Taylor Hornby](https://defuse.ca/) and +[Scott Arciszewski](https://paragonie.com/blog/author/scott-arcizewski) as well +as numerous open-source contributors. + +What separates this library from other PHP encryption libraries is, firstly, +that it is secure. The authors used to encounter insecure PHP encryption code on +a daily basis, so they created this library to bring more security to the +ecosystem. Secondly, this library is "difficult to misuse." Like +[libsodium](https://github.com/jedisct1/libsodium), its API is designed to be +easy to use in a secure way and hard to use in an insecure way. + +Dependencies +------------ + +This library requres no special dependencies except for PHP 5.4 or newer with +the OpenSSL extensions enabled (this is the default). It uses +[random\_compat](https://github.com/paragonie/random_compat), which is bundled +in with this library so that your users will not need to follow any special +installation steps. + +Getting Started +---------------- + +Start with the [**Tutorial**](docs/Tutorial.md). You can find instructions for +obtaining this library's code securely in the [Installing and +Verifying](docs/InstallingAndVerifying.md) documentation. + +After you've read the tutorial and got the code, refer to the formal +documentation for each of the classes this library provides: + +- [Crypto](docs/classes/Crypto.md) +- [File](docs/classes/File.md) +- [Key](docs/classes/Key.md) +- [KeyProtectedByPassword](docs/classes/KeyProtectedByPassword.md) + +If you encounter difficulties, see the [FAQ](docs/FAQ.md) answers. The fixes to +the most commonly-reported problems are explained there. + +If you're a cryptographer and want to understand the nitty-gritty details of how +this library works, look at the [Cryptography Details](docs/CryptoDetails.md) +documentation. + +If you're interested in contributing to this library, see the [Internal +Developer Documentation](docs/InternalDeveloperDocs.md). + +Examples +--------- + +If the documentation is not enough for you to understand how to use this +library, then you can look at an example project that uses this library: + +- [encutil](https://github.com/defuse/encutil) +- [fileencrypt](https://github.com/tsusanka/fileencrypt) + +Security Audit Status +--------------------- + +This code has not been subjected to a formal, paid, security audit. However, it +has received lots of review from members of the PHP security community, and the +authors are experienced with cryptography. In all likelihood, you are safer +using this library than almost any other encryption library for PHP. + +If you use this library as a part of your business and would like to help fund +a formal audit, please [contact Taylor Hornby](https://defuse.ca/contact.htm). + +Public Keys +------------ + +The GnuPG public key used to sign releases is available in +[dist/signingkey.asc](https://github.com/defuse/php-encryption/raw/master/dist/signingkey.asc). Its fingerprint is: + +``` +2FA6 1D8D 99B9 2658 6BAC 3D53 385E E055 A129 1538 +``` + +You can verify it against the Taylor Hornby's [contact +page](https://defuse.ca/contact.htm) and +[twitter](https://twitter.com/DefuseSec/status/723741424253059074). diff --git a/vendor/defuse/php-encryption/bin/generate-defuse-key b/vendor/defuse/php-encryption/bin/generate-defuse-key new file mode 100644 index 0000000000..24e31b5e00 --- /dev/null +++ b/vendor/defuse/php-encryption/bin/generate-defuse-key @@ -0,0 +1,14 @@ +#!/usr/bin/env php +saveToAsciiSafeString(), "\n"; diff --git a/vendor/defuse/php-encryption/composer.json b/vendor/defuse/php-encryption/composer.json new file mode 100644 index 0000000000..866b4975e0 --- /dev/null +++ b/vendor/defuse/php-encryption/composer.json @@ -0,0 +1,35 @@ +{ + "name": "defuse/php-encryption", + "description": "Secure PHP Encryption Library", + "license": "MIT", + "keywords": ["security", "encryption", "AES", "openssl", "cipher", "cryptography", "symmetric key cryptography", "crypto", "encrypt", "authenticated encryption"], + "authors": [ + { + "name": "Taylor Hornby", + "email": "taylor@defuse.ca", + "homepage": "https://defuse.ca/" + }, + { + "name": "Scott Arciszewski", + "email": "info@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "autoload": { + "psr-4": { + "Defuse\\Crypto\\": "src" + } + }, + "require": { + "paragonie/random_compat": "~2.0", + "ext-openssl": "*", + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5", + "nikic/php-parser": "^2.0|^3.0" + }, + "bin": [ + "bin/generate-defuse-key" + ] +} diff --git a/vendor/defuse/php-encryption/dist/Makefile b/vendor/defuse/php-encryption/dist/Makefile new file mode 100644 index 0000000000..4b65c9ec41 --- /dev/null +++ b/vendor/defuse/php-encryption/dist/Makefile @@ -0,0 +1,37 @@ +# This builds defuse-crypto.phar. To run this Makefile, `box` and `composer` +# must be installed and in your $PATH. Run it from inside the dist/ directory. + +box := $(shell which box) +composer := "composer" + +.PHONY: all +all: build-phar + +.PHONY: sign-phar +sign-phar: + gpg -u 7B4B2D98 --armor --output defuse-crypto.phar.sig --detach-sig defuse-crypto.phar + +# ensure we run in clean tree. export git tree and run there. +.PHONY: build-phar +build-phar: + @echo "Creating .phar from revision $(shell git rev-parse HEAD)." + rm -rf worktree + install -d worktree + (cd $(CURDIR)/..; git archive HEAD) | tar -x -C worktree + $(MAKE) -f $(CURDIR)/Makefile -C worktree defuse-crypto.phar + mv worktree/*.phar . + rm -rf worktree + +.PHONY: clean +clean: + rm -vf defuse-crypto.phar defuse-crypto.phar.sig + +# Inside workdir/: + +defuse-crypto.phar: dist/box.json composer.lock + cp dist/box.json . + php -d phar.readonly=0 $(box) build -c box.json -v + +composer.lock: + $(composer) install --no-dev + diff --git a/vendor/defuse/php-encryption/dist/box.json b/vendor/defuse/php-encryption/dist/box.json new file mode 100644 index 0000000000..f225f781e1 --- /dev/null +++ b/vendor/defuse/php-encryption/dist/box.json @@ -0,0 +1,25 @@ +{ + "chmod": "0755", + "finder": [ + { + "in": "src", + "name": "*.php" + }, + { + "in": "vendor/composer", + "name": "*.php" + }, + { + "in": "vendor/paragonie", + "name": "*.php", + "exclude": "other" + } + ], + "compactors": [ + "Herrera\\Box\\Compactor\\Php" + ], + "main": "vendor/autoload.php", + "output": "defuse-crypto.phar", + "shebang": false, + "stub": true +} diff --git a/vendor/defuse/php-encryption/dist/signingkey.asc b/vendor/defuse/php-encryption/dist/signingkey.asc new file mode 100644 index 0000000000..63b6aa3dd4 --- /dev/null +++ b/vendor/defuse/php-encryption/dist/signingkey.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v2 + +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 +IEgAL/CYqrk38w== +=lmD7 +-----END PGP PUBLIC KEY BLOCK----- diff --git a/vendor/defuse/php-encryption/docs/CryptoDetails.md b/vendor/defuse/php-encryption/docs/CryptoDetails.md new file mode 100644 index 0000000000..43abd72ab5 --- /dev/null +++ b/vendor/defuse/php-encryption/docs/CryptoDetails.md @@ -0,0 +1,64 @@ +Cryptography Details +===================== + +Here is a high-level description of how this library works. Any discrepancy +between this documentation and the actual implementation will be considered +a security bug. + +Let's start with the following definitions: + +- HKDF-SHA256(*k*, *n*, *info*, *s*) is the key derivation function specified in + RFC 5869 (using the SHA256 hash function). The parameters are: + - *k*: The initial keying material. + - *n*: The number of output bytes. + - *info*: The info string. + - *s*: The salt. +- AES-256-CTR(*m*, *k*, *iv*) is AES-256 encryption in CTR mode. The parameters + are: + - *m*: An arbitrary-length (possibly zero-length) message. + - *k*: A 32-byte key. + - *iv*: A 16-byte initialization vector (nonce). +- PBKDF2-SHA256(*p*, *s*, *i*, *n*) is the password-based key derivation + function defined in RFC 2898 (using the SHA256 hash function). The parameters + are: + - *p*: The password string. + - *s*: The salt string. + - *i*: The iteration count. + - *n*: The output length in bytes. +- VERSION is the string `"\xDE\xF5\x02\x00"`. +- AUTHINFO is the string `"DefusePHP|V2|KeyForAuthentication"`. +- ENCRINFO is the string `"DefusePHP|V2|KeyForEncryption"`. + +To encrypt a message *m* using a 32-byte key *k*, the following steps are taken: + +1. Generate a random 32-byte string *salt*. +2. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*). +3. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*). +4. Generate a random 16-byte initialization vector *iv*. +5. Compute *c* = AES-256-CTR(*m*, *ekey*, *iv*). +6. Combine *ctxt* = VERSION || *salt* || *iv* || *c*. +7. Compute *h* = HMAC-SHA256(*ctxt*, *akey*). +8. Output *ctxt* || *h*. + +Decryption is roughly the reverse process (see the code for details, since the +security of the decryption routine is highly implementation-dependent). + +For encryption using a password *p*, steps 1-3 above are replaced by: + +1. Generate a random 32-byte string *salt*. +2. Compute *k* = PBKDF2-SHA256(SHA256(*p*), *salt*, 100000, 32). +3. Derive the 32-byte authentication key *akey* = HKDF-SHA256(*k*, 32, AUTHINFO, *salt*) +4. Derive the 32-byte encryption key *ekey* = HKDF-SHA256(*k*, 32, ENCRINFO, *salt*) + +The remainder of the process is the same. Notice the reuse of the same *salt* +for PBKDF2-SHA256 and HKDF-SHA256. The prehashing of the password in step 2 is +done to prevent a [DoS attack using long +passwords](https://github.com/defuse/php-encryption/issues/230). + +For `KeyProtectedByPassword`, the serialized key is encrypted according to the +password encryption defined above. However, the actual password used for +encryption is the SHA256 hash of the password the user provided. This is done in +order to provide domain separation between the message encryption in the user's +application and the internal key encryption done by this library. It fixes +a [key replacement chosen-protocol +attack](https://github.com/defuse/php-encryption/issues/240). diff --git a/vendor/defuse/php-encryption/docs/FAQ.md b/vendor/defuse/php-encryption/docs/FAQ.md new file mode 100644 index 0000000000..135e235ce5 --- /dev/null +++ b/vendor/defuse/php-encryption/docs/FAQ.md @@ -0,0 +1,39 @@ +Frequently Asked Questions +=========================== + +How do I use this library to encrypt passwords? +------------------------------------------------ + +Passwords should not be encrypted, they should be hashed with a *slow* password +hashing function that's designed to slow down password guessing attacks. See +[How to Safely Store Your Users' Passwords in +2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016). + +How do I give it the same key every time instead of a new random key? +---------------------------------------------------------------------- + +A `Key` object can be saved to a string by calling its `saveToAsciiSafeString()` +method. You will have to save that string somewhere safe, and then load it back +into a `Key` object using `Key`'s `loadFromAsciiSafeString` static method. + +Where you store the string depends on your application. For example if you are +using `KeyProtectedByPassword` to encrypt files with a user's login password, +then you should not store the `Key` at all. If you are protecting sensitive data +on a server that may be compromised, then you should store it in a hardware +security module. When in doubt, consult a security expert. + +Why is an EnvironmentIsBrokenException getting thrown? +------------------------------------------------------- + +Either you've encountered a bug in this library, or your system doesn't support +the use of this library. For example, if your system does not have a secure +random number generator, this library will refuse to run, by throwing that +exception, instead of falling back to an insecure random number generator. + +Why am I getting a BadFormatException when loading a Key from a string? +------------------------------------------------------------------------ + +If you're getting this exception, then the string you're giving to +`loadFromAsciiSafeString()` is *not* the same as the string you got from +`saveToAsciiSafeString()`. Perhaps your database column isn't wide enough and +it's truncating the string as you insert it? diff --git a/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md b/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md new file mode 100644 index 0000000000..12b5fee430 --- /dev/null +++ b/vendor/defuse/php-encryption/docs/InstallingAndVerifying.md @@ -0,0 +1,53 @@ +Getting The Code +================= + +There are two ways to use this library in your applications. You can either: + +1. Use [Composer](https://getcomposer.org/), or +2. `require_once` a single `.phar` file in your application. + +If you are not using either option (for example, because you're using Git submodules), you may need to write your own autoloader ([example](https://gist.github.com/paragonie-scott/949daee819bb7f19c50e5e103170b400)). + +Option 1: Using Composer +------------------------- + +Run this inside the directory of your composer-enabled project: + +```sh +composer require defuse/php-encryption +``` + +Unfortunately, composer doesn't provide a way for you to verify that the code +you're getting was signed by this library's authors. If you want a more secure +option, use the `.phar` method described below. + +Option 2: Including a PHAR +---------------------------- + +The `.phar` option lets you include this library into your project simply by +calling `require_once` on a single file. Download `defuse-crypto.phar` and +`defuse-crypto.phar.sig` from this project's +[releases](https://github.com/defuse/php-encryption/releases) page. + +You should verify the integrity of the `.phar`. The `defuse-crypto.phar.sig` +contains the signature of `defuse-crypto.phar`. It is signed with Taylor +Hornby's PGP key. You can find Taylor's public key in `dist/signingkey.asc`. You +can verify the public key's fingerprint against the Taylor Hornby's [contact +page](https://defuse.ca/contact.htm) and +[twitter](https://twitter.com/DefuseSec/status/723741424253059074). + +Once you have verified the signature, it is safe to use the `.phar`. Place it +somewhere in your file system, e.g. `/var/www/lib/defuse-crypto.phar`, and then +pass that path to `require_once`. + +```php + Whenever there is a conflict between security and some other property, + > security will be favored. For example, the library has runtime tests, + > which make it slower, but will hopefully stop it from encrypting stuff + > if the platform it's running on is broken. + +- Rule #2: It should be difficult to misuse the library. + + > We assume the developers using this library have no experience with + > cryptography. We only assume that they know that the "key" is something + > you need to encrypt and decrypt the messages, and that it must be kept + > secret. Whenever possible, the library should refuse to encrypt or decrypt + > messages when it is not being used correctly. + +- Rule #3: The library aims only to be compatible with itself. + + > Other PHP encryption libraries try to support every possible type of + > encryption, even the insecure ones (e.g. ECB mode). Because there are so + > many options, inexperienced developers must decide whether to use "CBC + > mode" or "ECB mode" when both are meaningless terms to them. This + > inevitably leads to vulnerabilities. + + > This library will only support one secure mode. A developer using this + > library will call "encrypt" and "decrypt" methods without worrying about + > how they are implemented. + +- Rule #4: The library should require no special installation. + + > Some PHP encryption libraries, like libsodium-php, are not straightforward + > to install and cannot packaged with "just download and extract" + > applications. This library will always be just a handful of PHP files that + > you can copy to your source tree and require(). + +Publishing Releases +-------------------- + +To make a release, you will need to install [composer](https://getcomposer.org/) +and [box](https://github.com/box-project/box2) on your system. They will need to +be available in your `$PATH` so that running the commands `composer` and `box` +in your terminal run them, respectively. You will also need the private key for +signing (ID: 7B4B2D98) available. + +Once you have those tools installed and the key available follow these steps: + +**Remember to set the version number in `composer.json`!** + +Make a fresh clone of the repository: + +``` +git clone +``` + +Check out the branch you want to release: + +``` +git checkout +``` + +Check that the version number in composer.json is correct: + +``` +cat composer.json +``` + +Run the tests: + +``` +composer install +./test.sh +``` + +Generate the `.phar`: + +``` +cd dist +make build-phar +``` + +Test the `.phar`: + +``` +cd ../ +./test.sh dist/defuse-crypto.phar +``` + +Sign the `.phar`: + +``` +cd dist +make sign-phar +``` + +Tag the release: + +``` +git -c user.signingkey=7B4B2D98 tag -s "" -m "" +``` + +`` should be in the format `v2.0.0` and `` should look +like "Release of v2.0.0." + +Push the tag to github, then use the +[releases](https://github.com/defuse/php-encryption/releases) page to draft +a new release for that tag. Upload the `.phar` and the `.phar.sig` file to be +included as part of that release. diff --git a/vendor/defuse/php-encryption/docs/Tutorial.md b/vendor/defuse/php-encryption/docs/Tutorial.md new file mode 100644 index 0000000000..40285cc33e --- /dev/null +++ b/vendor/defuse/php-encryption/docs/Tutorial.md @@ -0,0 +1,298 @@ +Tutorial +========= + +Hello! If you're reading this file, it's because you want to add encryption to +one of your PHP projects. My job, as the person writing this documentation, is +to help you make sure you're doing the right thing and then show you how to use +this library to do it. To help me help you, please read the documentation +*carefully* and *deliberately*. + +A Word of Caution +------------------ + +Encryption is not magic dust you can sprinkle on a system to make it more +secure. The way encryption is integrated into a system's design needs to be +carefully thought out. Sometimes, encryption is the wrong thing to use. Other +times, encryption needs to be used in a very specific way in order for it to +work as intended. Even if you are sure of what you are doing, we strongly +recommend seeking advice from an expert. + +The first step is to think about your application's threat model. Ask yourself +the following questions. Who will want to attack my application, and what will +they get out of it? Are they trying to steal some information? Trying to alter +or destroy some information? Or just trying to make the system go down so people +can't access it? Then ask yourself how encryption can help combat those threats. +If you're going to add encryption to your application, you should have a very +clear idea of exactly which kinds of attacks it's helping to secure your +application against. Once you have your threat model, think about what kinds of +attacks it *does not* cover, and whether or not you should improve your threat +model to include those attacks. + +**This isn't for storing user login passwords:** The most common use of +cryptography in web applications is to protect the users' login passwords. If +you're trying to use this library to "encrypt" your users' passwords, you're in +the wrong place. Passwords shouldn't be *encrypted*, they should be *hashed* +with a slow computation-heavy function that makes password guessing attacks more +expensive. See [How to Safely Store Your Users' Passwords in +2016](https://paragonie.com/blog/2016/02/how-safely-store-password-in-2016). + +**This isn't for encrypting network communication:** Likewise, if you're trying +to encrypt messages sent between two parties over the Internet, you don't want +to be using this library. For that, set up a TLS connection between the two +points, or, if it's a chat app, use the [Signal +Protocol](https://whispersystems.org/blog/advanced-ratcheting/). + +What this library provides is symmetric encryption for "data at rest." This +means it is not suitable for use in building protocols where "data is in motion" +(i.e. moving over a network) except in limited set of cases. + +Getting the Code +----------------- + +There are several different ways to obtain this library's code and to add it to +your project. Even if you've already cloned the code from GitHub, you should +take steps to verify the cryptographic signatures to make sure the code you got +was not intercepted and modified by an attacker. + +Please head over to the [**Installing and +Verifying**](InstallingAndVerifying.md) documentation to get the code, and then +come back here to continue the tutorial. + +Using the Library +------------------ + +I'm going to assume you know what symmetric encryption is, and the difference +between symmetric and asymmetric encryption. If you don't, I recommend taking +[Dan Boneh's Cryptography I course](https://www.coursera.org/learn/crypto/) on +Coursera. + +To give you a quick introduction to the library, I'm going to explain how it +would be used in two sterotypical scenarios. Hopefully, one of these sterotypes +is close enough to what you want to do that you'll be able to figure out what +needs to be different on your own. + +### Formal Documentation + +While this tutorial should get you up and running fast, it's important to +understand how this library behaves. Please make sure to read the formal +documentation of all of the functions you're using, since there are some +important security warnings there. + +The following classes are available for you to use: + +- [Crypto](classes/Crypto.md): Encrypting and decrypting strings. +- [File](classes/File.md): Encrypting and decrypting files. +- [Key](classes/Key.md): Represents a secret encryption key. +- [KeyProtectedByPassword](classes/KeyProtectedByPassword.md): Represents + a secret encryption key that needs to be "unlocked" by a password before it + can be used. + +### Scenario #1: Keep data secret from the database administrator + +In this scenario, our threat model is as follows. Alice is a server +administrator responsible for managing a trusted web server. Eve is a database +administrator responsible for managing a database server. Dave is a web +developer working on code that will eventually run on the trusted web server. + +Let's say Alice and Dave trust each other, and Alice is going to host Dave's +application on her server. But both Alice and Dave don't trust Eve. They know +Eve is a good database administrator, but she might have incentive to steal the +data from the database. They want to keep some of the web application's data +secret from Eve. + +In order to do that, Alice will use the included `generate-defuse-key` script +which generates a random encryption key and prints it to standard output: + +```sh +$ composer require defuse/php-encryption +$ vendor/bin/generate-defuse-key +``` + +Alice will run this script once and save the output to a configuration file, say +in `/etc/daveapp-secret-key.txt` and set the file permissions so that only the +user that the website PHP scripts run as can access it. + +Dave will write his code to load the key from the configuration file: + +```php +saveToAsciiSafeString(); + // ... save $protected_key_encoded into the user's account record +} +``` + +Then, when the user logs in, Dave's code will load the protected key from the +user's account record, unlock it to get a `Key` object, and save the `Key` +object somewhere safe (like temporary memory-backed session storage). Note that +wherever Dave's code saves the key, it must be destroyed once the user logs out, +or else the attacker might be able to find users' keys even if they were never +logged in during the attack. + +```php +unlockKey($password); +$user_key_encoded = $user_key->saveToAsciiSafeString(); +// ... save $user_key_encoded in the session +``` + +```php + + + + + + diff --git a/vendor/defuse/php-encryption/src/Core.php b/vendor/defuse/php-encryption/src/Core.php new file mode 100644 index 0000000000..3f5ed5224e --- /dev/null +++ b/vendor/defuse/php-encryption/src/Core.php @@ -0,0 +1,446 @@ + PHP_INT_MAX - 255) { + throw new Ex\EnvironmentIsBrokenException( + 'Integer overflow may occur.' + ); + } + + /* + * We start at the rightmost byte (big-endian) + * So, too, does OpenSSL: http://stackoverflow.com/a/3146214/2224584 + */ + for ($i = Core::BLOCK_BYTE_SIZE - 1; $i >= 0; --$i) { + $sum = \ord($ctr[$i]) + $inc; + + /* Detect integer overflow and fail. */ + if (! \is_int($sum)) { + throw new Ex\EnvironmentIsBrokenException( + 'Integer overflow in CTR mode nonce increment.' + ); + } + + $ctr[$i] = \pack('C', $sum & 0xFF); + $inc = $sum >> 8; + } + return $ctr; + } + + /** + * Returns a random byte string of the specified length. + * + * @param int $octets + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + public static function secureRandom($octets) + { + self::ensureFunctionExists('random_bytes'); + try { + return \random_bytes($octets); + } catch (\Exception $ex) { + throw new Ex\EnvironmentIsBrokenException( + 'Your system does not have a secure random number generator.' + ); + } + } + + /** + * Computes the HKDF key derivation function specified in + * http://tools.ietf.org/html/rfc5869. + * + * @param string $hash Hash Function + * @param string $ikm Initial Keying Material + * @param int $length How many bytes? + * @param string $info What sort of key are we deriving? + * @param string $salt + * + * @throws Ex\EnvironmentIsBrokenException + * @psalm-suppress UndefinedFunction - We're checking if the function exists first. + * + * @return string + */ + public static function HKDF($hash, $ikm, $length, $info = '', $salt = null) + { + static $nativeHKDF = null; + if ($nativeHKDF === null) { + $nativeHKDF = \is_callable('\\hash_hkdf'); + } + if ($nativeHKDF) { + return \hash_hkdf($hash, $ikm, $length, $info, $salt); + } + + $digest_length = Core::ourStrlen(\hash_hmac($hash, '', '', true)); + + // Sanity-check the desired output length. + if (empty($length) || ! \is_int($length) || + $length < 0 || $length > 255 * $digest_length) { + throw new Ex\EnvironmentIsBrokenException( + 'Bad output length requested of HKDF.' + ); + } + + // "if [salt] not provided, is set to a string of HashLen zeroes." + if (\is_null($salt)) { + $salt = \str_repeat("\x00", $digest_length); + } + + // HKDF-Extract: + // PRK = HMAC-Hash(salt, IKM) + // The salt is the HMAC key. + $prk = \hash_hmac($hash, $ikm, $salt, true); + + // HKDF-Expand: + + // This check is useless, but it serves as a reminder to the spec. + if (Core::ourStrlen($prk) < $digest_length) { + throw new Ex\EnvironmentIsBrokenException(); + } + + // T(0) = '' + $t = ''; + $last_block = ''; + for ($block_index = 1; Core::ourStrlen($t) < $length; ++$block_index) { + // T(i) = HMAC-Hash(PRK, T(i-1) | info | 0x??) + $last_block = \hash_hmac( + $hash, + $last_block . $info . \chr($block_index), + $prk, + true + ); + // T = T(1) | T(2) | T(3) | ... | T(N) + $t .= $last_block; + } + + // ORM = first L octets of T + /** @var string $orm */ + $orm = Core::ourSubstr($t, 0, $length); + if (!\is_string($orm)) { + throw new Ex\EnvironmentIsBrokenException(); + } + return $orm; + } + + /** + * Checks if two equal-length strings are the same without leaking + * information through side channels. + * + * @param string $expected + * @param string $given + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return bool + */ + public static function hashEquals($expected, $given) + { + static $native = null; + if ($native === null) { + $native = \function_exists('hash_equals'); + } + if ($native) { + return \hash_equals($expected, $given); + } + + // We can't just compare the strings with '==', since it would make + // timing attacks possible. We could use the XOR-OR constant-time + // comparison algorithm, but that may not be a reliable defense in an + // interpreted language. So we use the approach of HMACing both strings + // with a random key and comparing the HMACs. + + // We're not attempting to make variable-length string comparison + // secure, as that's very difficult. Make sure the strings are the same + // length. + if (Core::ourStrlen($expected) !== Core::ourStrlen($given)) { + throw new Ex\EnvironmentIsBrokenException(); + } + + $blind = Core::secureRandom(32); + $message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind); + $correct_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $expected, $blind); + return $correct_compare === $message_compare; + } + /** + * Throws an exception if the constant doesn't exist. + * + * @param string $name + * @return void + * + * @throws Ex\EnvironmentIsBrokenException + */ + public static function ensureConstantExists($name) + { + if (! \defined($name)) { + throw new Ex\EnvironmentIsBrokenException(); + } + } + + /** + * Throws an exception if the function doesn't exist. + * + * @param string $name + * @return void + * + * @throws Ex\EnvironmentIsBrokenException + */ + public static function ensureFunctionExists($name) + { + if (! \function_exists($name)) { + throw new Ex\EnvironmentIsBrokenException(); + } + } + + /* + * We need these strlen() and substr() functions because when + * 'mbstring.func_overload' is set in php.ini, the standard strlen() and + * substr() are replaced by mb_strlen() and mb_substr(). + */ + + /** + * Computes the length of a string in bytes. + * + * @param string $str + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return int + */ + public static function ourStrlen($str) + { + static $exists = null; + if ($exists === null) { + $exists = \function_exists('mb_strlen'); + } + if ($exists) { + $length = \mb_strlen($str, '8bit'); + if ($length === false) { + throw new Ex\EnvironmentIsBrokenException(); + } + return $length; + } else { + return \strlen($str); + } + } + + /** + * Behaves roughly like the function substr() in PHP 7 does. + * + * @param string $str + * @param int $start + * @param int $length + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string|bool + */ + public static function ourSubstr($str, $start, $length = null) + { + static $exists = null; + if ($exists === null) { + $exists = \function_exists('mb_substr'); + } + + if ($exists) { + // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP + // 5.3, so we have to find the length ourselves. + if (! isset($length)) { + if ($start >= 0) { + $length = Core::ourStrlen($str) - $start; + } else { + $length = -$start; + } + } + + // This is required to make mb_substr behavior identical to substr. + // Without this, mb_substr() would return false, contra to what the + // PHP documentation says (it doesn't say it can return false.) + if ($start === Core::ourStrlen($str) && $length === 0) { + return ''; + } + + if ($start > Core::ourStrlen($str)) { + return false; + } + + $substr = \mb_substr($str, $start, $length, '8bit'); + if (Core::ourStrlen($substr) !== $length) { + throw new Ex\EnvironmentIsBrokenException( + 'Your version of PHP has bug #66797. Its implementation of + mb_substr() is incorrect. See the details here: + https://bugs.php.net/bug.php?id=66797' + ); + } + return $substr; + } + + // Unlike mb_substr(), substr() doesn't accept NULL for length + if (isset($length)) { + return \substr($str, $start, $length); + } else { + return \substr($str, $start); + } + } + + /** + * Computes the PBKDF2 password-based key derivation function. + * + * The PBKDF2 function is defined in RFC 2898. Test vectors can be found in + * RFC 6070. This implementation of PBKDF2 was originally created by Taylor + * Hornby, with improvements from http://www.variations-of-shadow.com/. + * + * @param string $algorithm The hash algorithm to use. Recommended: SHA256 + * @param string $password The password. + * @param string $salt A salt that is unique to the password. + * @param int $count Iteration count. Higher is better, but slower. Recommended: At least 1000. + * @param int $key_length The length of the derived key in bytes. + * @param bool $raw_output If true, the key is returned in raw binary format. Hex encoded otherwise. + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string A $key_length-byte key derived from the password and salt. + */ + public static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false) + { + // Type checks: + if (! \is_string($algorithm)) { + throw new \InvalidArgumentException( + 'pbkdf2(): algorithm must be a string' + ); + } + if (! \is_string($password)) { + throw new \InvalidArgumentException( + 'pbkdf2(): password must be a string' + ); + } + if (! \is_string($salt)) { + throw new \InvalidArgumentException( + 'pbkdf2(): salt must be a string' + ); + } + // Coerce strings to integers with no information loss or overflow + $count += 0; + $key_length += 0; + + $algorithm = \strtolower($algorithm); + if (! \in_array($algorithm, \hash_algos(), true)) { + throw new Ex\EnvironmentIsBrokenException( + 'Invalid or unsupported hash algorithm.' + ); + } + + // Whitelist, or we could end up with people using CRC32. + $ok_algorithms = [ + 'sha1', 'sha224', 'sha256', 'sha384', 'sha512', + 'ripemd160', 'ripemd256', 'ripemd320', 'whirlpool', + ]; + if (! \in_array($algorithm, $ok_algorithms, true)) { + throw new Ex\EnvironmentIsBrokenException( + 'Algorithm is not a secure cryptographic hash function.' + ); + } + + if ($count <= 0 || $key_length <= 0) { + throw new Ex\EnvironmentIsBrokenException( + 'Invalid PBKDF2 parameters.' + ); + } + + if (\function_exists('hash_pbkdf2')) { + // The output length is in NIBBLES (4-bits) if $raw_output is false! + if (! $raw_output) { + $key_length = $key_length * 2; + } + return \hash_pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output); + } + + $hash_length = Core::ourStrlen(\hash($algorithm, '', true)); + $block_count = \ceil($key_length / $hash_length); + + $output = ''; + for ($i = 1; $i <= $block_count; $i++) { + // $i encoded as 4 bytes, big endian. + $last = $salt . \pack('N', $i); + // first iteration + $last = $xorsum = \hash_hmac($algorithm, $last, $password, true); + // perform the other $count - 1 iterations + for ($j = 1; $j < $count; $j++) { + $xorsum ^= ($last = \hash_hmac($algorithm, $last, $password, true)); + } + $output .= $xorsum; + } + + if ($raw_output) { + return (string) Core::ourSubstr($output, 0, $key_length); + } else { + return Encoding::binToHex((string) Core::ourSubstr($output, 0, $key_length)); + } + } +} diff --git a/vendor/defuse/php-encryption/src/Crypto.php b/vendor/defuse/php-encryption/src/Crypto.php new file mode 100644 index 0000000000..fdb411c76e --- /dev/null +++ b/vendor/defuse/php-encryption/src/Crypto.php @@ -0,0 +1,393 @@ +deriveKeys($salt); + $ekey = $keys->getEncryptionKey(); + $akey = $keys->getAuthenticationKey(); + $iv = Core::secureRandom(Core::BLOCK_BYTE_SIZE); + + $ciphertext = Core::CURRENT_VERSION . $salt . $iv . self::plainEncrypt($plaintext, $ekey, $iv); + $auth = \hash_hmac(Core::HASH_FUNCTION_NAME, $ciphertext, $akey, true); + $ciphertext = $ciphertext . $auth; + + if ($raw_binary) { + return $ciphertext; + } + return Encoding::binToHex($ciphertext); + } + + /** + * Decrypts a ciphertext to a string with either a key or a password. + * + * @param string $ciphertext + * @param KeyOrPassword $secret + * @param bool $raw_binary + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\WrongKeyOrModifiedCiphertextException + * + * @return string + */ + private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw_binary) + { + RuntimeTests::runtimeTest(); + + if (! $raw_binary) { + try { + $ciphertext = Encoding::hexToBin($ciphertext); + } catch (Ex\BadFormatException $ex) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Ciphertext has invalid hex encoding.' + ); + } + } + + if (Core::ourStrlen($ciphertext) < Core::MINIMUM_CIPHERTEXT_SIZE) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Ciphertext is too short.' + ); + } + + // Get and check the version header. + /** @var string $header */ + $header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE); + if ($header !== Core::CURRENT_VERSION) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Bad version header.' + ); + } + + // Get the salt. + /** @var string $salt */ + $salt = Core::ourSubstr( + $ciphertext, + Core::HEADER_VERSION_SIZE, + Core::SALT_BYTE_SIZE + ); + if (!\is_string($salt)) { + throw new Ex\EnvironmentIsBrokenException(); + } + + // Get the IV. + /** @var string $iv */ + $iv = Core::ourSubstr( + $ciphertext, + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE, + Core::BLOCK_BYTE_SIZE + ); + if (!\is_string($iv)) { + throw new Ex\EnvironmentIsBrokenException(); + } + + // Get the HMAC. + /** @var string $hmac */ + $hmac = Core::ourSubstr( + $ciphertext, + Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE, + Core::MAC_BYTE_SIZE + ); + if (!\is_string($hmac)) { + throw new Ex\EnvironmentIsBrokenException(); + } + + // Get the actual encrypted ciphertext. + /** @var string $encrypted */ + $encrypted = Core::ourSubstr( + $ciphertext, + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + + Core::BLOCK_BYTE_SIZE, + Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE - + Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE + ); + if (!\is_string($encrypted)) { + throw new Ex\EnvironmentIsBrokenException(); + } + + // Derive the separate encryption and authentication keys from the key + // or password, whichever it is. + $keys = $secret->deriveKeys($salt); + + if (self::verifyHMAC($hmac, $header . $salt . $iv . $encrypted, $keys->getAuthenticationKey())) { + $plaintext = self::plainDecrypt($encrypted, $keys->getEncryptionKey(), $iv, Core::CIPHER_METHOD); + return $plaintext; + } else { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Integrity check failed.' + ); + } + } + + /** + * Raw unauthenticated encryption (insecure on its own). + * + * @param string $plaintext + * @param string $key + * @param string $iv + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + protected static function plainEncrypt($plaintext, $key, $iv) + { + Core::ensureConstantExists('OPENSSL_RAW_DATA'); + Core::ensureFunctionExists('openssl_encrypt'); + /** @var string $ciphertext */ + $ciphertext = \openssl_encrypt( + $plaintext, + Core::CIPHER_METHOD, + $key, + OPENSSL_RAW_DATA, + $iv + ); + + if (!\is_string($ciphertext)) { + throw new Ex\EnvironmentIsBrokenException( + 'openssl_encrypt() failed.' + ); + } + + return $ciphertext; + } + + /** + * Raw unauthenticated decryption (insecure on its own). + * + * @param string $ciphertext + * @param string $key + * @param string $iv + * @param string $cipherMethod + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod) + { + Core::ensureConstantExists('OPENSSL_RAW_DATA'); + Core::ensureFunctionExists('openssl_decrypt'); + + /** @var string $plaintext */ + $plaintext = \openssl_decrypt( + $ciphertext, + $cipherMethod, + $key, + OPENSSL_RAW_DATA, + $iv + ); + if (!\is_string($plaintext)) { + throw new Ex\EnvironmentIsBrokenException( + 'openssl_decrypt() failed.' + ); + } + + return $plaintext; + } + + /** + * Verifies an HMAC without leaking information through side-channels. + * + * @param string $expected_hmac + * @param string $message + * @param string $key + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return bool + */ + protected static function verifyHMAC($expected_hmac, $message, $key) + { + $message_hmac = \hash_hmac(Core::HASH_FUNCTION_NAME, $message, $key, true); + return Core::hashEquals($message_hmac, $expected_hmac); + } +} diff --git a/vendor/defuse/php-encryption/src/DerivedKeys.php b/vendor/defuse/php-encryption/src/DerivedKeys.php new file mode 100644 index 0000000000..86a48e5ea9 --- /dev/null +++ b/vendor/defuse/php-encryption/src/DerivedKeys.php @@ -0,0 +1,50 @@ +akey; + } + + /** + * Returns the encryption key. + * @return string + */ + public function getEncryptionKey() + { + return $this->ekey; + } + + /** + * Constructor for DerivedKeys. + * + * @param string $akey + * @param string $ekey + */ + public function __construct($akey, $ekey) + { + $this->akey = $akey; + $this->ekey = $ekey; + } +} diff --git a/vendor/defuse/php-encryption/src/Encoding.php b/vendor/defuse/php-encryption/src/Encoding.php new file mode 100644 index 0000000000..001fb6e89e --- /dev/null +++ b/vendor/defuse/php-encryption/src/Encoding.php @@ -0,0 +1,270 @@ +> 4; + $hex .= \pack( + 'CC', + 87 + $b + ((($b - 10) >> 8) & ~38), + 87 + $c + ((($c - 10) >> 8) & ~38) + ); + } + return $hex; + } + + /** + * Converts a hexadecimal string into a byte string without leaking + * information through side channels. + * + * @param string $hex_string + * + * @throws Ex\BadFormatException + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + public static function hexToBin($hex_string) + { + $hex_pos = 0; + $bin = ''; + $hex_len = Core::ourStrlen($hex_string); + $state = 0; + $c_acc = 0; + + while ($hex_pos < $hex_len) { + $c = \ord($hex_string[$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 Ex\BadFormatException( + 'Encoding::hexToBin() input is not a hex string.' + ); + } + $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; + ++$hex_pos; + } + return $bin; + } + + /** + * Remove trialing whitespace without table look-ups or branches. + * + * Calling this function may leak the length of the string as well as the + * number of trailing whitespace characters through side-channels. + * + * @param string $string + * @return string + */ + public static function trimTrailingWhitespace($string = '') + { + $length = Core::ourStrlen($string); + if ($length < 1) { + return ''; + } + do { + $prevLength = $length; + $last = $length - 1; + $chr = \ord($string[$last]); + + /* Null Byte (0x00), a.k.a. \0 */ + // if ($chr === 0x00) $length -= 1; + $sub = (($chr - 1) >> 8 ) & 1; + $length -= $sub; + $last -= $sub; + + /* Horizontal Tab (0x09) a.k.a. \t */ + $chr = \ord($string[$last]); + // if ($chr === 0x09) $length -= 1; + $sub = (((0x08 - $chr) & ($chr - 0x0a)) >> 8) & 1; + $length -= $sub; + $last -= $sub; + + /* New Line (0x0a), a.k.a. \n */ + $chr = \ord($string[$last]); + // if ($chr === 0x0a) $length -= 1; + $sub = (((0x09 - $chr) & ($chr - 0x0b)) >> 8) & 1; + $length -= $sub; + $last -= $sub; + + /* Carriage Return (0x0D), a.k.a. \r */ + $chr = \ord($string[$last]); + // if ($chr === 0x0d) $length -= 1; + $sub = (((0x0c - $chr) & ($chr - 0x0e)) >> 8) & 1; + $length -= $sub; + $last -= $sub; + + /* Space */ + $chr = \ord($string[$last]); + // if ($chr === 0x20) $length -= 1; + $sub = (((0x1f - $chr) & ($chr - 0x21)) >> 8) & 1; + $length -= $sub; + } while ($prevLength !== $length && $length > 0); + return (string) Core::ourSubstr($string, 0, $length); + } + + /* + * SECURITY NOTE ON APPLYING CHECKSUMS TO SECRETS: + * + * The checksum introduces a potential security weakness. For example, + * suppose we apply a checksum to a key, and that an adversary has an + * exploit against the process containing the key, such that they can + * overwrite an arbitrary byte of memory and then cause the checksum to + * be verified and learn the result. + * + * In this scenario, the adversary can extract the key one byte at + * a time by overwriting it with their guess of its value and then + * asking if the checksum matches. If it does, their guess was right. + * This kind of attack may be more easy to implement and more reliable + * than a remote code execution attack. + * + * This attack also applies to authenticated encryption as a whole, in + * the situation where the adversary can overwrite a byte of the key + * and then cause a valid ciphertext to be decrypted, and then + * determine whether the MAC check passed or failed. + * + * By using the full SHA256 hash instead of truncating it, I'm ensuring + * that both ways of going about the attack are equivalently difficult. + * A shorter checksum of say 32 bits might be more useful to the + * adversary as an oracle in case their writes are coarser grained. + * + * Because the scenario assumes a serious vulnerability, we don't try + * to prevent attacks of this style. + */ + + /** + * INTERNAL USE ONLY: Applies a version header, applies a checksum, and + * then encodes a byte string into a range of printable ASCII characters. + * + * @param string $header + * @param string $bytes + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + public static function saveBytesToChecksummedAsciiSafeString($header, $bytes) + { + // Headers must be a constant length to prevent one type's header from + // being a prefix of another type's header, leading to ambiguity. + if (Core::ourStrlen($header) !== self::SERIALIZE_HEADER_BYTES) { + throw new Ex\EnvironmentIsBrokenException( + 'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.' + ); + } + + return Encoding::binToHex( + $header . + $bytes . + \hash( + self::CHECKSUM_HASH_ALGO, + $header . $bytes, + true + ) + ); + } + + /** + * INTERNAL USE ONLY: Decodes, verifies the header and checksum, and returns + * the encoded byte string. + * + * @param string $expected_header + * @param string $string + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\BadFormatException + * + * @return string + */ + public static function loadBytesFromChecksummedAsciiSafeString($expected_header, $string) + { + // Headers must be a constant length to prevent one type's header from + // being a prefix of another type's header, leading to ambiguity. + if (Core::ourStrlen($expected_header) !== self::SERIALIZE_HEADER_BYTES) { + throw new Ex\EnvironmentIsBrokenException( + 'Header must be 4 bytes.' + ); + } + + /* If you get an exception here when attempting to load from a file, first pass your + key to Encoding::trimTrailingWhitespace() to remove newline characters, etc. */ + $bytes = Encoding::hexToBin($string); + + /* Make sure we have enough bytes to get the version header and checksum. */ + if (Core::ourStrlen($bytes) < self::SERIALIZE_HEADER_BYTES + self::CHECKSUM_BYTE_SIZE) { + throw new Ex\BadFormatException( + 'Encoded data is shorter than expected.' + ); + } + + /* Grab the version header. */ + $actual_header = (string) Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES); + + if ($actual_header !== $expected_header) { + throw new Ex\BadFormatException( + 'Invalid header.' + ); + } + + /* Grab the bytes that are part of the checksum. */ + $checked_bytes = (string) Core::ourSubstr( + $bytes, + 0, + Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE + ); + + /* Grab the included checksum. */ + $checksum_a = (string) Core::ourSubstr( + $bytes, + Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE, + self::CHECKSUM_BYTE_SIZE + ); + + /* Re-compute the checksum. */ + $checksum_b = \hash(self::CHECKSUM_HASH_ALGO, $checked_bytes, true); + + /* Check if the checksum matches. */ + if (! Core::hashEquals($checksum_a, $checksum_b)) { + throw new Ex\BadFormatException( + "Data is corrupted, the checksum doesn't match" + ); + } + + return (string) Core::ourSubstr( + $bytes, + self::SERIALIZE_HEADER_BYTES, + Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE + ); + } +} diff --git a/vendor/defuse/php-encryption/src/Exception/BadFormatException.php b/vendor/defuse/php-encryption/src/Exception/BadFormatException.php new file mode 100644 index 0000000000..804d9c17e8 --- /dev/null +++ b/vendor/defuse/php-encryption/src/Exception/BadFormatException.php @@ -0,0 +1,7 @@ +deriveKeys($file_salt); + $ekey = $keys->getEncryptionKey(); + $akey = $keys->getAuthenticationKey(); + + $ivsize = Core::BLOCK_BYTE_SIZE; + $iv = Core::secureRandom($ivsize); + + /* Initialize a streaming HMAC state. */ + /** @var resource $hmac */ + $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey); + if (!\is_resource($hmac)) { + throw new Ex\EnvironmentIsBrokenException( + 'Cannot initialize a hash context' + ); + } + + /* Write the header, salt, and IV. */ + self::writeBytes( + $outputHandle, + Core::CURRENT_VERSION . $file_salt . $iv, + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + $ivsize + ); + + /* Add the header, salt, and IV to the HMAC. */ + \hash_update($hmac, Core::CURRENT_VERSION); + \hash_update($hmac, $file_salt); + \hash_update($hmac, $iv); + + /* $thisIv will be incremented after each call to the encryption. */ + $thisIv = $iv; + + /* How many blocks do we encrypt at a time? We increment by this value. */ + $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE); + + /* Loop until we reach the end of the input file. */ + $at_file_end = false; + while (! (\feof($inputHandle) || $at_file_end)) { + /* Find out if we can read a full buffer, or only a partial one. */ + /** @var int */ + $pos = \ftell($inputHandle); + if (!\is_int($pos)) { + throw new Ex\IOException( + 'Could not get current position in input file during encryption' + ); + } + if ($pos + Core::BUFFER_BYTE_SIZE >= $inputSize) { + /* We're at the end of the file, so we need to break out of the loop. */ + $at_file_end = true; + $read = self::readBytes( + $inputHandle, + $inputSize - $pos + ); + } else { + $read = self::readBytes( + $inputHandle, + Core::BUFFER_BYTE_SIZE + ); + } + + /* Encrypt this buffer. */ + /** @var string */ + $encrypted = \openssl_encrypt( + $read, + Core::CIPHER_METHOD, + $ekey, + OPENSSL_RAW_DATA, + $thisIv + ); + + if (!\is_string($encrypted)) { + throw new Ex\EnvironmentIsBrokenException( + 'OpenSSL encryption error' + ); + } + + /* Write this buffer's ciphertext. */ + self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted)); + /* Add this buffer's ciphertext to the HMAC. */ + \hash_update($hmac, $encrypted); + + /* Increment the counter by the number of blocks in a buffer. */ + $thisIv = Core::incrementCounter($thisIv, $inc); + /* WARNING: Usually, unless the file is a multiple of the buffer + * size, $thisIv will contain an incorrect value here on the last + * iteration of this loop. */ + } + + /* Get the HMAC and append it to the ciphertext. */ + $final_mac = \hash_final($hmac, true); + self::writeBytes($outputHandle, $final_mac, Core::MAC_BYTE_SIZE); + } + + /** + * Decrypts a file-backed resource with either a key or a password. + * + * @param resource $inputHandle + * @param resource $outputHandle + * @param KeyOrPassword $secret + * @return void + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\IOException + * @throws Ex\WrongKeyOrModifiedCiphertextException + */ + public static function decryptResourceInternal($inputHandle, $outputHandle, KeyOrPassword $secret) + { + if (! \is_resource($inputHandle)) { + throw new Ex\IOException( + 'Input handle must be a resource!' + ); + } + if (! \is_resource($outputHandle)) { + throw new Ex\IOException( + 'Output handle must be a resource!' + ); + } + + /* Make sure the file is big enough for all the reads we need to do. */ + $stat = \fstat($inputHandle); + if ($stat['size'] < Core::MINIMUM_CIPHERTEXT_SIZE) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Input file is too small to have been created by this library.' + ); + } + + /* Check the version header. */ + $header = self::readBytes($inputHandle, Core::HEADER_VERSION_SIZE); + if ($header !== Core::CURRENT_VERSION) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Bad version header.' + ); + } + + /* Get the salt. */ + $file_salt = self::readBytes($inputHandle, Core::SALT_BYTE_SIZE); + + /* Get the IV. */ + $ivsize = Core::BLOCK_BYTE_SIZE; + $iv = self::readBytes($inputHandle, $ivsize); + + /* Derive the authentication and encryption keys. */ + $keys = $secret->deriveKeys($file_salt); + $ekey = $keys->getEncryptionKey(); + $akey = $keys->getAuthenticationKey(); + + /* We'll store the MAC of each buffer-sized chunk as we verify the + * actual MAC, so that we can check them again when decrypting. */ + $macs = []; + + /* $thisIv will be incremented after each call to the decryption. */ + $thisIv = $iv; + + /* How many blocks do we encrypt at a time? We increment by this value. */ + $inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE); + + /* Get the HMAC. */ + if (\fseek($inputHandle, (-1 * Core::MAC_BYTE_SIZE), SEEK_END) === false) { + throw new Ex\IOException( + 'Cannot seek to beginning of MAC within input file' + ); + } + + /* Get the position of the last byte in the actual ciphertext. */ + /** @var int $cipher_end */ + $cipher_end = \ftell($inputHandle); + if (!\is_int($cipher_end)) { + throw new Ex\IOException( + 'Cannot read input file' + ); + } + /* We have the position of the first byte of the HMAC. Go back by one. */ + --$cipher_end; + + /* Read the HMAC. */ + /** @var string $stored_mac */ + $stored_mac = self::readBytes($inputHandle, Core::MAC_BYTE_SIZE); + + /* Initialize a streaming HMAC state. */ + /** @var resource $hmac */ + $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey); + if (!\is_resource($hmac)) { + throw new Ex\EnvironmentIsBrokenException( + 'Cannot initialize a hash context' + ); + } + + /* Reset file pointer to the beginning of the file after the header */ + if (\fseek($inputHandle, Core::HEADER_VERSION_SIZE, SEEK_SET) === false) { + throw new Ex\IOException( + 'Cannot read seek within input file' + ); + } + + /* Seek to the start of the actual ciphertext. */ + if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize, SEEK_CUR) === false) { + throw new Ex\IOException( + 'Cannot seek input file to beginning of ciphertext' + ); + } + + /* PASS #1: Calculating the HMAC. */ + + \hash_update($hmac, $header); + \hash_update($hmac, $file_salt); + \hash_update($hmac, $iv); + /** @var resource $hmac2 */ + $hmac2 = \hash_copy($hmac); + + $break = false; + while (! $break) { + /** @var int $pos */ + $pos = \ftell($inputHandle); + if (!\is_int($pos)) { + throw new Ex\IOException( + 'Could not get current position in input file during decryption' + ); + } + + /* Read the next buffer-sized chunk (or less). */ + if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) { + $break = true; + $read = self::readBytes( + $inputHandle, + $cipher_end - $pos + 1 + ); + } else { + $read = self::readBytes( + $inputHandle, + Core::BUFFER_BYTE_SIZE + ); + } + + /* Update the HMAC. */ + \hash_update($hmac, $read); + + /* Remember this buffer-sized chunk's HMAC. */ + /** @var resource $chunk_mac */ + $chunk_mac = \hash_copy($hmac); + if (!\is_resource($chunk_mac)) { + throw new Ex\EnvironmentIsBrokenException( + 'Cannot duplicate a hash context' + ); + } + $macs []= \hash_final($chunk_mac); + } + + /* Get the final HMAC, which should match the stored one. */ + /** @var string $final_mac */ + $final_mac = \hash_final($hmac, true); + + /* Verify the HMAC. */ + if (! Core::hashEquals($final_mac, $stored_mac)) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'Integrity check failed.' + ); + } + + /* PASS #2: Decrypt and write output. */ + + /* Rewind to the start of the actual ciphertext. */ + if (\fseek($inputHandle, Core::SALT_BYTE_SIZE + $ivsize + Core::HEADER_VERSION_SIZE, SEEK_SET) === false) { + throw new Ex\IOException( + 'Could not move the input file pointer during decryption' + ); + } + + $at_file_end = false; + while (! $at_file_end) { + /** @var int $pos */ + $pos = \ftell($inputHandle); + if (!\is_int($pos)) { + throw new Ex\IOException( + 'Could not get current position in input file during decryption' + ); + } + + /* Read the next buffer-sized chunk (or less). */ + if ($pos + Core::BUFFER_BYTE_SIZE >= $cipher_end) { + $at_file_end = true; + $read = self::readBytes( + $inputHandle, + $cipher_end - $pos + 1 + ); + } else { + $read = self::readBytes( + $inputHandle, + Core::BUFFER_BYTE_SIZE + ); + } + + /* Recalculate the MAC (so far) and compare it with the one we + * remembered from pass #1 to ensure attackers didn't change the + * ciphertext after MAC verification. */ + \hash_update($hmac2, $read); + /** @var resource $calc_mac */ + $calc_mac = \hash_copy($hmac2); + if (!\is_resource($calc_mac)) { + throw new Ex\EnvironmentIsBrokenException( + 'Cannot duplicate a hash context' + ); + } + $calc = \hash_final($calc_mac); + + if (empty($macs)) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'File was modified after MAC verification' + ); + } elseif (! Core::hashEquals(\array_shift($macs), $calc)) { + throw new Ex\WrongKeyOrModifiedCiphertextException( + 'File was modified after MAC verification' + ); + } + + /* Decrypt this buffer-sized chunk. */ + /** @var string $decrypted */ + $decrypted = \openssl_decrypt( + $read, + Core::CIPHER_METHOD, + $ekey, + OPENSSL_RAW_DATA, + $thisIv + ); + if (!\is_string($decrypted)) { + throw new Ex\EnvironmentIsBrokenException( + 'OpenSSL decryption error' + ); + } + + /* Write the plaintext to the output file. */ + self::writeBytes( + $outputHandle, + $decrypted, + Core::ourStrlen($decrypted) + ); + + /* Increment the IV by the amount of blocks in a buffer. */ + /** @var string $thisIv */ + $thisIv = Core::incrementCounter($thisIv, $inc); + /* WARNING: Usually, unless the file is a multiple of the buffer + * size, $thisIv will contain an incorrect value here on the last + * iteration of this loop. */ + } + } + + /** + * Read from a stream; prevent partial reads. + * + * @param resource $stream + * @param int $num_bytes + * @return string + * + * @throws Ex\IOException + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + public static function readBytes($stream, $num_bytes) + { + if ($num_bytes < 0) { + throw new Ex\EnvironmentIsBrokenException( + 'Tried to read less than 0 bytes' + ); + } elseif ($num_bytes === 0) { + return ''; + } + $buf = ''; + $remaining = $num_bytes; + while ($remaining > 0 && ! \feof($stream)) { + /** @var string $read */ + $read = \fread($stream, $remaining); + if (!\is_string($read)) { + throw new Ex\IOException( + 'Could not read from the file' + ); + } + $buf .= $read; + $remaining -= Core::ourStrlen($read); + } + if (Core::ourStrlen($buf) !== $num_bytes) { + throw new Ex\IOException( + 'Tried to read past the end of the file' + ); + } + return $buf; + } + + /** + * Write to a stream; prevents partial writes. + * + * @param resource $stream + * @param string $buf + * @param int $num_bytes + * @return int + * + * @throws Ex\IOException + * + * @return string + */ + public static function writeBytes($stream, $buf, $num_bytes = null) + { + $bufSize = Core::ourStrlen($buf); + if ($num_bytes === null) { + $num_bytes = $bufSize; + } + if ($num_bytes > $bufSize) { + throw new Ex\IOException( + 'Trying to write more bytes than the buffer contains.' + ); + } + if ($num_bytes < 0) { + throw new Ex\IOException( + 'Tried to write less than 0 bytes' + ); + } + $remaining = $num_bytes; + while ($remaining > 0) { + /** @var int $written */ + $written = \fwrite($stream, $buf, $remaining); + if (!\is_int($written)) { + throw new Ex\IOException( + 'Could not write to the file' + ); + } + $buf = (string) Core::ourSubstr($buf, $written, null); + $remaining -= $written; + } + return $num_bytes; + } + + /** + * Returns the last PHP error's or warning's message string. + * + * @return string + */ + private static function getLastErrorMessage() + { + $error = error_get_last(); + if ($error === null) { + return '[no PHP error]'; + } else { + return $error['message']; + } + } +} diff --git a/vendor/defuse/php-encryption/src/Key.php b/vendor/defuse/php-encryption/src/Key.php new file mode 100644 index 0000000000..fe4bf7d542 --- /dev/null +++ b/vendor/defuse/php-encryption/src/Key.php @@ -0,0 +1,95 @@ +key_bytes + ); + } + + /** + * Gets the raw bytes of the key. + * + * @return string + */ + public function getRawBytes() + { + return $this->key_bytes; + } + + /** + * Constructs a new Key object from a string of raw bytes. + * + * @param string $bytes + * + * @throws Ex\EnvironmentIsBrokenException + */ + private function __construct($bytes) + { + if (Core::ourStrlen($bytes) !== self::KEY_BYTE_SIZE) { + throw new Ex\EnvironmentIsBrokenException( + 'Bad key length.' + ); + } + $this->key_bytes = $bytes; + } + +} diff --git a/vendor/defuse/php-encryption/src/KeyOrPassword.php b/vendor/defuse/php-encryption/src/KeyOrPassword.php new file mode 100644 index 0000000000..4a810d3f62 --- /dev/null +++ b/vendor/defuse/php-encryption/src/KeyOrPassword.php @@ -0,0 +1,133 @@ +secret_type === self::SECRET_TYPE_KEY) { + if (!($this->secret instanceof Key)) { + throw new Ex\CryptoException('Expected a Key object'); + } + $akey = Core::HKDF( + Core::HASH_FUNCTION_NAME, + $this->secret->getRawBytes(), + Core::KEY_BYTE_SIZE, + Core::AUTHENTICATION_INFO_STRING, + $salt + ); + $ekey = Core::HKDF( + Core::HASH_FUNCTION_NAME, + $this->secret->getRawBytes(), + Core::KEY_BYTE_SIZE, + Core::ENCRYPTION_INFO_STRING, + $salt + ); + return new DerivedKeys($akey, $ekey); + } elseif ($this->secret_type === self::SECRET_TYPE_PASSWORD) { + if (!\is_string($this->secret)) { + throw new Ex\CryptoException('Expected a string'); + } + /* Our PBKDF2 polyfill is vulnerable to a DoS attack documented in + * GitHub issue #230. The fix is to pre-hash the password to ensure + * it is short. We do the prehashing here instead of in pbkdf2() so + * that pbkdf2() still computes the function as defined by the + * standard. */ + $prehash = \hash(Core::HASH_FUNCTION_NAME, $this->secret, true); + $prekey = Core::pbkdf2( + Core::HASH_FUNCTION_NAME, + $prehash, + $salt, + self::PBKDF2_ITERATIONS, + Core::KEY_BYTE_SIZE, + true + ); + $akey = Core::HKDF( + Core::HASH_FUNCTION_NAME, + $prekey, + Core::KEY_BYTE_SIZE, + Core::AUTHENTICATION_INFO_STRING, + $salt + ); + /* Note the cryptographic re-use of $salt here. */ + $ekey = Core::HKDF( + Core::HASH_FUNCTION_NAME, + $prekey, + Core::KEY_BYTE_SIZE, + Core::ENCRYPTION_INFO_STRING, + $salt + ); + return new DerivedKeys($akey, $ekey); + } else { + throw new Ex\EnvironmentIsBrokenException('Bad secret type.'); + } + } + + /** + * Constructor for KeyOrPassword. + * + * @param int $secret_type + * @param mixed $secret (either a Key or a password string) + */ + private function __construct($secret_type, $secret) + { + $this->secret_type = $secret_type; + $this->secret = $secret; + } +} diff --git a/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php b/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php new file mode 100644 index 0000000000..9d32e76295 --- /dev/null +++ b/vendor/defuse/php-encryption/src/KeyProtectedByPassword.php @@ -0,0 +1,115 @@ +saveToAsciiSafeString(), + \hash(Core::HASH_FUNCTION_NAME, $password, true), + true + ); + + return new KeyProtectedByPassword($encrypted_key); + } + + /** + * Loads a KeyProtectedByPassword from its encoded form. + * + * @param string $saved_key_string + * + * @throws Ex\BadFormatException + * + * @return KeyProtectedByPassword + */ + public static function loadFromAsciiSafeString($saved_key_string) + { + $encrypted_key = Encoding::loadBytesFromChecksummedAsciiSafeString( + self::PASSWORD_KEY_CURRENT_VERSION, + $saved_key_string + ); + return new KeyProtectedByPassword($encrypted_key); + } + + /** + * Encodes the KeyProtectedByPassword into a string of printable ASCII + * characters. + * + * @throws Ex\EnvironmentIsBrokenException + * + * @return string + */ + public function saveToAsciiSafeString() + { + return Encoding::saveBytesToChecksummedAsciiSafeString( + self::PASSWORD_KEY_CURRENT_VERSION, + $this->encrypted_key + ); + } + + /** + * Decrypts the protected key, returning an unprotected Key object that can + * be used for encryption and decryption. + * + * @throws Ex\EnvironmentIsBrokenException + * @throws Ex\WrongKeyOrModifiedCiphertextException + * + * @return Key + */ + public function unlockKey($password) + { + try { + $inner_key_encoded = Crypto::decryptWithPassword( + $this->encrypted_key, + \hash(Core::HASH_FUNCTION_NAME, $password, true), + true + ); + return Key::loadFromAsciiSafeString($inner_key_encoded); + } catch (Ex\BadFormatException $ex) { + /* This should never happen unless an attacker replaced the + * encrypted key ciphertext with some other ciphertext that was + * encrypted with the same password. We transform the exception type + * here in order to make the API simpler, avoiding the need to + * document that this method might throw an Ex\BadFormatException. */ + throw new Ex\WrongKeyOrModifiedCiphertextException( + "The decrypted key was found to be in an invalid format. " . + "This very likely indicates it was modified by an attacker." + ); + } + } + + /** + * Constructor for KeyProtectedByPassword. + * + * @param string $encrypted_key + */ + private function __construct($encrypted_key) + { + $this->encrypted_key = $encrypted_key; + } +} diff --git a/vendor/defuse/php-encryption/src/RuntimeTests.php b/vendor/defuse/php-encryption/src/RuntimeTests.php new file mode 100644 index 0000000000..9f00a97a1f --- /dev/null +++ b/vendor/defuse/php-encryption/src/RuntimeTests.php @@ -0,0 +1,247 @@ +getRawBytes()) != Core::KEY_BYTE_SIZE) { + throw new Ex\EnvironmentIsBrokenException(); + } + + if (Core::ENCRYPTION_INFO_STRING == Core::AUTHENTICATION_INFO_STRING) { + throw new Ex\EnvironmentIsBrokenException(); + } + } catch (Ex\EnvironmentIsBrokenException $ex) { + // Do this, otherwise it will stay in the "tests are running" state. + $test_state = 3; + throw $ex; + } + + // Change this to '0' make the tests always re-run (for benchmarking). + $test_state = 1; + } + + /** + * High-level tests of Crypto operations. + * + * @throws Ex\EnvironmentIsBrokenException + * @return void + */ + private static function testEncryptDecrypt() + { + $key = Key::createNewRandomKey(); + $data = "EnCrYpT EvErYThInG\x00\x00"; + + // Make sure encrypting then decrypting doesn't change the message. + $ciphertext = Crypto::encrypt($data, $key, true); + try { + $decrypted = Crypto::decrypt($ciphertext, $key, true); + } catch (Ex\WrongKeyOrModifiedCiphertextException $ex) { + // It's important to catch this and change it into a + // Ex\EnvironmentIsBrokenException, otherwise a test failure could trick + // the user into thinking it's just an invalid ciphertext! + throw new Ex\EnvironmentIsBrokenException(); + } + if ($decrypted !== $data) { + throw new Ex\EnvironmentIsBrokenException(); + } + + // Modifying the ciphertext: Appending a string. + try { + Crypto::decrypt($ciphertext . 'a', $key, true); + throw new Ex\EnvironmentIsBrokenException(); + } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */ + } + + // Modifying the ciphertext: Changing an HMAC byte. + $indices_to_change = [ + 0, // The header. + Core::HEADER_VERSION_SIZE + 1, // the salt + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + 1, // the IV + Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE + Core::BLOCK_BYTE_SIZE + 1, // the ciphertext + ]; + + foreach ($indices_to_change as $index) { + try { + $ciphertext[$index] = \chr((\ord($ciphertext[$index]) + 1) % 256); + Crypto::decrypt($ciphertext, $key, true); + throw new Ex\EnvironmentIsBrokenException(); + } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */ + } + } + + // Decrypting with the wrong key. + $key = Key::createNewRandomKey(); + $data = 'abcdef'; + $ciphertext = Crypto::encrypt($data, $key, true); + $wrong_key = Key::createNewRandomKey(); + try { + Crypto::decrypt($ciphertext, $wrong_key, true); + throw new Ex\EnvironmentIsBrokenException(); + } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */ + } + + // Ciphertext too small. + $key = Key::createNewRandomKey(); + $ciphertext = \str_repeat('A', Core::MINIMUM_CIPHERTEXT_SIZE - 1); + try { + Crypto::decrypt($ciphertext, $key, true); + throw new Ex\EnvironmentIsBrokenException(); + } catch (Ex\WrongKeyOrModifiedCiphertextException $e) { /* expected */ + } + } + + /** + * Test HKDF against test vectors. + * + * @throws Ex\EnvironmentIsBrokenException + * @return void + */ + private static function HKDFTestVector() + { + // HKDF test vectors from RFC 5869 + + // Test Case 1 + $ikm = \str_repeat("\x0b", 22); + $salt = Encoding::hexToBin('000102030405060708090a0b0c'); + $info = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9'); + $length = 42; + $okm = Encoding::hexToBin( + '3cb25f25faacd57a90434f64d0362f2a' . + '2d2d0a90cf1a5a4c5db02d56ecc4c5bf' . + '34007208d5b887185865' + ); + $computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt); + if ($computed_okm !== $okm) { + throw new Ex\EnvironmentIsBrokenException(); + } + + // Test Case 7 + $ikm = \str_repeat("\x0c", 22); + $length = 42; + $okm = Encoding::hexToBin( + '2c91117204d745f3500d636a62f64f0a' . + 'b3bae548aa53d423b0d1f27ebba6f5e5' . + '673a081d70cce7acfc48' + ); + $computed_okm = Core::HKDF('sha1', $ikm, $length, '', null); + if ($computed_okm !== $okm) { + throw new Ex\EnvironmentIsBrokenException(); + } + } + + /** + * Test HMAC against test vectors. + * + * @throws Ex\EnvironmentIsBrokenException + * @return void + */ + private static function HMACTestVector() + { + // HMAC test vector From RFC 4231 (Test Case 1) + $key = \str_repeat("\x0b", 20); + $data = 'Hi There'; + $correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7'; + if (\hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) !== $correct) { + throw new Ex\EnvironmentIsBrokenException(); + } + } + + /** + * Test AES against test vectors. + * + * @throws Ex\EnvironmentIsBrokenException + * @return void + */ + private static function AESTestVector() + { + // AES CTR mode test vector from NIST SP 800-38A + $key = Encoding::hexToBin( + '603deb1015ca71be2b73aef0857d7781' . + '1f352c073b6108d72d9810a30914dff4' + ); + $iv = Encoding::hexToBin('f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff'); + $plaintext = Encoding::hexToBin( + '6bc1bee22e409f96e93d7e117393172a' . + 'ae2d8a571e03ac9c9eb76fac45af8e51' . + '30c81c46a35ce411e5fbc1191a0a52ef' . + 'f69f2445df4f9b17ad2b417be66c3710' + ); + $ciphertext = Encoding::hexToBin( + '601ec313775789a5b7a7f504bbf3d228' . + 'f443e3ca4d62b59aca84e990cacaf5c5' . + '2b0930daa23de94ce87017ba2d84988d' . + 'dfc9c58db67aada613c2dd08457941a6' + ); + + $computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv); + if ($computed_ciphertext !== $ciphertext) { + echo \str_repeat("\n", 30); + echo \bin2hex($computed_ciphertext); + echo "\n---\n"; + echo \bin2hex($ciphertext); + echo \str_repeat("\n", 30); + throw new Ex\EnvironmentIsBrokenException(); + } + + $computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD); + if ($computed_plaintext !== $plaintext) { + throw new Ex\EnvironmentIsBrokenException(); + } + } +} diff --git a/vendor/paragonie/random_compat/LICENSE b/vendor/paragonie/random_compat/LICENSE new file mode 100644 index 0000000000..45c7017dfb --- /dev/null +++ b/vendor/paragonie/random_compat/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Paragon Initiative Enterprises + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/vendor/paragonie/random_compat/build-phar.sh b/vendor/paragonie/random_compat/build-phar.sh new file mode 100644 index 0000000000..b4a5ba31cc --- /dev/null +++ b/vendor/paragonie/random_compat/build-phar.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +basedir=$( dirname $( readlink -f ${BASH_SOURCE[0]} ) ) + +php -dphar.readonly=0 "$basedir/other/build_phar.php" $* \ No newline at end of file diff --git a/vendor/paragonie/random_compat/composer.json b/vendor/paragonie/random_compat/composer.json new file mode 100644 index 0000000000..1c5978c6fb --- /dev/null +++ b/vendor/paragonie/random_compat/composer.json @@ -0,0 +1,37 @@ +{ + "name": "paragonie/random_compat", + "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", + "keywords": [ + "csprng", + "random", + "pseudorandom" + ], + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Paragon Initiative Enterprises", + "email": "security@paragonie.com", + "homepage": "https://paragonie.com" + } + ], + "support": { + "issues": "https://github.com/paragonie/random_compat/issues", + "email": "info@paragonie.com", + "source": "https://github.com/paragonie/random_compat" + }, + "require": { + "php": ">=5.2.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*|5.*" + }, + "suggest": { + "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." + }, + "autoload": { + "files": [ + "lib/random.php" + ] + } +} diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey new file mode 100644 index 0000000000..eb50ebfcd6 --- /dev/null +++ b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey @@ -0,0 +1,5 @@ +-----BEGIN PUBLIC KEY----- +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEEd+wCqJDrx5B4OldM0dQE0ZMX+lx1ZWm +pui0SUqD4G29L3NGsz9UhJ/0HjBdbnkhIK5xviT0X5vtjacF6ajgcCArbTB+ds+p ++h7Q084NuSuIpNb6YPfoUFgC/CL9kAoc +-----END PUBLIC KEY----- diff --git a/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc new file mode 100644 index 0000000000..6a1d7f3006 --- /dev/null +++ b/vendor/paragonie/random_compat/dist/random_compat.phar.pubkey.asc @@ -0,0 +1,11 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v2.0.22 (MingW32) + +iQEcBAABAgAGBQJWtW1hAAoJEGuXocKCZATaJf0H+wbZGgskK1dcRTsuVJl9IWip +QwGw/qIKI280SD6/ckoUMxKDCJiFuPR14zmqnS36k7N5UNPnpdTJTS8T11jttSpg +1LCmgpbEIpgaTah+cELDqFCav99fS+bEiAL5lWDAHBTE/XPjGVCqeehyPYref4IW +NDBIEsvnHPHPLsn6X5jq4+Yj5oUixgxaMPiR+bcO4Sh+RzOVB6i2D0upWfRXBFXA +NNnsg9/zjvoC7ZW73y9uSH+dPJTt/Vgfeiv52/v41XliyzbUyLalf02GNPY+9goV +JHG1ulEEBJOCiUD9cE1PUIJwHA/HqyhHIvV350YoEFiHl8iSwm7SiZu5kPjaq74= +=B6+8 +-----END PGP SIGNATURE----- diff --git a/vendor/paragonie/random_compat/lib/byte_safe_strings.php b/vendor/paragonie/random_compat/lib/byte_safe_strings.php new file mode 100644 index 0000000000..3de86b223c --- /dev/null +++ b/vendor/paragonie/random_compat/lib/byte_safe_strings.php @@ -0,0 +1,181 @@ + RandomCompat_strlen($binary_string)) { + return ''; + } + + return (string) mb_substr($binary_string, $start, $length, '8bit'); + } + + } else { + + /** + * substr() implementation that isn't brittle to mbstring.func_overload + * + * This version just uses the default substr() + * + * @param string $binary_string + * @param int $start + * @param int $length (optional) + * + * @throws TypeError + * + * @return string + */ + function RandomCompat_substr($binary_string, $start, $length = null) + { + if (!is_string($binary_string)) { + throw new TypeError( + 'RandomCompat_substr(): First argument should be a string' + ); + } + + if (!is_int($start)) { + throw new TypeError( + 'RandomCompat_substr(): Second argument should be an integer' + ); + } + + if ($length !== null) { + if (!is_int($length)) { + throw new TypeError( + 'RandomCompat_substr(): Third argument should be an integer, or omitted' + ); + } + + return (string) substr($binary_string, $start, $length); + } + + return (string) substr($binary_string, $start); + } + } +} diff --git a/vendor/paragonie/random_compat/lib/cast_to_int.php b/vendor/paragonie/random_compat/lib/cast_to_int.php new file mode 100644 index 0000000000..9a4fab9919 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/cast_to_int.php @@ -0,0 +1,75 @@ + operators might accidentally let a float + * through. + * + * @param int|float $number The number we want to convert to an int + * @param bool $fail_open Set to true to not throw an exception + * + * @return float|int + * @psalm-suppress InvalidReturnType + * + * @throws TypeError + */ + function RandomCompat_intval($number, $fail_open = false) + { + if (is_int($number) || is_float($number)) { + $number += 0; + } elseif (is_numeric($number)) { + $number += 0; + } + + if ( + is_float($number) + && + $number > ~PHP_INT_MAX + && + $number < PHP_INT_MAX + ) { + $number = (int) $number; + } + + if (is_int($number)) { + return (int) $number; + } elseif (!$fail_open) { + throw new TypeError( + 'Expected an integer.' + ); + } + return $number; + } +} diff --git a/vendor/paragonie/random_compat/lib/error_polyfill.php b/vendor/paragonie/random_compat/lib/error_polyfill.php new file mode 100644 index 0000000000..6a91990ce6 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/error_polyfill.php @@ -0,0 +1,49 @@ += 70000) { + return; +} + +if (!defined('RANDOM_COMPAT_READ_BUFFER')) { + define('RANDOM_COMPAT_READ_BUFFER', 8); +} + +$RandomCompatDIR = dirname(__FILE__); + +require_once $RandomCompatDIR . '/byte_safe_strings.php'; +require_once $RandomCompatDIR . '/cast_to_int.php'; +require_once $RandomCompatDIR . '/error_polyfill.php'; + +if (!is_callable('random_bytes')) { + /** + * PHP 5.2.0 - 5.6.x way to implement random_bytes() + * + * We use conditional statements here to define the function in accordance + * to the operating environment. It's a micro-optimization. + * + * In order of preference: + * 1. Use libsodium if available. + * 2. fread() /dev/urandom if available (never on Windows) + * 3. mcrypt_create_iv($bytes, MCRYPT_DEV_URANDOM) + * 4. COM('CAPICOM.Utilities.1')->GetRandom() + * + * See RATIONALE.md for our reasoning behind this particular order + */ + if (extension_loaded('libsodium')) { + // See random_bytes_libsodium.php + if (PHP_VERSION_ID >= 50300 && is_callable('\\Sodium\\randombytes_buf')) { + require_once $RandomCompatDIR . '/random_bytes_libsodium.php'; + } elseif (method_exists('Sodium', 'randombytes_buf')) { + require_once $RandomCompatDIR . '/random_bytes_libsodium_legacy.php'; + } + } + + /** + * Reading directly from /dev/urandom: + */ + if (DIRECTORY_SEPARATOR === '/') { + // DIRECTORY_SEPARATOR === '/' on Unix-like OSes -- this is a fast + // way to exclude Windows. + $RandomCompatUrandom = true; + $RandomCompat_basedir = ini_get('open_basedir'); + + if (!empty($RandomCompat_basedir)) { + $RandomCompat_open_basedir = explode( + PATH_SEPARATOR, + strtolower($RandomCompat_basedir) + ); + $RandomCompatUrandom = (array() !== array_intersect( + array('/dev', '/dev/', '/dev/urandom'), + $RandomCompat_open_basedir + )); + $RandomCompat_open_basedir = null; + } + + if ( + !is_callable('random_bytes') + && + $RandomCompatUrandom + && + @is_readable('/dev/urandom') + ) { + // Error suppression on is_readable() in case of an open_basedir + // or safe_mode failure. All we care about is whether or not we + // can read it at this point. If the PHP environment is going to + // panic over trying to see if the file can be read in the first + // place, that is not helpful to us here. + + // See random_bytes_dev_urandom.php + require_once $RandomCompatDIR . '/random_bytes_dev_urandom.php'; + } + // Unset variables after use + $RandomCompat_basedir = null; + } else { + $RandomCompatUrandom = false; + } + + /** + * mcrypt_create_iv() + * + * We only want to use mcypt_create_iv() if: + * + * - random_bytes() hasn't already been defined + * - the mcrypt extensions is loaded + * - One of these two conditions is true: + * - We're on Windows (DIRECTORY_SEPARATOR !== '/') + * - We're not on Windows and /dev/urandom is readabale + * (i.e. we're not in a chroot jail) + * - Special case: + * - If we're not on Windows, but the PHP version is between + * 5.6.10 and 5.6.12, we don't want to use mcrypt. It will + * hang indefinitely. This is bad. + * - If we're on Windows, we want to use PHP >= 5.3.7 or else + * we get insufficient entropy errors. + */ + if ( + !is_callable('random_bytes') + && + // Windows on PHP < 5.3.7 is broken, but non-Windows is not known to be. + (DIRECTORY_SEPARATOR === '/' || PHP_VERSION_ID >= 50307) + && + // Prevent this code from hanging indefinitely on non-Windows; + // see https://bugs.php.net/bug.php?id=69833 + ( + DIRECTORY_SEPARATOR !== '/' || + (PHP_VERSION_ID <= 50609 || PHP_VERSION_ID >= 50613) + ) + && + extension_loaded('mcrypt') + ) { + // See random_bytes_mcrypt.php + require_once $RandomCompatDIR . '/random_bytes_mcrypt.php'; + } + $RandomCompatUrandom = null; + + /** + * This is a Windows-specific fallback, for when the mcrypt extension + * isn't loaded. + */ + if ( + !is_callable('random_bytes') + && + extension_loaded('com_dotnet') + && + class_exists('COM') + ) { + $RandomCompat_disabled_classes = preg_split( + '#\s*,\s*#', + strtolower(ini_get('disable_classes')) + ); + + if (!in_array('com', $RandomCompat_disabled_classes)) { + try { + $RandomCompatCOMtest = new COM('CAPICOM.Utilities.1'); + if (method_exists($RandomCompatCOMtest, 'GetRandom')) { + // See random_bytes_com_dotnet.php + require_once $RandomCompatDIR . '/random_bytes_com_dotnet.php'; + } + } catch (com_exception $e) { + // Don't try to use it. + } + } + $RandomCompat_disabled_classes = null; + $RandomCompatCOMtest = null; + } + + /** + * throw new Exception + */ + if (!is_callable('random_bytes')) { + /** + * We don't have any more options, so let's throw an exception right now + * and hope the developer won't let it fail silently. + * + * @param mixed $length + * @return void + * @throws Exception + */ + function random_bytes($length) + { + unset($length); // Suppress "variable not used" warnings. + throw new Exception( + 'There is no suitable CSPRNG installed on your system' + ); + } + } +} + +if (!is_callable('random_int')) { + require_once $RandomCompatDIR . '/random_int.php'; +} + +$RandomCompatDIR = null; diff --git a/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php new file mode 100644 index 0000000000..fc1926e5ca --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_com_dotnet.php @@ -0,0 +1,88 @@ +GetRandom($bytes, 0)); + if (RandomCompat_strlen($buf) >= $bytes) { + /** + * Return our random entropy buffer here: + */ + return RandomCompat_substr($buf, 0, $bytes); + } + ++$execCount; + } while ($execCount < $bytes); + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} \ No newline at end of file diff --git a/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php new file mode 100644 index 0000000000..df5b91524e --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_dev_urandom.php @@ -0,0 +1,167 @@ + 0); + + /** + * Is our result valid? + */ + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + /** + * Return our random entropy buffer here: + */ + return $buf; + } + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Error reading from source device' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php new file mode 100644 index 0000000000..4af1a24227 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_libsodium.php @@ -0,0 +1,88 @@ + 2147483647) { + $buf = ''; + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= \Sodium\randombytes_buf($n); + } + } else { + $buf = \Sodium\randombytes_buf($bytes); + } + + if ($buf !== false) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php new file mode 100644 index 0000000000..705af5262b --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_libsodium_legacy.php @@ -0,0 +1,92 @@ + 2147483647) { + for ($i = 0; $i < $bytes; $i += 1073741824) { + $n = ($bytes - $i) > 1073741824 + ? 1073741824 + : $bytes - $i; + $buf .= Sodium::randombytes_buf((int) $n); + } + } else { + $buf .= Sodium::randombytes_buf((int) $bytes); + } + + if (is_string($buf)) { + if (RandomCompat_strlen($buf) === $bytes) { + return $buf; + } + } + + /** + * If we reach here, PHP has failed us. + */ + throw new Exception( + 'Could not gather sufficient random data' + ); + } +} diff --git a/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php new file mode 100644 index 0000000000..aac9c013d4 --- /dev/null +++ b/vendor/paragonie/random_compat/lib/random_bytes_mcrypt.php @@ -0,0 +1,77 @@ + operators might accidentally let a float + * through. + */ + + try { + $min = RandomCompat_intval($min); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $min must be an integer' + ); + } + + try { + $max = RandomCompat_intval($max); + } catch (TypeError $ex) { + throw new TypeError( + 'random_int(): $max must be an integer' + ); + } + + /** + * Now that we've verified our weak typing system has given us an integer, + * let's validate the logic then we can move forward with generating random + * integers along a given range. + */ + if ($min > $max) { + throw new Error( + 'Minimum value must be less than or equal to the maximum value' + ); + } + + if ($max === $min) { + return (int) $min; + } + + /** + * Initialize variables to 0 + * + * We want to store: + * $bytes => the number of random bytes we need + * $mask => an integer bitmask (for use with the &) operator + * so we can minimize the number of discards + */ + $attempts = $bits = $bytes = $mask = $valueShift = 0; + + /** + * At this point, $range is a positive number greater than 0. It might + * overflow, however, if $max - $min > PHP_INT_MAX. PHP will cast it to + * a float and we will lose some precision. + */ + $range = $max - $min; + + /** + * Test for integer overflow: + */ + if (!is_int($range)) { + + /** + * Still safely calculate wider ranges. + * Provided by @CodesInChaos, @oittaa + * + * @ref https://gist.github.com/CodesInChaos/03f9ea0b58e8b2b8d435 + * + * We use ~0 as a mask in this case because it generates all 1s + * + * @ref https://eval.in/400356 (32-bit) + * @ref http://3v4l.org/XX9r5 (64-bit) + */ + $bytes = PHP_INT_SIZE; + $mask = ~0; + + } else { + + /** + * $bits is effectively ceil(log($range, 2)) without dealing with + * type juggling + */ + while ($range > 0) { + if ($bits % 8 === 0) { + ++$bytes; + } + ++$bits; + $range >>= 1; + $mask = $mask << 1 | 1; + } + $valueShift = $min; + } + + $val = 0; + /** + * Now that we have our parameters set up, let's begin generating + * random integers until one falls between $min and $max + */ + do { + /** + * The rejection probability is at most 0.5, so this corresponds + * to a failure probability of 2^-128 for a working RNG + */ + if ($attempts > 128) { + throw new Exception( + 'random_int: RNG is broken - too many rejections' + ); + } + + /** + * Let's grab the necessary number of random bytes + */ + $randomByteString = random_bytes($bytes); + + /** + * Let's turn $randomByteString into an integer + * + * This uses bitwise operators (<< and |) to build an integer + * out of the values extracted from ord() + * + * Example: [9F] | [6D] | [32] | [0C] => + * 159 + 27904 + 3276800 + 201326592 => + * 204631455 + */ + $val &= 0; + for ($i = 0; $i < $bytes; ++$i) { + $val |= ord($randomByteString[$i]) << ($i * 8); + } + + /** + * Apply mask + */ + $val &= $mask; + $val += $valueShift; + + ++$attempts; + /** + * If $val overflows to a floating point number, + * ... or is larger than $max, + * ... or smaller than $min, + * then try again. + */ + } while (!is_int($val) || $val > $max || $val < $min); + + return (int) $val; + } +} diff --git a/vendor/paragonie/random_compat/other/build_phar.php b/vendor/paragonie/random_compat/other/build_phar.php new file mode 100644 index 0000000000..70ef4b2ed8 --- /dev/null +++ b/vendor/paragonie/random_compat/other/build_phar.php @@ -0,0 +1,57 @@ +buildFromDirectory(dirname(__DIR__).'/lib'); +rename( + dirname(__DIR__).'/lib/index.php', + dirname(__DIR__).'/lib/random.php' +); + +/** + * If we pass an (optional) path to a private key as a second argument, we will + * sign the Phar with OpenSSL. + * + * If you leave this out, it will produce an unsigned .phar! + */ +if ($argc > 1) { + if (!@is_readable($argv[1])) { + echo 'Could not read the private key file:', $argv[1], "\n"; + exit(255); + } + $pkeyFile = file_get_contents($argv[1]); + + $private = openssl_get_privatekey($pkeyFile); + if ($private !== false) { + $pkey = ''; + openssl_pkey_export($private, $pkey); + $phar->setSignatureAlgorithm(Phar::OPENSSL, $pkey); + + /** + * Save the corresponding public key to the file + */ + if (!@is_readable($dist.'/random_compat.phar.pubkey')) { + $details = openssl_pkey_get_details($private); + file_put_contents( + $dist.'/random_compat.phar.pubkey', + $details['key'] + ); + } + } else { + echo 'An error occurred reading the private key from OpenSSL.', "\n"; + exit(255); + } +} diff --git a/vendor/paragonie/random_compat/psalm-autoload.php b/vendor/paragonie/random_compat/psalm-autoload.php new file mode 100644 index 0000000000..d71d1b818c --- /dev/null +++ b/vendor/paragonie/random_compat/psalm-autoload.php @@ -0,0 +1,9 @@ + + + + + + + + + + + + From acd65aade17c2e8db1dcb012b6d14a732bc87244 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 9 Nov 2017 02:21:37 -0500 Subject: [PATCH 3/7] Switch to new php-encryption library version - Remove references to library/ files - Add namespace to library classes --- include/items.php | 3 --- mod/dfrn_notify.php | 15 +++++---------- src/Protocol/DFRN.php | 16 +++++----------- 3 files changed, 10 insertions(+), 24 deletions(-) diff --git a/include/items.php b/include/items.php index 64aeabceab..6d4d30e7cb 100644 --- a/include/items.php +++ b/include/items.php @@ -33,9 +33,6 @@ require_once 'mod/share.php'; require_once 'include/enotify.php'; require_once 'include/group.php'; -/// @TODO one day with composer autoloader no more needed -require_once 'library/defuse/php-encryption-1.2.1/Crypto.php'; - function construct_verb($item) { if ($item['verb']) { return $item['verb']; diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index e0e30a2488..c8dc093d17 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -11,10 +11,8 @@ use Friendica\Core\Config; use Friendica\Database\DBM; use Friendica\Protocol\DFRN; -require_once('include/items.php'); -require_once('include/event.php'); - -require_once('library/defuse/php-encryption-1.2.1/Crypto.php'); +require_once 'include/items.php'; +require_once 'include/event.php'; function dfrn_notify_post(App $a) { logger(__function__, LOGGER_TRACE); @@ -185,8 +183,8 @@ function dfrn_notify_post(App $a) { break; case 2: try { - $data = Crypto::decrypt(hex2bin($data), $final_key); - } catch (InvalidCiphertext $ex) { // VERY IMPORTANT + $data = \Defuse\Crypto\Crypto::decrypt(hex2bin($data), $final_key); + } catch (\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) { // VERY IMPORTANT /* * Either: * 1. The ciphertext was modified by the attacker, @@ -196,12 +194,9 @@ function dfrn_notify_post(App $a) { */ logger('The ciphertext has been tampered with!'); xml_status(0, 'The ciphertext has been tampered with!'); - } catch (Ex\CryptoTestFailed $ex) { + } catch (\Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) { logger('Cannot safely perform dencryption'); xml_status(0, 'CryptoTestFailed'); - } catch (Ex\CannotPerformOperation $ex) { - logger('Cannot safely perform decryption'); - xml_status(0, 'Cannot safely perform decryption'); } break; default: diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index f400d033ea..6ba8ed7d10 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1296,26 +1296,20 @@ class DFRN case 2: // RINO 2 based on php-encryption try { - $key = Crypto::createNewRandomKey(); - } catch (CryptoTestFailed $ex) { + $key = \Defuse\Crypto\Key::createNewRandomKey(); + } catch (\Defuse\Crypto\Exception\CryptoException $ex) { logger('Cannot safely create a key'); return -4; - } catch (CannotPerformOperation $ex) { - logger('Cannot safely create a key'); - return -5; } try { - $data = Crypto::encrypt($postvars['data'], $key); - } catch (CryptoTestFailed $ex) { + $data = \Defuse\Crypto\Crypto::encrypt($postvars['data'], $key); + } catch (\Defuse\Crypto\Exception\CryptoException $ex) { logger('Cannot safely perform encryption'); return -6; - } catch (CannotPerformOperation $ex) { - logger('Cannot safely perform encryption'); - return -7; } break; default: - logger("rino: invalid requested verision '$rino_remote_version'"); + logger("rino: invalid requested version '$rino_remote_version'"); return -8; } From b4ce07bdc5d9dea67f3e00947f8f80f57078c096 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 9 Nov 2017 02:21:54 -0500 Subject: [PATCH 4/7] Remove old library defuse/php-encryption --- .../defuse/php-encryption-1.2.1/.travis.yml | 22 - .../defuse/php-encryption-1.2.1/Crypto.php | 677 ------------------ library/defuse/php-encryption-1.2.1/README.md | 79 -- .../defuse/php-encryption-1.2.1/benchmark.php | 42 -- .../defuse/php-encryption-1.2.1/composer.json | 20 - .../defuse/php-encryption-1.2.1/example.php | 36 - library/defuse/php-encryption-1.2.1/test.sh | 30 - .../php-encryption-1.2.1/tests/runtime.php | 32 - 8 files changed, 938 deletions(-) delete mode 100644 library/defuse/php-encryption-1.2.1/.travis.yml delete mode 100644 library/defuse/php-encryption-1.2.1/Crypto.php delete mode 100644 library/defuse/php-encryption-1.2.1/README.md delete mode 100644 library/defuse/php-encryption-1.2.1/benchmark.php delete mode 100644 library/defuse/php-encryption-1.2.1/composer.json delete mode 100644 library/defuse/php-encryption-1.2.1/example.php delete mode 100644 library/defuse/php-encryption-1.2.1/test.sh delete mode 100644 library/defuse/php-encryption-1.2.1/tests/runtime.php diff --git a/library/defuse/php-encryption-1.2.1/.travis.yml b/library/defuse/php-encryption-1.2.1/.travis.yml deleted file mode 100644 index 20ec31c201..0000000000 --- a/library/defuse/php-encryption-1.2.1/.travis.yml +++ /dev/null @@ -1,22 +0,0 @@ -language: php -php: - - "5.6" - - "5.5" - - "5.4" - - "5.3" - - "5.2" -# Versions below here are not installed on travis-ci -# - "5.1" -# - "5.0" -# - "4.4" -# - "4.3" -# - "4.2" -# - "4.1" -# - "4.0" - -matrix: - allow_failures: - - php: "5.3" - - php: "5.2" - -script: ./test.sh diff --git a/library/defuse/php-encryption-1.2.1/Crypto.php b/library/defuse/php-encryption-1.2.1/Crypto.php deleted file mode 100644 index 5b60f6f121..0000000000 --- a/library/defuse/php-encryption-1.2.1/Crypto.php +++ /dev/null @@ -1,677 +0,0 @@ - 255 * $digest_length) { - throw new CannotPerformOperationException(); - } - - // "if [salt] not provided, is set to a string of HashLen zeroes." - if (is_null($salt)) { - $salt = str_repeat("\x00", $digest_length); - } - - // HKDF-Extract: - // PRK = HMAC-Hash(salt, IKM) - // The salt is the HMAC key. - $prk = hash_hmac($hash, $ikm, $salt, true); - - // HKDF-Expand: - - // This check is useless, but it serves as a reminder to the spec. - if (self::our_strlen($prk) < $digest_length) { - throw new CannotPerformOperationException(); - } - - // T(0) = '' - $t = ''; - $last_block = ''; - for ($block_index = 1; self::our_strlen($t) < $length; $block_index++) { - // T(i) = HMAC-Hash(PRK, T(i-1) | info | 0x??) - $last_block = hash_hmac( - $hash, - $last_block . $info . chr($block_index), - $prk, - true - ); - // T = T(1) | T(2) | T(3) | ... | T(N) - $t .= $last_block; - } - - // ORM = first L octets of T - $orm = self::our_substr($t, 0, $length); - if ($orm === FALSE) { - throw new CannotPerformOperationException(); - } - return $orm; - } - - private static function VerifyHMAC($correct_hmac, $message, $key) - { - $message_hmac = hash_hmac(self::HASH_FUNCTION, $message, $key, true); - - // We can't just compare the strings with '==', since it would make - // timing attacks possible. We could use the XOR-OR constant-time - // comparison algorithm, but I'm not sure if that's good enough way up - // here in an interpreted language. So we use the method of HMACing the - // strings we want to compare with a random key, then comparing those. - - // NOTE: This leaks information when the strings are not the same - // length, but they should always be the same length here. Enforce it: - if (self::our_strlen($correct_hmac) !== self::our_strlen($message_hmac)) { - throw new CannotPerformOperationException(); - } - - $blind = self::CreateNewRandomKey(); - $message_compare = hash_hmac(self::HASH_FUNCTION, $message_hmac, $blind); - $correct_compare = hash_hmac(self::HASH_FUNCTION, $correct_hmac, $blind); - return $correct_compare === $message_compare; - } - - private static function TestEncryptDecrypt() - { - $key = self::CreateNewRandomKey(); - $data = "EnCrYpT EvErYThInG\x00\x00"; - - // Make sure encrypting then decrypting doesn't change the message. - $ciphertext = self::Encrypt($data, $key); - try { - $decrypted = self::Decrypt($ciphertext, $key); - } catch (InvalidCiphertextException $ex) { - // It's important to catch this and change it into a - // CryptoTestFailedException, otherwise a test failure could trick - // the user into thinking it's just an invalid ciphertext! - throw new CryptoTestFailedException(); - } - if($decrypted !== $data) - { - throw new CryptoTestFailedException(); - } - - // Modifying the ciphertext: Appending a string. - try { - self::Decrypt($ciphertext . "a", $key); - throw new CryptoTestFailedException(); - } catch (InvalidCiphertextException $e) { /* expected */ } - - // Modifying the ciphertext: Changing an IV byte. - try { - $ciphertext[0] = chr((ord($ciphertext[0]) + 1) % 256); - self::Decrypt($ciphertext, $key); - throw new CryptoTestFailedException(); - } catch (InvalidCiphertextException $e) { /* expected */ } - - // Decrypting with the wrong key. - $key = self::CreateNewRandomKey(); - $data = "abcdef"; - $ciphertext = self::Encrypt($data, $key); - $wrong_key = self::CreateNewRandomKey(); - try { - self::Decrypt($ciphertext, $wrong_key); - throw new CryptoTestFailedException(); - } catch (InvalidCiphertextException $e) { /* expected */ } - - // Ciphertext too small (shorter than HMAC). - $key = self::CreateNewRandomKey(); - $ciphertext = str_repeat("A", self::MAC_BYTE_SIZE - 1); - try { - self::Decrypt($ciphertext, $key); - throw new CryptoTestFailedException(); - } catch (InvalidCiphertextException $e) { /* expected */ } - } - - private static function HKDFTestVector() - { - // HKDF test vectors from RFC 5869 - - // Test Case 1 - $ikm = str_repeat("\x0b", 22); - $salt = self::hexToBytes("000102030405060708090a0b0c"); - $info = self::hexToBytes("f0f1f2f3f4f5f6f7f8f9"); - $length = 42; - $okm = self::hexToBytes( - "3cb25f25faacd57a90434f64d0362f2a" . - "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" . - "34007208d5b887185865" - ); - $computed_okm = self::HKDF("sha256", $ikm, $length, $info, $salt); - if ($computed_okm !== $okm) { - throw new CryptoTestFailedException(); - } - - // Test Case 7 - $ikm = str_repeat("\x0c", 22); - $length = 42; - $okm = self::hexToBytes( - "2c91117204d745f3500d636a62f64f0a" . - "b3bae548aa53d423b0d1f27ebba6f5e5" . - "673a081d70cce7acfc48" - ); - $computed_okm = self::HKDF("sha1", $ikm, $length); - if ($computed_okm !== $okm) { - throw new CryptoTestFailedException(); - } - - } - - private static function HMACTestVector() - { - // HMAC test vector From RFC 4231 (Test Case 1) - $key = str_repeat("\x0b", 20); - $data = "Hi There"; - $correct = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"; - if (hash_hmac(self::HASH_FUNCTION, $data, $key) != $correct) { - throw new CryptoTestFailedException(); - } - } - - private static function AESTestVector() - { - // AES CBC mode test vector from NIST SP 800-38A - $key = self::hexToBytes("2b7e151628aed2a6abf7158809cf4f3c"); - $iv = self::hexToBytes("000102030405060708090a0b0c0d0e0f"); - $plaintext = self::hexToBytes( - "6bc1bee22e409f96e93d7e117393172a" . - "ae2d8a571e03ac9c9eb76fac45af8e51" . - "30c81c46a35ce411e5fbc1191a0a52ef" . - "f69f2445df4f9b17ad2b417be66c3710" - ); - $ciphertext = self::hexToBytes( - "7649abac8119b246cee98e9b12e9197d" . - "5086cb9b507219ee95db113a917678b2" . - "73bed6b8e3c1743b7116e69e22229516" . - "3ff1caa1681fac09120eca307586e1a7" . - /* Block due to padding. Not from NIST test vector. - Padding Block: 10101010101010101010101010101010 - Ciphertext: 3ff1caa1681fac09120eca307586e1a7 - (+) 2fe1dab1780fbc19021eda206596f1b7 - AES 8cb82807230e1321d3fae00d18cc2012 - - */ - "8cb82807230e1321d3fae00d18cc2012" - ); - - $computed_ciphertext = self::PlainEncrypt($plaintext, $key, $iv); - if ($computed_ciphertext !== $ciphertext) { - throw new CryptoTestFailedException(); - } - - $computed_plaintext = self::PlainDecrypt($ciphertext, $key, $iv); - if ($computed_plaintext !== $plaintext) { - throw new CryptoTestFailedException(); - } - } - - /* WARNING: Do not call this function on secrets. It creates side channels. */ - private static function hexToBytes($hex_string) - { - return pack("H*", $hex_string); - } - - private static function EnsureConstantExists($name) - { - if (!defined($name)) { - throw new CannotPerformOperationException(); - } - } - - private static function EnsureFunctionExists($name) - { - if (!function_exists($name)) { - throw new CannotPerformOperationException(); - } - } - - /* - * We need these strlen() and substr() functions because when - * 'mbstring.func_overload' is set in php.ini, the standard strlen() and - * substr() are replaced by mb_strlen() and mb_substr(). - */ - - private static function our_strlen($str) - { - if (function_exists('mb_strlen')) { - $length = mb_strlen($str, '8bit'); - if ($length === FALSE) { - throw new CannotPerformOperationException(); - } - return $length; - } else { - return strlen($str); - } - } - - private static function our_substr($str, $start, $length = NULL) - { - if (function_exists('mb_substr')) - { - // mb_substr($str, 0, NULL, '8bit') returns an empty string on PHP - // 5.3, so we have to find the length ourselves. - if (!isset($length)) { - if ($start >= 0) { - $length = self::our_strlen($str) - $start; - } else { - $length = -$start; - } - } - - return mb_substr($str, $start, $length, '8bit'); - } - - // Unlike mb_substr(), substr() doesn't accept NULL for length - if (isset($length)) { - return substr($str, $start, $length); - } else { - return substr($str, $start); - } - } - -} - -/* - * We want to catch all uncaught exceptions that come from the Crypto class, - * since by default, PHP will leak the key in the stack trace from an uncaught - * exception. This is a really ugly hack, but I think it's justified. - * - * Everything up to handler() getting called should be reliable, so this should - * reliably suppress the stack traces. The rest is just a bonus so that we don't - * make it impossible to debug other exceptions. - * - * This bit of code was adapted from: http://stackoverflow.com/a/7939492 - */ - -class CryptoExceptionHandler -{ - private $rethrow = NULL; - - public function __construct() - { - set_exception_handler(array($this, "handler")); - } - - public function handler($ex) - { - if ( - $ex instanceof InvalidCiphertextException || - $ex instanceof CannotPerformOperationException || - $ex instanceof CryptoTestFailedException - ) { - echo "FATAL ERROR: Uncaught crypto exception. Suppresssing output.\n"; - } else { - /* Re-throw the exception in the destructor. */ - $this->rethrow = $ex; - } - } - - public function __destruct() { - if ($this->rethrow) { - throw $this->rethrow; - } - } -} - -$crypto_exception_handler_object_dont_touch_me = new CryptoExceptionHandler(); - diff --git a/library/defuse/php-encryption-1.2.1/README.md b/library/defuse/php-encryption-1.2.1/README.md deleted file mode 100644 index 292ecf957e..0000000000 --- a/library/defuse/php-encryption-1.2.1/README.md +++ /dev/null @@ -1,79 +0,0 @@ -php-encryption -=============== - -This is a class for doing symmetric encryption in PHP. **Requires PHP 5.4 or newer.** - -[![Build Status](https://travis-ci.org/defuse/php-encryption.svg?branch=master)](https://travis-ci.org/defuse/php-encryption) - -Implementation --------------- - -Messages are encrypted with AES-128 in CBC mode and are authenticated with -HMAC-SHA256 (Encrypt-then-Mac). PKCS7 padding is used to pad the message to -a multiple of the block size. HKDF is used to split the user-provided key into -two keys: one for encryption, and the other for authentication. It is -implemented using the `openssl_` and `hash_hmac` functions. - -Warning --------- - -This is new code, and it hasn't received much review by experts. I have spent -many hours making it as secure as possible (extensive runtime tests, secure -coding practices), and auditing it for problems, but I may have missed some -issues. So be careful. Don't trust it with your life. Check out the open GitHub -issues for a list of known issues. If you find a problem with this library, -please report it by opening a GitHub issue. - -That said, you're probably much better off using this library than any other -encryption library written in PHP. - -Philosophy ------------ - -This library was created after noticing how much insecure PHP encryption code -there is. I once did a Google search for "php encryption" and found insecure -code or advice on 9 of the top 10 results. - -Encryption is becoming an essential component of modern websites. This library -aims to fulfil a subset of that need: Authenticated symmetric encryption of -short strings, given a random key. - -This library is developed around several core values: - -- Rule #1: Security is prioritized over everything else. - - > Whenever there is a conflict between security and some other property, - > security will be favored. For example, the library has runtime tests, - > which make it slower, but will hopefully stop it from encrypting stuff - > if the platform it's running on is broken. - -- Rule #2: It should be difficult to misuse the library. - - > We assume the developers using this library have no experience with - > cryptography. We only assume that they know that the "key" is something - > you need to encrypt and decrypt the messages, and that it must be - > protected. Whenever possible, the library should refuse to encrypt or - > decrypt messages when it is not being used correctly. - -- Rule #3: The library aims only to be compatible with itself. - - > Other PHP encryption libraries try to support every possible type of - > encryption, even the insecure ones (e.g. ECB mode). Because there are so - > many options, inexperienced developers must make decisions between - > things like "CBC" mode and "ECB" mode, knowing nothing about either one, - > which inevitably creates vulnerabilities. - - > This library will only support one secure mode. A developer using this - > library will call "encrypt" and "decrypt" not caring about how they are - > implemented. - -- Rule #4: The library should consist of a single PHP file and nothing more. - - > Some PHP encryption libraries, like libsodium-php [1], are not - > straightforward to install and cannot packaged with "just download and - > extract" applications. This library will always be just one PHP file - > that you can put in your source tree and require(). - -References: - - [1] https://github.com/jedisct1/libsodium-php diff --git a/library/defuse/php-encryption-1.2.1/benchmark.php b/library/defuse/php-encryption-1.2.1/benchmark.php deleted file mode 100644 index 3da61a6285..0000000000 --- a/library/defuse/php-encryption-1.2.1/benchmark.php +++ /dev/null @@ -1,42 +0,0 @@ - diff --git a/library/defuse/php-encryption-1.2.1/composer.json b/library/defuse/php-encryption-1.2.1/composer.json deleted file mode 100644 index 6856b9c72c..0000000000 --- a/library/defuse/php-encryption-1.2.1/composer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "defuse/php-encryption", - "description": "Secure PHP Encryption Library", - "license": "MIT", - "keywords": ["security", "encryption", "AES", "mcrypt", "cipher"], - "authors": [ - { - "name": "Taylor Hornby", - "email": "havoc@defuse.ca" - } - ], - "autoload": { - "files": ["Crypto.php"] - }, - "require": { - "php": ">=5.4.0", - "ext-openssl": "*", - "ext-mcrypt": "*" - } -} diff --git a/library/defuse/php-encryption-1.2.1/example.php b/library/defuse/php-encryption-1.2.1/example.php deleted file mode 100644 index 10e73f9154..0000000000 --- a/library/defuse/php-encryption-1.2.1/example.php +++ /dev/null @@ -1,36 +0,0 @@ - diff --git a/library/defuse/php-encryption-1.2.1/test.sh b/library/defuse/php-encryption-1.2.1/test.sh deleted file mode 100644 index d1691e7c6e..0000000000 --- a/library/defuse/php-encryption-1.2.1/test.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -echo "Normal" -echo "--------------------------------------------------" -php -d mbstring.func_overload=0 tests/runtime.php -if [ $? -ne 0 ]; then - echo "FAIL." - exit 1 -fi -echo "--------------------------------------------------" - -echo "" - -echo "Multibyte" -echo "--------------------------------------------------" -php -d mbstring.func_overload=7 tests/runtime.php -if [ $? -ne 0 ]; then - echo "FAIL." - exit 1 -fi -echo "--------------------------------------------------" - -echo "" - -if [ -z "$(php Crypto.php)" ]; then - echo "PASS: Crypto.php output is empty." -else - echo "FAIL: Crypto.php output is not empty." - exit 1 -fi diff --git a/library/defuse/php-encryption-1.2.1/tests/runtime.php b/library/defuse/php-encryption-1.2.1/tests/runtime.php deleted file mode 100644 index 76565c58e3..0000000000 --- a/library/defuse/php-encryption-1.2.1/tests/runtime.php +++ /dev/null @@ -1,32 +0,0 @@ - From d5aff9ac31a67cdd7a78327ed2915d2c7a7a133a Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 9 Nov 2017 02:35:11 -0500 Subject: [PATCH 5/7] Fix php-encryption version 2 compatibility issues --- mod/dfrn_notify.php | 3 ++- src/Protocol/DFRN.php | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index c8dc093d17..b8c771b75a 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -183,7 +183,8 @@ function dfrn_notify_post(App $a) { break; case 2: try { - $data = \Defuse\Crypto\Crypto::decrypt(hex2bin($data), $final_key); + $FinalKey = \Defuse\Crypto\Key::loadFromAsciiSafeString($final_key); + $data = \Defuse\Crypto\Crypto::decrypt(hex2bin($data), $FinalKey); } catch (\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) { // VERY IMPORTANT /* * Either: diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 6ba8ed7d10..7f37f9839b 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -1296,13 +1296,14 @@ class DFRN case 2: // RINO 2 based on php-encryption try { - $key = \Defuse\Crypto\Key::createNewRandomKey(); + $KeyObject = \Defuse\Crypto\Key::createNewRandomKey(); } catch (\Defuse\Crypto\Exception\CryptoException $ex) { logger('Cannot safely create a key'); return -4; } try { - $data = \Defuse\Crypto\Crypto::encrypt($postvars['data'], $key); + $data = \Defuse\Crypto\Crypto::encrypt($postvars['data'], $KeyObject); + $key = $KeyObject->saveToAsciiSafeString(); } catch (\Defuse\Crypto\Exception\CryptoException $ex) { logger('Cannot safely perform encryption'); return -6; From 918f2e8593cdf112f4d4dff665d2e084513d5b89 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 9 Nov 2017 03:01:02 -0500 Subject: [PATCH 6/7] Fix another php-encryption version migration error --- mod/dfrn_notify.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index b8c771b75a..7310205326 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -183,7 +183,7 @@ function dfrn_notify_post(App $a) { break; case 2: try { - $FinalKey = \Defuse\Crypto\Key::loadFromAsciiSafeString($final_key); + $FinalKey = \Defuse\Crypto\Key::loadFromAsciiSafeString(bintohex($final_key)); $data = \Defuse\Crypto\Crypto::decrypt(hex2bin($data), $FinalKey); } catch (\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) { // VERY IMPORTANT /* From 1262d6bfee193977ccddb746d5a3611980cb9983 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Thu, 9 Nov 2017 03:01:53 -0500 Subject: [PATCH 7/7] Function name typo --- mod/dfrn_notify.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index 7310205326..7397b415a5 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -183,7 +183,7 @@ function dfrn_notify_post(App $a) { break; case 2: try { - $FinalKey = \Defuse\Crypto\Key::loadFromAsciiSafeString(bintohex($final_key)); + $FinalKey = \Defuse\Crypto\Key::loadFromAsciiSafeString(bin2hex($final_key)); $data = \Defuse\Crypto\Crypto::decrypt(hex2bin($data), $FinalKey); } catch (\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) { // VERY IMPORTANT /*