![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/spomky-labs/pki-framework/src/CryptoBridge/Crypto/ |
<?php declare(strict_types=1); namespace SpomkyLabs\Pki\CryptoBridge\Crypto; use function array_key_exists; use function mb_strlen; use const OPENSSL_ALGO_MD4; use const OPENSSL_ALGO_MD5; use const OPENSSL_ALGO_SHA1; use const OPENSSL_ALGO_SHA224; use const OPENSSL_ALGO_SHA256; use const OPENSSL_ALGO_SHA384; use const OPENSSL_ALGO_SHA512; use const OPENSSL_RAW_DATA; use const OPENSSL_ZERO_PADDING; use RuntimeException; use SpomkyLabs\Pki\CryptoBridge\Crypto; use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\AlgorithmIdentifier; use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\Cipher\BlockCipherAlgorithmIdentifier; use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\Cipher\CipherAlgorithmIdentifier; use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\Cipher\RC2CBCAlgorithmIdentifier; use SpomkyLabs\Pki\CryptoTypes\AlgorithmIdentifier\Feature\SignatureAlgorithmIdentifier; use SpomkyLabs\Pki\CryptoTypes\Asymmetric\PrivateKeyInfo; use SpomkyLabs\Pki\CryptoTypes\Asymmetric\PublicKeyInfo; use SpomkyLabs\Pki\CryptoTypes\Signature\Signature; use UnexpectedValueException; /** * Crypto engine using OpenSSL extension. */ final class OpenSSLCrypto extends Crypto { /** * Mapping from algorithm OID to OpenSSL signature method identifier. * * @internal * * @var array<string, int> */ private const MAP_DIGEST_OID = [ AlgorithmIdentifier::OID_MD4_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_MD4, AlgorithmIdentifier::OID_MD5_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_MD5, AlgorithmIdentifier::OID_SHA1_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA1, AlgorithmIdentifier::OID_SHA224_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA224, AlgorithmIdentifier::OID_SHA256_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA256, AlgorithmIdentifier::OID_SHA384_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA384, AlgorithmIdentifier::OID_SHA512_WITH_RSA_ENCRYPTION => OPENSSL_ALGO_SHA512, AlgorithmIdentifier::OID_ECDSA_WITH_SHA1 => OPENSSL_ALGO_SHA1, AlgorithmIdentifier::OID_ECDSA_WITH_SHA224 => OPENSSL_ALGO_SHA224, AlgorithmIdentifier::OID_ECDSA_WITH_SHA256 => OPENSSL_ALGO_SHA256, AlgorithmIdentifier::OID_ECDSA_WITH_SHA384 => OPENSSL_ALGO_SHA384, AlgorithmIdentifier::OID_ECDSA_WITH_SHA512 => OPENSSL_ALGO_SHA512, ]; /** * Mapping from algorithm OID to OpenSSL cipher method name. * * @internal * * @var array<string, string> */ private const MAP_CIPHER_OID = [ AlgorithmIdentifier::OID_DES_CBC => 'des-cbc', AlgorithmIdentifier::OID_DES_EDE3_CBC => 'des-ede3-cbc', AlgorithmIdentifier::OID_AES_128_CBC => 'aes-128-cbc', AlgorithmIdentifier::OID_AES_192_CBC => 'aes-192-cbc', AlgorithmIdentifier::OID_AES_256_CBC => 'aes-256-cbc', ]; public function sign( string $data, PrivateKeyInfo $privkey_info, SignatureAlgorithmIdentifier $algo ): Signature { $this->_checkSignatureAlgoAndKey($algo, $privkey_info->algorithmIdentifier()); $result = openssl_sign($data, $signature, (string) $privkey_info->toPEM(), $this->_algoToDigest($algo)); if ($result === false) { throw new RuntimeException('openssl_sign() failed: ' . $this->_getLastError()); } return Signature::fromSignatureData($signature, $algo); } public function verify( string $data, Signature $signature, PublicKeyInfo $pubkey_info, SignatureAlgorithmIdentifier $algo ): bool { $this->_checkSignatureAlgoAndKey($algo, $pubkey_info->algorithmIdentifier()); $result = openssl_verify( $data, $signature->bitString() ->string(), (string) $pubkey_info->toPEM(), $this->_algoToDigest($algo) ); if ($result === -1) { throw new RuntimeException('openssl_verify() failed: ' . $this->_getLastError()); } return $result === 1; } public function encrypt(string $data, string $key, CipherAlgorithmIdentifier $algo): string { $this->_checkCipherKeySize($algo, $key); $iv = $algo->initializationVector(); $result = openssl_encrypt( $data, $this->_algoToCipher($algo), $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv ); if ($result === false) { throw new RuntimeException('openssl_encrypt() failed: ' . $this->_getLastError()); } return $result; } public function decrypt(string $data, string $key, CipherAlgorithmIdentifier $algo): string { $this->_checkCipherKeySize($algo, $key); $iv = $algo->initializationVector(); $result = openssl_decrypt( $data, $this->_algoToCipher($algo), $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv ); if ($result === false) { throw new RuntimeException('openssl_decrypt() failed: ' . $this->_getLastError()); } return $result; } /** * Validate cipher algorithm key size. */ protected function _checkCipherKeySize(CipherAlgorithmIdentifier $algo, string $key): void { if ($algo instanceof BlockCipherAlgorithmIdentifier) { if (mb_strlen($key, '8bit') !== $algo->keySize()) { throw new UnexpectedValueException( sprintf( 'Key length for %s must be %d, %d given.', $algo->name(), $algo->keySize(), mb_strlen($key, '8bit') ) ); } } } /** * Get last OpenSSL error message. */ protected function _getLastError(): ?string { // pump error message queue $msg = null; while (false !== ($err = openssl_error_string())) { $msg = $err; } return $msg; } /** * Check that given signature algorithm supports key of given type. * * @param SignatureAlgorithmIdentifier $sig_algo Signature algorithm * @param AlgorithmIdentifier $key_algo Key algorithm */ protected function _checkSignatureAlgoAndKey( SignatureAlgorithmIdentifier $sig_algo, AlgorithmIdentifier $key_algo ): void { if (! $sig_algo->supportsKeyAlgorithm($key_algo)) { throw new UnexpectedValueException( sprintf( 'Signature algorithm %s does not support key algorithm %s.', $sig_algo->name(), $key_algo->name() ) ); } } /** * Get OpenSSL digest method for given signature algorithm identifier. */ protected function _algoToDigest(SignatureAlgorithmIdentifier $algo): int { $oid = $algo->oid(); if (! array_key_exists($oid, self::MAP_DIGEST_OID)) { throw new UnexpectedValueException(sprintf('Digest method %s not supported.', $algo->name())); } return self::MAP_DIGEST_OID[$oid]; } /** * Get OpenSSL cipher method for given cipher algorithm identifier. */ protected function _algoToCipher(CipherAlgorithmIdentifier $algo): string { $oid = $algo->oid(); if (array_key_exists($oid, self::MAP_CIPHER_OID)) { return self::MAP_CIPHER_OID[$oid]; } if ($oid === AlgorithmIdentifier::OID_RC2_CBC) { if (! $algo instanceof RC2CBCAlgorithmIdentifier) { throw new UnexpectedValueException('Not an RC2-CBC algorithm.'); } return $this->_rc2AlgoToCipher($algo); } throw new UnexpectedValueException(sprintf('Cipher method %s not supported.', $algo->name())); } /** * Get OpenSSL cipher method for given RC2 algorithm identifier. */ protected function _rc2AlgoToCipher(RC2CBCAlgorithmIdentifier $algo): string { return match ($algo->effectiveKeyBits()) { 128 => 'rc2-cbc', 64 => 'rc2-64-cbc', 40 => 'rc2-40-cbc', default => throw new UnexpectedValueException($algo->effectiveKeyBits() . ' bit RC2 not supported.'), }; } }