Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit aa72b8b

Browse files
authoredMay 15, 2017
Merge pull request #341 from defuse/psalm
Add type safety analysis to Travis CI
2 parents 0364e3e + 083c342 commit aa72b8b

13 files changed

+184
-55
lines changed
 

‎.travis.yml

+21-8
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,29 @@
11
language: php
2-
php:
3-
- 7.1
4-
- 7.0
5-
- 5.6
6-
- 5.5
7-
- 5.4
8-
92
sudo: false
103

114
matrix:
12-
fast_finish: true
5+
fast_finish: true
6+
include:
7+
- php: "5.4"
8+
env: USE_PSALM=0
9+
- php: "5.5"
10+
env: USE_PSALM=0
11+
- php: "5.6"
12+
env: USE_PSALM=1
13+
- php: "7.0"
14+
env: USE_PSALM=1
15+
- php: "7.1"
16+
env: USE_PSALM=1
17+
- php: "nightly"
18+
env: USE_PSALM=1
19+
- php: "hhvm"
20+
env: USE_PSALM=1
21+
allow_failures:
22+
- php: "nightly"
23+
- php: "hhvm"
1324

1425
install:
26+
- if [[ $USE_PSALM -eq 1 ]]; then composer require --dev "vimeo/psalm:dev-master"; fi
1527
- composer install
1628
- curl -LSs https://box-project.github.io/box2/installer.php | php
1729
- mkdir ~/box
@@ -21,3 +33,4 @@ script:
2133
- ./test.sh
2234
- PATH=$PATH:~/box/ make -C dist/ build-phar
2335
- ./test.sh dist/defuse-crypto.phar
36+
- if [[ $USE_PSALM -eq 1 ]]; then vendor/bin/psalm; fi

‎composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,6 @@
2626
"php": ">=5.4.0"
2727
},
2828
"require-dev": {
29-
"nikic/php-parser": "^2.0"
29+
"nikic/php-parser": "^2.0|^3.0"
3030
}
3131
}

‎docs/InternalDeveloperDocs.md

+15
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ First do `composer install` and then you can run the tests by running
2525
`./test.sh`. This will download a PHPUnit PHAR, verify its cryptographic
2626
signatures, and then use it to run the tests in `test/unit`.
2727

