From 088abefe6e1bd048256ad640a6c0732fd7fedba4 Mon Sep 17 00:00:00 2001 From: Marcel Thole Date: Tue, 16 Jul 2024 09:16:45 +0200 Subject: [PATCH] Use native typehints Signed-off-by: Marcel Thole --- src/BlockCipher.php | 171 ++++--------- src/Exception/ExceptionInterface.php | 1 + src/Exception/InvalidArgumentException.php | 1 + src/Exception/NotFoundException.php | 1 + src/Exception/RuntimeException.php | 1 + src/FileCipher.php | 106 +++----- src/Hash.php | 37 +-- src/Hmac.php | 33 +-- src/Hybrid.php | 43 ++-- .../Exception/ExceptionInterface.php | 1 + .../Exception/InvalidArgumentException.php | 1 + .../Derivation/Exception/RuntimeException.php | 1 + src/Key/Derivation/Pbkdf2.php | 14 +- src/Key/Derivation/SaltedS2k.php | 8 +- src/Key/Derivation/Scrypt.php | 34 +-- src/Password/Apache.php | 90 +++---- src/Password/Bcrypt.php | 78 +----- src/Password/BcryptSha.php | 10 +- src/Password/Exception/ExceptionInterface.php | 1 + .../Exception/InvalidArgumentException.php | 1 + src/Password/Exception/RuntimeException.php | 1 + src/Password/PasswordInterface.php | 5 +- src/PublicKey/DiffieHellman.php | 147 ++++------- src/PublicKey/Rsa.php | 104 +++----- src/PublicKey/Rsa/AbstractKey.php | 39 +-- .../Rsa/Exception/ExceptionInterface.php | 1 + .../Exception/InvalidArgumentException.php | 1 + .../Rsa/Exception/RuntimeException.php | 1 + src/PublicKey/Rsa/PrivateKey.php | 35 +-- src/PublicKey/Rsa/PublicKey.php | 46 +--- src/PublicKey/RsaOptions.php | 89 ++----- .../Exception/ExceptionInterface.php | 1 + .../Exception/InvalidArgumentException.php | 1 + src/Symmetric/Exception/NotFoundException.php | 1 + src/Symmetric/Exception/RuntimeException.php | 1 + src/Symmetric/Openssl.php | 239 +++++------------- src/Symmetric/Padding/NoPadding.php | 10 +- src/Symmetric/Padding/PaddingInterface.php | 5 +- src/Symmetric/Padding/Pkcs7.php | 9 +- src/Symmetric/PaddingPluginManager.php | 3 +- src/Symmetric/SymmetricInterface.php | 77 ++---- src/SymmetricPluginManager.php | 1 + src/Utils.php | 10 +- 43 files changed, 433 insertions(+), 1027 deletions(-) diff --git a/src/BlockCipher.php b/src/BlockCipher.php index 19d54f6..69caae5 100644 --- a/src/BlockCipher.php +++ b/src/BlockCipher.php @@ -1,4 +1,5 @@ cipher = $cipher; + public function __construct( + /** + * Symmetric cipher + */ + protected SymmetricInterface $cipher + ) { } /** * Factory - * - * @param string $adapter - * @param array $options - * @return BlockCipher */ - public static function factory($adapter, $options = []) + public static function factory(string $adapter, array $options = []): static { $plugins = static::getSymmetricPluginManager(); try { $cipher = $plugins->get($adapter); - } catch (NotFoundException $e) { + } catch (NotFoundException) { throw new Exception\RuntimeException(sprintf( 'The symmetric adapter %s does not exist', $adapter @@ -115,12 +92,10 @@ public static function factory($adapter, $options = []) /** * Returns the symmetric cipher plugin manager. If it doesn't exist it's created. - * - * @return ContainerInterface */ - public static function getSymmetricPluginManager() + public static function getSymmetricPluginManager(): ContainerInterface { - if (static::$symmetricPlugins === null) { + if (! static::$symmetricPlugins instanceof ContainerInterface) { static::setSymmetricPluginManager(new SymmetricPluginManager()); } @@ -133,7 +108,7 @@ public static function getSymmetricPluginManager() * @param string|SymmetricPluginManager $plugins * @throws Exception\InvalidArgumentException */ - public static function setSymmetricPluginManager($plugins) + public static function setSymmetricPluginManager(string|ContainerInterface $plugins): void { if (is_string($plugins)) { if (! class_exists($plugins) || ! is_subclass_of($plugins, ContainerInterface::class)) { @@ -145,21 +120,13 @@ public static function setSymmetricPluginManager($plugins) } $plugins = new $plugins(); } - if (! $plugins instanceof ContainerInterface) { - throw new Exception\InvalidArgumentException(sprintf( - 'Symmetric plugin must implements Interop\Container\ContainerInterface;; received "%s"', - is_object($plugins) ? get_class($plugins) : gettype($plugins) - )); - } static::$symmetricPlugins = $plugins; } /** * Set the symmetric cipher - * - * @return BlockCipher Provides a fluent interface */ - public function setCipher(SymmetricInterface $cipher) + public function setCipher(SymmetricInterface $cipher): static { $this->cipher = $cipher; return $this; @@ -167,33 +134,26 @@ public function setCipher(SymmetricInterface $cipher) /** * Get symmetric cipher - * - * @return SymmetricInterface */ - public function getCipher() + public function getCipher(): SymmetricInterface { return $this->cipher; } /** * Set the number of iterations for Pbkdf2 - * - * @param int $num - * @return BlockCipher Provides a fluent interface */ - public function setKeyIteration($num) + public function setKeyIteration(int $num): static { - $this->keyIteration = (int) $num; + $this->keyIteration = $num; return $this; } /** * Get the number of iterations for Pbkdf2 - * - * @return int */ - public function getKeyIteration() + public function getKeyIteration(): int { return $this->keyIteration; } @@ -201,11 +161,9 @@ public function getKeyIteration() /** * Set the salt (IV) * - * @param string $salt - * @return BlockCipher Provides a fluent interface * @throws Exception\InvalidArgumentException */ - public function setSalt($salt) + public function setSalt(string $salt): static { try { $this->cipher->setSalt($salt); @@ -219,43 +177,34 @@ public function setSalt($salt) /** * Get the salt (IV) according to the size requested by the algorithm - * - * @return string */ - public function getSalt() + public function getSalt(): string|null { return $this->cipher->getSalt(); } /** * Get the original salt value - * - * @return string */ - public function getOriginalSalt() + public function getOriginalSalt(): string { return $this->cipher->getOriginalSalt(); } /** * Enable/disable the binary output - * - * @param bool $value - * @return BlockCipher Provides a fluent interface */ - public function setBinaryOutput($value) + public function setBinaryOutput(bool $value): static { - $this->binaryOutput = (bool) $value; + $this->binaryOutput = $value; return $this; } /** * Get the value of binary output - * - * @return bool */ - public function getBinaryOutput() + public function getBinaryOutput(): bool { return $this->binaryOutput; } @@ -263,13 +212,11 @@ public function getBinaryOutput() /** * Set the encryption/decryption key * - * @param string $key - * @return BlockCipher Provides a fluent interface * @throws Exception\InvalidArgumentException */ - public function setKey($key) + public function setKey(string $key): static { - if (empty($key)) { + if ($key === '' || $key === '0') { throw new Exception\InvalidArgumentException('The key cannot be empty'); } $this->key = $key; @@ -279,10 +226,8 @@ public function setKey($key) /** * Get the key - * - * @return string */ - public function getKey() + public function getKey(): string { return $this->key; } @@ -290,11 +235,9 @@ public function getKey() /** * Set algorithm of the symmetric cipher * - * @param string $algo - * @return BlockCipher Provides a fluent interface * @throws Exception\InvalidArgumentException */ - public function setCipherAlgorithm($algo) + public function setCipherAlgorithm(string $algo): static { try { $this->cipher->setAlgorithm($algo); @@ -307,20 +250,16 @@ public function setCipherAlgorithm($algo) /** * Get the cipher algorithm - * - * @return string|bool */ - public function getCipherAlgorithm() + public function getCipherAlgorithm(): string { return $this->cipher->getAlgorithm(); } /** * Get the supported algorithms of the symmetric cipher - * - * @return array */ - public function getCipherSupportedAlgorithms() + public function getCipherSupportedAlgorithms(): array { return $this->cipher->getSupportedAlgorithms(); } @@ -328,11 +267,9 @@ public function getCipherSupportedAlgorithms() /** * Set the hash algorithm for HMAC authentication * - * @param string $hash - * @return BlockCipher Provides a fluent interface * @throws Exception\InvalidArgumentException */ - public function setHashAlgorithm($hash) + public function setHashAlgorithm(string $hash): static { if (! Hash::isSupported($hash)) { throw new Exception\InvalidArgumentException( @@ -346,10 +283,8 @@ public function setHashAlgorithm($hash) /** * Get the hash algorithm for HMAC authentication - * - * @return string */ - public function getHashAlgorithm() + public function getHashAlgorithm(): string { return $this->hash; } @@ -357,11 +292,9 @@ public function getHashAlgorithm() /** * Set the hash algorithm for the Pbkdf2 * - * @param string $hash - * @return BlockCipher Provides a fluent interface * @throws Exception\InvalidArgumentException */ - public function setPbkdf2HashAlgorithm($hash) + public function setPbkdf2HashAlgorithm(string $hash): static { if (! Hash::isSupported($hash)) { throw new Exception\InvalidArgumentException( @@ -375,10 +308,8 @@ public function setPbkdf2HashAlgorithm($hash) /** * Get the Pbkdf2 hash algorithm - * - * @return string */ - public function getPbkdf2HashAlgorithm() + public function getPbkdf2HashAlgorithm(): string { return $this->pbkdf2Hash; } @@ -386,11 +317,9 @@ public function getPbkdf2HashAlgorithm() /** * Encrypt then authenticate using HMAC * - * @param string $data - * @return string * @throws Exception\InvalidArgumentException */ - public function encrypt($data) + public function encrypt(string $data): string { // 0 (as integer), 0.0 (as float) & '0' (as string) will return false, though these should be allowed // Must be a string, integer, or float in order to encrypt @@ -407,7 +336,7 @@ public function encrypt($data) $data = (string) $data; } - if (empty($this->key)) { + if (! isset($this->key) || ($this->key === '' || $this->key === '0')) { throw new Exception\InvalidArgumentException('No key specified for the encryption'); } $keySize = $this->cipher->getKeySize(); @@ -443,11 +372,9 @@ public function encrypt($data) /** * Decrypt * - * @param string $data - * @return string|bool * @throws Exception\InvalidArgumentException */ - public function decrypt($data) + public function decrypt(string $data): string|false { if (! is_string($data)) { throw new Exception\InvalidArgumentException('The data to decrypt must be a string'); @@ -455,7 +382,7 @@ public function decrypt($data) if ('' === $data) { throw new Exception\InvalidArgumentException('The data to decrypt cannot be empty'); } - if (empty($this->key)) { + if (! isset($this->key) || ($this->key === '' || $this->key === '0')) { throw new Exception\InvalidArgumentException('No key specified for the decryption'); } @@ -495,12 +422,9 @@ public function decrypt($data) /** * Note: CCM and GCM modes do not need HMAC * - * @param string $data - * @param int $keySize - * @return string * @throws Exception\InvalidArgumentException */ - private function encryptViaCcmOrGcm($data, $keySize) + private function encryptViaCcmOrGcm(string $data, int $keySize): string { $this->cipher->setKey(Pbkdf2::calc( $this->getPbkdf2HashAlgorithm(), @@ -518,12 +442,9 @@ private function encryptViaCcmOrGcm($data, $keySize) /** * Note: CCM and GCM modes do not need HMAC * - * @param string $data - * @param int $keySize - * @return string * @throws Exception\InvalidArgumentException */ - private function decryptViaCcmOrGcm($data, $keySize) + private function decryptViaCcmOrGcm(string $data, int $keySize): string { $cipherText = $this->binaryOutput ? $data : base64_decode($data); $iv = mb_substr($cipherText, $this->cipher->getTagSize(), $this->cipher->getSaltSize(), '8bit'); diff --git a/src/Exception/ExceptionInterface.php b/src/Exception/ExceptionInterface.php index 7032589..e32dffb 100644 --- a/src/Exception/ExceptionInterface.php +++ b/src/Exception/ExceptionInterface.php @@ -1,4 +1,5 @@ cipher = $cipher; @@ -77,40 +66,32 @@ public function __construct(?Symmetric\SymmetricInterface $cipher = null) /** * Set the cipher object - * - * @param SymmetricInterface $cipher */ - public function setCipher(Symmetric\SymmetricInterface $cipher) + public function setCipher(SymmetricInterface $cipher): void { $this->cipher = $cipher; } /** * Get the cipher object - * - * @return SymmetricInterface */ - public function getCipher() + public function getCipher(): ?SymmetricInterface { return $this->cipher; } /** * Set the number of iterations for Pbkdf2 - * - * @param int $num */ - public function setKeyIteration($num) + public function setKeyIteration(int $num): void { - $this->keyIteration = (int) $num; + $this->keyIteration = $num; } /** * Get the number of iterations for Pbkdf2 - * - * @return int */ - public function getKeyIteration() + public function getKeyIteration(): int { return $this->keyIteration; } @@ -118,53 +99,44 @@ public function getKeyIteration() /** * Set the encryption/decryption key * - * @param string $key * @throws Exception\InvalidArgumentException */ - public function setKey($key) + public function setKey(string $key): void { - if (empty($key)) { + if ($key === '' || $key === '0') { throw new Exception\InvalidArgumentException('The key cannot be empty'); } - $this->key = (string) $key; + $this->key = $key; } /** * Get the key - * - * @return string|null */ - public function getKey() + public function getKey(): string|null { return $this->key; } /** * Set algorithm of the symmetric cipher - * - * @param string $algo */ - public function setCipherAlgorithm($algo) + public function setCipherAlgorithm(string $algo): void { $this->cipher->setAlgorithm($algo); } /** * Get the cipher algorithm - * - * @return string|bool */ - public function getCipherAlgorithm() + public function getCipherAlgorithm(): string { return $this->cipher->getAlgorithm(); } /** * Get the supported algorithms of the symmetric cipher - * - * @return array */ - public function getCipherSupportedAlgorithms() + public function getCipherSupportedAlgorithms(): array { return $this->cipher->getSupportedAlgorithms(); } @@ -172,25 +144,22 @@ public function getCipherSupportedAlgorithms() /** * Set the hash algorithm for HMAC authentication * - * @param string $hash * @throws Exception\InvalidArgumentException */ - public function setHashAlgorithm($hash) + public function setHashAlgorithm(string $hash): void { if (! Hash::isSupported($hash)) { throw new Exception\InvalidArgumentException( "The specified hash algorithm '{$hash}' is not supported by Laminas\Crypt\Hash" ); } - $this->hash = (string) $hash; + $this->hash = $hash; } /** * Get the hash algorithm for HMAC authentication - * - * @return string */ - public function getHashAlgorithm() + public function getHashAlgorithm(): string { return $this->hash; } @@ -198,25 +167,22 @@ public function getHashAlgorithm() /** * Set the hash algorithm for the Pbkdf2 * - * @param string $hash * @throws Exception\InvalidArgumentException */ - public function setPbkdf2HashAlgorithm($hash) + public function setPbkdf2HashAlgorithm(string $hash): void { if (! Hash::isSupported($hash)) { throw new Exception\InvalidArgumentException( "The specified hash algorithm '{$hash}' is not supported by Laminas\Crypt\Hash" ); } - $this->pbkdf2Hash = (string) $hash; + $this->pbkdf2Hash = $hash; } /** * Get the Pbkdf2 hash algorithm - * - * @return string */ - public function getPbkdf2HashAlgorithm() + public function getPbkdf2HashAlgorithm(): string { return $this->pbkdf2Hash; } @@ -224,15 +190,12 @@ public function getPbkdf2HashAlgorithm() /** * Encrypt then authenticate a file using HMAC * - * @param string $fileIn - * @param string $fileOut - * @return bool * @throws Exception\InvalidArgumentException */ - public function encrypt($fileIn, $fileOut) + public function encrypt(string $fileIn, string $fileOut): bool { $this->checkFileInOut($fileIn, $fileOut); - if (empty($this->key)) { + if (! isset($this->key) || ($this->key === '' || $this->key === '0')) { throw new Exception\InvalidArgumentException('No key specified for encryption'); } @@ -270,7 +233,7 @@ public function encrypt($fileIn, $fileOut) $result = $this->cipher->encrypt($data); if ($size <= self::BUFFER_SIZE) { // Write a placeholder for the HMAC and write the IV - fwrite($write, str_repeat(0, Hmac::getOutputSize($hashAlgo))); + fwrite($write, str_repeat('0', Hmac::getOutputSize($hashAlgo))); } else { $result = mb_substr($result, $saltSize, null, '8bit'); } @@ -299,15 +262,12 @@ public function encrypt($fileIn, $fileOut) /** * Decrypt a file * - * @param string $fileIn - * @param string $fileOut - * @return bool * @throws Exception\InvalidArgumentException */ - public function decrypt($fileIn, $fileOut) + public function decrypt(string $fileIn, string $fileOut): bool { $this->checkFileInOut($fileIn, $fileOut); - if (empty($this->key)) { + if (! isset($this->key) || ($this->key === '' || $this->key === '0')) { throw new Exception\InvalidArgumentException('No key specified for decryption'); } @@ -369,11 +329,9 @@ public function decrypt($fileIn, $fileOut) /** * Check that input file exists and output file don't * - * @param string $fileIn - * @param string $fileOut * @throws Exception\InvalidArgumentException */ - protected function checkFileInOut($fileIn, $fileOut) + protected function checkFileInOut(string $fileIn, string $fileOut): void { if (! file_exists($fileIn)) { throw new Exception\InvalidArgumentException(sprintf( diff --git a/src/Hash.php b/src/Hash.php index c6c199c..74a7a9b 100644 --- a/src/Hash.php +++ b/src/Hash.php @@ -1,4 +1,5 @@ bCipher = $bCipher ?? BlockCipher::factory('openssl'); - $this->rsa = $rsa ?? new PublicKey\Rsa(); } /** * Encrypt using a keyrings * - * @param string $plaintext - * @param array|string $keys - * @return string * @throws RuntimeException */ - public function encrypt($plaintext, $keys = null) + public function encrypt(string $plaintext, array|string|Stringable|null $keys = null): string { // generate a random session key $sessionKey = Rand::getBytes($this->bCipher->getCipher()->getKeySize()); @@ -73,7 +69,7 @@ public function encrypt($plaintext, $keys = null) $pubkey = is_string($pubkey) ? new PubKey($pubkey) : $pubkey; $encKeys .= sprintf( "%s:%s:", - base64_encode($id), + base64_encode((string) $id), base64_encode($this->rsa->encrypt($sessionKey, $pubkey)) ); } @@ -83,15 +79,14 @@ public function encrypt($plaintext, $keys = null) /** * Decrypt using a private key * - * @param string $msg - * @param string $privateKey - * @param string $passPhrase - * @param string $id - * @return string * @throws RuntimeException */ - public function decrypt($msg, $privateKey = null, $passPhrase = null, $id = "") - { + public function decrypt( + string $msg, + string|PrivateKey|null $privateKey = null, + ?string $passPhrase = null, + string $id = "" + ): string|false { // get the session key [$encKeys, $ciphertext] = explode(';', $msg, 2); @@ -116,25 +111,21 @@ public function decrypt($msg, $privateKey = null, $passPhrase = null, $id = "") // decrypt the plaintext with the blockcipher algorithm $this->bCipher->setKey($sessionKey); - return $this->bCipher->decrypt($ciphertext, $sessionKey); + return $this->bCipher->decrypt($ciphertext); } /** * Get the BlockCipher adapter - * - * @return BlockCipher */ - public function getBlockCipherInstance() + public function getBlockCipherInstance(): BlockCipher { return $this->bCipher; } /** * Get the Rsa instance - * - * @return Rsa */ - public function getRsaInstance() + public function getRsaInstance(): Rsa { return $this->rsa; } diff --git a/src/Key/Derivation/Exception/ExceptionInterface.php b/src/Key/Derivation/Exception/ExceptionInterface.php index 4b84ee2..388f313 100644 --- a/src/Key/Derivation/Exception/ExceptionInterface.php +++ b/src/Key/Derivation/Exception/ExceptionInterface.php @@ -1,4 +1,5 @@ 0 and a power of 2"); @@ -66,13 +64,8 @@ public static function calc($password, $salt, $n, $r, $p, $length) * scryptROMix * * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4 - * - * @param string $b - * @param int $n - * @param int $r - * @return string */ - protected static function scryptROMix($b, $n, $r) + protected static function scryptROMix(string $b, int $n, int $r): string { $x = $b; $v = []; @@ -92,12 +85,8 @@ protected static function scryptROMix($b, $n, $r) * scryptBlockMix * * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-3 - * - * @param string $b - * @param int $r - * @return string */ - protected static function scryptBlockMix($b, $r) + protected static function scryptBlockMix(string $b, int $r): string { $x = mb_substr($b, -64, null, '8bit'); $even = ''; @@ -124,11 +113,8 @@ protected static function scryptBlockMix($b, $r) * * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2 * @see http://cr.yp.to/salsa20.html - * - * @param string $b - * @return string */ - protected static function salsa208Core32($b) + protected static function salsa208Core32(string $b): string { $b32 = []; for ($i = 0; $i < 16; $i++) { @@ -218,11 +204,8 @@ protected static function salsa208Core32($b) * * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-2 * @see http://cr.yp.to/salsa20.html - * - * @param string $b - * @return string */ - protected static function salsa208Core64($b) + protected static function salsa208Core64(string $b): string { $b32 = []; for ($i = 0; $i < 16; $i++) { @@ -315,11 +298,8 @@ protected static function salsa208Core64($b) * Each block B is a string of 64 bytes. * * @see https://tools.ietf.org/html/draft-josefsson-scrypt-kdf-01#section-4 - * - * @param string $b - * @return int */ - protected static function integerify($b) + protected static function integerify(string $b): int { $v = 'v'; if (PHP_INT_SIZE === 8) { diff --git a/src/Password/Apache.php b/src/Password/Apache.php index a30ae3a..cab769f 100644 --- a/src/Password/Apache.php +++ b/src/Password/Apache.php @@ -1,4 +1,5 @@ $value) { - switch (strtolower($key)) { + switch (strtolower((string) $key)) { case 'format': $this->setFormat($value); break; @@ -89,13 +87,11 @@ public function __construct($options = []) /** * Generate the hash of a password * - * @param string $password * @throws Exception\RuntimeException - * @return string */ - public function create($password) + public function create(string $password): string { - if (empty($this->format)) { + if (! isset($this->format) || ($this->format === '' || $this->format === '0')) { throw new Exception\RuntimeException( 'You must specify a password format' ); @@ -111,7 +107,11 @@ public function create($password) $hash = $this->apr1Md5($password); break; case 'digest': - if (empty($this->userName) || empty($this->authName)) { + if ( + ! isset($this->userName) + || ($this->userName === '' || $this->userName === '0') + || (! isset($this->authName) || ($this->authName === '' || $this->authName === '0')) + ) { throw new Exception\RuntimeException( 'You must specify UserName and AuthName (realm) to generate the digest' ); @@ -125,12 +125,8 @@ public function create($password) /** * Verify if a password is correct against a hash value - * - * @param string $password - * @param string $hash - * @return bool */ - public function verify($password, $hash) + public function verify(string $password, string $hash): bool { if (mb_substr($hash, 0, 5, '8bit') === '{SHA}') { $hash2 = '{SHA}' . base64_encode(sha1($password, true)); @@ -148,10 +144,14 @@ public function verify($password, $hash) return Utils::compareStrings($hash, $hash2); } - $bcryptPattern = '/\$2[ay]?\$[0-9]{2}\$[' . addcslashes(static::BASE64, '+/') . '\.]{53}/'; + $bcryptPattern = '/\$2[ay]?\$[0-9]{2}\$[' . addcslashes((string) static::BASE64, '+/') . '\.]{53}/'; if (mb_strlen($hash, '8bit') > 13 && ! preg_match($bcryptPattern, $hash)) { // digest - if (empty($this->userName) || empty($this->authName)) { + if ( + ! isset($this->userName) + || ($this->userName === '' || $this->userName === '0') + || (! isset($this->authName) || ($this->authName === '' || $this->authName === '0')) + ) { throw new Exception\RuntimeException( 'You must specify UserName and AuthName (realm) to verify the digest' ); @@ -166,11 +166,10 @@ public function verify($password, $hash) /** * Set the format of the password * - * @param string $format * @throws Exception\InvalidArgumentException * @return Apache Provides a fluent interface */ - public function setFormat($format) + public function setFormat(string $format): Apache { $format = strtolower($format); if (! in_array($format, $this->supportedFormat)) { @@ -187,21 +186,16 @@ public function setFormat($format) /** * Get the format of the password - * - * @return string */ - public function getFormat() + public function getFormat(): string { return $this->format; } /** * Set the AuthName (for digest authentication) - * - * @param string $name - * @return Apache Provides a fluent interface */ - public function setAuthName($name) + public function setAuthName(string $name): static { $this->authName = $name; @@ -210,21 +204,16 @@ public function setAuthName($name) /** * Get the AuthName (for digest authentication) - * - * @return string */ - public function getAuthName() + public function getAuthName(): string { return $this->authName; } /** * Set the username - * - * @param string $name - * @return Apache Provides a fluent interface */ - public function setUserName($name) + public function setUserName(string $name): static { $this->userName = $name; @@ -233,33 +222,24 @@ public function setUserName($name) /** * Get the username - * - * @return string */ - public function getUserName() + public function getUserName(): string { return $this->userName; } /** * Convert a binary string using the alphabet "./0-9A-Za-z" - * - * @param string $value - * @return string */ - protected function toAlphabet64($value) + protected function toAlphabet64(string $value): string { return strtr(strrev(mb_substr(base64_encode($value), 2, null, '8bit')), self::BASE64, self::ALPHA64); } /** * APR1 MD5 algorithm - * - * @param string $password - * @param null|string $salt - * @return string */ - protected function apr1Md5($password, $salt = null) + protected function apr1Md5(string $password, string|null $salt = null): string { if (null === $salt) { $salt = Rand::getString(8, self::ALPHA64); @@ -270,7 +250,7 @@ protected function apr1Md5($password, $salt = null) ); } for ($i = 0; $i < 8; $i++) { - if (strpos(self::ALPHA64, $salt[$i]) === false) { + if (! str_contains(self::ALPHA64, $salt[$i])) { throw new Exception\InvalidArgumentException( 'The salt value must be a string in the alphabet "./0-9A-Za-z"' ); @@ -284,18 +264,18 @@ protected function apr1Md5($password, $salt = null) $text .= mb_substr($bin, 0, min(16, $i), '8bit'); } for ($i = $len; $i > 0; $i >>= 1) { - $text .= $i & 1 ? chr(0) : $password[0]; + $text .= ($i & 1) !== 0 ? chr(0) : $password[0]; } $bin = pack("H32", md5($text)); for ($i = 0; $i < 1000; $i++) { - $new = $i & 1 ? $password : $bin; - if ($i % 3) { + $new = ($i & 1) !== 0 ? $password : $bin; + if ($i % 3 !== 0) { $new .= $salt; } - if ($i % 7) { + if ($i % 7 !== 0) { $new .= $password; } - $new .= $i & 1 ? $bin : $password; + $new .= ($i & 1) !== 0 ? $bin : $password; $bin = pack("H32", md5($new)); } $tmp = ''; diff --git a/src/Password/Bcrypt.php b/src/Password/Bcrypt.php index 4ab7148..b36fc4b 100644 --- a/src/Password/Bcrypt.php +++ b/src/Password/Bcrypt.php @@ -1,24 +1,20 @@ (int) $this->cost]; - if (PHP_VERSION_ID < 70000) { // salt is deprecated from PHP 7.0 - $salt = $this->salt ?: Rand::getBytes(self::MIN_SALT_SIZE); - $options['salt'] = $salt; - } return password_hash($password, PASSWORD_BCRYPT, $options); } /** * Verify if a password is correct against a hash value - * - * @param string $password - * @param string $hash - * @return bool */ - public function verify($password, $hash) + public function verify(string $password, string $hash): bool { return password_verify($password, $hash); } @@ -97,13 +80,11 @@ public function verify($password, $hash) /** * Set the cost parameter * - * @param int|string $cost * @throws Exception\InvalidArgumentException - * @return Bcrypt Provides a fluent interface */ - public function setCost($cost) + public function setCost(int|string $cost): static { - if (! empty($cost)) { + if ($cost !== 0 && ($cost !== '' && $cost !== '0')) { $cost = (int) $cost; if ($cost < 4 || $cost > 31) { throw new Exception\InvalidArgumentException( @@ -117,51 +98,12 @@ public function setCost($cost) /** * Get the cost parameter - * - * @return string */ - public function getCost() + public function getCost(): string { return $this->cost; } - /** - * Set the salt value - * - * @param string $salt - * @throws Exception\InvalidArgumentException - * @return Bcrypt Provides a fluent interface - */ - public function setSalt($salt) - { - if (PHP_VERSION_ID >= 70000) { - trigger_error('Salt support is deprecated starting with PHP 7.0.0', E_USER_DEPRECATED); - } - - if (mb_strlen($salt, '8bit') < self::MIN_SALT_SIZE) { - throw new Exception\InvalidArgumentException( - 'The length of the salt must be at least ' . self::MIN_SALT_SIZE . ' bytes' - ); - } - - $this->salt = $salt; - return $this; - } - - /** - * Get the salt value - * - * @return string - */ - public function getSalt() - { - if (PHP_VERSION_ID >= 70000) { - trigger_error('Salt support is deprecated starting with PHP 7.0.0', E_USER_DEPRECATED); - } - - return $this->salt; - } - /** * Benchmark the bcrypt hash generation to determine the cost parameter based on time to target. * @@ -175,7 +117,7 @@ public function getSalt() * @param float $timeTarget Defaults to 50ms (0.05) * @return int Maximum cost value that falls within the time to target. */ - public function benchmarkCost($timeTarget = 0.05) + public function benchmarkCost(float $timeTarget = 0.05): int { $cost = 8; diff --git a/src/Password/BcryptSha.php b/src/Password/BcryptSha.php index ae14c2d..4c6a159 100644 --- a/src/Password/BcryptSha.php +++ b/src/Password/BcryptSha.php @@ -1,4 +1,5 @@ math = Math\BigInteger\BigInteger::factory(); @@ -118,21 +106,19 @@ public function __construct($prime, $generator, $privateKey = null, $privateKeyF * Set whether to use openssl extension * * @static - * @param bool $flag */ - public static function useOpensslExtension($flag = true) + public static function useOpensslExtension(bool $flag = true): void { - static::$useOpenssl = (bool) $flag; + static::$useOpenssl = $flag; } /** * Generate own public key. If a private number has not already been set, * one will be generated at this stage. * - * @return DiffieHellman Provides a fluent interface * @throws RuntimeException */ - public function generateKeys() + public function generateKeys(): static { if (function_exists('openssl_dh_compute_key') && static::$useOpenssl !== false) { $details = [ @@ -180,18 +166,15 @@ public function generateKeys() /** * Setter for the value of the public number * - * @param string $number - * @param string $format - * @return DiffieHellman Provides a fluent interface * @throws InvalidArgumentException */ - public function setPublicKey($number, $format = self::FORMAT_NUMBER) + public function setPublicKey(string $number, string $format = self::FORMAT_NUMBER): static { $number = $this->convert($number, $format, self::FORMAT_NUMBER); if (! preg_match('/^\d+$/', $number)) { throw new Exception\InvalidArgumentException('Invalid parameter; not a positive natural number'); } - $this->publicKey = (string) $number; + $this->publicKey = $number; return $this; } @@ -199,11 +182,9 @@ public function setPublicKey($number, $format = self::FORMAT_NUMBER) /** * Returns own public key for communication to the second party to this transaction * - * @param string $format - * @return string * @throws InvalidArgumentException */ - public function getPublicKey($format = self::FORMAT_NUMBER) + public function getPublicKey(string $format = self::FORMAT_NUMBER): string { if ($this->publicKey === null) { throw new Exception\InvalidArgumentException( @@ -225,18 +206,14 @@ public function getPublicKey($format = self::FORMAT_NUMBER) * If you need the binary form of the shared secret key, call * getSharedSecretKey() with the optional parameter for Binary output. * - * @param string $publicKey - * @param string $publicKeyFormat - * @param string $secretKeyFormat - * @return string * @throws InvalidArgumentException * @throws RuntimeException */ public function computeSecretKey( - $publicKey, - $publicKeyFormat = self::FORMAT_NUMBER, - $secretKeyFormat = self::FORMAT_NUMBER - ) { + string $publicKey, + string $publicKeyFormat = self::FORMAT_NUMBER, + string $secretKeyFormat = self::FORMAT_NUMBER + ): string { if (function_exists('openssl_dh_compute_key') && static::$useOpenssl !== false) { $publicKey = $this->convert($publicKey, $publicKeyFormat, self::FORMAT_BINARY); $secretKey = openssl_dh_compute_key($publicKey, $this->opensslKeyResource); @@ -262,13 +239,11 @@ public function computeSecretKey( /** * Return the computed shared secret key from the DiffieHellman transaction * - * @param string $format - * @return string * @throws InvalidArgumentException */ - public function getSharedSecretKey($format = self::FORMAT_NUMBER) + public function getSharedSecretKey(string $format = self::FORMAT_NUMBER): string { - if (! isset($this->secretKey)) { + if ($this->secretKey === null) { throw new Exception\InvalidArgumentException( 'A secret key has not yet been computed; call computeSecretKey() first' ); @@ -280,11 +255,9 @@ public function getSharedSecretKey($format = self::FORMAT_NUMBER) /** * Setter for the value of the prime number * - * @param string $number - * @return DiffieHellman Provides a fluent interface * @throws InvalidArgumentException */ - public function setPrime($number) + public function setPrime(string $number): static { if (! preg_match('/^\d+$/', $number) || $number < 11) { throw new Exception\InvalidArgumentException( @@ -292,7 +265,7 @@ public function setPrime($number) . 'should be a large natural number prime' ); } - $this->prime = (string) $number; + $this->prime = $number; return $this; } @@ -300,13 +273,11 @@ public function setPrime($number) /** * Getter for the value of the prime number * - * @param string $format - * @return string * @throws InvalidArgumentException */ - public function getPrime($format = self::FORMAT_NUMBER) + public function getPrime(string $format = self::FORMAT_NUMBER): string { - if (! isset($this->prime)) { + if ($this->prime === null) { throw new Exception\InvalidArgumentException('No prime number has been set'); } @@ -316,18 +287,16 @@ public function getPrime($format = self::FORMAT_NUMBER) /** * Setter for the value of the generator number * - * @param string $number - * @return DiffieHellman Provides a fluent interface * @throws InvalidArgumentException */ - public function setGenerator($number) + public function setGenerator(string $number): static { if (! preg_match('/^\d+$/', $number) || $number < 2) { throw new Exception\InvalidArgumentException( 'Invalid parameter; not a positive natural number greater than 1' ); } - $this->generator = (string) $number; + $this->generator = $number; return $this; } @@ -335,13 +304,11 @@ public function setGenerator($number) /** * Getter for the value of the generator number * - * @param string $format - * @return string * @throws InvalidArgumentException */ - public function getGenerator($format = self::FORMAT_NUMBER) + public function getGenerator(string $format = self::FORMAT_NUMBER): string { - if (! isset($this->generator)) { + if ($this->generator === null) { throw new Exception\InvalidArgumentException('No generator number has been set'); } @@ -351,29 +318,23 @@ public function getGenerator($format = self::FORMAT_NUMBER) /** * Setter for the value of the private number * - * @param string $number - * @param string $format - * @return DiffieHellman Provides a fluent interface * @throws InvalidArgumentException */ - public function setPrivateKey($number, $format = self::FORMAT_NUMBER) + public function setPrivateKey(string $number, string $format = self::FORMAT_NUMBER): static { $number = $this->convert($number, $format, self::FORMAT_NUMBER); if (! preg_match('/^\d+$/', $number)) { throw new Exception\InvalidArgumentException('Invalid parameter; not a positive natural number'); } - $this->privateKey = (string) $number; + $this->privateKey = $number; return $this; } /** * Getter for the value of the private number - * - * @param string $format - * @return string */ - public function getPrivateKey($format = self::FORMAT_NUMBER) + public function getPrivateKey(string $format = self::FORMAT_NUMBER): string { if (! $this->hasPrivateKey()) { $this->setPrivateKey($this->generatePrivateKey(), self::FORMAT_BINARY); @@ -384,24 +345,20 @@ public function getPrivateKey($format = self::FORMAT_NUMBER) /** * Check whether a private key currently exists. - * - * @return bool */ - public function hasPrivateKey() + public function hasPrivateKey(): bool { - return isset($this->privateKey); + return $this->privateKey !== null; } /** * Convert number between formats - * - * @param string $number - * @param string $inputFormat - * @param string $outputFormat - * @return string */ - protected function convert($number, $inputFormat = self::FORMAT_NUMBER, $outputFormat = self::FORMAT_BINARY) - { + protected function convert( + string $number, + string $inputFormat = self::FORMAT_NUMBER, + string $outputFormat = self::FORMAT_BINARY + ): string { if ($inputFormat === $outputFormat) { return $number; } @@ -419,15 +376,11 @@ protected function convert($number, $inputFormat = self::FORMAT_NUMBER, $outputF } // convert to output format - switch ($outputFormat) { - case self::FORMAT_BINARY: - return $this->math->intToBin($number); - case self::FORMAT_BTWOC: - return $this->math->intToBin($number, true); - case self::FORMAT_NUMBER: - default: - return $number; - } + return match ($outputFormat) { + self::FORMAT_BINARY => $this->math->intToBin($number), + self::FORMAT_BTWOC => $this->math->intToBin($number, true), + default => $number, + }; } /** @@ -436,10 +389,8 @@ protected function convert($number, $inputFormat = self::FORMAT_NUMBER, $outputF * generate a random key. Having a random number generator installed * on linux/bsd is highly recommended! The alternative is not recommended * for production unless without any other option. - * - * @return string */ - protected function generatePrivateKey() + protected function generatePrivateKey(): string { return Math\Rand::getBytes(mb_strlen($this->getPrime(), '8bit')); } diff --git a/src/PublicKey/Rsa.php b/src/PublicKey/Rsa.php index 63038ab..3bb1632 100644 --- a/src/PublicKey/Rsa.php +++ b/src/PublicKey/Rsa.php @@ -1,9 +1,14 @@ options = new RsaOptions(); - } else { - $this->options = $options; - } } /** * Set options - * - * @return Rsa Provides a fluent interface */ - public function setOptions(RsaOptions $options) + public function setOptions(RsaOptions $options): static { $this->options = $options; return $this; @@ -125,20 +117,16 @@ public function setOptions(RsaOptions $options) /** * Get options - * - * @return RsaOptions */ - public function getOptions() + public function getOptions(): RsaOptions { return $this->options; } /** * Return last openssl error(s) - * - * @return string */ - public function getOpensslErrorString() + public function getOpensslErrorString(): string { $message = ''; while (false !== ($error = openssl_error_string())) { @@ -150,14 +138,12 @@ public function getOpensslErrorString() /** * Sign with private key * - * @param string $data - * @return string * @throws Rsa\Exception\RuntimeException */ - public function sign($data, ?Rsa\PrivateKey $privateKey = null) + public function sign(string $data, ?Rsa\PrivateKey $privateKey = null): string { $signature = ''; - if (null === $privateKey) { + if (! $privateKey instanceof PrivateKey) { $privateKey = $this->options->getPrivateKey(); } @@ -177,7 +163,7 @@ public function sign($data, ?Rsa\PrivateKey $privateKey = null) return $signature; } - return base64_encode($signature); + return base64_encode((string) $signature); } /** @@ -192,19 +178,16 @@ public function sign($data, ?Rsa\PrivateKey $privateKey = null) * @see Rsa::MODE_BASE64 * @see Rsa::MODE_RAW * - * @param string $data - * @param string $signature * @param int $mode Input encoding - * @return bool * @throws Rsa\Exception\RuntimeException */ public function verify( - $data, - $signature, + string $data, + string $signature, ?Rsa\PublicKey $publicKey = null, - $mode = self::MODE_AUTO - ) { - if (null === $publicKey) { + int $mode = self::MODE_AUTO + ): bool { + if (! $publicKey instanceof PublicKey) { $publicKey = $this->options->getPublicKey(); } @@ -242,26 +225,20 @@ public function verify( /** * Encrypt with private/public key * - * @param string $data - * @return string * @throws Rsa\Exception\InvalidArgumentException */ - public function encrypt($data, ?Rsa\AbstractKey $key = null) + public function encrypt(string $data, ?Rsa\AbstractKey $key = null): string { - if (null === $key) { + if (! $key instanceof AbstractKey) { $key = $this->options->getPublicKey(); } - if (null === $key) { + if (! $key instanceof AbstractKey) { throw new Exception\InvalidArgumentException('No key specified for the decryption'); } - $padding = $this->getOptions()->getOpensslPadding(); - if (null === $padding) { - $encrypted = $key->encrypt($data); - } else { - $encrypted = $key->encrypt($data, $padding); - } + $padding = $this->getOptions()->getOpensslPadding(); + $encrypted = null === $padding ? $key->encrypt($data) : $key->encrypt($data, $padding); if ($this->options->getBinaryOutput()) { return $encrypted; @@ -282,21 +259,19 @@ public function encrypt($data, ?Rsa\AbstractKey $key = null) * @see Rsa::MODE_BASE64 * @see Rsa::MODE_RAW * - * @param string $data * @param int $mode Input encoding - * @return string * @throws Rsa\Exception\InvalidArgumentException */ public function decrypt( - $data, + string $data, ?Rsa\AbstractKey $key = null, - $mode = self::MODE_AUTO - ) { - if (null === $key) { + int $mode = self::MODE_AUTO + ): string { + if (! $key instanceof AbstractKey) { $key = $this->options->getPrivateKey(); } - if (null === $key) { + if (! $key instanceof AbstractKey) { throw new Exception\InvalidArgumentException('No key specified for the decryption'); } @@ -323,19 +298,4 @@ public function decrypt( return $key->decrypt($data, $padding); } } - - /** - * Generate new private/public key pair - * - * @see RsaOptions::generateKeys() - * - * @param array $opensslConfig - * @return Rsa Provides a fluent interface - * @throws Rsa\Exception\RuntimeException - */ - public function generateKeys(array $opensslConfig = []) - { - $this->options->generateKeys($opensslConfig); - return $this; - } } diff --git a/src/PublicKey/Rsa/AbstractKey.php b/src/PublicKey/Rsa/AbstractKey.php index e2e30e5..391864e 100644 --- a/src/PublicKey/Rsa/AbstractKey.php +++ b/src/PublicKey/Rsa/AbstractKey.php @@ -1,18 +1,19 @@ details['bits']; - } + protected array $details = []; /** * Retrieve openssl key resource @@ -52,32 +41,24 @@ public function getOpensslKeyResource() * Encrypt using this key * * @abstract - * @param string $data - * @return string */ - abstract public function encrypt($data); + abstract public function encrypt(string $data): string; /** * Decrypt using this key * * @abstract - * @param string $data - * @return string */ - abstract public function decrypt($data); + abstract public function decrypt(string $data): string; /** * Get string representation of this key * * @abstract - * @return string */ - abstract public function toString(); + abstract public function toString(): string; - /** - * @return string - */ - public function __toString() + public function __toString(): string { return $this->toString(); } diff --git a/src/PublicKey/Rsa/Exception/ExceptionInterface.php b/src/PublicKey/Rsa/Exception/ExceptionInterface.php index 00e01f1..7e3ce62 100644 --- a/src/PublicKey/Rsa/Exception/ExceptionInterface.php +++ b/src/PublicKey/Rsa/Exception/ExceptionInterface.php @@ -1,4 +1,5 @@ publicKey === null) { $this->publicKey = new PublicKey($this->details['key']); @@ -84,15 +76,12 @@ public function getPublicKey() /** * Encrypt using this key * - * @param string $data - * @param integer $padding - * @return string * @throws Exception\RuntimeException * @throws Exception\InvalidArgumentException */ - public function encrypt($data, $padding = OPENSSL_PKCS1_PADDING) + public function encrypt(string $data, int $padding = OPENSSL_PKCS1_PADDING): string { - if (empty($data)) { + if ($data === '' || $data === '0') { throw new Exception\InvalidArgumentException('The data to encrypt cannot be empty'); } @@ -116,13 +105,10 @@ public function encrypt($data, $padding = OPENSSL_PKCS1_PADDING) * * @see http://archiv.infsec.ethz.ch/education/fs08/secsem/bleichenbacher98.pdf * - * @param string $data - * @param integer $padding - * @return string * @throws Exception\RuntimeException * @throws Exception\InvalidArgumentException */ - public function decrypt($data, $padding = OPENSSL_PKCS1_OAEP_PADDING) + public function decrypt(string $data, int $padding = OPENSSL_PKCS1_OAEP_PADDING): string { if (! is_string($data)) { throw new Exception\InvalidArgumentException('The data to decrypt must be a string'); @@ -142,10 +128,7 @@ public function decrypt($data, $padding = OPENSSL_PKCS1_OAEP_PADDING) return $decrypted; } - /** - * @return string - */ - public function toString() + public function toString(): string { return $this->pemString; } diff --git a/src/PublicKey/Rsa/PublicKey.php b/src/PublicKey/Rsa/PublicKey.php index 16e30d8..e071a64 100644 --- a/src/PublicKey/Rsa/PublicKey.php +++ b/src/PublicKey/Rsa/PublicKey.php @@ -1,4 +1,5 @@ certificateString = $pemStringOrCertificate; } else { $this->pemString = $pemStringOrCertificate; @@ -79,15 +76,12 @@ public function __construct($pemStringOrCertificate) * * @see http://archiv.infsec.ethz.ch/education/fs08/secsem/bleichenbacher98.pdf * - * @param string $data - * @param string $padding * @throws Exception\InvalidArgumentException * @throws Exception\RuntimeException - * @return string */ - public function encrypt($data, $padding = OPENSSL_PKCS1_OAEP_PADDING) + public function encrypt(string $data, int $padding = OPENSSL_PKCS1_OAEP_PADDING): string { - if (empty($data)) { + if ($data === '' || $data === '0') { throw new Exception\InvalidArgumentException('The data to encrypt cannot be empty'); } @@ -105,13 +99,10 @@ public function encrypt($data, $padding = OPENSSL_PKCS1_OAEP_PADDING) /** * Decrypt using this key * - * @param string $data - * @param string $padding - * @throws Exception\InvalidArgumentException * @throws Exception\RuntimeException - * @return string + * @throws Exception\InvalidArgumentException */ - public function decrypt($data, $padding = OPENSSL_PKCS1_PADDING) + public function decrypt(string $data, int $padding = OPENSSL_PKCS1_PADDING): string { if (! is_string($data)) { throw new Exception\InvalidArgumentException('The data to decrypt must be a string'); @@ -131,27 +122,16 @@ public function decrypt($data, $padding = OPENSSL_PKCS1_PADDING) return $decrypted; } - /** - * Get certificate string - * - * @return string - */ - public function getCertificate() - { - return $this->certificateString; - } - /** * To string * - * @return string * @throws Exception\RuntimeException */ - public function toString() + public function toString(): string { - if (! empty($this->certificateString)) { + if (isset($this->certificateString) && ($this->certificateString !== '' && $this->certificateString !== '0')) { return $this->certificateString; - } elseif (! empty($this->pemString)) { + } elseif ($this->pemString !== '' && $this->pemString !== '0') { return $this->pemString; } throw new Exception\RuntimeException('No public key string representation is available'); diff --git a/src/PublicKey/RsaOptions.php b/src/PublicKey/RsaOptions.php index b8b2b7a..028a178 100644 --- a/src/PublicKey/RsaOptions.php +++ b/src/PublicKey/RsaOptions.php @@ -1,4 +1,5 @@ privateKey = $key; $this->publicKey = $this->privateKey->getPublicKey(); @@ -70,20 +59,16 @@ public function setPrivateKey(Rsa\PrivateKey $key) /** * Get private key - * - * @return null|Rsa\PrivateKey */ - public function getPrivateKey() + public function getPrivateKey(): Rsa\PrivateKey|null { return $this->privateKey; } /** * Set public key - * - * @return RsaOptions Provides a fluent interface */ - public function setPublicKey(Rsa\PublicKey $key) + public function setPublicKey(Rsa\PublicKey $key): static { $this->publicKey = $key; return $this; @@ -91,23 +76,18 @@ public function setPublicKey(Rsa\PublicKey $key) /** * Get public key - * - * @return null|Rsa\PublicKey */ - public function getPublicKey() + public function getPublicKey(): Rsa\PublicKey|null { return $this->publicKey; } /** * Set pass phrase - * - * @param string $phrase - * @return RsaOptions Provides a fluent interface */ - public function setPassPhrase($phrase) + public function setPassPhrase(string $phrase): static { - $this->passPhrase = (string) $phrase; + $this->passPhrase = $phrase; return $this; } @@ -116,7 +96,7 @@ public function setPassPhrase($phrase) * * @return string */ - public function getPassPhrase() + public function getPassPhrase(): string|null { return $this->passPhrase; } @@ -124,12 +104,10 @@ public function getPassPhrase() /** * Set hash algorithm * - * @param string $hash - * @return RsaOptions Provides a fluent interface * @throws Rsa\Exception\RuntimeException * @throws Rsa\Exception\InvalidArgumentException */ - public function setHashAlgorithm($hash) + public function setHashAlgorithm(string $hash): static { $hashUpper = strtoupper($hash); if (! defined('OPENSSL_ALGO_' . $hashUpper)) { @@ -145,18 +123,15 @@ public function setHashAlgorithm($hash) /** * Get hash algorithm - * - * @return string */ - public function getHashAlgorithm() + public function getHashAlgorithm(): string { return $this->hashAlgorithm; } - /** @return string */ - public function getOpensslSignatureAlgorithm() + public function getOpensslSignatureAlgorithm(): int { - if (! isset($this->opensslSignatureAlgorithm)) { + if ($this->opensslSignatureAlgorithm === null) { $this->opensslSignatureAlgorithm = constant('OPENSSL_ALGO_' . strtoupper($this->hashAlgorithm)); } return $this->opensslSignatureAlgorithm; @@ -164,56 +139,44 @@ public function getOpensslSignatureAlgorithm() /** * Enable/disable the binary output - * - * @param bool $value - * @return RsaOptions Provides a fluent interface */ - public function setBinaryOutput($value) + public function setBinaryOutput(bool $value): static { - $this->binaryOutput = (bool) $value; + $this->binaryOutput = $value; return $this; } /** * Get the value of binary output - * - * @return bool */ - public function getBinaryOutput() + public function getBinaryOutput(): bool { return $this->binaryOutput; } /** * Get the OPENSSL padding - * - * @return int|null */ - public function getOpensslPadding() + public function getOpensslPadding(): int|null { return $this->opensslPadding; } /** * Set the OPENSSL padding - * - * @param int|null $opensslPadding - * @return RsaOptions Provides a fluent interface */ - public function setOpensslPadding($opensslPadding) + public function setOpensslPadding(int $opensslPadding): static { - $this->opensslPadding = (int) $opensslPadding; + $this->opensslPadding = $opensslPadding; return $this; } /** * Generate new private/public key pair * - * @param array $opensslConfig - * @return RsaOptions Provides a fluent interface * @throws Rsa\Exception\RuntimeException */ - public function generateKeys(array $opensslConfig = []) + public function generateKeys(array $opensslConfig = []): static { $opensslConfig = array_replace( [ diff --git a/src/Symmetric/Exception/ExceptionInterface.php b/src/Symmetric/Exception/ExceptionInterface.php index f922eed..78e9f2f 100644 --- a/src/Symmetric/Exception/ExceptionInterface.php +++ b/src/Symmetric/Exception/ExceptionInterface.php @@ -1,4 +1,5 @@ */ - public $supportedAlgos; + public array $supportedAlgos = []; /** * Constructor * - * @param array|Traversable $options * @throws Exception\RuntimeException * @throws Exception\InvalidArgumentException */ - public function __construct($options = []) + public function __construct(Traversable|array $options = []) { if (! extension_loaded('openssl')) { throw new Exception\RuntimeException(sprintf( @@ -193,10 +170,8 @@ public function __construct($options = []) self::class )); } - // Add the GCM and CCM modes for PHP 7.1+ - if (PHP_VERSION_ID >= 70100) { - array_push($this->encryptionModes, 'gcm', 'ccm'); - } + $this->encryptionModes[] = 'gcm'; + $this->encryptionModes[] = 'ccm'; $this->setOptions($options); $this->setDefaultOptions($options); } @@ -204,12 +179,10 @@ public function __construct($options = []) /** * Set default options * - * @param array $options - * @return void * @throws Exception\RuntimeException * @throws Exception\InvalidArgumentException */ - public function setOptions($options) + public function setOptions(Traversable|array $options): void { if (empty($options)) { return; @@ -262,11 +235,8 @@ public function setOptions($options) /** * Set default options - * - * @param array $options - * @return void */ - protected function setDefaultOptions($options = []) + protected function setDefaultOptions(array|ArrayAccess $options = []): void { if (isset($options['padding'])) { return; @@ -281,12 +251,10 @@ protected function setDefaultOptions($options = []) * Returns the padding plugin manager. * * Creates one if none is present. - * - * @return ContainerInterface */ - public static function getPaddingPluginManager() + public static function getPaddingPluginManager(): ContainerInterface { - if (static::$paddingPlugins === null) { + if (! static::$paddingPlugins instanceof ContainerInterface) { self::setPaddingPluginManager(new PaddingPluginManager()); } @@ -296,11 +264,9 @@ public static function getPaddingPluginManager() /** * Set the padding plugin manager * - * @param string|ContainerInterface $plugins * @throws Exception\InvalidArgumentException - * @return void */ - public static function setPaddingPluginManager($plugins) + public static function setPaddingPluginManager(string|ContainerInterface $plugins): void { if (is_string($plugins)) { if (! class_exists($plugins) || ! is_subclass_of($plugins, ContainerInterface::class)) { @@ -314,23 +280,13 @@ public static function setPaddingPluginManager($plugins) $plugins = new $plugins(); } - if (! $plugins instanceof ContainerInterface) { - throw new Exception\InvalidArgumentException(sprintf( - 'Padding plugins must implements %s; received "%s"', - ContainerInterface::class, - is_object($plugins) ? get_class($plugins) : gettype($plugins) - )); - } - static::$paddingPlugins = $plugins; } /** * Get the key size for the selected cipher - * - * @return int */ - public function getKeySize() + public function getKeySize(): int { return $this->keySizes[$this->algo]; } @@ -339,15 +295,13 @@ public function getKeySize() * Set the encryption key * If the key is longer than maximum supported, it will be truncated by getKey(). * - * @param string $key - * @return Openssl Provides a fluent interface * @throws Exception\InvalidArgumentException */ - public function setKey($key) + public function setKey(string $key): static { $keyLen = mb_strlen($key, '8bit'); - if (! $keyLen) { + if ($keyLen === 0) { throw new Exception\InvalidArgumentException('The key cannot be empty'); } @@ -364,13 +318,11 @@ public function setKey($key) /** * Get the encryption key - * - * @return string */ - public function getKey() + public function getKey(): ?string { - if (empty($this->key)) { - return; + if (! isset($this->key) || ($this->key === '' || $this->key === '0')) { + return null; } return mb_substr($this->key, 0, $this->getKeySize(), '8bit'); } @@ -378,11 +330,9 @@ public function getKey() /** * Set the encryption algorithm (cipher) * - * @param string $algo - * @return Openssl Provides a fluent interface * @throws Exception\InvalidArgumentException */ - public function setAlgorithm($algo) + public function setAlgorithm(string $algo): static { if (! in_array($algo, $this->getSupportedAlgorithms())) { throw new Exception\InvalidArgumentException(sprintf( @@ -397,20 +347,16 @@ public function setAlgorithm($algo) /** * Get the encryption algorithm - * - * @return string */ - public function getAlgorithm() + public function getAlgorithm(): string { return $this->algo; } /** * Set the padding object - * - * @return Openssl Provides a fluent interface */ - public function setPadding(Padding\PaddingInterface $padding) + public function setPadding(PaddingInterface $padding): static { $this->padding = $padding; return $this; @@ -418,10 +364,8 @@ public function setPadding(Padding\PaddingInterface $padding) /** * Get the padding object - * - * @return Padding\PaddingInterface */ - public function getPadding() + public function getPadding(): PaddingInterface { return $this->padding; } @@ -429,12 +373,10 @@ public function getPadding() /** * Set Additional Authentication Data * - * @param string $aad - * @return self * @throws Exception\InvalidArgumentException * @throws Exception\RuntimeException */ - public function setAad($aad) + public function setAad(string $aad): static { if (! $this->isAuthEncAvailable()) { throw new Exception\RuntimeException( @@ -448,13 +390,6 @@ public function setAad($aad) ); } - if (! is_string($aad)) { - throw new Exception\InvalidArgumentException(sprintf( - 'The provided $aad must be a string, %s given', - gettype($aad) - )); - } - $this->aad = $aad; return $this; @@ -462,20 +397,16 @@ public function setAad($aad) /** * Get the Additional Authentication Data - * - * @return string */ - public function getAad() + public function getAad(): string { return $this->aad; } /** * Get the authentication tag - * - * @return string */ - public function getTag() + public function getTag(): string|null { return $this->tag; } @@ -483,20 +414,11 @@ public function getTag() /** * Set the tag size for CCM and GCM mode * - * @param int $size - * @return self * @throws Exception\InvalidArgumentException * @throws Exception\RuntimeException */ - public function setTagSize($size) + public function setTagSize(int $size): static { - if (! is_int($size)) { - throw new Exception\InvalidArgumentException(sprintf( - 'The provided $size must be an integer, %s given', - gettype($size) - )); - } - if (! $this->isAuthEncAvailable()) { throw new Exception\RuntimeException( 'You need PHP 7.1+ and OpenSSL with CCM or GCM mode to set the Tag Size' @@ -522,10 +444,8 @@ public function setTagSize($size) /** * Get the tag size for CCM and GCM mode - * - * @return int */ - public function getTagSize() + public function getTagSize(): int { return $this->tagSize; } @@ -533,14 +453,12 @@ public function getTagSize() /** * Encrypt * - * @param string $data * @throws Exception\InvalidArgumentException - * @return string */ - public function encrypt($data) + public function encrypt(string $data): string { // Cannot encrypt empty string - if (! is_string($data) || $data === '') { + if ($data === '') { throw new Exception\InvalidArgumentException('The data to encrypt cannot be empty'); } @@ -552,7 +470,7 @@ public function encrypt($data) throw new Exception\InvalidArgumentException('The salt (IV) cannot be empty'); } - if (null === $this->getPadding()) { + if (! $this->getPadding() instanceof PaddingInterface) { throw new Exception\InvalidArgumentException('You must specify a padding method'); } @@ -604,20 +522,18 @@ public function encrypt($data) /** * Decrypt * - * @param string $data * @throws Exception\InvalidArgumentException - * @return string */ - public function decrypt($data) + public function decrypt(string $data): string { - if (empty($data)) { + if ($data === '' || $data === '0') { throw new Exception\InvalidArgumentException('The data to decrypt cannot be empty'); } if (null === $this->getKey()) { throw new Exception\InvalidArgumentException('No decryption key specified'); } - if (null === $this->getPadding()) { + if (! $this->getPadding() instanceof PaddingInterface) { throw new Exception\InvalidArgumentException('You must specify a padding method'); } @@ -650,10 +566,8 @@ public function decrypt($data) /** * Get the salt (IV) size - * - * @return int */ - public function getSaltSize() + public function getSaltSize(): int|false { return openssl_cipher_iv_length( $this->encryptionAlgos[$this->algo] . '-' . $this->mode @@ -662,12 +576,10 @@ public function getSaltSize() /** * Get the supported algorithms - * - * @return array */ - public function getSupportedAlgorithms() + public function getSupportedAlgorithms(): array { - if (empty($this->supportedAlgos)) { + if ($this->supportedAlgos === []) { foreach ($this->encryptionAlgos as $name => $algo) { // CBC mode is supported by all the algorithms if (in_array($algo . '-cbc', $this->getOpensslAlgos())) { @@ -681,11 +593,9 @@ public function getSupportedAlgorithms() /** * Set the salt (IV) * - * @param string $salt - * @return Openssl Provides a fluent interface * @throws Exception\InvalidArgumentException */ - public function setSalt($salt) + public function setSalt(string $salt): static { if ($this->getSaltSize() <= 0) { throw new Exception\InvalidArgumentException(sprintf( @@ -695,7 +605,7 @@ public function setSalt($salt) )); } - if (empty($salt)) { + if ($salt === '' || $salt === '0') { throw new Exception\InvalidArgumentException('The salt (IV) cannot be empty'); } @@ -712,13 +622,11 @@ public function setSalt($salt) /** * Get the salt (IV) according to the size requested by the algorithm - * - * @return string */ - public function getSalt() + public function getSalt(): ?string { - if (empty($this->iv)) { - return; + if (! isset($this->iv) || ($this->iv === '' || $this->iv === '0')) { + return null; } if (mb_strlen($this->iv, '8bit') < $this->getSaltSize()) { @@ -733,10 +641,8 @@ public function getSalt() /** * Get the original salt value - * - * @return string */ - public function getOriginalSalt() + public function getOriginalSalt(): string { return $this->iv; } @@ -744,13 +650,11 @@ public function getOriginalSalt() /** * Set the cipher mode * - * @param string $mode - * @return Openssl Provides a fluent interface * @throws Exception\InvalidArgumentException */ - public function setMode($mode) + public function setMode(string $mode): static { - if (empty($mode)) { + if ($mode === '' || $mode === '0') { return $this; } if (! in_array($mode, $this->getSupportedModes())) { @@ -766,22 +670,18 @@ public function setMode($mode) /** * Get the cipher mode - * - * @return string */ - public function getMode() + public function getMode(): string { return $this->mode; } /** * Return the OpenSSL supported encryption algorithms - * - * @return array */ - protected function getOpensslAlgos() + protected function getOpensslAlgos(): array { - if (empty($this->opensslAlgos)) { + if ($this->opensslAlgos === []) { $this->opensslAlgos = openssl_get_cipher_methods(true); } return $this->opensslAlgos; @@ -789,10 +689,8 @@ protected function getOpensslAlgos() /** * Get all supported encryption modes for the selected algorithm - * - * @return array */ - public function getSupportedModes() + public function getSupportedModes(): array { $modes = []; foreach ($this->encryptionModes as $mode) { @@ -806,20 +704,16 @@ public function getSupportedModes() /** * Get the block size - * - * @return int */ - public function getBlockSize() + public function getBlockSize(): int { return $this->blockSizes[$this->algo]; } /** * Return true if authenticated encryption is available - * - * @return bool */ - public function isAuthEncAvailable() + public function isAuthEncAvailable(): bool { // Counter with CBC-MAC $ccm = in_array('aes-256-ccm', $this->getOpensslAlgos()); @@ -829,21 +723,12 @@ public function isAuthEncAvailable() return PHP_VERSION_ID >= 70100 && ($ccm || $gcm); } - /** - * @return bool - */ - private function isCcmOrGcm() + private function isCcmOrGcm(): bool { return in_array(strtolower($this->mode), ['gcm', 'ccm'], true); } - /** - * @param string $cipherText - * @param string $iv - * @param string $tag - * @return string|bool false on failure - */ - private function attemptOpensslDecrypt($cipherText, $iv, $tag) + private function attemptOpensslDecrypt(string $cipherText, string $iv, string|null $tag): string|false { if ($this->isCcmOrGcm()) { return openssl_decrypt( diff --git a/src/Symmetric/Padding/NoPadding.php b/src/Symmetric/Padding/NoPadding.php index 92552eb..a6ecce5 100644 --- a/src/Symmetric/Padding/NoPadding.php +++ b/src/Symmetric/Padding/NoPadding.php @@ -1,4 +1,5 @@ */ - private $paddings = [ + private array $paddings = [ 'pkcs7' => Padding\Pkcs7::class, 'nopadding' => Padding\NoPadding::class, 'null' => Padding\NoPadding::class, diff --git a/src/Symmetric/SymmetricInterface.php b/src/Symmetric/SymmetricInterface.php index 2c4a40c..a4461b1 100644 --- a/src/Symmetric/SymmetricInterface.php +++ b/src/Symmetric/SymmetricInterface.php @@ -1,87 +1,48 @@