Skip to content

Commit 0d4d27c

Browse files
authoredApr 23, 2018
Merge pull request #398 from defuse/make-throw-ifs-an-assert
Improve Test Coverage
2 parents 39fba0c + d2b04d2 commit 0d4d27c

12 files changed

+308
-196
lines changed
 

‎src/Core.php

+55-66
Original file line numberDiff line numberDiff line change
@@ -50,29 +50,26 @@ final class Core
5050
*/
5151
public static function incrementCounter($ctr, $inc)
5252
{
53-
if (Core::ourStrlen($ctr) !== Core::BLOCK_BYTE_SIZE) {
54-
throw new Ex\EnvironmentIsBrokenException(
55-
'Trying to increment a nonce of the wrong size.'
56-
);
57-
}
58-
59-
if (! \is_int($inc)) {
60-
throw new Ex\EnvironmentIsBrokenException(
61-
'Trying to increment nonce by a non-integer.'
62-
);
63-
}
64-
65-
if ($inc < 0) {
66-
throw new Ex\EnvironmentIsBrokenException(
67-
'Trying to increment nonce by a negative amount.'
68-
);
69-
}
70-
71-
if ($inc > PHP_INT_MAX - 255) {
72-
throw new Ex\EnvironmentIsBrokenException(
73-
'Integer overflow may occur.'
74-
);
75-
}
53+
Core::ensureTrue(
54+
Core::ourStrlen($ctr) === Core::BLOCK_BYTE_SIZE,
55+
'Trying to increment a nonce of the wrong size.'
56+
);
57+
58+
Core::ensureTrue(
59+
\is_int($inc),
60+
'Trying to increment nonce by a non-integer.'
61+
);
62+
63+
// The caller is probably re-using CTR-mode keystream if they increment by 0.
64+
Core::ensureTrue(
65+
$inc > 0,
66+
'Trying to increment a nonce by a nonpositive amount'
67+
);
68+
69+
Core::ensureTrue(
70+
$inc <= PHP_INT_MAX - 255,
71+
'Integer overflow may occur'
72+
);
7673

7774
/*
7875
* We start at the rightmost byte (big-endian)
@@ -82,11 +79,7 @@ public static function incrementCounter($ctr, $inc)
8279
$sum = \ord($ctr[$i]) + $inc;
8380

8481
/* Detect integer overflow and fail. */
85-
if (! \is_int($sum)) {
86-
throw new Ex\EnvironmentIsBrokenException(
87-
'Integer overflow in CTR mode nonce increment.'
88-
);
89-
}
82+
Core::ensureTrue(\is_int($sum), 'Integer overflow in CTR mode nonce increment');
9083

9184
$ctr[$i] = \pack('C', $sum & 0xFF);
9285
$inc = $sum >> 8;
@@ -146,12 +139,10 @@ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
146139
$digest_length = Core::ourStrlen(\hash_hmac($hash, '', '', true));
147140

148141
// Sanity-check the desired output length.
149-
if (empty($length) || ! \is_int($length) ||
150-
$length < 0 || $length > 255 * $digest_length) {
151-
throw new Ex\EnvironmentIsBrokenException(
152-
'Bad output length requested of HKDF.'
153-
);
154-
}
142+
Core::ensureTrue(
143+
!empty($length) && \is_int($length) && $length >= 0 && $length <= 255 * $digest_length,
144+
'Bad output length requested of HDKF.'
145+
);
155146

156147
// "if [salt] not provided, is set to a string of HashLen zeroes."
157148
if (\is_null($salt)) {
@@ -166,9 +157,7 @@ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
166157
// HKDF-Expand:
167158

168159
// This check is useless, but it serves as a reminder to the spec.
169-
if (Core::ourStrlen($prk) < $digest_length) {
170-
throw new Ex\EnvironmentIsBrokenException();
171-
}
160+
Core::ensureTrue(Core::ourStrlen($prk) >= $digest_length);
172161

173162
// T(0) = ''
174163
$t = '';
@@ -188,9 +177,7 @@ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
188177
// ORM = first L octets of T
189178
/** @var string $orm */
190179
$orm = Core::ourSubstr($t, 0, $length);
191-
if (!\is_string($orm)) {
192-
throw new Ex\EnvironmentIsBrokenException();
193-
}
180+
Core::ensureTrue(\is_string($orm));
194181
return $orm;
195182
}
196183

@@ -224,9 +211,7 @@ public static function hashEquals($expected, $given)
224211
// We're not attempting to make variable-length string comparison
225212
// secure, as that's very difficult. Make sure the strings are the same
226213
// length.
227-
if (Core::ourStrlen($expected) !== Core::ourStrlen($given)) {
228-
throw new Ex\EnvironmentIsBrokenException();
229-
}
214+
Core::ensureTrue(Core::ourStrlen($expected) === Core::ourStrlen($given));
230215

231216
$blind = Core::secureRandom(32);
232217
$message_compare = \hash_hmac(Core::HASH_FUNCTION_NAME, $given, $blind);
@@ -243,9 +228,7 @@ public static function hashEquals($expected, $given)
243228
*/
244229
public static function ensureConstantExists($name)
245230
{
246-
if (! \defined($name)) {
247-
throw new Ex\EnvironmentIsBrokenException();
248-
}
231+
Core::ensureTrue(\defined($name));
249232
}
250233

251234
/**
@@ -258,8 +241,22 @@ public static function ensureConstantExists($name)
258241
*/
259242
public static function ensureFunctionExists($name)
260243
{
261-
if (! \function_exists($name)) {
262-
throw new Ex\EnvironmentIsBrokenException();
244+
Core::ensureTrue(\function_exists($name));
245+
}
246+
247+
/**
248+
* Throws an exception if the condition is false.
249+
*
250+
* @param bool $condition
251+
* @param string $message
252+
* @return void
253+
*
254+
* @throws Ex\EnvironmentIsBrokenException
255+
*/
256+
public static function ensureTrue($condition, $message = '')
257+
{
258+
if (!$condition) {
259+
throw new Ex\EnvironmentIsBrokenException($message);
263260
}
264261
}
265262

@@ -286,9 +283,7 @@ public static function ourStrlen($str)
286283
}
287284
if ($exists) {
288285
$length = \mb_strlen($str, '8bit');
289-
if ($length === false) {
290-
throw new Ex\EnvironmentIsBrokenException();
291-
}
286+
Core::ensureTrue($length !== false);
292287
return $length;
293288
} else {
294289
return \strlen($str);
@@ -403,28 +398,22 @@ public static function pbkdf2($algorithm, $password, $salt, $count, $key_length,
403398
$key_length += 0;
404399

405400
$algorithm = \strtolower($algorithm);
406-
if (! \in_array($algorithm, \hash_algos(), true)) {
407-
throw new Ex\EnvironmentIsBrokenException(
408-
'Invalid or unsupported hash algorithm.'
409-
);
410-
}
401+
Core::ensureTrue(
402+
\in_array($algorithm, \hash_algos(), true),
403+
'Invalid or unsupported hash algorithm.'
404+
);
411405

412406
// Whitelist, or we could end up with people using CRC32.
413407
$ok_algorithms = [
414408
'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
415409
'ripemd160', 'ripemd256', 'ripemd320', 'whirlpool',
416410
];
417-
if (! \in_array($algorithm, $ok_algorithms, true)) {
418-
throw new Ex\EnvironmentIsBrokenException(
419-
'Algorithm is not a secure cryptographic hash function.'
420-
);
421-
}
411+
Core::ensureTrue(
412+
\in_array($algorithm, $ok_algorithms, true),
413+
'Algorithm is not a secure cryptographic hash function.'
414+
);
422415

423-
if ($count <= 0 || $key_length <= 0) {
424-
throw new Ex\EnvironmentIsBrokenException(
425-
'Invalid PBKDF2 parameters.'
426-
);
427-
}
416+
Core::ensureTrue($count > 0 && $key_length > 0, 'Invalid PBKDF2 parameters.');
428417

429418
if (\function_exists('hash_pbkdf2')) {
430419
// The output length is in NIBBLES (4-bits) if $raw_output is false!

‎src/Crypto.php

+22-36
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,18 @@ class Crypto
1818
*
1919
* @return string
2020
*/
21-
public static function encrypt($plaintext, Key $key, $raw_binary = false)
21+
public static function encrypt($plaintext, $key, $raw_binary = false)
2222
{
2323
if (!\is_string($plaintext)) {
2424
throw new \TypeError(
2525
'String expected for argument 1. ' . \ucfirst(\gettype($plaintext)) . ' given instead.'
2626
);
2727
}
28+
if (!($key instanceof Key)) {
29+
throw new \TypeError(
30+
'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.'
31+
);
32+
}
2833
if (!\is_bool($raw_binary)) {
2934
throw new \TypeError(
3035
'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
@@ -87,13 +92,18 @@ public static function encryptWithPassword($plaintext, $password, $raw_binary =
8792
*
8893
* @return string
8994
*/
90-
public static function decrypt($ciphertext, Key $key, $raw_binary = false)
95+
public static function decrypt($ciphertext, $key, $raw_binary = false)
9196
{
9297
if (!\is_string($ciphertext)) {
9398
throw new \TypeError(
9499
'String expected for argument 1. ' . \ucfirst(\gettype($ciphertext)) . ' given instead.'
95100
);
96101
}
102+
if (!($key instanceof Key)) {
103+
throw new \TypeError(
104+
'Key expected for argument 2. ' . \ucfirst(\gettype($key)) . ' given instead.'
105+
);
106+
}
97107
if (!\is_bool($raw_binary)) {
98108
throw new \TypeError(
99109
'Boolean expected for argument 3. ' . \ucfirst(\gettype($raw_binary)) . ' given instead.'
@@ -181,16 +191,12 @@ public static function legacyDecrypt($ciphertext, $key)
181191
* @var string
182192
*/
183193
$hmac = Core::ourSubstr($ciphertext, 0, Core::LEGACY_MAC_BYTE_SIZE);
184-
if (!\is_string($hmac)) {
185-
throw new Ex\EnvironmentIsBrokenException();
186-
}
194+
Core::ensureTrue(\is_string($hmac));
187195
/**
188196
* @var string
189197
*/
190198
$messageCiphertext = Core::ourSubstr($ciphertext, Core::LEGACY_MAC_BYTE_SIZE);
191-
if (!\is_string($messageCiphertext)) {
192-
throw new Ex\EnvironmentIsBrokenException();
193-
}
199+
Core::ensureTrue(\is_string($messageCiphertext));
194200

195201
// Regenerate the same authentication sub-key.
196202
$akey = Core::HKDF(
@@ -221,17 +227,13 @@ public static function legacyDecrypt($ciphertext, $key)
221227
* @var string
222228
*/
223229
$iv = Core::ourSubstr($messageCiphertext, 0, Core::LEGACY_BLOCK_BYTE_SIZE);
224-
if (!\is_string($iv)) {
225-
throw new Ex\EnvironmentIsBrokenException();
226-
}
230+
Core::ensureTrue(\is_string($iv));
227231

228232
/**
229233
* @var string
230234
*/
231235
$actualCiphertext = Core::ourSubstr($messageCiphertext, Core::LEGACY_BLOCK_BYTE_SIZE);
232-
if (!\is_string($actualCiphertext)) {
233-
throw new Ex\EnvironmentIsBrokenException();
234-
}
236+
Core::ensureTrue(\is_string($actualCiphertext));
235237

236238
// Do the decryption.
237239
$plaintext = self::plainDecrypt($actualCiphertext, $ekey, $iv, Core::LEGACY_CIPHER_METHOD);
@@ -320,9 +322,7 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw
320322
Core::HEADER_VERSION_SIZE,
321323
Core::SALT_BYTE_SIZE
322324
);
323-
if (!\is_string($salt)) {
324-
throw new Ex\EnvironmentIsBrokenException();
325-
}
325+
Core::ensureTrue(\is_string($salt));
326326

327327
// Get the IV.
328328
/** @var string $iv */
@@ -331,9 +331,7 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw
331331
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE,
332332
Core::BLOCK_BYTE_SIZE
333333
);
334-
if (!\is_string($iv)) {
335-
throw new Ex\EnvironmentIsBrokenException();
336-
}
334+
Core::ensureTrue(\is_string($iv));
337335

338336
// Get the HMAC.
339337
/** @var string $hmac */
@@ -342,9 +340,7 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw
342340
Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE,
343341
Core::MAC_BYTE_SIZE
344342
);
345-
if (!\is_string($hmac)) {
346-
throw new Ex\EnvironmentIsBrokenException();
347-
}
343+
Core::ensureTrue(\is_string($hmac));
348344

349345
// Get the actual encrypted ciphertext.
350346
/** @var string $encrypted */
@@ -355,9 +351,7 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw
355351
Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE -
356352
Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE
357353
);
358-
if (!\is_string($encrypted)) {
359-
throw new Ex\EnvironmentIsBrokenException();
360-
}
354+
Core::ensureTrue(\is_string($encrypted));
361355

362356
// Derive the separate encryption and authentication keys from the key
363357
// or password, whichever it is.
@@ -397,11 +391,7 @@ protected static function plainEncrypt($plaintext, $key, $iv)
397391
$iv
398392
);
399393

400-
if (!\is_string($ciphertext)) {
401-
throw new Ex\EnvironmentIsBrokenException(
402-
'openssl_encrypt() failed.'
403-
);
404-
}
394+
Core::ensureTrue(\is_string($ciphertext), 'openssl_encrypt() failed');
405395

406396
return $ciphertext;
407397
}
@@ -431,11 +421,7 @@ protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod)
431421
OPENSSL_RAW_DATA,
432422
$iv
433423
);
434-
if (!\is_string($plaintext)) {
435-
throw new Ex\EnvironmentIsBrokenException(
436-
'openssl_decrypt() failed.'
437-
);
438-
}
424+
Core::ensureTrue(\is_string($plaintext), 'openssl_decrypt() failed.');
439425

440426
return $plaintext;
441427
}

‎src/Encoding.php

+8-10
Original file line numberDiff line numberDiff line change
@@ -178,11 +178,10 @@ public static function saveBytesToChecksummedAsciiSafeString($header, $bytes)
178178
{
179179
// Headers must be a constant length to prevent one type's header from
180180
// being a prefix of another type's header, leading to ambiguity.
181-
if (Core::ourStrlen($header) !== self::SERIALIZE_HEADER_BYTES) {
182-
throw new Ex\EnvironmentIsBrokenException(
183-
'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.'
184-
);
185-
}
181+
Core::ensureTrue(
182+
Core::ourStrlen($header) === self::SERIALIZE_HEADER_BYTES,
183+
'Header must be ' . self::SERIALIZE_HEADER_BYTES . ' bytes.'
184+
);
186185

187186
return Encoding::binToHex(
188187
$header .
@@ -211,11 +210,10 @@ public static function loadBytesFromChecksummedAsciiSafeString($expected_header,
211210
{
212211
// Headers must be a constant length to prevent one type's header from
213212
// being a prefix of another type's header, leading to ambiguity.
214-
if (Core::ourStrlen($expected_header) !== self::SERIALIZE_HEADER_BYTES) {
215-
throw new Ex\EnvironmentIsBrokenException(
216-
'Header must be 4 bytes.'
217-
);
218-
}
213+
Core::ensureTrue(
214+
Core::ourStrlen($expected_header) === self::SERIALIZE_HEADER_BYTES,
215+
'Header must be 4 bytes.'
216+
);
219217

220218
/* If you get an exception here when attempting to load from a file, first pass your
221219
key to Encoding::trimTrailingWhitespace() to remove newline characters, etc. */

‎src/File.php

+13-35
Original file line numberDiff line numberDiff line change
@@ -348,11 +348,10 @@ private static function encryptResourceInternal($inputHandle, $outputHandle, Key
348348
/* Initialize a streaming HMAC state. */
349349
/** @var resource $hmac */
350350
$hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
351-
if (!\is_resource($hmac) && !\is_object($hmac)) {
352-
throw new Ex\EnvironmentIsBrokenException(
353-
'Cannot initialize a hash context'
354-
);
355-
}
351+
Core::ensureTrue(
352+
\is_resource($hmac) || \is_object($hmac),
353+
'Cannot initialize a hash context'
354+
);
356355

357356
/* Write the header, salt, and IV. */
358357
self::writeBytes(
@@ -407,11 +406,7 @@ private static function encryptResourceInternal($inputHandle, $outputHandle, Key
407406
$thisIv
408407
);
409408

410-
if (!\is_string($encrypted)) {
411-
throw new Ex\EnvironmentIsBrokenException(
412-
'OpenSSL encryption error'
413-
);
414-
}
409+
Core::ensureTrue(\is_string($encrypted), 'OpenSSL encryption error');
415410

416411
/* Write this buffer's ciphertext. */
417412
self::writeBytes($outputHandle, $encrypted, Core::ourStrlen($encrypted));
@@ -518,11 +513,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
518513
/* Initialize a streaming HMAC state. */
519514
/** @var resource $hmac */
520515
$hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
521-
if (!\is_resource($hmac) && !\is_object($hmac)) {
522-
throw new Ex\EnvironmentIsBrokenException(
523-
'Cannot initialize a hash context'
524-
);
525-
}
516+
Core::ensureTrue(\is_resource($hmac) || \is_object($hmac), 'Cannot initialize a hash context');
526517

527518
/* Reset file pointer to the beginning of the file after the header */
528519
if (\fseek($inputHandle, Core::HEADER_VERSION_SIZE, SEEK_SET) === false) {
@@ -576,11 +567,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
576567
/* Remember this buffer-sized chunk's HMAC. */
577568
/** @var resource $chunk_mac */
578569
$chunk_mac = \hash_copy($hmac);
579-
if (!\is_resource($chunk_mac) && !\is_object($chunk_mac)) {
580-
throw new Ex\EnvironmentIsBrokenException(
581-
'Cannot duplicate a hash context'
582-
);
583-
}
570+
Core::ensureTrue(\is_resource($chunk_mac) || \is_object($chunk_mac), 'Cannot duplicate a hash context');
584571
$macs []= \hash_final($chunk_mac);
585572
}
586573

@@ -634,11 +621,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
634621
\hash_update($hmac2, $read);
635622
/** @var resource $calc_mac */
636623
$calc_mac = \hash_copy($hmac2);
637-
if (!\is_resource($calc_mac) && !\is_object($calc_mac)) {
638-
throw new Ex\EnvironmentIsBrokenException(
639-
'Cannot duplicate a hash context'
640-
);
641-
}
624+
Core::ensureTrue(\is_resource($calc_mac) || \is_object($calc_mac), 'Cannot duplicate a hash context');
642625
$calc = \hash_final($calc_mac);
643626

644627
if (empty($macs)) {
@@ -660,11 +643,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
660643
OPENSSL_RAW_DATA,
661644
$thisIv
662645
);
663-
if (!\is_string($decrypted)) {
664-
throw new Ex\EnvironmentIsBrokenException(
665-
'OpenSSL decryption error'
666-
);
667-
}
646+
Core::ensureTrue(\is_string($decrypted), 'OpenSSL decryption error');
668647

669648
/* Write the plaintext to the output file. */
670649
self::writeBytes(
@@ -696,13 +675,12 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
696675
*/
697676
public static function readBytes($stream, $num_bytes)
698677
{
699-
if ($num_bytes < 0) {
700-
throw new Ex\EnvironmentIsBrokenException(
701-
'Tried to read less than 0 bytes'
702-
);
703-
} elseif ($num_bytes === 0) {
678+
Core::ensureTrue($num_bytes >= 0, 'Tried to read less than 0 bytes');
679+
680+
if ($num_bytes === 0) {
704681
return '';
705682
}
683+
706684
$buf = '';
707685
$remaining = $num_bytes;
708686
while ($remaining > 0 && ! \feof($stream)) {

‎src/Key.php

+4-5
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,10 @@ public function getRawBytes()
8484
*/
8585
private function __construct($bytes)
8686
{
87-
if (Core::ourStrlen($bytes) !== self::KEY_BYTE_SIZE) {
88-
throw new Ex\EnvironmentIsBrokenException(
89-
'Bad key length.'
90-
);
91-
}
87+
Core::ensureTrue(
88+
Core::ourStrlen($bytes) === self::KEY_BYTE_SIZE,
89+
'Bad key length.'
90+
);
9291
$this->key_bytes = $bytes;
9392
}
9493

‎src/KeyOrPassword.php

+25-9
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,26 @@ public static function createFromPassword($password)
5757
*/
5858
public function deriveKeys($salt)
5959
{
60-
if (Core::ourStrlen($salt) !== Core::SALT_BYTE_SIZE) {
61-
throw new Ex\EnvironmentIsBrokenException('Bad salt.');
62-
}
60+
Core::ensureTrue(
61+
Core::ourStrlen($salt) === Core::SALT_BYTE_SIZE,
62+
'Bad salt.'
63+
);
6364

6465
if ($this->secret_type === self::SECRET_TYPE_KEY) {
65-
if (!($this->secret instanceof Key)) {
66-
throw new Ex\CryptoException('Expected a Key object');
67-
}
66+
Core::ensureTrue($this->secret instanceof Key);
67+
/**
68+
* @psalm-suppress PossiblyInvalidMethodCall
69+
*/
6870
$akey = Core::HKDF(
6971
Core::HASH_FUNCTION_NAME,
7072
$this->secret->getRawBytes(),
7173
Core::KEY_BYTE_SIZE,
7274
Core::AUTHENTICATION_INFO_STRING,
7375
$salt
7476
);
77+
/**
78+
* @psalm-suppress PossiblyInvalidMethodCall
79+
*/
7580
$ekey = Core::HKDF(
7681
Core::HASH_FUNCTION_NAME,
7782
$this->secret->getRawBytes(),
@@ -81,15 +86,18 @@ public function deriveKeys($salt)
8186
);
8287
return new DerivedKeys($akey, $ekey);
8388
} elseif ($this->secret_type === self::SECRET_TYPE_PASSWORD) {
84-
if (!\is_string($this->secret)) {
85-
throw new Ex\CryptoException('Expected a string');
86-
}
89+
Core::ensureTrue(\is_string($this->secret));
8790
/* Our PBKDF2 polyfill is vulnerable to a DoS attack documented in
8891
* GitHub issue #230. The fix is to pre-hash the password to ensure
8992
* it is short. We do the prehashing here instead of in pbkdf2() so
9093
* that pbkdf2() still computes the function as defined by the
9194
* standard. */
95+
96+
/**
97+
* @psalm-suppress PossiblyInvalidArgument
98+
*/
9299
$prehash = \hash(Core::HASH_FUNCTION_NAME, $this->secret, true);
100+
93101
$prekey = Core::pbkdf2(
94102
Core::HASH_FUNCTION_NAME,
95103
$prehash,
@@ -127,6 +135,14 @@ public function deriveKeys($salt)
127135
*/
128136
private function __construct($secret_type, $secret)
129137
{
138+
// The constructor is private, so these should never throw.
139+
if ($secret_type === self::SECRET_TYPE_KEY) {
140+
Core::ensureTrue($secret instanceof Key);
141+
} elseif ($secret_type === self::SECRET_TYPE_PASSWORD) {
142+
Core::ensureTrue(\is_string($secret));
143+
} else {
144+
throw new Ex\EnvironmentIsBrokenException('Bad secret type.');
145+
}
130146
$this->secret_type = $secret_type;
131147
$this->secret = $secret;
132148
}

‎src/RuntimeTests.php

+10-29
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,9 @@ public static function runtimeTest()
5959
RuntimeTests::HKDFTestVector();
6060

6161
RuntimeTests::testEncryptDecrypt();
62-
if (Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) != Core::KEY_BYTE_SIZE) {
63-
throw new Ex\EnvironmentIsBrokenException();
64-
}
62+
Core::ensureTrue(Core::ourStrlen(Key::createNewRandomKey()->getRawBytes()) === Core::KEY_BYTE_SIZE);
6563

66-
if (Core::ENCRYPTION_INFO_STRING == Core::AUTHENTICATION_INFO_STRING) {
67-
throw new Ex\EnvironmentIsBrokenException();
68-
}
64+
Core::ensureTrue(Core::ENCRYPTION_INFO_STRING !== Core::AUTHENTICATION_INFO_STRING);
6965
} catch (Ex\EnvironmentIsBrokenException $ex) {
7066
// Do this, otherwise it will stay in the "tests are running" state.
7167
$test_state = 3;
@@ -97,9 +93,7 @@ private static function testEncryptDecrypt()
9793
// the user into thinking it's just an invalid ciphertext!
9894
throw new Ex\EnvironmentIsBrokenException();
9995
}
100-
if ($decrypted !== $data) {
101-
throw new Ex\EnvironmentIsBrokenException();
102-
}
96+
Core::ensureTrue($decrypted === $data);
10397

10498
// Modifying the ciphertext: Appending a string.
10599
try {
@@ -167,9 +161,7 @@ private static function HKDFTestVector()
167161
'34007208d5b887185865'
168162
);
169163
$computed_okm = Core::HKDF('sha256', $ikm, $length, $info, $salt);
170-
if ($computed_okm !== $okm) {
171-
throw new Ex\EnvironmentIsBrokenException();
172-
}
164+
Core::ensureTrue($computed_okm === $okm);
173165

174166
// Test Case 7
175167
$ikm = \str_repeat("\x0c", 22);
@@ -180,9 +172,7 @@ private static function HKDFTestVector()
180172
'673a081d70cce7acfc48'
181173
);
182174
$computed_okm = Core::HKDF('sha1', $ikm, $length, '', null);
183-
if ($computed_okm !== $okm) {
184-
throw new Ex\EnvironmentIsBrokenException();
185-
}
175+
Core::ensureTrue($computed_okm === $okm);
186176
}
187177

188178
/**
@@ -197,9 +187,9 @@ private static function HMACTestVector()
197187
$key = \str_repeat("\x0b", 20);
198188
$data = 'Hi There';
199189
$correct = 'b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7';
200-
if (\hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) !== $correct) {
201-
throw new Ex\EnvironmentIsBrokenException();
202-
}
190+
Core::ensureTrue(
191+
\hash_hmac(Core::HASH_FUNCTION_NAME, $data, $key) === $correct
192+
);
203193
}
204194

205195
/**
@@ -230,18 +220,9 @@ private static function AESTestVector()
230220
);
231221

232222
$computed_ciphertext = Crypto::plainEncrypt($plaintext, $key, $iv);
233-
if ($computed_ciphertext !== $ciphertext) {
234-
echo \str_repeat("\n", 30);
235-
echo \bin2hex($computed_ciphertext);
236-
echo "\n---\n";
237-
echo \bin2hex($ciphertext);
238-
echo \str_repeat("\n", 30);
239-
throw new Ex\EnvironmentIsBrokenException();
240-
}
223+
Core::ensureTrue($computed_ciphertext === $ciphertext);
241224

242225
$computed_plaintext = Crypto::plainDecrypt($ciphertext, $key, $iv, Core::CIPHER_METHOD);
243-
if ($computed_plaintext !== $plaintext) {
244-
throw new Ex\EnvironmentIsBrokenException();
245-
}
226+
Core::ensureTrue($computed_plaintext === $plaintext);
246227
}
247228
}

‎test/unit/CoreTest.php

+18
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,22 @@ public function testOurSubstrOutOfBorders()
106106
Core::ourSubstr('abc', 5, 2)
107107
);
108108
}
109+
110+
/**
111+
* @expectedException \InvalidArgumentException
112+
*/
113+
public function testOurSubstrNegativeLength()
114+
{
115+
Core::ourSubstr('abc', 0, -1);
116+
}
117+
118+
public function testOurSubstrNegativeStart()
119+
{
120+
$this->assertSame('c', Core::ourSubstr('abc', -1, 1));
121+
}
122+
123+
public function testOurSubstrLengthIsMax()
124+
{
125+
$this->assertSame('bc', Core::ourSubstr('abc', 1, 500));
126+
}
109127
}

‎test/unit/CryptoTest.php

+117
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,121 @@ public function testDecryptHexAsRaw()
110110
$ciphertext = Crypto::encryptWithPassword('testdata', 'password', false);
111111
Crypto::decryptWithPassword($ciphertext, 'password', true);
112112
}
113+
114+
/**
115+
* @expectedException \TypeError
116+
*/
117+
public function testEncryptTypeErrorA()
118+
{
119+
$key = Key::createNewRandomKey();
120+
Crypto::encrypt(3, $key, false);
121+
}
122+
123+
/**
124+
* @expectedException \TypeError
125+
*/
126+
public function testEncryptTypeErrorB()
127+
{
128+
Crypto::encrypt("plaintext", 3, false);
129+
}
130+
131+
/**
132+
* @expectedException \TypeError
133+
*/
134+
public function testEncryptTypeErrorC()
135+
{
136+
$key = Key::createNewRandomKey();
137+
Crypto::encrypt("plaintext", $key, 3);
138+
}
139+
140+
/**
141+
* @expectedException \TypeError
142+
*/
143+
public function testEncryptWithPasswordTypeErrorA()
144+
{
145+
Crypto::encryptWithPassword(3, "password", false);
146+
}
147+
148+
/**
149+
* @expectedException \TypeError
150+
*/
151+
public function testEncryptWithPasswordTypeErrorB()
152+
{
153+
Crypto::encryptWithPassword("plaintext", 3, false);
154+
}
155+
156+
/**
157+
* @expectedException \TypeError
158+
*/
159+
public function testEncryptWithPasswordTypeErrorC()
160+
{
161+
Crypto::encryptWithPassword("plaintext", "password", 3);
162+
}
163+
164+
/**
165+
* @expectedException \TypeError
166+
*/
167+
public function testDecryptTypeErrorA()
168+
{
169+
$key = Key::createNewRandomKey();
170+
Crypto::decrypt(3, $key, false);
171+
}
172+
173+
/**
174+
* @expectedException \TypeError
175+
*/
176+
public function testDecryptTypeErrorB()
177+
{
178+
Crypto::decrypt("ciphertext", 3, false);
179+
}
180+
181+
/**
182+
* @expectedException \TypeError
183+
*/
184+
public function testDecryptTypeErrorC()
185+
{
186+
$key = Key::createNewRandomKey();
187+
Crypto::decrypt("ciphertext", $key, 3);
188+
}
189+
190+
/**
191+
* @expectedException \TypeError
192+
*/
193+
public function testDecryptWithPasswordTypeErrorA()
194+
{
195+
Crypto::decryptWithPassword(3, "password", false);
196+
}
197+
198+
/**
199+
* @expectedException \TypeError
200+
*/
201+
public function testDecryptWithPasswordTypeErrorB()
202+
{
203+
Crypto::decryptWithPassword("ciphertext", 3, false);
204+
}
205+
206+
/**
207+
* @expectedException \TypeError
208+
*/
209+
public function testDecryptWithPasswordTypeErrorC()
210+
{
211+
Crypto::decryptWithPassword("ciphertext", "password", 3);
212+
}
213+
214+
/**
215+
* @expectedException \TypeError
216+
*/
217+
public function testLegacyDecryptTypeErrorA()
218+
{
219+
Crypto::legacyDecrypt(3, "key");
220+
}
221+
222+
/**
223+
* @expectedException \TypeError
224+
*/
225+
public function testLegacyDecryptTypeErrorB()
226+
{
227+
Crypto::legacyDecrypt("ciphertext", 3);
228+
}
229+
113230
}

‎test/unit/CtrModeTest.php

+11-6
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,6 @@ class CtrModeTest extends PHPUnit_Framework_TestCase
77
public function counterTestVectorProvider()
88
{
99
return [
10-
/* Incrementing by zero makes no change. */
11-
[
12-
'01234567890123456789012345778901',
13-
'01234567890123456789012345778901',
14-
0,
15-
],
1610
/* First byte, no overflow. */
1711
[
1812
'00000000000000000000000000000000',
@@ -143,6 +137,17 @@ public function testIncrementByNegativeValue()
143137
);
144138
}
145139

140+
/**
141+
* @expectedException \Defuse\Crypto\Exception\EnvironmentIsBrokenException
142+
*/
143+
public function testIncrementByZero()
144+
{
145+
\Defuse\Crypto\Core::incrementCounter(
146+
str_repeat("\x00", 16),
147+
0
148+
);
149+
}
150+
146151
public function allNonZeroByteValuesProvider()
147152
{
148153
$all_bytes = [];

‎test/unit/LegacyDecryptTest.php

+12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

3+
use \Defuse\Crypto\Core;
34
use \Defuse\Crypto\Crypto;
45
use \Defuse\Crypto\Encoding;
56

@@ -42,4 +43,15 @@ public function testDecryptLegacyCiphertextWrongKey()
4243
// ^- I changed that byte
4344
);
4445
}
46+
47+
/**
48+
* @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException
49+
* @expectedExceptionMessage short
50+
*/
51+
public function testLegacyDecryptTooShort()
52+
{
53+
$too_short = str_repeat("a", Core::LEGACY_MAC_BYTE_SIZE);
54+
Crypto::legacyDecrypt($too_short, "0123456789ABCDEF");
55+
}
56+
4557
}

‎test/unit/PasswordTest.php

+13
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,17 @@ function testPasswordActuallyChanges()
5656

5757
$pkey1->unlockKey('password');
5858
}
59+
60+
/**
61+
* @expectedException \Defuse\Crypto\Exception\BadFormatException
62+
*/
63+
function testMalformedLoad()
64+
{
65+
$pkey1 = KeyProtectedByPassword::createRandomPasswordProtectedKey('password');
66+
$pkey1_enc_ascii = $pkey1->saveToAsciiSafeString();
67+
68+
$pkey1_enc_ascii[0] = "\xFF";
69+
70+
KeyProtectedByPassword::loadFromAsciiSafeString($pkey1_enc_ascii);
71+
}
5972
}

0 commit comments

Comments
 (0)
Please sign in to comment.