Skip to content

Commit 6c01bf2

Browse files
Merge branch 'master' into generate-key-cli
2 parents 4dfdd8d + aa72b8b commit 6c01bf2

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,7 +26,7 @@
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
"bin": [
3232
"bin/generate-defuse-key"

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

0 commit comments

Comments
 (0)