Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 21 additions & 8 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
language: php
php:
- 7.1
- 7.0
- 5.6
- 5.5
- 5.4

sudo: false

matrix:
fast_finish: true
fast_finish: true
include:
- php: "5.4"
env: USE_PSALM=0
- php: "5.5"
env: USE_PSALM=0
- php: "5.6"
env: USE_PSALM=1
- php: "7.0"
env: USE_PSALM=1
- php: "7.1"
env: USE_PSALM=1
- php: "nightly"
env: USE_PSALM=1
- php: "hhvm"
env: USE_PSALM=1
allow_failures:
- php: "nightly"
- php: "hhvm"

install:
- if [[ $USE_PSALM -eq 1 ]]; then composer require --dev "vimeo/psalm:dev-master"; fi
- composer install
- curl -LSs https://box-project.github.io/box2/installer.php | php
- mkdir ~/box
Expand All @@ -21,3 +33,4 @@ script:
- ./test.sh
- PATH=$PATH:~/box/ make -C dist/ build-phar
- ./test.sh dist/defuse-crypto.phar
- if [[ $USE_PSALM -eq 1 ]]; then vendor/bin/psalm; fi
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
"php": ">=5.4.0"
},
"require-dev": {
"nikic/php-parser": "^2.0"
"nikic/php-parser": "^2.0|^3.0"
}
}
15 changes: 15 additions & 0 deletions docs/InternalDeveloperDocs.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ First do `composer install` and then you can run the tests by running
`./test.sh`. This will download a PHPUnit PHAR, verify its cryptographic
signatures, and then use it to run the tests in `test/unit`.

Getting and Using Psalm
-----------------------