28+
Getting and Using Psalm
29+
-----------------------
30+
31+
[Psalm](https://github.com/vimeo/psalm) is a static analysis suite for PHP projects.
32+
We use Psalm to ensure type safety throughout our library.
33+
34+
To install Psalm, you just need to run one command:
35+
36+
composer require --dev "vimeo/psalm:dev-master"
37+
38+
To verify that your code changes are still strictly type-safe, run the following
39+
command:
40+
41+
vendor/bin/psalm
42+
2843
Reporting Bugs
2944
---------------
3045

‎psalm.xml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0"?>
2+
<psalm
3+
stopOnFirstError="false"
4+
useDocblockTypes="true"
5+
>
6+
<projectFiles>
7+
<directory name="src" />
8+
</projectFiles>
9+
</psalm>

‎src/Core.php

+9-5
Original file line numberDiff line numberDiff line change
@@ -124,14 +124,15 @@ public static function secureRandom($octets)
124124
* @param string $salt
125125
*
126126
* @throws Ex\EnvironmentIsBrokenException
127+
* @psalm-suppress UndefinedFunction - We're checking if the function exists first.
127128
*
128129
* @return string
129130
*/
130131
public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
131132
{
132133
static $nativeHKDF = null;
133134
if ($nativeHKDF === null) {
134-
$nativeHKDF = \function_exists('hash_hkdf');
135+
$nativeHKDF = \is_callable('\\hash_hkdf');
135136
}
136137
if ($nativeHKDF) {
137138
return \hash_hkdf($hash, $ikm, $length, $info, $salt);
@@ -180,8 +181,9 @@ public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
180181
}
181182

182183
// ORM = first L octets of T
184+
/** @var string $orm */
183185
$orm = Core::ourSubstr($t, 0, $length);
184-
if ($orm === false) {
186+
if (!\is_string($orm)) {
185187
throw new Ex\EnvironmentIsBrokenException();
186188
}
187189
return $orm;
@@ -230,6 +232,7 @@ public static function hashEquals($expected, $given)
230232
* Throws an exception if the constant doesn't exist.
231233
*
232234
* @param string $name
235+
* @return void
233236
*
234237
* @throws Ex\EnvironmentIsBrokenException
235238
*/
@@ -244,6 +247,7 @@ public static function ensureConstantExists($name)
244247
* Throws an exception if the function doesn't exist.
245248
*
246249
* @param string $name
250+
* @return void
247251
*
248252
* @throws Ex\EnvironmentIsBrokenException
249253
*/
@@ -295,7 +299,7 @@ public static function ourStrlen($str)
295299
*
296300
* @throws Ex\EnvironmentIsBrokenException
297301
*
298-
* @return string
302+
* @return string|bool
299303
*/
300304
public static function ourSubstr($str, $start, $length = null)
301305
{
@@ -434,9 +438,9 @@ public static function pbkdf2($algorithm, $password, $salt, $count, $key_length,
434438
}
435439

436440
if ($raw_output) {
437-
return Core::ourSubstr($output, 0, $key_length);
441+
return (string) Core::ourSubstr($output, 0, $key_length);
438442
} else {
439-
return Encoding::binToHex(Core::ourSubstr($output, 0, $key_length));
443+
return Encoding::binToHex((string) Core::ourSubstr($output, 0, $key_length));
440444
}
441445
}
442446
}

‎src/Crypto.php

+33-12
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,18 @@ public static function legacyDecrypt($ciphertext, $key)
111111
'Ciphertext is too short.'
112112
);
113113
}
114+
/**
115+
* @var string
116+
*/
114117
$hmac = Core::ourSubstr($ciphertext, 0, Core::LEGACY_MAC_BYTE_SIZE);
115-
if ($hmac === false) {
118+
if (!\is_string($hmac)) {
116119
throw new Ex\EnvironmentIsBrokenException();
117120
}
121+
/**
122+
* @var string
123+
*/
118124
$ciphertext = Core::ourSubstr($ciphertext, Core::LEGACY_MAC_BYTE_SIZE);
119-
if ($ciphertext === false) {
125+
if (!\is_string($ciphertext)) {
120126
throw new Ex\EnvironmentIsBrokenException();
121127
}
122128

@@ -145,17 +151,24 @@ public static function legacyDecrypt($ciphertext, $key)
145151
'Ciphertext is too short.'
146152
);
147153
}
154+
/**
155+
* @var string
156+
*/
148157
$iv = Core::ourSubstr($ciphertext, 0, Core::LEGACY_BLOCK_BYTE_SIZE);
149-
if ($iv === false) {
158+
if (!\is_string($iv)) {
150159
throw new Ex\EnvironmentIsBrokenException();
151160
}
152-
$ciphertext = Core::ourSubstr($ciphertext, Core::LEGACY_BLOCK_BYTE_SIZE);
153-
if ($ciphertext === false) {
161+
162+
/**
163+
* @var string
164+
*/
165+
$actualCiphertext = Core::ourSubstr($ciphertext, Core::LEGACY_BLOCK_BYTE_SIZE);
166+
if (!\is_string($actualCiphertext)) {
154167
throw new Ex\EnvironmentIsBrokenException();
155168
}
156169

157170
// Do the decryption.
158-
$plaintext = self::plainDecrypt($ciphertext, $ekey, $iv, Core::LEGACY_CIPHER_METHOD);
171+
$plaintext = self::plainDecrypt($actualCiphertext, $ekey, $iv, Core::LEGACY_CIPHER_METHOD);
159172
return $plaintext;
160173
} else {
161174
throw new Ex\WrongKeyOrModifiedCiphertextException(
@@ -226,6 +239,7 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw
226239
}
227240

228241
// Get and check the version header.
242+
/** @var string $header */
229243
$header = Core::ourSubstr($ciphertext, 0, Core::HEADER_VERSION_SIZE);
230244
if ($header !== Core::CURRENT_VERSION) {
231245
throw new Ex\WrongKeyOrModifiedCiphertextException(
@@ -234,44 +248,48 @@ private static function decryptInternal($ciphertext, KeyOrPassword $secret, $raw
234248
}
235249

236250
// Get the salt.
251+
/** @var string $salt */
237252
$salt = Core::ourSubstr(
238253
$ciphertext,
239254
Core::HEADER_VERSION_SIZE,
240255
Core::SALT_BYTE_SIZE
241256
);
242-
if ($salt === false) {
257+
if (!\is_string($salt)) {
243258
throw new Ex\EnvironmentIsBrokenException();
244259
}
245260

246261
// Get the IV.
262+
/** @var string $iv */
247263
$iv = Core::ourSubstr(
248264
$ciphertext,
249265
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE,
250266
Core::BLOCK_BYTE_SIZE
251267
);
252-
if ($iv === false) {
268+
if (!\is_string($iv)) {
253269
throw new Ex\EnvironmentIsBrokenException();
254270
}
255271

256272
// Get the HMAC.
273+
/** @var string $hmac */
257274
$hmac = Core::ourSubstr(
258275
$ciphertext,
259276
Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE,
260277
Core::MAC_BYTE_SIZE
261278
);
262-
if ($hmac === false) {
279+
if (!\is_string($hmac)) {
263280
throw new Ex\EnvironmentIsBrokenException();
264281
}
265282

266283
// Get the actual encrypted ciphertext.
284+
/** @var string $encrypted */
267285
$encrypted = Core::ourSubstr(
268286
$ciphertext,
269287
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE +
270288
Core::BLOCK_BYTE_SIZE,
271289
Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE -
272290
Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE
273291
);
274-
if ($encrypted === false) {
292+
if (!\is_string($encrypted)) {
275293
throw new Ex\EnvironmentIsBrokenException();
276294
}
277295

@@ -304,6 +322,7 @@ protected static function plainEncrypt($plaintext, $key, $iv)
304322
{
305323
Core::ensureConstantExists('OPENSSL_RAW_DATA');
306324
Core::ensureFunctionExists('openssl_encrypt');
325+
/** @var string $ciphertext */
307326
$ciphertext = \openssl_encrypt(
308327
$plaintext,
309328
Core::CIPHER_METHOD,
@@ -312,7 +331,7 @@ protected static function plainEncrypt($plaintext, $key, $iv)
312331
$iv
313332
);
314333

315-
if ($ciphertext === false) {
334+
if (!\is_string($ciphertext)) {
316335
throw new Ex\EnvironmentIsBrokenException(
317336
'openssl_encrypt() failed.'
318337
);
@@ -337,14 +356,16 @@ protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod)
337356
{
338357
Core::ensureConstantExists('OPENSSL_RAW_DATA');
339358
Core::ensureFunctionExists('openssl_decrypt');
359+
360+
/** @var string $plaintext */
340361
$plaintext = \openssl_decrypt(
341362
$ciphertext,
342363
$cipherMethod,
343364
$key,
344365
OPENSSL_RAW_DATA,
345366
$iv
346367
);
347-
if ($plaintext === false) {
368+
if (!\is_string($plaintext)) {
348369
throw new Ex\EnvironmentIsBrokenException(
349370
'openssl_decrypt() failed.'
350371
);

‎src/DerivedKeys.php

+15-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,25 @@
22

33
namespace Defuse\Crypto;
44

5+
/**
6+
* Class DerivedKeys
7+
* @package Defuse\Crypto
8+
*/
59
final class DerivedKeys
610
{
7-
private $akey = null;
8-
private $ekey = null;
11+
/**
12+
* @var string
13+
*/
14+
private $akey = '';
15+
16+
/**
17+
* @var string
18+
*/
19+
private $ekey = '';
920

1021
/**
1122
* Returns the authentication key.
23+
* @return string
1224
*/
1325
public function getAuthenticationKey()
1426
{
@@ -17,6 +29,7 @@ public function getAuthenticationKey()
1729

1830
/**
1931
* Returns the encryption key.
32+
* @return string
2033
*/
2134
public function getEncryptionKey()
2235
{

‎src/Encoding.php

+5-5
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public static function trimTrailingWhitespace($string = '')
131131
$sub = (((0x1f - $chr) & ($chr - 0x21)) >> 8) & 1;
132132
$length -= $sub;
133133
} while ($prevLength !== $length && $length > 0);
134-
return Core::ourSubstr($string, 0, $length);
134+
return (string) Core::ourSubstr($string, 0, $length);
135135
}
136136

137137
/*
@@ -229,7 +229,7 @@ public static function loadBytesFromChecksummedAsciiSafeString($expected_header,
229229
}
230230

231231
/* Grab the version header. */
232-
$actual_header = Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES);
232+
$actual_header = (string) Core::ourSubstr($bytes, 0, self::SERIALIZE_HEADER_BYTES);
233233

234234
if ($actual_header !== $expected_header) {
235235
throw new Ex\BadFormatException(
@@ -238,14 +238,14 @@ public static function loadBytesFromChecksummedAsciiSafeString($expected_header,
238238
}
239239

240240
/* Grab the bytes that are part of the checksum. */
241-
$checked_bytes = Core::ourSubstr(
241+
$checked_bytes = (string) Core::ourSubstr(
242242
$bytes,
243243
0,
244244
Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE
245245
);
246246

247247
/* Grab the included checksum. */
248-
$checksum_a = Core::ourSubstr(
248+
$checksum_a = (string) Core::ourSubstr(
249249
$bytes,
250250
Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE,
251251
self::CHECKSUM_BYTE_SIZE
@@ -261,7 +261,7 @@ public static function loadBytesFromChecksummedAsciiSafeString($expected_header,
261261
);
262262
}
263263

264-
return Core::ourSubstr(
264+
return (string) Core::ourSubstr(
265265
$bytes,
266266
self::SERIALIZE_HEADER_BYTES,
267267
Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE

‎src/File.php

+47-18
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ final class File
1212
* @param string $inputFilename
1313
* @param string $outputFilename
1414
* @param Key $key
15+
* @return void
1516
*
1617
* @throws Ex\EnvironmentIsBrokenException
1718
* @throws Ex\IOException
@@ -32,6 +33,7 @@ public static function encryptFile($inputFilename, $outputFilename, Key $key)
3233
* @param string $inputFilename
3334
* @param string $outputFilename
3435
* @param string $password
36+
* @return void
3537
*
3638
* @throws Ex\EnvironmentIsBrokenException
3739
* @throws Ex\IOException
@@ -51,6 +53,7 @@ public static function encryptFileWithPassword($inputFilename, $outputFilename,
5153
* @param string $inputFilename
5254
* @param string $outputFilename
5355
* @param Key $key
56+
* @return void
5457
*
5558
* @throws Ex\EnvironmentIsBrokenException
5659
* @throws Ex\IOException
@@ -72,6 +75,7 @@ public static function decryptFile($inputFilename, $outputFilename, Key $key)
7275
* @param string $inputFilename
7376
* @param string $outputFilename
7477
* @param string $password
78+
* @return void
7579
*
7680
* @throws Ex\EnvironmentIsBrokenException
7781
* @throws Ex\IOException
@@ -93,6 +97,7 @@ public static function decryptFileWithPassword($inputFilename, $outputFilename,
9397
* @param resource $inputHandle
9498
* @param resource $outputHandle
9599
* @param Key $key
100+
* @return void
96101
*
97102
* @throws Ex\EnvironmentIsBrokenException
98103
* @throws Ex\WrongKeyOrModifiedCiphertextException
@@ -114,6 +119,7 @@ public static function encryptResource($inputHandle, $outputHandle, Key $key)
114119
* @param resource $inputHandle
115120
* @param resource $outputHandle
116121
* @param string $password
122+
* @return void
117123
*
118124
* @throws Ex\EnvironmentIsBrokenException
119125
* @throws Ex\IOException
@@ -135,6 +141,7 @@ public static function encryptResourceWithPassword($inputHandle, $outputHandle,
135141
* @param resource $inputHandle
136142
* @param resource $outputHandle
137143
* @param Key $key
144+
* @return void
138145
*
139146
* @throws Ex\EnvironmentIsBrokenException
140147
* @throws Ex\IOException
@@ -156,6 +163,7 @@ public static function decryptResource($inputHandle, $outputHandle, Key $key)
156163
* @param resource $inputHandle
157164
* @param resource $outputHandle
158165
* @param string $password
166+
* @return void
159167
*
160168
* @throws Ex\EnvironmentIsBrokenException
161169
* @throws Ex\IOException
@@ -176,6 +184,7 @@ public static function decryptResourceWithPassword($inputHandle, $outputHandle,
176184
* @param string $inputFilename
177185
* @param string $outputFilename
178186
* @param KeyOrPassword $secret
187+
* @return void
179188
*
180189
* @throws Ex\CryptoException
181190
* @throws Ex\IOException
@@ -240,6 +249,7 @@ private static function encryptFileInternal($inputFilename, $outputFilename, Key
240249
* @param string $inputFilename
241250
* @param string $outputFilename
242251
* @param KeyOrPassword $secret
252+
* @return void
243253
*
244254
* @throws Ex\CryptoException
245255
* @throws Ex\IOException
@@ -254,7 +264,7 @@ private static function decryptFileInternal($inputFilename, $outputFilename, Key
254264
self::getLastErrorMessage()
255265
);
256266
}
257-
267+
258268
if (\is_callable('\\stream_set_read_buffer')) {
259269
/* This call can fail, but the only consequence is performance. */
260270
\stream_set_read_buffer($if, 0);
@@ -269,7 +279,7 @@ private static function decryptFileInternal($inputFilename, $outputFilename, Key
269279
self::getLastErrorMessage()
270280
);
271281
}
272-
282+
273283
if (\is_callable('\\stream_set_write_buffer')) {
274284
/* This call can fail, but the only consequence is performance. */
275285
\stream_set_write_buffer($of, 0);
@@ -306,6 +316,7 @@ private static function decryptFileInternal($inputFilename, $outputFilename, Key
306316
* @param resource $inputHandle
307317
* @param resource $outputHandle
308318
* @param KeyOrPassword $secret
319+
* @return void
309320
*
310321
* @throws Ex\EnvironmentIsBrokenException
311322
* @throws Ex\IOException
@@ -335,8 +346,9 @@ private static function encryptResourceInternal($inputHandle, $outputHandle, Key
335346
$iv = Core::secureRandom($ivsize);
336347

337348
/* Initialize a streaming HMAC state. */
349+
/** @var resource $hmac */
338350
$hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
339-
if ($hmac === false) {
351+
if (!\is_resource($hmac)) {
340352
throw new Ex\EnvironmentIsBrokenException(
341353
'Cannot initialize a hash context'
342354
);
@@ -358,14 +370,15 @@ private static function encryptResourceInternal($inputHandle, $outputHandle, Key
358370
$thisIv = $iv;
359371

360372
/* How many blocks do we encrypt at a time? We increment by this value. */
361-
$inc = Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE;
373+
$inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE);
362374

363375
/* Loop until we reach the end of the input file. */
364376
$at_file_end = false;
365377
while (! (\feof($inputHandle) || $at_file_end)) {
366378
/* Find out if we can read a full buffer, or only a partial one. */
379+
/** @var int */
367380
$pos = \ftell($inputHandle);
368-
if ($pos === false) {
381+
if (!\is_int($pos)) {
369382
throw new Ex\IOException(
370383
'Could not get current position in input file during encryption'
371384
);
@@ -385,6 +398,7 @@ private static function encryptResourceInternal($inputHandle, $outputHandle, Key
385398
}
386399

387400
/* Encrypt this buffer. */
401+
/** @var string */
388402
$encrypted = \openssl_encrypt(
389403
$read,
390404
Core::CIPHER_METHOD,
@@ -393,7 +407,7 @@ private static function encryptResourceInternal($inputHandle, $outputHandle, Key
393407
$thisIv
394408
);
395409

396-
if ($encrypted === false) {
410+
if (!\is_string($encrypted)) {
397411
throw new Ex\EnvironmentIsBrokenException(
398412
'OpenSSL encryption error'
399413
);
@@ -422,6 +436,7 @@ private static function encryptResourceInternal($inputHandle, $outputHandle, Key
422436
* @param resource $inputHandle
423437
* @param resource $outputHandle
424438
* @param KeyOrPassword $secret
439+
* @return void
425440
*
426441
* @throws Ex\EnvironmentIsBrokenException
427442
* @throws Ex\IOException
@@ -476,7 +491,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
476491
$thisIv = $iv;
477492

478493
/* How many blocks do we encrypt at a time? We increment by this value. */
479-
$inc = Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE;
494+
$inc = (int) (Core::BUFFER_BYTE_SIZE / Core::BLOCK_BYTE_SIZE);
480495

481496
/* Get the HMAC. */
482497
if (\fseek($inputHandle, (-1 * Core::MAC_BYTE_SIZE), SEEK_END) === false) {
@@ -486,8 +501,9 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
486501
}
487502

488503
/* Get the position of the last byte in the actual ciphertext. */
504+
/** @var int $cipher_end */
489505
$cipher_end = \ftell($inputHandle);
490-
if ($cipher_end === false) {
506+
if (!\is_int($cipher_end)) {
491507
throw new Ex\IOException(
492508
'Cannot read input file'
493509
);
@@ -496,11 +512,13 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
496512
--$cipher_end;
497513

498514
/* Read the HMAC. */
515+
/** @var string $stored_mac */
499516
$stored_mac = self::readBytes($inputHandle, Core::MAC_BYTE_SIZE);
500517

501518
/* Initialize a streaming HMAC state. */
519+
/** @var resource $hmac */
502520
$hmac = \hash_init(Core::HASH_FUNCTION_NAME, HASH_HMAC, $akey);
503-
if ($hmac === false) {
521+
if (!\is_resource($hmac)) {
504522
throw new Ex\EnvironmentIsBrokenException(
505523
'Cannot initialize a hash context'
506524
);
@@ -525,12 +543,14 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
525543
\hash_update($hmac, $header);
526544
\hash_update($hmac, $file_salt);
527545
\hash_update($hmac, $iv);
546+
/** @var resource $hmac2 */
528547
$hmac2 = \hash_copy($hmac);
529548

530549
$break = false;
531550
while (! $break) {
551+
/** @var int $pos */
532552
$pos = \ftell($inputHandle);
533-
if ($pos === false) {
553+
if (!\is_int($pos)) {
534554
throw new Ex\IOException(
535555
'Could not get current position in input file during decryption'
536556
);
@@ -554,8 +574,9 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
554574
\hash_update($hmac, $read);
555575

556576
/* Remember this buffer-sized chunk's HMAC. */
577+
/** @var resource $chunk_mac */
557578
$chunk_mac = \hash_copy($hmac);
558-
if ($chunk_mac === false) {
579+
if (!\is_resource($chunk_mac)) {
559580
throw new Ex\EnvironmentIsBrokenException(
560581
'Cannot duplicate a hash context'
561582
);
@@ -564,6 +585,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
564585
}
565586

566587
/* Get the final HMAC, which should match the stored one. */
588+
/** @var string $final_mac */
567589
$final_mac = \hash_final($hmac, true);
568590

569591
/* Verify the HMAC. */
@@ -584,8 +606,9 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
584606

585607
$at_file_end = false;
586608
while (! $at_file_end) {
609+
/** @var int $pos */
587610
$pos = \ftell($inputHandle);
588-
if ($pos === false) {
611+
if (!\is_int($pos)) {
589612
throw new Ex\IOException(
590613
'Could not get current position in input file during decryption'
591614
);
@@ -609,8 +632,9 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
609632
* remembered from pass #1 to ensure attackers didn't change the
610633
* ciphertext after MAC verification. */
611634
\hash_update($hmac2, $read);
635+
/** @var resource $calc_mac */
612636
$calc_mac = \hash_copy($hmac2);
613-
if ($calc_mac === false) {
637+
if (!\is_resource($calc_mac)) {
614638
throw new Ex\EnvironmentIsBrokenException(
615639
'Cannot duplicate a hash context'
616640
);
@@ -628,14 +652,15 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
628652
}
629653

630654
/* Decrypt this buffer-sized chunk. */
655+
/** @var string $decrypted */
631656
$decrypted = \openssl_decrypt(
632657
$read,
633658
Core::CIPHER_METHOD,
634659
$ekey,
635660
OPENSSL_RAW_DATA,
636661
$thisIv
637662
);
638-
if ($decrypted === false) {
663+
if (!\is_string($decrypted)) {
639664
throw new Ex\EnvironmentIsBrokenException(
640665
'OpenSSL decryption error'
641666
);
@@ -649,6 +674,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
649674
);
650675

651676
/* Increment the IV by the amount of blocks in a buffer. */
677+
/** @var string $thisIv */
652678
$thisIv = Core::incrementCounter($thisIv, $inc);
653679
/* WARNING: Usually, unless the file is a multiple of the buffer
654680
* size, $thisIv will contain an incorrect value here on the last
@@ -661,6 +687,7 @@ public static function decryptResourceInternal($inputHandle, $outputHandle, KeyO
661687
*
662688
* @param resource $stream
663689
* @param int $num_bytes
690+
* @return string
664691
*
665692
* @throws Ex\IOException
666693
* @throws Ex\EnvironmentIsBrokenException
@@ -679,9 +706,9 @@ public static function readBytes($stream, $num_bytes)
679706
$buf = '';
680707
$remaining = $num_bytes;
681708
while ($remaining > 0 && ! \feof($stream)) {
709+
/** @var string $read */
682710
$read = \fread($stream, $remaining);
683-
684-
if ($read === false) {
711+
if (!\is_string($read)) {
685712
throw new Ex\IOException(
686713
'Could not read from the file'
687714
);
@@ -703,6 +730,7 @@ public static function readBytes($stream, $num_bytes)
703730
* @param resource $stream
704731
* @param string $buf
705732
* @param int $num_bytes
733+
* @return int
706734
*
707735
* @throws Ex\IOException
708736
*
@@ -726,13 +754,14 @@ public static function writeBytes($stream, $buf, $num_bytes = null)
726754
}
727755
$remaining = $num_bytes;
728756
while ($remaining > 0) {
757+
/** @var int $written */
729758
$written = \fwrite($stream, $buf, $remaining);
730-
if ($written === false) {
759+
if (!\is_int($written)) {
731760
throw new Ex\IOException(
732761
'Could not write to the file'
733762
);
734763
}
735-
$buf = Core::ourSubstr($buf, $written, null);
764+
$buf = (string) Core::ourSubstr($buf, $written, null);
736765
$remaining -= $written;
737766
}
738767
return $num_bytes;

‎src/Key.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ final class Key
99
const KEY_CURRENT_VERSION = "\xDE\xF0\x00\x00";
1010
const KEY_BYTE_SIZE = 32;
1111

12-
private $key_bytes = null;
12+
/**
13+
* @var string
14+
*/
15+
private $key_bytes;
1316

1417
/**
1518
* Creates new random key.

‎src/KeyOrPassword.php

+16-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,15 @@ final class KeyOrPassword
1010
const SECRET_TYPE_KEY = 1;
1111
const SECRET_TYPE_PASSWORD = 2;
1212

13-
private $secret_type = null;
14-
private $secret = null;
13+
/**
14+
* @var int
15+
*/
16+
private $secret_type = 0;
17+
18+
/**
19+
* @var Key|string
20+
*/
21+
private $secret;
1522

1623
/**
1724
* Initializes an instance of KeyOrPassword from a key.
@@ -43,6 +50,7 @@ public static function createFromPassword($password)
4350
*
4451
* @param string $salt
4552
*
53+
* @throws Ex\CryptoException
4654
* @throws Ex\EnvironmentIsBrokenException
4755
*
4856
* @return DerivedKeys
@@ -54,6 +62,9 @@ public function deriveKeys($salt)
5462
}
5563

5664
if ($this->secret_type === self::SECRET_TYPE_KEY) {
65+
if (!($this->secret instanceof Key)) {
66+
throw new Ex\CryptoException('Expected a Key object');
67+
}
5768
$akey = Core::HKDF(
5869
Core::HASH_FUNCTION_NAME,
5970
$this->secret->getRawBytes(),
@@ -70,6 +81,9 @@ public function deriveKeys($salt)
7081
);
7182
return new DerivedKeys($akey, $ekey);
7283
} elseif ($this->secret_type === self::SECRET_TYPE_PASSWORD) {
84+
if (!\is_string($this->secret)) {
85+
throw new Ex\CryptoException('Expected a string');
86+
}
7387
/* Our PBKDF2 polyfill is vulnerable to a DoS attack documented in
7488
* GitHub issue #230. The fix is to pre-hash the password to ensure
7589
* it is short. We do the prehashing here instead of in pbkdf2() so

‎src/KeyProtectedByPassword.php

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ final class KeyProtectedByPassword
88
{
99
const PASSWORD_KEY_CURRENT_VERSION = "\xDE\xF1\x00\x00";
1010

11-
private $encrypted_key = null;
11+
/**
12+
* @var string
13+
*/
14+
private $encrypted_key = '';
1215

1316
/**
1417
* Creates a random key protected by the provided password.

‎src/RuntimeTests.php

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class RuntimeTests extends Crypto
1717
* Runs the runtime tests.
1818
*
1919
* @throws Ex\EnvironmentIsBrokenException
20+
* @return void
2021
*/
2122
public static function runtimeTest()
2223
{
@@ -79,6 +80,7 @@ public static function runtimeTest()
7980
* High-level tests of Crypto operations.
8081
*
8182
* @throws Ex\EnvironmentIsBrokenException
83+
* @return void
8284
*/
8385
private static function testEncryptDecrypt()
8486
{
@@ -148,6 +150,7 @@ private static function testEncryptDecrypt()
148150
* Test HKDF against test vectors.
149151
*
150152
* @throws Ex\EnvironmentIsBrokenException
153+
* @return void
151154
*/
152155
private static function HKDFTestVector()
153156
{
@@ -186,6 +189,7 @@ private static function HKDFTestVector()
186189
* Test HMAC against test vectors.
187190
*
188191
* @throws Ex\EnvironmentIsBrokenException
192+
* @return void
189193
*/
190194
private static function HMACTestVector()
191195
{
@@ -202,6 +206,7 @@ private static function HMACTestVector()
202206
* Test AES against test vectors.
203207
*
204208
* @throws Ex\EnvironmentIsBrokenException
209+
* @return void
205210
*/
206211
private static function AESTestVector()
207212
{

0 commit comments

Comments
 (0)
Please sign in to comment.