diff --git a/src/Core.php b/src/Core.php index 73c3029..3506cda 100644 --- a/src/Core.php +++ b/src/Core.php @@ -50,29 +50,26 @@ final class Core */ public static function incrementCounter($ctr, $inc) { - if (Core::ourStrlen($ctr) !== Core::BLOCK_BYTE_SIZE) { - throw new Ex\EnvironmentIsBrokenException( - 'Trying to increment a nonce of the wrong size.' - ); - } - - if (! \is_int($inc)) { - throw new Ex\EnvironmentIsBrokenException( - 'Trying to increment nonce by a non-integer.' - ); - } - - if ($inc < 0) { - throw new Ex\EnvironmentIsBrokenException( - 'Trying to increment nonce by a negative amount.' - ); - } - - if ($inc > PHP_INT_MAX - 255) { - throw new Ex\EnvironmentIsBrokenException( - 'Integer overflow may occur.' - ); - } + Core::ensureTrue( + Core::ourStrlen($ctr) === Core::BLOCK_BYTE_SIZE, + 'Trying to increment a nonce of the wrong size.' + ); + + Core::ensureTrue( + \is_int($inc), + 'Trying to increment nonce by a non-integer.' + ); + + // The caller is probably re-using CTR-mode keystream if they increment by 0. + Core::ensureTrue( + $inc > 0, + 'Trying to increment a nonce by a nonpositive amount' + ); + + Core::ensureTrue( + $inc <= PHP_INT_MAX - 255, + 'Integer overflow may occur' + ); /* * We start at the rightmost byte (big-endian) @@ -82,11 +79,7 @@ public static function incrementCounter($ctr, $inc) $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.' - ); - } + Core::ensureTrue(\is_int($sum), 'Integer overflow in CTR mode nonce increment'); $ctr[$i] = \pack('C', $sum & 0xFF); $inc = $sum >> 8; @@ -146,12 +139,10 @@ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null) $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.' - ); - } + Core::ensureTrue( + !empty($length) && \is_int($length) && $length >= 0 && $length <= 255 * $digest_length, + 'Bad output length requested of HDKF.' + ); // "if [salt] not provided, is set to a string of HashLen zeroes." if (\is_null($salt)) { @@ -166,9 +157,7 @@ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null) // 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(); - } + Core::ensureTrue(Core::ourStrlen($prk) >= $digest_length); // T(0) = '' $t = ''; @@ -188,9 +177,7 @@ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null) // ORM = first L octets of T /** @var string $orm */ $orm = Core::ourSubstr($t, 0, $length); - if (!\is_string($orm)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($orm)); return $orm; } @@ -224,9 +211,7 @@ public static function hashEquals($expected, $given) // 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(); - } + Core::ensureTrue(Core::ourStrlen($expected) === Core::ourStrlen($given)); $blind = Core::secureRandom(32); $message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind); @@ -243,9 +228,7 @@ public static function hashEquals($expected, $given) */ public static function ensureConstantExists($name) { - if (! \defined($name)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\defined($name)); } /** @@ -258,8 +241,22 @@ public static function ensureConstantExists($name) */ public static function ensureFunctionExists($name) { - if (! \function_exists($name)) { - throw new Ex\EnvironmentIsBrokenException(); + Core::ensureTrue(\function_exists($name)); + } + + /** + * Throws an exception if the condition is false. + * + * @param bool $condition + * @param string $message + * @return void + * + * @throws Ex\EnvironmentIsBrokenException + */ + public static function ensureTrue($condition, $message = '') + { + if (!$condition) { + throw new Ex\EnvironmentIsBrokenException($message); } } @@ -286,9 +283,7 @@ public static function ourStrlen($str) } if ($exists) { $length = \mb_strlen($str, '8bit'); - if ($length === false) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($length !== false); return $length; } else { return \strlen($str); @@ -403,28 +398,22 @@ public static function pbkdf2($algorithm, $password, $salt, $count, $key_length, $key_length += 0; $algorithm = \strtolower($algorithm); - if (! \in_array($algorithm, \hash_algos(), true)) { - throw new Ex\EnvironmentIsBrokenException( - 'Invalid or unsupported hash algorithm.' - ); - } + Core::ensureTrue( + \in_array($algorithm, \hash_algos(), true), + '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.' - ); - } + Core::ensureTrue( + \in_array($algorithm, $ok_algorithms, true), + 'Algorithm is not a secure cryptographic hash function.' + ); - if ($count <= 0 || $key_length <= 0) { - throw new Ex\EnvironmentIsBrokenException( - 'Invalid PBKDF2 parameters.' - ); - } + Core::ensureTrue($count > 0 && $key_length > 0, 'Invalid PBKDF2 parameters.'); if (\function_exists('hash_pbkdf2')) { // The output length is in NIBBLES (4-bits) if $raw_output is false! diff --git a/src/Crypto.php b/src/Crypto.php index bac67d2..86eb204 100644 --- a/src/Crypto.php +++ b/src/Crypto.php @@ -18,13 +18,18 @@ class Crypto * * @return string */ - public static function encrypt($plaintext, Key $key, $raw_binary = false) + public static function encrypt($plaintext, $key, $raw_binary = false) { if (!\is_string($plaintext)) { throw new \TypeError( 'String expected for argument 1. ' . \ucfirst(\gettype($plaintext)) . ' given instead.' ); } + if (!($key instanceof Key)) { + throw new \TypeError( + 'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.' + ); + } if (!\is_bool($raw_binary)) { throw new \TypeError( 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.' @@ -87,13 +92,18 @@ public static function encryptWithPassword($plaintext, $password, $raw_binary = * * @return string */ - public static function decrypt($ciphertext, Key $key, $raw_binary = false) + public static function decrypt($ciphertext, $key, $raw_binary = false) { if (!\is_string($ciphertext)) { throw new \TypeError( 'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.' ); } + if (!($key instanceof Key)) { + throw new \TypeError( + 'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.' + ); + } if (!\is_bool($raw_binary)) { throw new \TypeError( 'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.' @@ -181,16 +191,12 @@ public static function legacyDecrypt($ciphertext, $key) * @var string */ $hmac = Core::ourSubstr($ciphertext, 0, Core::LEGACY_MAC_BYTE_SIZE); - if (!\is_string($hmac)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($hmac)); /** * @var string */ $messageCiphertext = Core::ourSubstr($ciphertext, Core::LEGACY_MAC_BYTE_SIZE); - if (!\is_string($messageCiphertext)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($messageCiphertext)); // Regenerate the same authentication sub-key. $akey = Core::HKDF( @@ -221,17 +227,13 @@ public static function legacyDecrypt($ciphertext, $key) * @var string */ $iv = Core::ourSubstr($messageCiphertext, 0, Core::LEGACY_BLOCK_BYTE_SIZE); - if (!\is_string($iv)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($iv)); /** * @var string */ $actualCiphertext = Core::ourSubstr($messageCiphertext, Core::LEGACY_BLOCK_BYTE_SIZE); - if (!\is_string($actualCiphertext)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($actualCiphertext)); // Do the decryption. $plaintext = self::plainDecrypt($actualCiphertext, $ekey, $iv, Core::LEGACY_CIPHER_METHOD); @@ -320,9 +322,7 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw Core::HEADER_VERSION_SIZE, Core::SALT_BYTE_SIZE ); - if (!\is_string($salt)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($salt)); // Get the IV. /** @var string $iv */ @@ -331,9 +331,7 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE, Core::BLOCK_BYTE_SIZE ); - if (!\is_string($iv)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($iv)); // Get the HMAC. /** @var string $hmac */ @@ -342,9 +340,7 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE, Core::MAC_BYTE_SIZE ); - if (!\is_string($hmac)) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(\is_string($hmac)); // Get the actual encrypted ciphertext. /** @var string $encrypted */ @@ -355,9 +351,7 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw 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(); - } + Core::ensureTrue(\is_string($encrypted)); // Derive the separate encryption and authentication keys from the key // or password, whichever it is. @@ -397,11 +391,7 @@ protected static function plainEncrypt($plaintext, $key, $iv) $iv ); - if (!\is_string($ciphertext)) { - throw new Ex\EnvironmentIsBrokenException( - 'openssl_encrypt() failed.' - ); - } + Core::ensureTrue(\is_string($ciphertext), 'openssl_encrypt() failed'); return $ciphertext; } @@ -431,11 +421,7 @@ protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod) OPENSSL_RAW_DATA, $iv ); - if (!\is_string($plaintext)) { - throw new Ex\EnvironmentIsBrokenException( - 'openssl_decrypt() failed.' - ); - } + Core::ensureTrue(\is_string($plaintext), 'openssl_decrypt() failed.'); return $plaintext; } diff --git a/src/Encoding.php b/src/Encoding.php index 001fb6e..8f933cf 100644 --- a/src/Encoding.php +++ b/src/Encoding.php @@ -178,11 +178,10 @@ 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.' - ); - } + Core::ensureTrue( + Core::ourStrlen($header) === self::SERIALIZE_HEADER_BYTES, + 'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.' + ); return Encoding::binToHex( $header . @@ -211,11 +210,10 @@ public static function loadBytesFromChecksummedAsciiSafeString($expected_header, { // 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.' - ); - } + Core::ensureTrue( + Core::ourStrlen($expected_header) === self::SERIALIZE_HEADER_BYTES, + '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. */ diff --git a/src/File.php b/src/File.php index 9f068a5..0d4ed74 100644 --- a/src/File.php +++ b/src/File.php @@ -348,11 +348,10 @@ private static function encryptResourceInternal($inputHandle, $outputHandle, Key /* Initialize a streaming HMAC state. */ /** @var resource $hmac */ $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey); - if (!\is_resource($hmac) && !\is_object($hmac)) { - throw new Ex\EnvironmentIsBrokenException( - 'Cannot initialize a hash context' - ); - } + Core::ensureTrue( + \is_resource($hmac) || \is_object($hmac), + 'Cannot initialize a hash context' + ); /* Write the header, salt, and IV. */ self::writeBytes( @@ -407,11 +406,7 @@ private static function encryptResourceInternal($inputHandle, $outputHandle, Key $thisIv ); - if (!\is_string($encrypted)) { - throw new Ex\EnvironmentIsBrokenException( - 'OpenSSL encryption error' - ); - } + Core::ensureTrue(\is_string($encrypted), 'OpenSSL encryption error'); /* Write this buffer's ciphertext. */ self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted)); @@ -518,11 +513,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO /* Initialize a streaming HMAC state. */ /** @var resource $hmac */ $hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey); - if (!\is_resource($hmac) && !\is_object($hmac)) { - throw new Ex\EnvironmentIsBrokenException( - 'Cannot initialize a hash context' - ); - } + Core::ensureTrue(\is_resource($hmac) || \is_object($hmac), '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) { @@ -576,11 +567,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO /* Remember this buffer-sized chunk's HMAC. */ /** @var resource $chunk_mac */ $chunk_mac = \hash_copy($hmac); - if (!\is_resource($chunk_mac) && !\is_object($chunk_mac)) { - throw new Ex\EnvironmentIsBrokenException( - 'Cannot duplicate a hash context' - ); - } + Core::ensureTrue(\is_resource($chunk_mac) || \is_object($chunk_mac), 'Cannot duplicate a hash context'); $macs []= \hash_final($chunk_mac); } @@ -634,11 +621,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO \hash_update($hmac2, $read); /** @var resource $calc_mac */ $calc_mac = \hash_copy($hmac2); - if (!\is_resource($calc_mac) && !\is_object($calc_mac)) { - throw new Ex\EnvironmentIsBrokenException( - 'Cannot duplicate a hash context' - ); - } + Core::ensureTrue(\is_resource($calc_mac) || \is_object($calc_mac), 'Cannot duplicate a hash context'); $calc = \hash_final($calc_mac); if (empty($macs)) { @@ -660,11 +643,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO OPENSSL_RAW_DATA, $thisIv ); - if (!\is_string($decrypted)) { - throw new Ex\EnvironmentIsBrokenException( - 'OpenSSL decryption error' - ); - } + Core::ensureTrue(\is_string($decrypted), 'OpenSSL decryption error'); /* Write the plaintext to the output file. */ self::writeBytes( @@ -696,13 +675,12 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO */ 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) { + Core::ensureTrue($num_bytes >= 0, 'Tried to read less than 0 bytes'); + + if ($num_bytes === 0) { return ''; } + $buf = ''; $remaining = $num_bytes; while ($remaining > 0 && ! \feof($stream)) { diff --git a/src/Key.php b/src/Key.php index fe4bf7d..27b919f 100644 --- a/src/Key.php +++ b/src/Key.php @@ -84,11 +84,10 @@ public function getRawBytes() */ private function __construct($bytes) { - if (Core::ourStrlen($bytes) !== self::KEY_BYTE_SIZE) { - throw new Ex\EnvironmentIsBrokenException( - 'Bad key length.' - ); - } + Core::ensureTrue( + Core::ourStrlen($bytes) === self::KEY_BYTE_SIZE, + 'Bad key length.' + ); $this->key_bytes = $bytes; } diff --git a/src/KeyOrPassword.php b/src/KeyOrPassword.php index 4a810d3..890b2c2 100644 --- a/src/KeyOrPassword.php +++ b/src/KeyOrPassword.php @@ -57,14 +57,16 @@ public static function createFromPassword($password) */ public function deriveKeys($salt) { - if (Core::ourStrlen($salt) !== Core::SALT_BYTE_SIZE) { - throw new Ex\EnvironmentIsBrokenException('Bad salt.'); - } + Core::ensureTrue( + Core::ourStrlen($salt) === Core::SALT_BYTE_SIZE, + 'Bad salt.' + ); if ($this->secret_type === self::SECRET_TYPE_KEY) { - if (!($this->secret instanceof Key)) { - throw new Ex\CryptoException('Expected a Key object'); - } + Core::ensureTrue($this->secret instanceof Key); + /** + * @psalm-suppress PossiblyInvalidMethodCall + */ $akey = Core::HKDF( Core::HASH_FUNCTION_NAME, $this->secret->getRawBytes(), @@ -72,6 +74,9 @@ public function deriveKeys($salt) Core::AUTHENTICATION_INFO_STRING, $salt ); + /** + * @psalm-suppress PossiblyInvalidMethodCall + */ $ekey = Core::HKDF( Core::HASH_FUNCTION_NAME, $this->secret->getRawBytes(), @@ -81,15 +86,18 @@ public function deriveKeys($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'); - } + Core::ensureTrue(\is_string($this->secret)); /* 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. */ + + /** + * @psalm-suppress PossiblyInvalidArgument + */ $prehash = \hash(Core::HASH_FUNCTION_NAME, $this->secret, true); + $prekey = Core::pbkdf2( Core::HASH_FUNCTION_NAME, $prehash, @@ -127,6 +135,14 @@ public function deriveKeys($salt) */ private function __construct($secret_type, $secret) { + // The constructor is private, so these should never throw. + if ($secret_type === self::SECRET_TYPE_KEY) { + Core::ensureTrue($secret instanceof Key); + } elseif ($secret_type === self::SECRET_TYPE_PASSWORD) { + Core::ensureTrue(\is_string($secret)); + } else { + throw new Ex\EnvironmentIsBrokenException('Bad secret type.'); + } $this->secret_type = $secret_type; $this->secret = $secret; } diff --git a/src/RuntimeTests.php b/src/RuntimeTests.php index 9f00a97..65ce55d 100644 --- a/src/RuntimeTests.php +++ b/src/RuntimeTests.php @@ -59,13 +59,9 @@ public static function runtimeTest() RuntimeTests::HKDFTestVector(); RuntimeTests::testEncryptDecrypt(); - if (Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) != Core::KEY_BYTE_SIZE) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) === Core::KEY_BYTE_SIZE); - if (Core::ENCRYPTION_INFO_STRING == Core::AUTHENTICATION_INFO_STRING) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue(Core::ENCRYPTION_INFO_STRING !== Core::AUTHENTICATION_INFO_STRING); } catch (Ex\EnvironmentIsBrokenException $ex) { // Do this, otherwise it will stay in the "tests are running" state. $test_state = 3; @@ -97,9 +93,7 @@ private static function testEncryptDecrypt() // the user into thinking it's just an invalid ciphertext! throw new Ex\EnvironmentIsBrokenException(); } - if ($decrypted !== $data) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($decrypted === $data); // Modifying the ciphertext: Appending a string. try { @@ -167,9 +161,7 @@ private static function HKDFTestVector() '34007208d5b887185865' ); $computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt); - if ($computed_okm !== $okm) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($computed_okm === $okm); // Test Case 7 $ikm = \str_repeat("\x0c", 22); @@ -180,9 +172,7 @@ private static function HKDFTestVector() '673a081d70cce7acfc48' ); $computed_okm = Core::HKDF('sha1', $ikm, $length, '', null); - if ($computed_okm !== $okm) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($computed_okm === $okm); } /** @@ -197,9 +187,9 @@ private static function HMACTestVector() $key = \str_repeat("\x0b", 20); $data = 'Hi There'; $correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7'; - if (\hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) !== $correct) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue( + \hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) === $correct + ); } /** @@ -230,18 +220,9 @@ private static function AESTestVector() ); $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(); - } + Core::ensureTrue($computed_ciphertext === $ciphertext); $computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD); - if ($computed_plaintext !== $plaintext) { - throw new Ex\EnvironmentIsBrokenException(); - } + Core::ensureTrue($computed_plaintext === $plaintext); } } diff --git a/test/unit/CoreTest.php b/test/unit/CoreTest.php index 41d62c0..5873f9b 100644 --- a/test/unit/CoreTest.php +++ b/test/unit/CoreTest.php @@ -106,4 +106,22 @@ public function testOurSubstrOutOfBorders() Core::ourSubstr('abc', 5, 2) ); } + + /** + * @expectedException \InvalidArgumentException + */ + public function testOurSubstrNegativeLength() + { + Core::ourSubstr('abc', 0, -1); + } + + public function testOurSubstrNegativeStart() + { + $this->assertSame('c', Core::ourSubstr('abc', -1, 1)); + } + + public function testOurSubstrLengthIsMax() + { + $this->assertSame('bc', Core::ourSubstr('abc', 1, 500)); + } } diff --git a/test/unit/CryptoTest.php b/test/unit/CryptoTest.php index 1ed8d7a..e94153d 100644 --- a/test/unit/CryptoTest.php +++ b/test/unit/CryptoTest.php @@ -110,4 +110,121 @@ public function testDecryptHexAsRaw() $ciphertext = Crypto::encryptWithPassword('testdata', 'password', false); Crypto::decryptWithPassword($ciphertext, 'password', true); } + + /** + * @expectedException \TypeError + */ + public function testEncryptTypeErrorA() + { + $key = Key::createNewRandomKey(); + Crypto::encrypt(3, $key, false); + } + + /** + * @expectedException \TypeError + */ + public function testEncryptTypeErrorB() + { + Crypto::encrypt("plaintext", 3, false); + } + + /** + * @expectedException \TypeError + */ + public function testEncryptTypeErrorC() + { + $key = Key::createNewRandomKey(); + Crypto::encrypt("plaintext", $key, 3); + } + + /** + * @expectedException \TypeError + */ + public function testEncryptWithPasswordTypeErrorA() + { + Crypto::encryptWithPassword(3, "password", false); + } + + /** + * @expectedException \TypeError + */ + public function testEncryptWithPasswordTypeErrorB() + { + Crypto::encryptWithPassword("plaintext", 3, false); + } + + /** + * @expectedException \TypeError + */ + public function testEncryptWithPasswordTypeErrorC() + { + Crypto::encryptWithPassword("plaintext", "password", 3); + } + + /** + * @expectedException \TypeError + */ + public function testDecryptTypeErrorA() + { + $key = Key::createNewRandomKey(); + Crypto::decrypt(3, $key, false); + } + + /** + * @expectedException \TypeError + */ + public function testDecryptTypeErrorB() + { + Crypto::decrypt("ciphertext", 3, false); + } + + /** + * @expectedException \TypeError + */ + public function testDecryptTypeErrorC() + { + $key = Key::createNewRandomKey(); + Crypto::decrypt("ciphertext", $key, 3); + } + + /** + * @expectedException \TypeError + */ + public function testDecryptWithPasswordTypeErrorA() + { + Crypto::decryptWithPassword(3, "password", false); + } + + /** + * @expectedException \TypeError + */ + public function testDecryptWithPasswordTypeErrorB() + { + Crypto::decryptWithPassword("ciphertext", 3, false); + } + + /** + * @expectedException \TypeError + */ + public function testDecryptWithPasswordTypeErrorC() + { + Crypto::decryptWithPassword("ciphertext", "password", 3); + } + + /** + * @expectedException \TypeError + */ + public function testLegacyDecryptTypeErrorA() + { + Crypto::legacyDecrypt(3, "key"); + } + + /** + * @expectedException \TypeError + */ + public function testLegacyDecryptTypeErrorB() + { + Crypto::legacyDecrypt("ciphertext", 3); + } + } diff --git a/test/unit/CtrModeTest.php b/test/unit/CtrModeTest.php index cd548c0..f4ab297 100644 --- a/test/unit/CtrModeTest.php +++ b/test/unit/CtrModeTest.php @@ -7,12 +7,6 @@ class CtrModeTest extends PHPUnit_Framework_TestCase public function counterTestVectorProvider() { return [ - /* Incrementing by zero makes no change. */ - [ - '01234567890123456789012345778901', - '01234567890123456789012345778901', - 0, - ], /* First byte, no overflow. */ [ '00000000000000000000000000000000', @@ -143,6 +137,17 @@ public function testIncrementByNegativeValue() ); } + /** + * @expectedException \Defuse\Crypto\Exception\EnvironmentIsBrokenException + */ + public function testIncrementByZero() + { + \Defuse\Crypto\Core::incrementCounter( + str_repeat("\x00", 16), + 0 + ); + } + public function allNonZeroByteValuesProvider() { $all_bytes = []; diff --git a/test/unit/LegacyDecryptTest.php b/test/unit/LegacyDecryptTest.php index e7f93b7..59832b8 100644 --- a/test/unit/LegacyDecryptTest.php +++ b/test/unit/LegacyDecryptTest.php @@ -1,5 +1,6 @@ unlockKey('password'); } + + /** + * @expectedException \Defuse\Crypto\Exception\BadFormatException + */ + function testMalformedLoad() + { + $pkey1 = KeyProtectedByPassword::createRandomPasswordProtectedKey('password'); + $pkey1_enc_ascii = $pkey1->saveToAsciiSafeString(); + + $pkey1_enc_ascii[0] = "\xFF"; + + KeyProtectedByPassword::loadFromAsciiSafeString($pkey1_enc_ascii); + } }