diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 4cb9d7f..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,107 +0,0 @@ -name: CI - -on: [push] - -jobs: - old: - name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} - runs-on: ${{ matrix.operating-system }} - strategy: - matrix: - operating-system: ['ubuntu-16.04'] - php-versions: ['5.4', '5.5', '5.6', '7.0'] - phpunit-versions: ['7.5.20'] - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-versions }} - extensions: mbstring, intl - ini-values: post_max_size=256M, max_execution_time=180 - tools: psalm, phpunit:${{ matrix.phpunit-versions }} - - - name: Fix permissions - run: sudo chmod -R 0777 . - - - name: Install dependencies - run: composer self-update --1; composer install - - - name: PHPUnit tests - uses: php-actions/phpunit@v2 - with: - memory_limit: 256M - - moderate: - name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} - runs-on: ${{ matrix.operating-system }} - strategy: - matrix: - operating-system: ['ubuntu-latest'] - php-versions: ['7.1', '7.2', '7.3'] - phpunit-versions: ['latest'] - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-versions }} - extensions: mbstring, intl, sodium - ini-values: post_max_size=256M, max_execution_time=180 - tools: psalm, phpunit:${{ matrix.phpunit-versions }} - - - name: Fix permissions - run: sudo chmod -R 0777 . - - - name: Install dependencies - run: composer install - - - name: PHPUnit tests - uses: php-actions/phpunit@v2 - timeout-minutes: 30 - with: - memory_limit: 256M - - modern: - name: PHP ${{ matrix.php-versions }} Test on ${{ matrix.operating-system }} - runs-on: ${{ matrix.operating-system }} - strategy: - matrix: - operating-system: ['ubuntu-latest'] - php-versions: ['7.4', '8.0'] - phpunit-versions: ['latest'] - steps: - - name: Checkout - uses: actions/checkout@v2 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-versions }} - extensions: mbstring, intl, sodium - ini-values: post_max_size=256M, max_execution_time=180 - tools: psalm, phpunit:${{ matrix.phpunit-versions }} - - - name: Fix permissions - run: sudo chmod -R 0777 . - - - name: Install dependencies - run: composer install - - - name: PHPUnit tests - uses: php-actions/phpunit@v2 - timeout-minutes: 30 - with: - memory_limit: 256M - - - name: Install Psalm - if: contains(['7.4', '8.0'], ${{ matrix.php-version }}) - run: composer require --dev vimeo/psalm:^4 - - - name: Static Analysis - if: contains(['7.4', '8.0'], ${{ matrix.php-version }}) - run: vendor/bin/psalm diff --git a/.travis.yml b/.travis.yml index b0a8565..0aa111b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,15 +9,20 @@ matrix: - php: "7.0" env: USE_PSALM=0 - php: "7.1" - env: USE_PSALM=1 + env: USE_PSALM=0 - php: "7.2" - env: USE_PSALM=1 + env: USE_PSALM=0 - php: "7.3" - env: USE_PSALM=1 + env: USE_PSALM=0 - php: "7.4" env: USE_PSALM=1 - php: "8.0" env: USE_PSALM=1 + - php: "8.1" + env: USE_PSALM=1 + - php: "8.2" + env: USE_PSALM=1 + dist: focal - php: "nightly" env: USE_PSALM=1 - php: "hhvm" @@ -25,19 +30,23 @@ matrix: allow_failures: - php: "nightly" - php: "hhvm" - - php: "8.0" + # Travis-CI's 8.2 is currently broken, see: + # https://github.com/defuse/php-encryption/pull/506#issuecomment-1594084107 + #- php: "8.2" install: - composer install - - curl -LSs https://box-project.github.io/box2/installer.php | php - - mkdir ~/box - - mv box.phar ~/box/box before_script: - echo "xdebug.mode = coverage" > extra_php_config.ini - phpenv config-add extra_php_config.ini script: - ./test.sh - - PATH=$PATH:~/box/ make -C dist/ build-phar - - ./test.sh dist/defuse-crypto.phar +# - mkdir /tmp/box +# - chmod 755 /tmp/box +# - curl -LSs https://github.com/box-project/box/releases/download/4.3.8/box.phar -o /tmp/box/box +# - chmod 755 /tmp/box/box +# - PATH="$PATH:/tmp/box/" which box +# - PATH="$PATH:/tmp/box/" make -C dist/ build-phar +# - ./test.sh dist/defuse-crypto.phar - if [[ $USE_PSALM -eq 1 ]]; then composer require --with-all-dependencies --dev "vimeo/psalm:dev-master"; fi - if [[ $USE_PSALM -eq 1 ]]; then composer install; fi - if [[ $USE_PSALM -eq 1 ]]; then vendor/bin/psalm; fi diff --git a/composer.json b/composer.json index 025f38d..7f15ba0 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,8 @@ "php": ">=5.6.0" }, "require-dev": { - "phpunit/phpunit": "^4|^5|^6|^7|^8|^9" + "phpunit/phpunit": "^5|^6|^7|^8|^9|^10", + "yoast/phpunit-polyfills": "^2.0.0" }, "bin": [ "bin/generate-defuse-key" diff --git a/src/Core.php b/src/Core.php index 2f3a319..bd99a1a 100644 --- a/src/Core.php +++ b/src/Core.php @@ -98,9 +98,14 @@ public static function incrementCounter($ctr, $inc) */ public static function secureRandom($octets) { + if ($octets <= 0) { + throw new Ex\CryptoException( + 'A zero or negative amount of random bytes was requested.' + ); + } self::ensureFunctionExists('random_bytes'); try { - return \random_bytes($octets); + return \random_bytes(max(1, $octets)); } catch (\Exception $ex) { throw new Ex\EnvironmentIsBrokenException( 'Your system does not have a secure random number generator.' diff --git a/src/File.php b/src/File.php index 3a64c4a..ad2eac1 100644 --- a/src/File.php +++ b/src/File.php @@ -196,7 +196,9 @@ private static function encryptFileInternal($inputFilename, $outputFilename, Key } /* Open the input file. */ + self::removePHPUnitErrorHandler(); $if = @\fopen($inputFilename, 'rb'); + self::restorePHPUnitErrorHandler(); if ($if === false) { throw new Ex\IOException( 'Cannot open input file for encrypting: ' . @@ -209,7 +211,9 @@ private static function encryptFileInternal($inputFilename, $outputFilename, Key } /* Open the output file. */ + self::removePHPUnitErrorHandler(); $of = @\fopen($outputFilename, 'wb'); + self::restorePHPUnitErrorHandler(); if ($of === false) { \fclose($if); throw new Ex\IOException( @@ -265,7 +269,9 @@ private static function decryptFileInternal($inputFilename, $outputFilename, Key } /* Open the input file. */ + self::removePHPUnitErrorHandler(); $if = @\fopen($inputFilename, 'rb'); + self::restorePHPUnitErrorHandler(); if ($if === false) { throw new Ex\IOException( 'Cannot open input file for decrypting: ' . @@ -279,7 +285,9 @@ private static function decryptFileInternal($inputFilename, $outputFilename, Key } /* Open the output file. */ + self::removePHPUnitErrorHandler(); $of = @\fopen($outputFilename, 'wb'); + self::restorePHPUnitErrorHandler(); if ($of === false) { \fclose($if); throw new Ex\IOException( @@ -770,9 +778,38 @@ private static function getLastErrorMessage() { $error = error_get_last(); if ($error === null) { - return '[no PHP error]'; + return '[no PHP error, or you have a custom error handler set]'; } else { return $error['message']; } } + + /** + * PHPUnit sets an error handler, which prevents getLastErrorMessage() from working, + * because error_get_last does not work when custom handlers are set. + * + * This is a workaround, which should be a no-op in production deployments, to make + * getLastErrorMessage() return the error messages that the PHPUnit tests expect. + * + * If, in a production deployment, a custom error handler is set, the exception + * handling will still work as usual, but the error messages will be confusing. + * + * @return void + */ + private static function removePHPUnitErrorHandler() { + if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) { + set_error_handler(null); + } + } + + /** + * Undoes what removePHPUnitErrorHandler did. + * + * @return void + */ + private static function restorePHPUnitErrorHandler() { + if (defined('PHPUNIT_COMPOSER_INSTALL') || defined('__PHPUNIT_PHAR__')) { + restore_error_handler(); + } + } } diff --git a/test/phpunit-10.xml b/test/phpunit-10.xml new file mode 100644 index 0000000..c1808f0 --- /dev/null +++ b/test/phpunit-10.xml @@ -0,0 +1,9 @@ + + + + ../src + + + + + diff --git a/test/phpunit-5.xml b/test/phpunit-5.xml new file mode 100644 index 0000000..f76c419 --- /dev/null +++ b/test/phpunit-5.xml @@ -0,0 +1,7 @@ + + + + ../src + + + diff --git a/test/phpunit-8.xml b/test/phpunit-8.xml new file mode 100644 index 0000000..f76c419 --- /dev/null +++ b/test/phpunit-8.xml @@ -0,0 +1,7 @@ + + + + ../src + + + diff --git a/test/phpunit.sh b/test/phpunit.sh index 187696a..4de7df6 100755 --- a/test/phpunit.sh +++ b/test/phpunit.sh @@ -33,19 +33,12 @@ if [ "$clean" -eq 1 ]; then fi # Let's grab the latest release and its signature +phpunitversion=$([ $PHP_VERSION -ge 80100 ] && echo "10" || ([ $PHP_VERSION -ge 70200 ] && echo "8" || echo "5")) if [ ! -f phpunit.phar ]; then - if [[ $PHP_VERSION -ge 50600 ]]; then - wget -O phpunit.phar https://phar.phpunit.de/phpunit-5.7.phar - else - wget -O phpunit.phar https://phar.phpunit.de/phpunit-4.8.phar - fi + wget -O phpunit.phar https://phar.phpunit.de/phpunit-$phpunitversion.phar fi if [ ! -f phpunit.phar.asc ]; then - if [[ $PHP_VERSION -ge 50600 ]]; then - wget -O phpunit.phar.asc https://phar.phpunit.de/phpunit-5.7.phar.asc - else - wget -O phpunit.phar.asc https://phar.phpunit.de/phpunit-4.8.phar.asc - fi + wget -O phpunit.phar.asc https://phar.phpunit.de/phpunit-$phpunitversion.phar.asc fi # What are the major/minor versions? @@ -56,19 +49,19 @@ gpg --verify phpunit.phar.asc phpunit.phar if [ $? -eq 0 ]; then echo if [ "$2" -eq "1" ]; then - COVERAGE1_ARGS="--coverage-clover=$parentdir/coverage1.xml -c $parentdir/test/phpunit.xml" - COVERAGE2_ARGS="--coverage-clover=$parentdir/coverage2.xml -c $parentdir/test/phpunit.xml" + COVERAGE1_ARGS="--coverage-clover=$parentdir/coverage1.xml" + COVERAGE2_ARGS="--coverage-clover=$parentdir/coverage2.xml" else COVERAGE1_ARGS="" COVERAGE2_ARGS="" fi echo -e "\033[33mBegin Unit Testing\033[0m" # Run the test suite with normal func_overload. - php -d mbstring.func_overload=0 phpunit.phar $COVERAGE1_ARGS --bootstrap "$parentdir/$1" "$parentdir/test/unit" && \ + php -d mbstring.func_overload=0 phpunit.phar -c "$parentdir/test/phpunit-$phpunitversion.xml" $COVERAGE1_ARGS --bootstrap "$parentdir/$1" "$parentdir/test/unit" && \ # Run the test suite again with funky func_overload. # This is deprecated in PHP 7 and PHPUnit is no longer compatible with the options. if [[ $PHP_VERSION -le 50600 ]]; then - php -d mbstring.func_overload=7 phpunit.phar $COVERAGE2_ARGS --bootstrap "$parentdir/$1" "$parentdir/test/unit" + php -d mbstring.func_overload=7 phpunit.phar -c "$parentdir/test/phpunit-$phpunitversion.xml" $COVERAGE2_ARGS --bootstrap "$parentdir/$1" "$parentdir/test/unit" fi EXITCODE=$? # Cleanup diff --git a/test/phpunit.xml b/test/phpunit.xml deleted file mode 100644 index 2808abe..0000000 --- a/test/phpunit.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - ../src - - - diff --git a/test/unit/BackwardsCompatibilityTest.php b/test/unit/BackwardsCompatibilityTest.php index 5556f97..3abe5f2 100644 --- a/test/unit/BackwardsCompatibilityTest.php +++ b/test/unit/BackwardsCompatibilityTest.php @@ -3,25 +3,22 @@ use \Defuse\Crypto\Crypto; use \Defuse\Crypto\Encoding; use \Defuse\Crypto\Key; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; -class BackwardsCompatibilityTest extends PHPUnit_Framework_TestCase +class BackwardsCompatibilityTest extends TestCase { - /* helper function to create a key with raw bytes */ - public function keyHelper($rawkey) { - $key = Key::createNewRandomKey(); - $func = function ($bytes) { - $this->key_bytes = $bytes; - }; - $helper = $func->bindTo($key,$key); - $helper($rawkey); - return $key; - } + /* helper function to create a key with raw bytes */ + public function keyHelper($rawkey) { + $key = Key::createNewRandomKey(); + $func = function ($bytes) { + $this->key_bytes = $bytes; + }; + $helper = $func->bindTo($key,$key); + $helper($rawkey); + return $key; + } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - * @expectedExceptionMessage invalid hex encoding - */ public function testDecryptLegacyWithWrongMethodStraightUpHex() { $cipher = Encoding::hexToBin( @@ -34,6 +31,9 @@ public function testDecryptLegacyWithWrongMethodStraightUpHex() '00000000000000000000000000000000' ); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); + $this->expectExceptionMessage('invalid hex encoding'); + /* Make it try to parse the binary as hex. */ $plain = Crypto::decrypt( $cipher, @@ -45,10 +45,6 @@ public function testDecryptLegacyWithWrongMethodStraightUpHex() ); } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - * @expectedExceptionMessage Bad version header - */ public function testDecryptLegacyWithWrongMethodStraightUpBinary() { $cipher = Encoding::hexToBin( @@ -61,6 +57,9 @@ public function testDecryptLegacyWithWrongMethodStraightUpBinary() '00000000000000000000000000000000' ); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); + $this->expectExceptionMessage('Bad version header'); + /* This time, treat the binary as binary. */ $plain = Crypto::decrypt( $cipher, diff --git a/test/unit/CoreTest.php b/test/unit/CoreTest.php index 6466bc3..69cfe08 100644 --- a/test/unit/CoreTest.php +++ b/test/unit/CoreTest.php @@ -1,8 +1,9 @@ expectException(\InvalidArgumentException::class); Core::ourSubstr('abc', 0, -1); } @@ -128,4 +127,24 @@ public function testOurSubstrLengthIsMax() { $this->assertSame('bc', Core::ourSubstr('abc', 1, 500)); } + + public function testSecureRandomZeroLength() + { + $this->expectException(\Defuse\Crypto\Exception\CryptoException::class); + $this->expectExceptionMessage('zero or negative'); + Core::secureRandom(0); + } + + public function testSecureRandomNegativeLength() + { + $this->expectException(\Defuse\Crypto\Exception\CryptoException::class); + $this->expectExceptionMessage('zero or negative'); + Core::secureRandom(-1); + } + + public function testSecureRandomPositiveLength() + { + $x = Core::secureRandom(10); + $this->assertSame(10, strlen($x)); + } } diff --git a/test/unit/CryptoTest.php b/test/unit/CryptoTest.php index e94153d..ea81fb8 100644 --- a/test/unit/CryptoTest.php +++ b/test/unit/CryptoTest.php @@ -3,9 +3,10 @@ use \Defuse\Crypto\Core; use \Defuse\Crypto\Crypto; use \Defuse\Crypto\Key; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; use Defuse\Crypto\Exception as Ex; -class CryptoTest extends PHPUnit_Framework_TestCase +class CryptoTest extends TestCase { # Test for issue #165 -- encrypting then decrypting empty string fails. public function testEmptyString() @@ -93,137 +94,105 @@ public function testEncryptDecryptWithPassword() } } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - */ public function testDecryptRawAsHex() { $ciphertext = Crypto::encryptWithPassword('testdata', 'password', true); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); Crypto::decryptWithPassword($ciphertext, 'password', false); } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - */ public function testDecryptHexAsRaw() { $ciphertext = Crypto::encryptWithPassword('testdata', 'password', false); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); Crypto::decryptWithPassword($ciphertext, 'password', true); } - /** - * @expectedException \TypeError - */ public function testEncryptTypeErrorA() { $key = Key::createNewRandomKey(); + $this->expectException(\TypeError::class); Crypto::encrypt(3, $key, false); } - /** - * @expectedException \TypeError - */ public function testEncryptTypeErrorB() { + $this->expectException(\TypeError::class); Crypto::encrypt("plaintext", 3, false); } - /** - * @expectedException \TypeError - */ public function testEncryptTypeErrorC() { $key = Key::createNewRandomKey(); + $this->expectException(\TypeError::class); Crypto::encrypt("plaintext", $key, 3); } - /** - * @expectedException \TypeError - */ public function testEncryptWithPasswordTypeErrorA() { + $this->expectException(\TypeError::class); Crypto::encryptWithPassword(3, "password", false); } - /** - * @expectedException \TypeError - */ public function testEncryptWithPasswordTypeErrorB() { + $this->expectException(\TypeError::class); Crypto::encryptWithPassword("plaintext", 3, false); } - /** - * @expectedException \TypeError - */ public function testEncryptWithPasswordTypeErrorC() { + $this->expectException(\TypeError::class); Crypto::encryptWithPassword("plaintext", "password", 3); } - /** - * @expectedException \TypeError - */ public function testDecryptTypeErrorA() { $key = Key::createNewRandomKey(); + $this->expectException(\TypeError::class); Crypto::decrypt(3, $key, false); } - /** - * @expectedException \TypeError - */ public function testDecryptTypeErrorB() { + $this->expectException(\TypeError::class); Crypto::decrypt("ciphertext", 3, false); } - /** - * @expectedException \TypeError - */ public function testDecryptTypeErrorC() { $key = Key::createNewRandomKey(); + $this->expectException(\TypeError::class); Crypto::decrypt("ciphertext", $key, 3); } - /** - * @expectedException \TypeError - */ public function testDecryptWithPasswordTypeErrorA() { + $this->expectException(\TypeError::class); Crypto::decryptWithPassword(3, "password", false); } - /** - * @expectedException \TypeError - */ public function testDecryptWithPasswordTypeErrorB() { + $this->expectException(\TypeError::class); Crypto::decryptWithPassword("ciphertext", 3, false); } - /** - * @expectedException \TypeError - */ public function testDecryptWithPasswordTypeErrorC() { + $this->expectException(\TypeError::class); Crypto::decryptWithPassword("ciphertext", "password", 3); } - /** - * @expectedException \TypeError - */ public function testLegacyDecryptTypeErrorA() { + $this->expectException(\TypeError::class); Crypto::legacyDecrypt(3, "key"); } - /** - * @expectedException \TypeError - */ public function testLegacyDecryptTypeErrorB() { + $this->expectException(\TypeError::class); Crypto::legacyDecrypt("ciphertext", 3); } diff --git a/test/unit/CtrModeTest.php b/test/unit/CtrModeTest.php index f4ab297..72e3abd 100644 --- a/test/unit/CtrModeTest.php +++ b/test/unit/CtrModeTest.php @@ -1,10 +1,11 @@ expectException(\Defuse\Crypto\Exception\EnvironmentIsBrokenException::class); \Defuse\Crypto\Core::incrementCounter( str_repeat("\x00", 16), -1 ); } - /** - * @expectedException \Defuse\Crypto\Exception\EnvironmentIsBrokenException - */ public function testIncrementByZero() { + $this->expectException(\Defuse\Crypto\Exception\EnvironmentIsBrokenException::class); \Defuse\Crypto\Core::incrementCounter( str_repeat("\x00", 16), 0 ); } - public function allNonZeroByteValuesProvider() + public static function allNonZeroByteValuesProvider() { $all_bytes = []; for ($i = 1; $i <= 0xff; $i++) { @@ -159,43 +156,37 @@ public function allNonZeroByteValuesProvider() /** * @dataProvider allNonZeroByteValuesProvider - * @expectedException \Defuse\Crypto\Exception\EnvironmentIsBrokenException */ public function testIncrementCausingOverflowInFirstByte($lsb) { /* Smallest value that will overflow. */ $increment = (PHP_INT_MAX - $lsb) + 1; $start = str_repeat("\x00", 15) . chr($lsb); + $this->expectException(\Defuse\Crypto\Exception\EnvironmentIsBrokenException::class); \Defuse\Crypto\Core::incrementCounter($start, $increment); } - /** - * @expectedException \Defuse\Crypto\Exception\EnvironmentIsBrokenException - */ public function testIncrementWithShortIvLength() { + $this->expectException(\Defuse\Crypto\Exception\EnvironmentIsBrokenException::class); \Defuse\Crypto\Core::incrementCounter( str_repeat("\x00", 15), 1 ); } - /** - * @expectedException \Defuse\Crypto\Exception\EnvironmentIsBrokenException - */ public function testIncrementWithLongIvLength() { + $this->expectException(\Defuse\Crypto\Exception\EnvironmentIsBrokenException::class); \Defuse\Crypto\Core::incrementCounter( str_repeat("\x00", 17), 1 ); } - /** - * @expectedException \Defuse\Crypto\Exception\EnvironmentIsBrokenException - */ public function testIncrementByNonInteger() { + $this->expectException(\Defuse\Crypto\Exception\EnvironmentIsBrokenException::class); \Defuse\Crypto\Core::incrementCounter( str_repeat("\x00", 16), 1.0 diff --git a/test/unit/EncodingTest.php b/test/unit/EncodingTest.php index b707b82..4e1e274 100644 --- a/test/unit/EncodingTest.php +++ b/test/unit/EncodingTest.php @@ -2,8 +2,9 @@ use \Defuse\Crypto\Encoding; use \Defuse\Crypto\Core; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; -class EncodingTest extends PHPUnit_Framework_TestCase +class EncodingTest extends TestCase { public function testEncodeDecodeEquivalency() { @@ -46,10 +47,6 @@ public function testEncodeDecodeEquivalencyTwoBytes() } } - /** - * @expectedException \Defuse\Crypto\Exception\BadFormatException - * @expectedExceptionMessage checksum doesn't match - */ public function testIncorrectChecksum() { $header = Core::secureRandom(Core::HEADER_VERSION_SIZE); @@ -65,13 +62,11 @@ public function testIncorrectChecksum() $str[2*Encoding::SERIALIZE_HEADER_BYTES + 6] = 'f'; $str[2*Encoding::SERIALIZE_HEADER_BYTES + 7] = 'f'; $str[2*Encoding::SERIALIZE_HEADER_BYTES + 8] = 'f'; + $this->expectException(\Defuse\Crypto\Exception\BadFormatException::class); + $this->expectExceptionMessage("checksum doesn't match"); Encoding::loadBytesFromChecksummedAsciiSafeString($header, $str); } - /** - * @expectedException \Defuse\Crypto\Exception\BadFormatException - * @expectedExceptionMessage not a hex string - */ public function testBadHexEncoding() { $header = Core::secureRandom(Core::HEADER_VERSION_SIZE); @@ -80,6 +75,8 @@ public function testBadHexEncoding() Core::secureRandom(Core::KEY_BYTE_SIZE) ); $str[0] = 'Z'; + $this->expectException(\Defuse\Crypto\Exception\BadFormatException::class); + $this->expectExceptionMessage('not a hex string'); Encoding::loadBytesFromChecksummedAsciiSafeString($header, $str); } diff --git a/test/unit/FileTest.php b/test/unit/FileTest.php index 324c7bb..98fb17b 100644 --- a/test/unit/FileTest.php +++ b/test/unit/FileTest.php @@ -1,14 +1,15 @@ key = Key::createNewRandomKey(); } - public function tearDown() + public function tear_down() { array_map('unlink', glob(self::$TEMP_DIR . '/*')); rmdir(self::$TEMP_DIR); @@ -149,29 +150,27 @@ public function testResourceToResourceWithPassword($srcFile) 'Original file mismatches the result of encrypt and decrypt'); } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - * @expectedExceptionMessage Input file is too small to have been created by this library. - */ public function testDecryptBadMagicNumber() { $junk = self::$TEMP_DIR . '/junk'; file_put_contents($junk, 'This file does not have the right magic number.'); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); + $this->expectExceptionMessage('Input file is too small to have been created by this library.'); File::decryptFile($junk, self::$TEMP_DIR . '/unjunked', $this->key); } /** * @dataProvider garbageCiphertextProvider - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException */ public function testDecryptGarbage($ciphertext) { $junk = self::$TEMP_DIR . '/junk'; file_put_contents($junk, $ciphertext); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); File::decryptFile($junk, self::$TEMP_DIR . '/unjunked', $this->key); } - public function garbageCiphertextProvider() + public static function garbageCiphertextProvider() { $ciphertexts = [ [str_repeat('this is not anything that can be decrypted.', 100)], @@ -182,19 +181,14 @@ public function garbageCiphertextProvider() return $ciphertexts; } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - */ public function testDecryptEmptyFile() { $junk = self::$TEMP_DIR . '/junk'; file_put_contents($junk, ''); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); File::decryptFile($junk, self::$TEMP_DIR . '/unjunked', $this->key); } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - */ public function testDecryptTruncatedCiphertext() { // This tests for issue #115 on GitHub. @@ -209,6 +203,7 @@ public function testDecryptTruncatedCiphertext() $truncated = substr($ciphertext, 0, 64); file_put_contents($truncated_path, $truncated); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); File::decryptFile($truncated_path, $plaintext_path, $this->key); } @@ -243,10 +238,6 @@ public function testEncryptWithFileDecryptWithCrypto() $this->assertSame($plaintext, $plaintext_decrypted); } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - * @excpectedExceptionMessage Message Authentication failure; tampering detected. - */ public function testExtraData() { $src = self::$FILE_DIR . '/wat-gigantic-duck.jpg'; @@ -256,6 +247,8 @@ public function testExtraData() file_put_contents($dest, str_repeat('A', 2048), FILE_APPEND); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); + $this->expectExceptionMessage('Integrity check failed.'); File::decryptFile($dest, $dest . '.jpg', $this->key); } @@ -265,129 +258,102 @@ public function testFileCreateRandomKey() $this->assertInstanceOf('\Defuse\Crypto\Key', $result); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage No such file or directory - */ public function testBadSourcePathEncrypt() { + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('No such file or directory'); File::encryptFile('./i-do-not-exist', 'output-file', $this->key); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage No such file or directory - */ public function testBadSourcePathDecrypt() { + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('No such file or directory'); File::decryptFile('./i-do-not-exist', 'output-file', $this->key); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage No such file or directory - */ public function testBadSourcePathEncryptWithPassword() { + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('No such file or directory'); File::encryptFileWithPassword('./i-do-not-exist', 'output-file', 'password'); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage No such file or directory - */ public function testBadSourcePathDecryptWithPassword() { + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('No such file or directory'); File::decryptFileWithPassword('./i-do-not-exist', 'output-file', 'password'); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage Is a directory - */ public function testBadDestinationPathEncrypt() { $src = self::$FILE_DIR . '/wat-gigantic-duck.jpg'; + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('Is a directory'); File::encryptFile($src, './', $this->key); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage Is a directory - */ public function testBadDestinationPathDecrypt() { $src = self::$FILE_DIR . '/wat-gigantic-duck.jpg'; + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('Is a directory'); File::decryptFile($src, './', $this->key); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage Is a directory - */ public function testBadDestinationPathEncryptWithPassword() { $src = self::$FILE_DIR . '/wat-gigantic-duck.jpg'; + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('Is a directory'); File::encryptFileWithPassword($src, './', 'password'); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage Is a directory - */ public function testBadDestinationPathDecryptWithPassword() { $src = self::$FILE_DIR . '/wat-gigantic-duck.jpg'; + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('Is a directory'); File::decryptFileWithPassword($src, './', 'password'); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage must be a resource - */ public function testNonResourceInputEncrypt() { $resource = fopen('php://memory', 'wb'); + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('must be a resource'); File::encryptResource('not a resource', $resource, $this->key); fclose($resource); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage must be a resource - */ public function testNonResourceOutputEncrypt() { $resource = fopen('php://memory', 'wb'); + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('must be a resource'); File::encryptResource($resource, 'not a resource', $this->key); fclose($resource); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage must be a resource - */ public function testNonResourceInputDecrypt() { $resource = fopen('php://memory', 'wb'); + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('must be a resource'); File::decryptResource('not a resource', $resource, $this->key); fclose($resource); } - /** - * @expectedException \Defuse\Crypto\Exception\IOException - * @expectedExceptionMessage must be a resource - */ public function testNonResourceOutputDecrypt() { $resource = fopen('php://memory', 'wb'); + $this->expectException(\Defuse\Crypto\Exception\IOException::class); + $this->expectExceptionMessage('must be a resource'); File::decryptResource($resource, 'not a resource', $this->key); fclose($resource); } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - */ public function testNonFileResourceDecrypt() { /* This should behave equivalently to an empty file. Calling fstat() on @@ -396,14 +362,15 @@ public function testNonFileResourceDecrypt() $output = fopen('php://memory', 'wb'); try { File::decryptResource($stdin, $output, $this->key); - } catch (Exception $ex) { + } catch (\Exception $ex) { fclose($output); fclose($stdin); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); throw $ex; } } - public function fileToFileProvider() + public static function fileToFileProvider() { $data = []; diff --git a/test/unit/KeyTest.php b/test/unit/KeyTest.php index 03c9d84..d64df35 100644 --- a/test/unit/KeyTest.php +++ b/test/unit/KeyTest.php @@ -2,8 +2,9 @@ use \Defuse\Crypto\Core; use \Defuse\Crypto\Key; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; -class KeyTest extends PHPUnit_Framework_TestCase +class KeyTest extends TestCase { public function testCreateNewRandomKey() { @@ -19,15 +20,13 @@ public function testSaveAndLoadKey() $this->assertSame($key1->getRawBytes(), $key2->getRawBytes()); } - /** - * @expectedException \Defuse\Crypto\Exception\BadFormatException - * @excpectedExceptionMessage key version header - */ public function testIncorrectHeader() { $key = Key::createNewRandomKey(); $str = $key->saveToAsciiSafeString(); $str[0] = 'f'; + $this->expectException(\Defuse\Crypto\Exception\BadFormatException::class); + $this->expectExceptionMessage('Invalid header.'); Key::loadFromAsciiSafeString($str); } } diff --git a/test/unit/LegacyDecryptTest.php b/test/unit/LegacyDecryptTest.php index 59832b8..e379b34 100644 --- a/test/unit/LegacyDecryptTest.php +++ b/test/unit/LegacyDecryptTest.php @@ -3,8 +3,9 @@ use \Defuse\Crypto\Core; use \Defuse\Crypto\Crypto; use \Defuse\Crypto\Encoding; +use Yoast\PHPUnitPolyfills\TestCases\TestCase; -class LegacyDecryptTest extends PHPUnit_Framework_TestCase +class LegacyDecryptTest extends TestCase { public function testDecryptLegacyCiphertext() { @@ -24,9 +25,6 @@ public function testDecryptLegacyCiphertext() $this->assertSame($plain, 'This is a test message'); } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - */ public function testDecryptLegacyCiphertextWrongKey() { $cipher = Encoding::hexToBin( @@ -37,6 +35,7 @@ public function testDecryptLegacyCiphertextWrongKey() '024b5e2009106870f1db25d8b85fd01f' ); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); $plain = Crypto::legacyDecrypt( $cipher, "\x01\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F" @@ -44,13 +43,11 @@ public function testDecryptLegacyCiphertextWrongKey() ); } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - * @expectedExceptionMessage short - */ public function testLegacyDecryptTooShort() { $too_short = str_repeat("a", Core::LEGACY_MAC_BYTE_SIZE); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); + $this->expectExceptionMessage('short'); Crypto::legacyDecrypt($too_short, "0123456789ABCDEF"); } diff --git a/test/unit/PasswordTest.php b/test/unit/PasswordTest.php index a1c2370..38bffae 100644 --- a/test/unit/PasswordTest.php +++ b/test/unit/PasswordTest.php @@ -1,8 +1,9 @@ assertSame($key1->getRawBytes(), $key2->getRawBytes()); } - /** - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException - */ public function testKeyProtectedByPasswordWrong() { $pkey = KeyProtectedByPassword::createRandomPasswordProtectedKey('rightpassword'); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); $key1 = $pkey->unlockKey('wrongpassword'); } @@ -47,19 +46,16 @@ public function testChangePassword() /** * Check that changing the password actually changes the password. - * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException */ function testPasswordActuallyChanges() { $pkey1 = KeyProtectedByPassword::createRandomPasswordProtectedKey('password'); $pkey1->changePassword('password', 'new password'); + $this->expectException(\Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException::class); $pkey1->unlockKey('password'); } - /** - * @expectedException \Defuse\Crypto\Exception\BadFormatException - */ function testMalformedLoad() { $pkey1 = KeyProtectedByPassword::createRandomPasswordProtectedKey('password'); @@ -67,6 +63,7 @@ function testMalformedLoad() $pkey1_enc_ascii[0] = "\xFF"; + $this->expectException(\Defuse\Crypto\Exception\BadFormatException::class); KeyProtectedByPassword::loadFromAsciiSafeString($pkey1_enc_ascii); } } diff --git a/test/unit/RuntimeTestTest.php b/test/unit/RuntimeTestTest.php index 7790323..78325e6 100644 --- a/test/unit/RuntimeTestTest.php +++ b/test/unit/RuntimeTestTest.php @@ -1,8 +1,9 @@