[Psalm](https://github.com/vimeo/psalm) is a static analysis suite for PHP projects.
We use Psalm to ensure type safety throughout our library.

To install Psalm, you just need to run one command:

composer require --dev "vimeo/psalm:dev-master"

To verify that your code changes are still strictly type-safe, run the following
command:

vendor/bin/psalm

Reporting Bugs
---------------

Expand Down
9 changes: 9 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0"?>
<psalm
stopOnFirstError="false"
useDocblockTypes="true"
>
<projectFiles>
<directory name="src" />
</projectFiles>
</psalm>
14 changes: 9 additions & 5 deletions src/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,14 +124,15 @@ public static function secureRandom($octets)
* @param string $salt
*
* @throws Ex\EnvironmentIsBrokenException
* @psalm-suppress UndefinedFunction - We're checking if the function exists first.
*
* @return string
*/
public static function HKDF($hash, $ikm, $length, $info = '', $salt = null)
{
static $nativeHKDF = null;
if ($nativeHKDF === null) {
$nativeHKDF = \function_exists('hash_hkdf');
$nativeHKDF = \is_callable('\\hash_hkdf');
}
if ($nativeHKDF) {
return \hash_hkdf($hash, $ikm, $length, $info, $salt);
Expand Down Expand Up @@ -180,8 +181,9 @@ 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 ($orm === false) {
if (!\is_string($orm)) {
throw new Ex\EnvironmentIsBrokenException();
}
return $orm;
Expand Down Expand Up @@ -230,6 +232,7 @@ public static function hashEquals($expected, $given)
* Throws an exception if the constant doesn't exist.
*
* @param string $name
* @return void
*
* @throws Ex\EnvironmentIsBrokenException
*/
Expand All @@ -244,6 +247,7 @@ public static function ensureConstantExists($name)
* Throws an exception if the function doesn't exist.
*
* @param string $name
* @return void
*
* @throws Ex\EnvironmentIsBrokenException
*/
Expand Down Expand Up @@ -295,7 +299,7 @@ public static function ourStrlen($str)
*
* @throws Ex\EnvironmentIsBrokenException
*
* @return string
* @return string|bool
*/
public static function ourSubstr($str, $start, $length = null)
{
Expand Down Expand Up @@ -434,9 +438,9 @@ public static function pbkdf2($algorithm, $password, $salt, $count, $key_length,
}

if ($raw_output) {
return Core::ourSubstr($output, 0, $key_length);
return (string) Core::ourSubstr($output, 0, $key_length);
} else {
return Encoding::binToHex(Core::ourSubstr($output, 0, $key_length));
return Encoding::binToHex((string) Core::ourSubstr($output, 0, $key_length));
}
}
}
45 changes: 33 additions & 12 deletions src/Crypto.php
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,18 @@ public static function legacyDecrypt($ciphertext, $key)
'Ciphertext is too short.'
);
}
/**
* @var string
*/
$hmac = Core::ourSubstr($ciphertext, 0, Core::LEGACY_MAC_BYTE_SIZE);
if ($hmac === false) {
if (!\is_string($hmac)) {
throw new Ex\EnvironmentIsBrokenException();
}
/**
* @var string
*/
$ciphertext = Core::ourSubstr($ciphertext, Core::LEGACY_MAC_BYTE_SIZE);
if ($ciphertext === false) {
if (!\is_string($ciphertext)) {
throw new Ex\EnvironmentIsBrokenException();
}

Expand Down Expand Up @@ -145,17 +151,24 @@ public static function legacyDecrypt($ciphertext, $key)
'Ciphertext is too short.'
);
}
/**
* @var string
*/
$iv = Core::ourSubstr($ciphertext, 0, Core::LEGACY_BLOCK_BYTE_SIZE);
if ($iv === false) {
if (!\is_string($iv)) {
throw new Ex\EnvironmentIsBrokenException();
}
$ciphertext = Core::ourSubstr($ciphertext, Core::LEGACY_BLOCK_BYTE_SIZE);
if ($ciphertext === false) {

/**
* @var string
*/
$actualCiphertext = Core::ourSubstr($ciphertext, Core::LEGACY_BLOCK_BYTE_SIZE);
if (!\is_string($actualCiphertext)) {
throw new Ex\EnvironmentIsBrokenException();
}

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

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

// Get the salt.
/** @var string $salt */
$salt = Core::ourSubstr(
$ciphertext,
Core::HEADER_VERSION_SIZE,
Core::SALT_BYTE_SIZE
);
if ($salt === false) {
if (!\is_string($salt)) {
throw new Ex\EnvironmentIsBrokenException();
}

// Get the IV.
/** @var string $iv */
$iv = Core::ourSubstr(
$ciphertext,
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE,
Core::BLOCK_BYTE_SIZE
);
if ($iv === false) {
if (!\is_string($iv)) {
throw new Ex\EnvironmentIsBrokenException();
}

// Get the HMAC.
/** @var string $hmac */
$hmac = Core::ourSubstr(
$ciphertext,
Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE,
Core::MAC_BYTE_SIZE
);
if ($hmac === false) {
if (!\is_string($hmac)) {
throw new Ex\EnvironmentIsBrokenException();
}

// Get the actual encrypted ciphertext.
/** @var string $encrypted */
$encrypted = Core::ourSubstr(
$ciphertext,
Core::HEADER_VERSION_SIZE + Core::SALT_BYTE_SIZE +
Core::BLOCK_BYTE_SIZE,
Core::ourStrlen($ciphertext) - Core::MAC_BYTE_SIZE - Core::SALT_BYTE_SIZE -
Core::BLOCK_BYTE_SIZE - Core::HEADER_VERSION_SIZE
);
if ($encrypted === false) {
if (!\is_string($encrypted)) {
throw new Ex\EnvironmentIsBrokenException();
}

Expand Down Expand Up @@ -304,6 +322,7 @@ protected static function plainEncrypt($plaintext, $key, $iv)
{
Core::ensureConstantExists('OPENSSL_RAW_DATA');
Core::ensureFunctionExists('openssl_encrypt');
/** @var string $ciphertext */
$ciphertext = \openssl_encrypt(
$plaintext,
Core::CIPHER_METHOD,
Expand All @@ -312,7 +331,7 @@ protected static function plainEncrypt($plaintext, $key, $iv)
$iv
);

if ($ciphertext === false) {
if (!\is_string($ciphertext)) {
throw new Ex\EnvironmentIsBrokenException(
'openssl_encrypt() failed.'
);
Expand All @@ -337,14 +356,16 @@ protected static function plainDecrypt($ciphertext, $key, $iv, $cipherMethod)
{
Core::ensureConstantExists('OPENSSL_RAW_DATA');
Core::ensureFunctionExists('openssl_decrypt');

/** @var string $plaintext */
$plaintext = \openssl_decrypt(
$ciphertext,
$cipherMethod,
$key,
OPENSSL_RAW_DATA,
$iv
);
if ($plaintext === false) {
if (!\is_string($plaintext)) {
throw new Ex\EnvironmentIsBrokenException(
'openssl_decrypt() failed.'
);
Expand Down
17 changes: 15 additions & 2 deletions src/DerivedKeys.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,25 @@

namespace Defuse\Crypto;

/**
* Class DerivedKeys
* @package Defuse\Crypto
*/
final class DerivedKeys
{
private $akey = null;
private $ekey = null;
/**
* @var string
*/
private $akey = '';

/**
* @var string
*/
private $ekey = '';

/**
* Returns the authentication key.
* @return string
*/
public function getAuthenticationKey()
{
Expand All @@ -17,6 +29,7 @@ public function getAuthenticationKey()

/**
* Returns the encryption key.
* @return string
*/
public function getEncryptionKey()
{
Expand Down
10 changes: 5 additions & 5 deletions src/Encoding.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public static function trimTrailingWhitespace($string = '')
$sub = (((0x1f - $chr) & ($chr - 0x21)) >> 8) & 1;
$length -= $sub;
} while ($prevLength !== $length && $length > 0);
return Core::ourSubstr($string, 0, $length);
return (string) Core::ourSubstr($string, 0, $length);
}

/*
Expand Down Expand Up @@ -229,7 +229,7 @@ public static function loadBytesFromChecksummedAsciiSafeString($expected_header,
}

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

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

/* Grab the bytes that are part of the checksum. */
$checked_bytes = Core::ourSubstr(
$checked_bytes = (string) Core::ourSubstr(
$bytes,
0,
Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE
);

/* Grab the included checksum. */
$checksum_a = Core::ourSubstr(
$checksum_a = (string) Core::ourSubstr(
$bytes,
Core::ourStrlen($bytes) - self::CHECKSUM_BYTE_SIZE,
self::CHECKSUM_BYTE_SIZE
Expand All @@ -261,7 +261,7 @@ public static function loadBytesFromChecksummedAsciiSafeString($expected_header,
);
}

return Core::ourSubstr(
return (string) Core::ourSubstr(
$bytes,
self::SERIALIZE_HEADER_BYTES,
Core::ourStrlen($bytes) - self::SERIALIZE_HEADER_BYTES - self::CHECKSUM_BYTE_SIZE
Expand Down
Loading