From 17adee3c79731dda9842e3c989419ca0fb6584c5 Mon Sep 17 00:00:00 2001 From: azjezz Date: Fri, 16 Nov 2018 20:56:13 +0100 Subject: [PATCH 01/20] version 4.0-dev initial commit --- README.md | 83 +++++++++++++--- composer.json | 61 ++++++------ src/Exception/CryptoException.php | 11 +++ src/Exception/HashingException.php | 11 +++ src/Hasher/PasswordHasher.php | 94 ++++++++++++++++++ src/Hasher/PasswordHasherInterface.php | 23 +++++ src/PasswordLock.php | 132 +++++++++---------------- tests/Hasher/PasswordHasherTest.php | 44 +++++++++ tests/PasswordLockTest.php | 60 ++++++++--- 9 files changed, 381 insertions(+), 138 deletions(-) create mode 100644 src/Exception/CryptoException.php create mode 100644 src/Exception/HashingException.php create mode 100644 src/Hasher/PasswordHasher.php create mode 100644 src/Hasher/PasswordHasherInterface.php create mode 100644 tests/Hasher/PasswordHasherTest.php diff --git a/README.md b/README.md index 1e79d25..5b48889 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **MIT Licensed** - feel free to use to enhance the security of any of your PHP projects -Wraps Bcrypt-SHA384 in Authenticated Encryption. Published by [Paragon Initiative Enteprises](https://paragonie.com). Check out our other [open source projects](https://paragonie.com/projects) too. +Wraps Password Hashing in Authenticated Encryption. Published by [Paragon Initiative Enteprises](https://paragonie.com). Check out our other [open source projects](https://paragonie.com/projects) too. Depends on [defuse/php-encryption](https://github.com/defuse/php-encryption) for authenticated symmetric-key encryption. @@ -27,15 +27,19 @@ But realistically, this library is only about as a secure as bcrypt. ### Hash Password, Encrypt Hash, Authenticate Ciphertext ```php -use \ParagonIE\PasswordLock\PasswordLock; -use \Defuse\Crypto\Key; +use ParagonIE\PasswordLock\PasswordLock; +use Defuse\Crypto\Key; $key = Key::createNewRandomKey(); + +$passwordLock = new PasswordLock(); + if (isset($_POST['password'])) { if (!is_string($_POST['password'])) { die("Password must be a string"); } - $storeMe = PasswordLock::hashAndEncrypt($_POST['password'], $key); + + $storeMe = $passwordLock->hashAndEncrypt($_POST['password'], $key); } ``` @@ -46,7 +50,8 @@ if (isset($_POST['password'])) { if (!is_string($_POST['password'])) { die("Password must be a string"); } - if (PasswordLock::decryptAndVerify($_POST['password'], $storeMe, $key)) { + + if ($passwordLock->decryptAndVerify($_POST['password'], $storeMe, $key)) { // Success! } } @@ -59,13 +64,67 @@ $newKey = \Defuse\Crypto\Key::createNewRandomKey(); $newHash = PasswordLock::rotateKey($storeMe, $key, $newKey); ``` -### Migrate from Version 1 of the library +### Using Password hasher + +by default, PasswordLock uses Bcrypt-SHA384 based PasswordHasher. + +```php + 2048 +]); +$lock = new PasswordLock($hasher); +``` + +## Costume Password Hasher + +`ParagonIE\PasswordLock\PasswordLock` accepts any `ParagonIE\PasswordLock\Hasher\PasswordHasherInterface` implementation as the first argument. ```php -$newHash = PasswordLock::upgradeFromVersion1( - $_POST['password'], - $oldHash, - $oldKey, - $newKey -); +algorithm = $algorithm; + $this->options = $options; + } + + /** + * @param string $password + * + * @return string + */ + public function hash(string $password): string + { + $hash = password_hash( + Base64::encode( + hash('sha384', $password, true) + ), + $this->getAlgorithm(), + $this->getOptions() + ); + + if (!is_string($hash)) { + throw new HashingException('Unknown hashing error.'); + } + + return $hash; + } + + /** + * @param string $password + * @param string $hash + * + * @return bool + */ + public function verify(string $password, string $hash): bool + { + return password_verify( + Base64::encode( + hash('sha384', $password, true) + ), + $hash + ); + } + + /** + * @return int + */ + public function getAlgorithm(): int + { + return $this->algorithm; + } + + /** + * @return array + */ + public function getOptions(): array + { + return $this->options; + } +} diff --git a/src/Hasher/PasswordHasherInterface.php b/src/Hasher/PasswordHasherInterface.php new file mode 100644 index 0000000..185595d --- /dev/null +++ b/src/Hasher/PasswordHasherInterface.php @@ -0,0 +1,23 @@ +hasher = $hasher ?? new PasswordHasher(); } + /** - * 1. VerifyHMAC-then-Decrypt the ciphertext to get the hash - * 2. Verify that the password matches the hash + * 1. Hash password + * 2. Encrypt-then-MAC the hash * * @param string $password - * @param string $ciphertext - * @param string $aesKey - must be exactly 16 bytes - * @return bool - * @throws \Exception - * @throws \InvalidArgumentException + * @param Key $aesKey + * + * @return string + * + * @throws EnvironmentIsBrokenException */ - public static function decryptAndVerifyLegacy(string $password, string $ciphertext, string $aesKey): bool + public function hashAndEncrypt(string $password, Key $aesKey): string { - if (Binary::safeStrlen($aesKey) !== 16) { - throw new \Exception("Encryption keys must be 16 bytes long"); - } - $hash = Crypto::legacyDecrypt( - $ciphertext, - $aesKey - ); - if (!\is_string($hash)) { - throw new \Exception("Unknown hashing error."); - } - return \password_verify( - Base64::encode( - \hash('sha256', $password, true) - ), - $hash - ); + $hash = $this->hasher->hash($password); + + return Crypto::encrypt($hash, $aesKey); } /** @@ -70,64 +50,42 @@ public static function decryptAndVerifyLegacy(string $password, string $cipherte * * @param string $password * @param string $ciphertext - * @param Key $aesKey + * @param Key $aesKey + * * @return bool - * @throws \Exception - * @throws \InvalidArgumentException + * + * @throws EnvironmentIsBrokenException + * @throws WrongKeyOrModifiedCiphertextException */ - public static function decryptAndVerify(string $password, string $ciphertext, Key $aesKey): bool + public function decryptAndVerify(string $password, string $ciphertext, Key $aesKey): bool { $hash = Crypto::decrypt( $ciphertext, $aesKey ); - if (!\is_string($hash)) { - throw new \Exception("Unknown hashing error."); + + if (!is_string($hash)) { + throw new CryptoException('Unknown decryption error.'); } - return \password_verify( - Base64::encode( - \hash('sha384', $password, true) - ), - $hash - ); + + return $this->hasher->verify($password, $hash); } /** * Key rotation method -- decrypt with your old key then re-encrypt with your new key * * @param string $ciphertext - * @param Key $oldKey - * @param Key $newKey + * @param Key $oldKey + * @param Key $newKey + * * @return string + * + * @throws EnvironmentIsBrokenException + * @throws WrongKeyOrModifiedCiphertextException */ public static function rotateKey(string $ciphertext, Key $oldKey, Key $newKey): string { $plaintext = Crypto::decrypt($ciphertext, $oldKey); return Crypto::encrypt($plaintext, $newKey); } - - /** - * For migrating from an older version of the library - * - * @param string $password - * @param string $ciphertext - * @param string $oldKey - * @param Key $newKey - * @return string - * @throws \Exception - */ - public static function upgradeFromVersion1( - string $password, - string $ciphertext, - string $oldKey, - Key $newKey - ): string { - if (!self::decryptAndVerifyLegacy($password, $ciphertext, $oldKey)) { - throw new \Exception( - 'The correct password is necessary for legacy migration.' - ); - } - $plaintext = Crypto::legacyDecrypt($ciphertext, $oldKey); - return self::hashAndEncrypt($plaintext, $newKey); - } } diff --git a/tests/Hasher/PasswordHasherTest.php b/tests/Hasher/PasswordHasherTest.php new file mode 100644 index 0000000..efdfa65 --- /dev/null +++ b/tests/Hasher/PasswordHasherTest.php @@ -0,0 +1,44 @@ +hasher = new PasswordHasher(); + } + + public function testHash(): void + { + $hash = $this->hasher->hash('RED AIRPLANE'); + + $this->assertTrue( + $this->hasher->verify('RED AIRPLANE', $hash) + ); + + $this->assertFalse( + $this->hasher->verify('RED AiRPLANE', $hash) + ); + } + + public function testDefaultParameters(): void + { + $this->assertEquals( + PASSWORD_DEFAULT, + $this->hasher->getAlgorithm() + ); + + $this->assertSame( + [], + $this->hasher->getOptions() + ); + } +} diff --git a/tests/PasswordLockTest.php b/tests/PasswordLockTest.php index c5e4d59..71b6414 100644 --- a/tests/PasswordLockTest.php +++ b/tests/PasswordLockTest.php @@ -1,40 +1,78 @@ lock = new PasswordLock(); + } + + /** + * @throws EnvironmentIsBrokenException + * @throws WrongKeyOrModifiedCiphertextException + */ + public function testHash(): void { $key = Key::createNewRandomKey(); - $password = PasswordLock::hashAndEncrypt('YELLOW SUBMARINE', $key); + $password = $this->lock->hashAndEncrypt('YELLOW SUBMARINE', $key); $this->assertTrue( - PasswordLock::decryptAndVerify('YELLOW SUBMARINE', $password, $key) + $this->lock->decryptAndVerify('YELLOW SUBMARINE', $password, $key) ); $this->assertFalse( - PasswordLock::decryptAndVerify('YELLOW SUBMARINF', $password, $key) + $this->lock->decryptAndVerify('YELLOW SUBMARINF', $password, $key) ); } - + /** * @expectedException \Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException + * + * @throws EnvironmentIsBrokenException */ - public function testBitflip() + public function testBitflip(): void { $key = Key::createNewRandomKey(); - $password = PasswordLock::hashAndEncrypt('YELLOW SUBMARINE', $key); - $password[0] = (\ord($password[0]) === 0 ? 255 : 0); + + $password = $this->lock->hashAndEncrypt('YELLOW SUBMARINE', $key); + + $password[0] = (ord($password[0]) === 0 ? 255 : 0); - PasswordLock::decryptAndVerify('YELLOW SUBMARINE', $password, $key); + $this->lock->decryptAndVerify('YELLOW SUBMARINE', $password, $key); + } + + /** + * @throws EnvironmentIsBrokenException + */ + public function testNullByteTruncation(): void + { + $key = Key::createNewRandomKey(); + + $hash1 = $this->lock->hashAndEncrypt("abc\0defg", $key); + $hash2 = $this->lock->hashAndEncrypt("abc", $key); + + $this->assertNotSame($hash1, $hash2); } } From 063029e4bd438ecbeacadea119efc19924bb4bbe Mon Sep 17 00:00:00 2001 From: azjezz Date: Fri, 16 Nov 2018 21:18:40 +0100 Subject: [PATCH 02/20] only document parameters and return values that don't have typehint --- src/Hasher/PasswordHasher.php | 23 ----------------------- src/Hasher/PasswordHasherInterface.php | 11 ----------- src/PasswordLock.php | 19 +------------------ 3 files changed, 1 insertion(+), 52 deletions(-) diff --git a/src/Hasher/PasswordHasher.php b/src/Hasher/PasswordHasher.php index 1b55728..2719d5d 100644 --- a/src/Hasher/PasswordHasher.php +++ b/src/Hasher/PasswordHasher.php @@ -26,23 +26,12 @@ class PasswordHasher implements PasswordHasherInterface */ protected $algorithm; - /** - * PasswordHasher constructor. - * - * @param int $algorithm - * @param array $options - */ public function __construct(int $algorithm = PASSWORD_DEFAULT, array $options = []) { $this->algorithm = $algorithm; $this->options = $options; } - /** - * @param string $password - * - * @return string - */ public function hash(string $password): string { $hash = password_hash( @@ -60,12 +49,6 @@ public function hash(string $password): string return $hash; } - /** - * @param string $password - * @param string $hash - * - * @return bool - */ public function verify(string $password, string $hash): bool { return password_verify( @@ -76,17 +59,11 @@ public function verify(string $password, string $hash): bool ); } - /** - * @return int - */ public function getAlgorithm(): int { return $this->algorithm; } - /** - * @return array - */ public function getOptions(): array { return $this->options; diff --git a/src/Hasher/PasswordHasherInterface.php b/src/Hasher/PasswordHasherInterface.php index 185595d..421e7c1 100644 --- a/src/Hasher/PasswordHasherInterface.php +++ b/src/Hasher/PasswordHasherInterface.php @@ -6,18 +6,7 @@ interface PasswordHasherInterface { - /** - * @param string $password - * - * @return string - */ public function hash(string $password): string; - /** - * @param string $password - * @param string $hash - * - * @return bool - */ public function verify(string $password, string $hash): bool; } diff --git a/src/PasswordLock.php b/src/PasswordLock.php index 97a5ef2..7fea1e6 100644 --- a/src/PasswordLock.php +++ b/src/PasswordLock.php @@ -30,11 +30,6 @@ public function __construct(PasswordHasherInterface $hasher = null) * 1. Hash password * 2. Encrypt-then-MAC the hash * - * @param string $password - * @param Key $aesKey - * - * @return string - * * @throws EnvironmentIsBrokenException */ public function hashAndEncrypt(string $password, Key $aesKey): string @@ -48,12 +43,6 @@ public function hashAndEncrypt(string $password, Key $aesKey): string * 1. VerifyHMAC-then-Decrypt the ciphertext to get the hash * 2. Verify that the password matches the hash * - * @param string $password - * @param string $ciphertext - * @param Key $aesKey - * - * @return bool - * * @throws EnvironmentIsBrokenException * @throws WrongKeyOrModifiedCiphertextException */ @@ -67,19 +56,13 @@ public function decryptAndVerify(string $password, string $ciphertext, Key $aesK if (!is_string($hash)) { throw new CryptoException('Unknown decryption error.'); } - + return $this->hasher->verify($password, $hash); } /** * Key rotation method -- decrypt with your old key then re-encrypt with your new key * - * @param string $ciphertext - * @param Key $oldKey - * @param Key $newKey - * - * @return string - * * @throws EnvironmentIsBrokenException * @throws WrongKeyOrModifiedCiphertextException */ From 689a5615a3a330e070ef286794cf0f3632a3e16d Mon Sep 17 00:00:00 2001 From: azjezz Date: Fri, 16 Nov 2018 21:19:33 +0100 Subject: [PATCH 03/20] remove redundant condition --- src/PasswordLock.php | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/PasswordLock.php b/src/PasswordLock.php index 7fea1e6..300371e 100644 --- a/src/PasswordLock.php +++ b/src/PasswordLock.php @@ -8,12 +8,9 @@ use Defuse\Crypto\Exception\EnvironmentIsBrokenException; use Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException; use Defuse\Crypto\Key; -use ParagonIE\PasswordLock\Exception\CryptoException; use ParagonIE\PasswordLock\Hasher\PasswordHasher; use ParagonIE\PasswordLock\Hasher\PasswordHasherInterface; -use function is_string; - class PasswordLock { /** @@ -53,10 +50,6 @@ public function decryptAndVerify(string $password, string $ciphertext, Key $aesK $aesKey ); - if (!is_string($hash)) { - throw new CryptoException('Unknown decryption error.'); - } - return $this->hasher->verify($password, $hash); } From 69f92d08c5489db767474adda6a654114f53a424 Mon Sep 17 00:00:00 2001 From: azjezz Date: Fri, 16 Nov 2018 21:20:12 +0100 Subject: [PATCH 04/20] delete unused exception. --- src/Exception/CryptoException.php | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 src/Exception/CryptoException.php diff --git a/src/Exception/CryptoException.php b/src/Exception/CryptoException.php deleted file mode 100644 index 27d24d5..0000000 --- a/src/Exception/CryptoException.php +++ /dev/null @@ -1,11 +0,0 @@ - Date: Fri, 16 Nov 2018 21:30:15 +0100 Subject: [PATCH 05/20] update CI config file --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4dfdbc0..b5781be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,13 @@ language: php sudo: false php: - - 7.0 - 7.1 - 7.2 + - nighty matrix: + allow_failures: + - php: nighty fast_finish: true install: @@ -16,4 +18,4 @@ install: script: - vendor/bin/phpunit - - vendor/bin/psalm + - vendor/bin/psalm \ No newline at end of file From 2ebcba1ff8b1174bb3b27bb2f093871382e2e8ef Mon Sep 17 00:00:00 2001 From: azjezz Date: Fri, 16 Nov 2018 22:04:32 +0100 Subject: [PATCH 06/20] fix CI build for PHP Nightly --- .travis.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index b5781be..11764b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,14 @@ language: php sudo: false -php: - - 7.1 - - 7.2 - - nighty - matrix: - allow_failures: - - php: nighty fast_finish: true + include: + - php: 7.1 + - php: 7.2 + - php: nightly + allow_failures: + - php: nightly install: - composer self-update From b4f0312984127e1fbb2f69d5a8b5605fc77e936f Mon Sep 17 00:00:00 2001 From: azjezz Date: Fri, 16 Nov 2018 22:05:09 +0100 Subject: [PATCH 07/20] add PHP 7.3 to CI Build --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 11764b3..6d484ad 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,10 @@ matrix: include: - php: 7.1 - php: 7.2 + - php: 7.3 - php: nightly allow_failures: + - php: 7.3 - php: nightly install: From e56ae7692a9ae8276fb2e3a5236e0bed5392485a Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 13:03:46 +0100 Subject: [PATCH 08/20] add the key as a constructor argument --- README.md | 28 +++++++++++++++++++--------- src/PasswordLock.php | 17 ++++++++++++----- tests/PasswordLockTest.php | 28 ++++++++++++++-------------- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 5b48889..039e61d 100644 --- a/README.md +++ b/README.md @@ -27,31 +27,37 @@ But realistically, this library is only about as a secure as bcrypt. ### Hash Password, Encrypt Hash, Authenticate Ciphertext ```php +hashAndEncrypt($_POST['password'], $key); + $storeMe = $passwordLock->hashAndEncrypt($_POST['password']); } ``` ### Verify MAC, Decrypt Ciphertext, Verify Password ```php +decryptAndVerify($_POST['password'], $storeMe, $key)) { + if ($passwordLock->decryptAndVerify($_POST['password'], $storeMe)) { // Success! } } @@ -60,6 +66,10 @@ if (isset($_POST['password'])) { ### Re-encrypt a hash with a different encryption key ```php + 2048 ]); -$lock = new PasswordLock($hasher); +$lock = new PasswordLock($key,$hasher); ``` ## Costume Password Hasher @@ -126,5 +136,5 @@ class MyPasswordHasher implements PasswordHasherInterface } $hasher = new MyPasswordHasher(); -$lock = new PasswordLock($hasher); +$lock = new PasswordLock($key,$hasher); ``` diff --git a/src/PasswordLock.php b/src/PasswordLock.php index 300371e..1da3b2d 100644 --- a/src/PasswordLock.php +++ b/src/PasswordLock.php @@ -13,13 +13,20 @@ class PasswordLock { + /** + * @var Key + */ + protected $key; + /** * @var PasswordHasherInterface */ protected $hasher; - public function __construct(PasswordHasherInterface $hasher = null) + + public function __construct(Key $key,PasswordHasherInterface $hasher = null) { + $this->key = $key; $this->hasher = $hasher ?? new PasswordHasher(); } @@ -29,11 +36,11 @@ public function __construct(PasswordHasherInterface $hasher = null) * * @throws EnvironmentIsBrokenException */ - public function hashAndEncrypt(string $password, Key $aesKey): string + public function hashAndEncrypt(string $password): string { $hash = $this->hasher->hash($password); - return Crypto::encrypt($hash, $aesKey); + return Crypto::encrypt($hash, $this->key); } /** @@ -43,11 +50,11 @@ public function hashAndEncrypt(string $password, Key $aesKey): string * @throws EnvironmentIsBrokenException * @throws WrongKeyOrModifiedCiphertextException */ - public function decryptAndVerify(string $password, string $ciphertext, Key $aesKey): bool + public function decryptAndVerify(string $password, string $ciphertext): bool { $hash = Crypto::decrypt( $ciphertext, - $aesKey + $this->key ); return $this->hasher->verify($password, $hash); diff --git a/tests/PasswordLockTest.php b/tests/PasswordLockTest.php index 71b6414..c494197 100644 --- a/tests/PasswordLockTest.php +++ b/tests/PasswordLockTest.php @@ -23,27 +23,31 @@ class PasswordLockTest extends TestCase */ protected $lock; + /** + * @throws EnvironmentIsBrokenException + */ public function setUp() { - $this->lock = new PasswordLock(); + $this->lock = new PasswordLock( + Key::createNewRandomKey() + ); } + /** * @throws EnvironmentIsBrokenException * @throws WrongKeyOrModifiedCiphertextException */ public function testHash(): void { - $key = Key::createNewRandomKey(); + $password = $this->lock->hashAndEncrypt('YELLOW SUBMARINE'); - $password = $this->lock->hashAndEncrypt('YELLOW SUBMARINE', $key); - $this->assertTrue( - $this->lock->decryptAndVerify('YELLOW SUBMARINE', $password, $key) + $this->lock->decryptAndVerify('YELLOW SUBMARINE', $password) ); $this->assertFalse( - $this->lock->decryptAndVerify('YELLOW SUBMARINF', $password, $key) + $this->lock->decryptAndVerify('YELLOW SUBMARINF', $password) ); } @@ -54,13 +58,11 @@ public function testHash(): void */ public function testBitflip(): void { - $key = Key::createNewRandomKey(); - - $password = $this->lock->hashAndEncrypt('YELLOW SUBMARINE', $key); + $password = $this->lock->hashAndEncrypt('YELLOW SUBMARINE'); $password[0] = (ord($password[0]) === 0 ? 255 : 0); - $this->lock->decryptAndVerify('YELLOW SUBMARINE', $password, $key); + $this->lock->decryptAndVerify('YELLOW SUBMARINE', $password); } /** @@ -68,10 +70,8 @@ public function testBitflip(): void */ public function testNullByteTruncation(): void { - $key = Key::createNewRandomKey(); - - $hash1 = $this->lock->hashAndEncrypt("abc\0defg", $key); - $hash2 = $this->lock->hashAndEncrypt("abc", $key); + $hash1 = $this->lock->hashAndEncrypt("abc\0defg"); + $hash2 = $this->lock->hashAndEncrypt("abc"); $this->assertNotSame($hash1, $hash2); } From ee78c8a49d5f2593994634f3f0a2068e1c287348 Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 13:06:27 +0100 Subject: [PATCH 09/20] refector method names for cleaner interface --- README.md | 6 +++--- src/PasswordLock.php | 4 ++-- tests/PasswordLockTest.php | 14 +++++++------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 039e61d..9646933 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ A hash then encrypt strategy offers **agility**; if your secret key is compromis * You don't have to worry about the 72 character limit for bcrypt * You don't have to worry about accidentally creating a null-byte truncation vulnerability -* If your database gets hacked, and your database is on a separate machine from your webserver, the attacker has to first decrypt the hashes before attempting to crack any of them. +* If your database gets hacked, and your database is on a separate machine from your web server, the attacker has to first decrypt the hashes before attempting to crack any of them. Here's a [proof-of-concept](http://3v4l.org/61VZq) for the first two points. @@ -41,7 +41,7 @@ if (isset($_POST['password'])) { die('Password must be a string'); } - $storeMe = $passwordLock->hashAndEncrypt($_POST['password']); + $storeMe = $passwordLock->lock($_POST['password']); } ``` @@ -57,7 +57,7 @@ if (isset($_POST['password'])) { die('Password must be a string'); } - if ($passwordLock->decryptAndVerify($_POST['password'], $storeMe)) { + if ($passwordLock->check($_POST['password'], $storeMe)) { // Success! } } diff --git a/src/PasswordLock.php b/src/PasswordLock.php index 1da3b2d..4410cdf 100644 --- a/src/PasswordLock.php +++ b/src/PasswordLock.php @@ -36,7 +36,7 @@ public function __construct(Key $key,PasswordHasherInterface $hasher = null) * * @throws EnvironmentIsBrokenException */ - public function hashAndEncrypt(string $password): string + public function lock(string $password): string { $hash = $this->hasher->hash($password); @@ -50,7 +50,7 @@ public function hashAndEncrypt(string $password): string * @throws EnvironmentIsBrokenException * @throws WrongKeyOrModifiedCiphertextException */ - public function decryptAndVerify(string $password, string $ciphertext): bool + public function check(string $password, string $ciphertext): bool { $hash = Crypto::decrypt( $ciphertext, diff --git a/tests/PasswordLockTest.php b/tests/PasswordLockTest.php index c494197..4103767 100644 --- a/tests/PasswordLockTest.php +++ b/tests/PasswordLockTest.php @@ -40,14 +40,14 @@ public function setUp() */ public function testHash(): void { - $password = $this->lock->hashAndEncrypt('YELLOW SUBMARINE'); + $password = $this->lock->lock('YELLOW SUBMARINE'); $this->assertTrue( - $this->lock->decryptAndVerify('YELLOW SUBMARINE', $password) + $this->lock->check('YELLOW SUBMARINE', $password) ); $this->assertFalse( - $this->lock->decryptAndVerify('YELLOW SUBMARINF', $password) + $this->lock->check('YELLOW SUBMARINF', $password) ); } @@ -58,11 +58,11 @@ public function testHash(): void */ public function testBitflip(): void { - $password = $this->lock->hashAndEncrypt('YELLOW SUBMARINE'); + $password = $this->lock->lock('YELLOW SUBMARINE'); $password[0] = (ord($password[0]) === 0 ? 255 : 0); - $this->lock->decryptAndVerify('YELLOW SUBMARINE', $password); + $this->lock->check('YELLOW SUBMARINE', $password); } /** @@ -70,8 +70,8 @@ public function testBitflip(): void */ public function testNullByteTruncation(): void { - $hash1 = $this->lock->hashAndEncrypt("abc\0defg"); - $hash2 = $this->lock->hashAndEncrypt("abc"); + $hash1 = $this->lock->lock("abc\0defg"); + $hash2 = $this->lock->lock("abc"); $this->assertNotSame($hash1, $hash2); } From c7f669d0c36f04efc560a0c1f46c045f396b61be Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 13:13:17 +0100 Subject: [PATCH 10/20] test key rotation --- tests/PasswordLockTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/PasswordLockTest.php b/tests/PasswordLockTest.php index 4103767..7d31240 100644 --- a/tests/PasswordLockTest.php +++ b/tests/PasswordLockTest.php @@ -75,4 +75,23 @@ public function testNullByteTruncation(): void $this->assertNotSame($hash1, $hash2); } + + /** + * @throws EnvironmentIsBrokenException + * @throws WrongKeyOrModifiedCiphertextException + */ + public function testKeyRotation(): void + { + $key1 = Key::createNewRandomKey(); + $lock1 = new PasswordLock($key1); + + $key2 = Key::createNewRandomKey(); + $lock2 = new PasswordLock($key2); + + $hash1 = $lock1->lock('ParagonIE'); + $hash2 = PasswordLock::rotateKey($hash1, $key1, $key2); + + $this->assertNotSame($hash1, $hash2); + $this->assertTrue($lock2->check('ParagonIE', $hash2)); + } } From 818182023590d9f339a41872c04e79fa5dc745cf Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:12:05 +0100 Subject: [PATCH 11/20] add php-cs-fixer --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 49c3ed6..a345e9c 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,8 @@ }, "require-dev": { "phpunit/phpunit": "^6", - "vimeo/psalm": "^0 || ^1" + "vimeo/psalm": "^0 || ^1", + "friendsofphp/php-cs-fixer": "^2.13" }, "autoload": { "psr-4": { From a8357f7b5ea5a31c2603727fb0502ed10046dce8 Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:12:31 +0100 Subject: [PATCH 12/20] add composer scripts --- composer.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/composer.json b/composer.json index a345e9c..ef6016f 100644 --- a/composer.json +++ b/composer.json @@ -37,6 +37,17 @@ "ParagonIE\\PasswordLock\\Tests\\": "tests/" } }, + "scripts": { + "test": "phpunit --colors=always", + "analyze": "pslam", + "cs-check": "php-cs-fixer fix --dry-run -vvv", + "cs-fix": "php-cs-fixer fix -vvv", + "check": [ + "@cs-check", + "@analyze", + "@test" + ] + }, "support": { "email": "info@paragonie.com", "issues": "https://github.com/paragonie/password_lock/issues", From e4721685fd6af16f5be2d2f09f0a08ac7f27a4e9 Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:19:44 +0100 Subject: [PATCH 13/20] update CI build file. --- .travis.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6d484ad..333a31b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,12 @@ matrix: fast_finish: true include: - php: 7.1 + env: + - DEPS=lowest + - php: 7.1 + env: + - CS_CHECK=1 + - ANALYZE=1 - php: 7.2 - php: 7.3 - php: nightly @@ -18,5 +24,6 @@ install: - chmod +x ./run-tests.sh script: - - vendor/bin/phpunit - - vendor/bin/psalm \ No newline at end of file + - composer test + - if [[ $ANALYZE == 'true' ]]; then composer analyze ; fi + - if [[ $CS_CHECK == 'true' ]]; then composer cs-check ; fi \ No newline at end of file From c80ce1b3812c3a99a64e5c563e6b88fd0f396e1e Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:21:32 +0100 Subject: [PATCH 14/20] add php-cs-fixer config file. --- .php_cs.cache | 1 + .php_cs.dist | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 .php_cs.cache create mode 100644 .php_cs.dist diff --git a/.php_cs.cache b/.php_cs.cache new file mode 100644 index 0000000..b4d99f0 --- /dev/null +++ b/.php_cs.cache @@ -0,0 +1 @@ +{"php":"7.2.12","version":"2.13.1:v2.13.1#54814c62d5beef3ba55297b9b3186ed8b8a1b161","rules":{"encoding":true,"full_opening_tag":true,"blank_line_after_namespace":true,"braces":{"allow_single_line_closure":true},"class_definition":{"single_line":true},"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"method_argument_space":true,"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":true,"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":{"elements":["const","method","property"]},"psr4":true,"binary_operator_spaces":true,"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["while","declare","do","for","foreach","if","switch","try"]},"cast_spaces":true,"class_attributes_separation":true,"concat_space":{"spacing":"one"},"declare_equal_normalize":true,"function_typehint_space":true,"include":true,"increment_style":true,"lowercase_cast":true,"lowercase_static_reference":true,"magic_constant_casing":true,"magic_method_casing":true,"native_function_casing":true,"new_with_braces":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_empty_comment":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_blank_lines":{"tokens":["curly_brace_block","extra","parenthesis_brace_block","square_brace_block","throw","use"]},"no_leading_import_slash":true,"no_leading_namespace_whitespace":true,"no_mixed_echo_print":{"use":"echo"},"no_multiline_whitespace_around_double_arrow":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_around_offset":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_unneeded_control_parentheses":true,"no_unneeded_curly_braces":true,"no_unneeded_final_method":true,"no_unused_imports":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"object_operator_without_whitespace":true,"php_unit_fqcn_annotation":true,"phpdoc_align":{"tags":["param","return","throws","type","var"]},"phpdoc_annotation_without_dot":true,"phpdoc_indent":true,"phpdoc_inline_tag":true,"phpdoc_no_access":true,"phpdoc_no_alias_tag":true,"phpdoc_no_empty_return":true,"phpdoc_no_package":true,"phpdoc_no_useless_inheritdoc":true,"phpdoc_return_self_reference":true,"phpdoc_scalar":true,"phpdoc_separation":true,"phpdoc_single_line_var_spacing":true,"phpdoc_summary":true,"phpdoc_to_comment":true,"phpdoc_trim":true,"phpdoc_types":true,"phpdoc_var_without_name":true,"protected_to_private":true,"return_type_declaration":true,"semicolon_after_instruction":true,"short_scalar_cast":true,"single_blank_line_before_namespace":true,"single_line_comment_style":{"comment_types":["hash"]},"single_quote":true,"space_after_semicolon":{"remove_in_empty_for_expressions":true},"standardize_increment":true,"standardize_not_equals":true,"ternary_operator_spaces":true,"trailing_comma_in_multiline_array":true,"trim_array_spaces":true,"unary_operator_spaces":true,"whitespace_after_comma_in_array":true,"yoda_style":{"equal":true,"identical":true,"always_move_variable":true},"dir_constant":true,"ereg_to_preg":true,"error_suppression":true,"fopen_flag_order":true,"fopen_flags":true,"function_to_constant":true,"implode_call":true,"is_null":{"use_yoda_style":true},"modernize_types_casting":true,"native_constant_invocation":{"fix_built_in":false,"include":["DIRECTORY_SEPARATOR","PHP_SAPI","PHP_VERSION_ID"],"scope":"namespaced"},"native_function_invocation":{"include":["@compiler_optimized"],"scope":"namespaced"},"no_alias_functions":true,"no_homoglyph_names":true,"non_printable_character":{"use_escape_sequences_in_strings":true},"php_unit_construct":true,"set_type_to_cast":true,"doctrine_annotation_array_assignment":{"operator":":"},"doctrine_annotation_braces":true,"doctrine_annotation_indentation":true,"doctrine_annotation_spaces":{"before_array_assignments_colon":false},"ternary_to_null_coalescing":true,"void_return":true,"combine_nested_dirname":true,"declare_strict_types":true,"random_api_migration":{"replacements":{"mt_rand":"random_int","rand":"random_int"}},"pow_to_exponentiation":true,"strict_param":true,"align_multiline_comment":true,"array_syntax":{"syntax":"short"},"combine_consecutive_issets":true,"combine_consecutive_unsets":true,"compact_nullable_typehint":true,"escape_implicit_backslashes":true,"linebreak_after_opening_tag":true,"list_syntax":{"syntax":"short"},"method_chaining_indentation":true,"method_separation":true,"no_extra_consecutive_blank_lines":{"tokens":["break","continue","extra","return","throw","use","parenthesis_brace_block","square_brace_block","curly_brace_block"]},"no_php4_constructor":true,"no_unreachable_default_argument_value":true,"no_useless_else":true,"no_useless_return":true,"ordered_imports":true,"ordered_class_elements":true,"no_superfluous_elseif":true,"no_short_echo_tag":true,"no_null_property_initialization":true,"blank_line_before_return":true,"heredoc_to_nowdoc":true},"hashes":{"src\/Exception\/HashingException.php":2572493559,"src\/PasswordLock.php":721281799,"src\/Hasher\/PasswordHasherInterface.php":3091791932,"src\/Hasher\/PasswordHasher.php":3664820193}} \ No newline at end of file diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 0000000..0436875 --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,107 @@ +setRules([ + '@PSR1' => true, + '@PSR2' => true, + 'psr4' => true, + 'declare_strict_types' => true, + 'strict_param' => true, + 'strict_comparison' => false, + 'align_multiline_comment' => true, + 'array_syntax' => ['syntax' => 'short'], + 'binary_operator_spaces' => true, + 'blank_line_after_opening_tag' => true, + 'blank_line_before_statement' => [ + 'statements' => [ + 'while', 'declare', 'do', 'for', 'foreach', 'if', 'switch', 'try' + ] + ], + 'cast_spaces' => true, + 'class_attributes_separation' => true, + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, + 'compact_nullable_typehint' => true, + 'concat_space' => ['spacing' => 'one'], + 'declare_equal_normalize' => true, + 'dir_constant' => true, + 'ereg_to_preg' => true, + 'escape_implicit_backslashes' => true, + 'is_null' => ['use_yoda_style' => true], + 'linebreak_after_opening_tag' => true, + 'list_syntax' => ['syntax' => 'short'], + 'lowercase_cast' => true, + 'magic_constant_casing' => true, + 'method_chaining_indentation' => true, + 'method_separation' => true, + 'modernize_types_casting' => true, + 'no_alias_functions' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_empty_comment' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_consecutive_blank_lines' => [ + 'tokens' => [ + 'break', 'continue', 'extra', 'return', 'throw', 'use', + 'parenthesis_brace_block', 'square_brace_block', 'curly_brace_block' + ], + ], + 'no_homoglyph_names' => true, + 'no_leading_import_slash' => true, + 'no_php4_constructor' => true, + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_spaces_around_offset' => true, + 'no_trailing_comma_in_list_call' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unneeded_curly_braces' => true, + 'no_unneeded_final_method' => true, + 'no_unreachable_default_argument_value' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'normalize_index_brace' => true, + 'return_type_declaration' => true, + 'trim_array_spaces' => true, + 'unary_operator_spaces' => true, + 'whitespace_after_comma_in_array' => true, + 'yoda_style' => [ + 'equal' => true, + 'identical' => true, + 'always_move_variable' => true + ], + 'ordered_imports' => true, + 'ordered_class_elements' => true, + 'no_superfluous_elseif' => true, + 'no_short_echo_tag' => true, + 'no_null_property_initialization' => true, + 'no_closing_tag' => true, + 'blank_line_before_return' => true, + 'class_keyword_remove' => false, + 'self_accessor' => false, + 'encoding' => true, + 'full_opening_tag' => true, + 'heredoc_to_nowdoc' => true, + 'mb_str_functions' => false, + 'phpdoc_align' => [ + 'tags' => [ + 'param', 'return', 'throws', 'type', 'var' + ], + ], + 'phpdoc_to_comment' => true, + 'no_trailing_whitespace' => true, + ]) + ->setRiskyAllowed(true) + ->setUsingCache(true) + ->setHideProgress(false) + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__.'/src') + ->name('*.php') + ); \ No newline at end of file From ed840a311db811f3ceaa7bcf971803910d8a3206 Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:22:42 +0100 Subject: [PATCH 15/20] apply cs-fix --- src/Hasher/PasswordHasher.php | 8 +++----- src/PasswordLock.php | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Hasher/PasswordHasher.php b/src/Hasher/PasswordHasher.php index 2719d5d..fadd2d2 100644 --- a/src/Hasher/PasswordHasher.php +++ b/src/Hasher/PasswordHasher.php @@ -6,13 +6,11 @@ use ParagonIE\ConstantTime\Base64; use ParagonIE\PasswordLock\Exception\HashingException; - -use function password_hash; -use function password_verify; +use const PASSWORD_DEFAULT; use function hash; use function is_string; - -use const PASSWORD_DEFAULT; +use function password_hash; +use function password_verify; class PasswordHasher implements PasswordHasherInterface { diff --git a/src/PasswordLock.php b/src/PasswordLock.php index 4410cdf..add97f9 100644 --- a/src/PasswordLock.php +++ b/src/PasswordLock.php @@ -23,8 +23,7 @@ class PasswordLock */ protected $hasher; - - public function __construct(Key $key,PasswordHasherInterface $hasher = null) + public function __construct(Key $key, PasswordHasherInterface $hasher = null) { $this->key = $key; $this->hasher = $hasher ?? new PasswordHasher(); @@ -69,6 +68,7 @@ public function check(string $password, string $ciphertext): bool public static function rotateKey(string $ciphertext, Key $oldKey, Key $newKey): string { $plaintext = Crypto::decrypt($ciphertext, $oldKey); + return Crypto::encrypt($plaintext, $newKey); } } From 1995b498349aa65942d9a97a1c154cac8e6141b0 Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:23:23 +0100 Subject: [PATCH 16/20] update php-cs-fixer cache file --- .php_cs.cache | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.php_cs.cache b/.php_cs.cache index b4d99f0..69bbfc7 100644 --- a/.php_cs.cache +++ b/.php_cs.cache @@ -1 +1 @@ -{"php":"7.2.12","version":"2.13.1:v2.13.1#54814c62d5beef3ba55297b9b3186ed8b8a1b161","rules":{"encoding":true,"full_opening_tag":true,"blank_line_after_namespace":true,"braces":{"allow_single_line_closure":true},"class_definition":{"single_line":true},"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"method_argument_space":true,"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":true,"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":{"elements":["const","method","property"]},"psr4":true,"binary_operator_spaces":true,"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["while","declare","do","for","foreach","if","switch","try"]},"cast_spaces":true,"class_attributes_separation":true,"concat_space":{"spacing":"one"},"declare_equal_normalize":true,"function_typehint_space":true,"include":true,"increment_style":true,"lowercase_cast":true,"lowercase_static_reference":true,"magic_constant_casing":true,"magic_method_casing":true,"native_function_casing":true,"new_with_braces":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_empty_comment":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_blank_lines":{"tokens":["curly_brace_block","extra","parenthesis_brace_block","square_brace_block","throw","use"]},"no_leading_import_slash":true,"no_leading_namespace_whitespace":true,"no_mixed_echo_print":{"use":"echo"},"no_multiline_whitespace_around_double_arrow":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_around_offset":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_unneeded_control_parentheses":true,"no_unneeded_curly_braces":true,"no_unneeded_final_method":true,"no_unused_imports":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"object_operator_without_whitespace":true,"php_unit_fqcn_annotation":true,"phpdoc_align":{"tags":["param","return","throws","type","var"]},"phpdoc_annotation_without_dot":true,"phpdoc_indent":true,"phpdoc_inline_tag":true,"phpdoc_no_access":true,"phpdoc_no_alias_tag":true,"phpdoc_no_empty_return":true,"phpdoc_no_package":true,"phpdoc_no_useless_inheritdoc":true,"phpdoc_return_self_reference":true,"phpdoc_scalar":true,"phpdoc_separation":true,"phpdoc_single_line_var_spacing":true,"phpdoc_summary":true,"phpdoc_to_comment":true,"phpdoc_trim":true,"phpdoc_types":true,"phpdoc_var_without_name":true,"protected_to_private":true,"return_type_declaration":true,"semicolon_after_instruction":true,"short_scalar_cast":true,"single_blank_line_before_namespace":true,"single_line_comment_style":{"comment_types":["hash"]},"single_quote":true,"space_after_semicolon":{"remove_in_empty_for_expressions":true},"standardize_increment":true,"standardize_not_equals":true,"ternary_operator_spaces":true,"trailing_comma_in_multiline_array":true,"trim_array_spaces":true,"unary_operator_spaces":true,"whitespace_after_comma_in_array":true,"yoda_style":{"equal":true,"identical":true,"always_move_variable":true},"dir_constant":true,"ereg_to_preg":true,"error_suppression":true,"fopen_flag_order":true,"fopen_flags":true,"function_to_constant":true,"implode_call":true,"is_null":{"use_yoda_style":true},"modernize_types_casting":true,"native_constant_invocation":{"fix_built_in":false,"include":["DIRECTORY_SEPARATOR","PHP_SAPI","PHP_VERSION_ID"],"scope":"namespaced"},"native_function_invocation":{"include":["@compiler_optimized"],"scope":"namespaced"},"no_alias_functions":true,"no_homoglyph_names":true,"non_printable_character":{"use_escape_sequences_in_strings":true},"php_unit_construct":true,"set_type_to_cast":true,"doctrine_annotation_array_assignment":{"operator":":"},"doctrine_annotation_braces":true,"doctrine_annotation_indentation":true,"doctrine_annotation_spaces":{"before_array_assignments_colon":false},"ternary_to_null_coalescing":true,"void_return":true,"combine_nested_dirname":true,"declare_strict_types":true,"random_api_migration":{"replacements":{"mt_rand":"random_int","rand":"random_int"}},"pow_to_exponentiation":true,"strict_param":true,"align_multiline_comment":true,"array_syntax":{"syntax":"short"},"combine_consecutive_issets":true,"combine_consecutive_unsets":true,"compact_nullable_typehint":true,"escape_implicit_backslashes":true,"linebreak_after_opening_tag":true,"list_syntax":{"syntax":"short"},"method_chaining_indentation":true,"method_separation":true,"no_extra_consecutive_blank_lines":{"tokens":["break","continue","extra","return","throw","use","parenthesis_brace_block","square_brace_block","curly_brace_block"]},"no_php4_constructor":true,"no_unreachable_default_argument_value":true,"no_useless_else":true,"no_useless_return":true,"ordered_imports":true,"ordered_class_elements":true,"no_superfluous_elseif":true,"no_short_echo_tag":true,"no_null_property_initialization":true,"blank_line_before_return":true,"heredoc_to_nowdoc":true},"hashes":{"src\/Exception\/HashingException.php":2572493559,"src\/PasswordLock.php":721281799,"src\/Hasher\/PasswordHasherInterface.php":3091791932,"src\/Hasher\/PasswordHasher.php":3664820193}} \ No newline at end of file +{"php":"7.2.12","version":"2.13.1:v2.13.1#54814c62d5beef3ba55297b9b3186ed8b8a1b161","rules":{"encoding":true,"full_opening_tag":true,"blank_line_after_namespace":true,"braces":true,"class_definition":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"psr4":true,"declare_strict_types":true,"strict_param":true,"align_multiline_comment":true,"array_syntax":{"syntax":"short"},"binary_operator_spaces":true,"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["while","declare","do","for","foreach","if","switch","try"]},"cast_spaces":true,"class_attributes_separation":true,"combine_consecutive_issets":true,"combine_consecutive_unsets":true,"compact_nullable_typehint":true,"concat_space":{"spacing":"one"},"declare_equal_normalize":true,"dir_constant":true,"ereg_to_preg":true,"escape_implicit_backslashes":true,"is_null":{"use_yoda_style":true},"linebreak_after_opening_tag":true,"list_syntax":{"syntax":"short"},"lowercase_cast":true,"magic_constant_casing":true,"method_chaining_indentation":true,"method_separation":true,"modernize_types_casting":true,"no_alias_functions":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_empty_comment":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_consecutive_blank_lines":{"tokens":["break","continue","extra","return","throw","use","parenthesis_brace_block","square_brace_block","curly_brace_block"]},"no_homoglyph_names":true,"no_leading_import_slash":true,"no_php4_constructor":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_around_offset":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_unneeded_control_parentheses":true,"no_unneeded_curly_braces":true,"no_unneeded_final_method":true,"no_unreachable_default_argument_value":true,"no_unused_imports":true,"no_useless_else":true,"no_useless_return":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"return_type_declaration":true,"trim_array_spaces":true,"unary_operator_spaces":true,"whitespace_after_comma_in_array":true,"yoda_style":{"equal":true,"identical":true,"always_move_variable":true},"ordered_imports":true,"ordered_class_elements":true,"no_superfluous_elseif":true,"no_short_echo_tag":true,"no_null_property_initialization":true,"blank_line_before_return":true,"heredoc_to_nowdoc":true,"phpdoc_align":{"tags":["param","return","throws","type","var"]},"phpdoc_to_comment":true},"hashes":{"src\/Exception\/HashingException.php":2572493559,"src\/PasswordLock.php":180371002,"src\/Hasher\/PasswordHasherInterface.php":3091791932,"src\/Hasher\/PasswordHasher.php":3257075415}} \ No newline at end of file From 7f9af57b854f016e68a25677062a3647aa63b675 Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:24:51 +0100 Subject: [PATCH 17/20] fix typo in travis configurations --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 333a31b..31ee1cb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,8 @@ matrix: - DEPS=lowest - php: 7.1 env: - - CS_CHECK=1 - - ANALYZE=1 + - CS_CHECK=true + - ANALYZE=true - php: 7.2 - php: 7.3 - php: nightly From 66d0b3108a01811ff5366d64d2412665e14dc0ae Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:30:07 +0100 Subject: [PATCH 18/20] apply cs-fix to tests --- .php_cs.cache | 2 +- tests/PasswordLockTest.php | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.php_cs.cache b/.php_cs.cache index 69bbfc7..ae22ad0 100644 --- a/.php_cs.cache +++ b/.php_cs.cache @@ -1 +1 @@ -{"php":"7.2.12","version":"2.13.1:v2.13.1#54814c62d5beef3ba55297b9b3186ed8b8a1b161","rules":{"encoding":true,"full_opening_tag":true,"blank_line_after_namespace":true,"braces":true,"class_definition":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"psr4":true,"declare_strict_types":true,"strict_param":true,"align_multiline_comment":true,"array_syntax":{"syntax":"short"},"binary_operator_spaces":true,"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["while","declare","do","for","foreach","if","switch","try"]},"cast_spaces":true,"class_attributes_separation":true,"combine_consecutive_issets":true,"combine_consecutive_unsets":true,"compact_nullable_typehint":true,"concat_space":{"spacing":"one"},"declare_equal_normalize":true,"dir_constant":true,"ereg_to_preg":true,"escape_implicit_backslashes":true,"is_null":{"use_yoda_style":true},"linebreak_after_opening_tag":true,"list_syntax":{"syntax":"short"},"lowercase_cast":true,"magic_constant_casing":true,"method_chaining_indentation":true,"method_separation":true,"modernize_types_casting":true,"no_alias_functions":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_empty_comment":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_consecutive_blank_lines":{"tokens":["break","continue","extra","return","throw","use","parenthesis_brace_block","square_brace_block","curly_brace_block"]},"no_homoglyph_names":true,"no_leading_import_slash":true,"no_php4_constructor":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_around_offset":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_unneeded_control_parentheses":true,"no_unneeded_curly_braces":true,"no_unneeded_final_method":true,"no_unreachable_default_argument_value":true,"no_unused_imports":true,"no_useless_else":true,"no_useless_return":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"return_type_declaration":true,"trim_array_spaces":true,"unary_operator_spaces":true,"whitespace_after_comma_in_array":true,"yoda_style":{"equal":true,"identical":true,"always_move_variable":true},"ordered_imports":true,"ordered_class_elements":true,"no_superfluous_elseif":true,"no_short_echo_tag":true,"no_null_property_initialization":true,"blank_line_before_return":true,"heredoc_to_nowdoc":true,"phpdoc_align":{"tags":["param","return","throws","type","var"]},"phpdoc_to_comment":true},"hashes":{"src\/Exception\/HashingException.php":2572493559,"src\/PasswordLock.php":180371002,"src\/Hasher\/PasswordHasherInterface.php":3091791932,"src\/Hasher\/PasswordHasher.php":3257075415}} \ No newline at end of file +{"php":"7.2.12","version":"2.13.1:v2.13.1#54814c62d5beef3ba55297b9b3186ed8b8a1b161","rules":{"encoding":true,"full_opening_tag":true,"blank_line_after_namespace":true,"braces":true,"class_definition":true,"elseif":true,"function_declaration":true,"indentation_type":true,"line_ending":true,"lowercase_constants":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ensure_fully_multiline"},"no_break_comment":true,"no_closing_tag":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":{"elements":["property"]},"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":true,"psr4":true,"declare_strict_types":true,"strict_param":true,"align_multiline_comment":true,"array_syntax":{"syntax":"short"},"binary_operator_spaces":true,"blank_line_after_opening_tag":true,"blank_line_before_statement":{"statements":["while","declare","do","for","foreach","if","switch","try"]},"cast_spaces":true,"class_attributes_separation":true,"combine_consecutive_issets":true,"combine_consecutive_unsets":true,"compact_nullable_typehint":true,"concat_space":{"spacing":"one"},"declare_equal_normalize":true,"dir_constant":true,"ereg_to_preg":true,"escape_implicit_backslashes":true,"is_null":{"use_yoda_style":true},"linebreak_after_opening_tag":true,"list_syntax":{"syntax":"short"},"lowercase_cast":true,"magic_constant_casing":true,"method_chaining_indentation":true,"method_separation":true,"modernize_types_casting":true,"no_alias_functions":true,"no_blank_lines_after_class_opening":true,"no_blank_lines_after_phpdoc":true,"no_empty_comment":true,"no_empty_phpdoc":true,"no_empty_statement":true,"no_extra_consecutive_blank_lines":{"tokens":["break","continue","extra","return","throw","use","parenthesis_brace_block","square_brace_block","curly_brace_block"]},"no_homoglyph_names":true,"no_leading_import_slash":true,"no_php4_constructor":true,"no_short_bool_cast":true,"no_singleline_whitespace_before_semicolons":true,"no_spaces_around_offset":true,"no_trailing_comma_in_list_call":true,"no_trailing_comma_in_singleline_array":true,"no_unneeded_control_parentheses":true,"no_unneeded_curly_braces":true,"no_unneeded_final_method":true,"no_unreachable_default_argument_value":true,"no_unused_imports":true,"no_useless_else":true,"no_useless_return":true,"no_whitespace_before_comma_in_array":true,"no_whitespace_in_blank_line":true,"normalize_index_brace":true,"return_type_declaration":true,"trim_array_spaces":true,"unary_operator_spaces":true,"whitespace_after_comma_in_array":true,"yoda_style":{"equal":true,"identical":true,"always_move_variable":true},"ordered_imports":true,"ordered_class_elements":true,"no_superfluous_elseif":true,"no_short_echo_tag":true,"no_null_property_initialization":true,"blank_line_before_return":true,"heredoc_to_nowdoc":true,"phpdoc_align":{"tags":["param","return","throws","type","var"]},"phpdoc_to_comment":true},"hashes":{"src\/Exception\/HashingException.php":2572493559,"src\/PasswordLock.php":180371002,"src\/Hasher\/PasswordHasherInterface.php":3091791932,"src\/Hasher\/PasswordHasher.php":3257075415,"tests\/PasswordLockTest.php":3624153454,"tests\/Hasher\/PasswordHasherTest.php":824329663}} \ No newline at end of file diff --git a/tests/PasswordLockTest.php b/tests/PasswordLockTest.php index 7d31240..cb467a3 100644 --- a/tests/PasswordLockTest.php +++ b/tests/PasswordLockTest.php @@ -6,10 +6,9 @@ use Defuse\Crypto\Exception\EnvironmentIsBrokenException; use Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException; -use ParagonIE\PasswordLock\PasswordLock; use Defuse\Crypto\Key; +use ParagonIE\PasswordLock\PasswordLock; use PHPUnit\Framework\TestCase; - use function ord; /** @@ -33,7 +32,6 @@ public function setUp() ); } - /** * @throws EnvironmentIsBrokenException * @throws WrongKeyOrModifiedCiphertextException @@ -45,7 +43,7 @@ public function testHash(): void $this->assertTrue( $this->lock->check('YELLOW SUBMARINE', $password) ); - + $this->assertFalse( $this->lock->check('YELLOW SUBMARINF', $password) ); @@ -60,8 +58,8 @@ public function testBitflip(): void { $password = $this->lock->lock('YELLOW SUBMARINE'); - $password[0] = (ord($password[0]) === 0 ? 255 : 0); - + $password[0] = (0 === ord($password[0]) ? 255 : 0); + $this->lock->check('YELLOW SUBMARINE', $password); } From e81457e6abf6251502fa67eaae3f7786501446a0 Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:34:32 +0100 Subject: [PATCH 19/20] fix typo in composer.json [pslam -> psalm] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ef6016f..b029ac8 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,7 @@ }, "scripts": { "test": "phpunit --colors=always", - "analyze": "pslam", + "analyze": "psalm", "cs-check": "php-cs-fixer fix --dry-run -vvv", "cs-fix": "php-cs-fixer fix -vvv", "check": [ From f90c0d5ff31a289b3d4da4bcc661aeb2ec894923 Mon Sep 17 00:00:00 2001 From: azjezz Date: Sat, 17 Nov 2018 15:38:01 +0100 Subject: [PATCH 20/20] remove php-cs-fixer for php >=7.3 --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 31ee1cb..81e8fc9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,13 +13,18 @@ matrix: - ANALYZE=true - php: 7.2 - php: 7.3 + env: + - NO_CS=true - php: nightly + env: + - NO_CS=true allow_failures: - php: 7.3 - php: nightly install: - composer self-update + - if [[ $NO_CS == 'true' ]]; then composer remove --dev friendsofphp/php-cs-fixer ; fi - composer update - chmod +x ./run-tests.sh