From acf57c6cc37d4965e1e983a288bc25b44a38fff9 Mon Sep 17 00:00:00 2001 From: fernando Date: Thu, 18 Jul 2024 14:52:11 +1000 Subject: [PATCH] feat: phpcbf only v3 bringing gree/jose package within HW sdk --- .../Util/HyperwalletEncryption.php | 120 ++++++------- src/Services/Jose/JOSE_JWE.php | 12 +- src/Services/Jose/JOSE_JWK.php | 63 ++++--- src/Services/Jose/JOSE_JWS.php | 6 +- src/Services/Jose/JOSE_JWT.php | 2 - src/Services/Jose/URLSafeBase64.php | 158 +----------------- 6 files changed, 120 insertions(+), 241 deletions(-) diff --git a/src/Hyperwallet/Util/HyperwalletEncryption.php b/src/Hyperwallet/Util/HyperwalletEncryption.php index c8f658a..f0ed2ee 100644 --- a/src/Hyperwallet/Util/HyperwalletEncryption.php +++ b/src/Hyperwallet/Util/HyperwalletEncryption.php @@ -1,4 +1,5 @@ clientPrivateKeySetLocation = $clientPrivateKeySetLocation; $this->hyperwalletKeySetLocation = $hyperwalletKeySetLocation; $this->encryptionAlgorithm = $encryptionAlgorithm; @@ -103,10 +110,9 @@ public function __construct($clientPrivateKeySetLocation, $hyperwalletKeySetLoca * * @throws HyperwalletException */ - public function encrypt($body) { + public function encrypt($body) + { $privateJwsKey = $this->getPrivateJwsKey(); - var_dump($privateJwsKey); - exit; $jws = new JOSE_JWS(new JOSE_JWT($body)); $jws->header['exp'] = $this->getSignatureExpirationTime(); $jws->header['kid'] = $this->jwsKid; @@ -127,7 +133,8 @@ public function encrypt($body) { * * @throws HyperwalletException */ - public function decrypt($body) { + public function decrypt($body) + { $privateJweKey = $this->getPrivateJweKey(); $jwe = JOSE_JWT::decode($body); $decryptedBody = $jwe->decrypt($privateJweKey); @@ -146,7 +153,8 @@ public function decrypt($body) { * * @throws HyperwalletException */ - private function getPrivateJwsKey() { + private function getPrivateJwsKey() + { $privateKeyData = $this->getJwk($this->clientPrivateKeySetLocation, $this->signAlgorithm); $this->jwsKid = $privateKeyData['kid']; return $this->getPrivateKey($privateKeyData); @@ -159,7 +167,8 @@ private function getPrivateJwsKey() { * * @throws HyperwalletException */ - private function getPublicJweKey() { + private function getPublicJweKey() + { $publicKeyData = $this->getJwk($this->hyperwalletKeySetLocation, $this->encryptionAlgorithm); $this->jweKid = $publicKeyData['kid']; return $this->getPublicKey($this->convertPrivateKeyToPublic($publicKeyData)); @@ -172,7 +181,8 @@ private function getPublicJweKey() { * * @throws HyperwalletException */ - private function getPrivateJweKey() { + private function getPrivateJweKey() + { $privateKeyData = $this->getJwk($this->clientPrivateKeySetLocation, $this->encryptionAlgorithm); return $this->getPrivateKey($privateKeyData); } @@ -184,7 +194,8 @@ private function getPrivateJweKey() { * * @throws HyperwalletException */ - private function getPublicJwsKey() { + private function getPublicJwsKey() + { $publicKeyData = $this->getJwk($this->hyperwalletKeySetLocation, $this->signAlgorithm); return $this->getPublicKey($this->convertPrivateKeyToPublic($publicKeyData)); } @@ -195,32 +206,24 @@ private function getPublicJwsKey() { * @param array $privateKeyData The JWK key data * @return RSA */ - private function getPrivateKey($privateKeyData) { - var_dump($privateKeyData); - $n = $this->keyParamToBigInteger($privateKeyData['n']); - $e = $this->keyParamToBigInteger($privateKeyData['e']); - $d = $this->keyParamToBigInteger($privateKeyData['d']); - $p = $this->keyParamToBigInteger($privateKeyData['p']); - $q = $this->keyParamToBigInteger($privateKeyData['q']); - $qi = $this->keyParamToBigInteger($privateKeyData['qi']); - $dp = $this->keyParamToBigInteger($privateKeyData['dp']); - $dq = $this->keyParamToBigInteger($privateKeyData['dq']); - $primes = array($p, $q); - $exponents = array($dp, $dq); - $coefficients = array($qi, $qi); - array_unshift($primes, "phoney"); - unset($primes[0]); - array_unshift($exponents, "phoney"); - unset($exponents[0]); - array_unshift($coefficients, "phoney"); - unset($coefficients[0]); + private function getPrivateKey($privateKeyData) + { + $pemData = RSA::load([ + 'e' => $this->keyParamToBigInteger($privateKeyData['e']), + 'n' => $this->keyParamToBigInteger($privateKeyData['n']), + 'd' => $this->keyParamToBigInteger($privateKeyData['d']), + 'p' => $this->keyParamToBigInteger($privateKeyData['p']), + 'q' => $this->keyParamToBigInteger($privateKeyData['q']), + 'dp' => $this->keyParamToBigInteger($privateKeyData['dp']), + 'dq' => $this->keyParamToBigInteger($privateKeyData['dq']), + 'qi' => $this->keyParamToBigInteger($privateKeyData['qi']), + ]); + + $privateKey = RSA::loadPrivateKey($pemData->toString('PKCS1')); - $pemData = (new RSA())->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients); - $privateKey = new RSA(); - $privateKey->loadKey($pemData); if ($privateKeyData['alg'] == 'RSA-OAEP-256') { - $privateKey->setHash('sha256'); - $privateKey->setMGFHash('sha256'); +// $privateKey->setHash('sha256'); +// $privateKey->setMGFHash('sha256'); } return $privateKey; } @@ -231,10 +234,8 @@ private function getPrivateKey($privateKeyData) { * @param string $param base 64 encoded string * @return BigInteger */ - private function keyParamToBigInteger($param) { - var_dump(URLSafeBase64::decode($param)); - exit; - + private function keyParamToBigInteger($param) + { return new BigInteger('0x' . bin2hex(URLSafeBase64::decode($param)), 16); } @@ -244,12 +245,13 @@ private function keyParamToBigInteger($param) { * @param array $publicKeyData The JWK key data * @return RSA */ - private function getPublicKey($publicKeyData) { + private function getPublicKey($publicKeyData) + { $publicKeyRaw = new JOSE_JWK($publicKeyData); $publicKey = $publicKeyRaw->toKey(); if ($publicKeyData['alg'] == 'RSA-OAEP-256') { - $publicKey->setHash('sha256'); - $publicKey->setMGFHash('sha256'); +// $publicKey->setHash('sha256'); +// $publicKey->setMGFHash('sha256'); } return $publicKey; } @@ -263,8 +265,9 @@ private function getPublicKey($publicKeyData) { * * @throws HyperwalletException */ - private function getJwk($keySetLocation, $alg) { - if (filter_var($keySetLocation, FILTER_VALIDATE_URL) === FALSE) { + private function getJwk($keySetLocation, $alg) + { + if (filter_var($keySetLocation, FILTER_VALIDATE_URL) === false) { if (!file_exists($keySetLocation)) { throw new HyperwalletException("Wrong JWK key set location path = " . $keySetLocation); } @@ -281,8 +284,9 @@ private function getJwk($keySetLocation, $alg) { * * @throws HyperwalletException */ - private function findJwkByAlgorithm($jwkSetArray, $alg) { - foreach($jwkSetArray['keys'] as $jwk) { + private function findJwkByAlgorithm($jwkSetArray, $alg) + { + foreach ($jwkSetArray['keys'] as $jwk) { if ($alg == $jwk['alg']) { return $jwk; } @@ -296,7 +300,8 @@ private function findJwkByAlgorithm($jwkSetArray, $alg) { * @param string $jwk JWK key * @return array */ - private function convertPrivateKeyToPublic($jwk) { + private function convertPrivateKeyToPublic($jwk) + { if (isset($jwk['d'])) { unset($jwk['d']); } @@ -323,7 +328,8 @@ private function convertPrivateKeyToPublic($jwk) { * * @return integer */ - private function getSignatureExpirationTime() { + private function getSignatureExpirationTime() + { date_default_timezone_set("UTC"); $secondsInMinute = 60; return time() + $this->jwsExpirationMinutes * $secondsInMinute; @@ -336,15 +342,16 @@ private function getSignatureExpirationTime() { * * @throws HyperwalletException */ - public function checkJwsExpiration($header) { - if(!isset($header['exp'])) { + public function checkJwsExpiration($header) + { + if (!isset($header['exp'])) { throw new HyperwalletException('While trying to verify JWS signature no [exp] header is found'); } $exp = $header['exp']; - if(!is_numeric($exp)) { + if (!is_numeric($exp)) { throw new HyperwalletException('Wrong value in [exp] header of JWS signature, must be integer'); } - if((int)time() > (int)$exp) { + if ((int)time() > (int)$exp) { throw new HyperwalletException('JWS signature has expired, checked by [exp] JWS header'); } } @@ -356,10 +363,11 @@ public function checkJwsExpiration($header) { * * @throws HyperwalletException */ - public function getVendorPath() { + public function getVendorPath() + { $reflector = new \ReflectionClass(ClassLoader::class); - $vendorPath = preg_replace('/^(.*)\/composer\/ClassLoader\.php$/', '$1', $reflector->getFileName() ); - if($vendorPath && is_dir($vendorPath)) { + $vendorPath = preg_replace('/^(.*)\/composer\/ClassLoader\.php$/', '$1', $reflector->getFileName()); + if ($vendorPath && is_dir($vendorPath)) { return $vendorPath . '/'; } throw new HyperwalletException('Failed to find a vendor path'); diff --git a/src/Services/Jose/JOSE_JWE.php b/src/Services/Jose/JOSE_JWE.php index 2447501..11b3f03 100644 --- a/src/Services/Jose/JOSE_JWE.php +++ b/src/Services/Jose/JOSE_JWE.php @@ -82,10 +82,8 @@ private function rsa($public_or_private_key, $padding_mode) { } else if ($public_or_private_key instanceof RSA) { $rsa = $public_or_private_key; } else { - $rsa = new RSA(); - $rsa->loadKey($public_or_private_key); + } - $rsa->setEncryptionMode($padding_mode); return $rsa; } @@ -96,7 +94,7 @@ private function cipher() { throw new UnexpectedAlgorithm('Algorithm not supported'); case 'A128CBC-HS256': case 'A256CBC-HS512': - $cipher = new AES(AES::MODE_CBC); + $cipher = new AES('cbc'); break; default: throw new UnexpectedAlgorithm('Unknown algorithm'); @@ -108,7 +106,7 @@ private function cipher() { break; case 'A256GCM': case 'A256CBC-HS512': - $cipher->setBlockLength(256); +// $cipher->setBlockLength(256); break; default: throw new UnexpectedAlgorithm('Unknown algorithm'); @@ -128,7 +126,7 @@ private function generateIv() { break; case 'A256GCM': case 'A256CBC-HS512': - $this->iv = $this->generateRandomBytes(256 / 8); + $this->iv = $this->generateRandomBytes(128 / 8); break; default: throw new UnexpectedAlgorithm('Unknown algorithm'); @@ -161,6 +159,7 @@ private function encryptContentEncryptionKey($public_key_or_secret) { $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); break; case 'RSA-OAEP': + case 'RSA-OAEP-256': $rsa = $this->rsa($public_key_or_secret, RSA::ENCRYPTION_OAEP); $this->jwe_encrypted_key = $rsa->encrypt($this->content_encryption_key); break; @@ -189,6 +188,7 @@ private function decryptContentEncryptionKey($private_key_or_secret) { $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_PKCS1); $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); break; + case 'RSA-OAEP-256': case 'RSA-OAEP': $rsa = $this->rsa($private_key_or_secret, RSA::ENCRYPTION_OAEP); $this->content_encryption_key = $rsa->decrypt($this->jwe_encrypted_key); diff --git a/src/Services/Jose/JOSE_JWK.php b/src/Services/Jose/JOSE_JWK.php index e9914d0..0bd3d99 100644 --- a/src/Services/Jose/JOSE_JWK.php +++ b/src/Services/Jose/JOSE_JWK.php @@ -5,14 +5,17 @@ use phpseclib3\Crypt\RSA; use phpseclib3\Math\BigInteger; use phpseclib3\Crypt\Hash; +use Services\Jose\Exception\InvalidFormat; use Services\Jose\Exception\UnexpectedAlgorithm; -class JOSE_JWK { +class JOSE_JWK +{ var $components = array(); - function __construct($components = array()) { + function __construct($components = array()) + { if (!array_key_exists('kty', $components)) { - throw new JOSE_Exception_InvalidFormat('"kty" is required'); + throw new InvalidFormat('"kty" is required'); } $this->components = $components; if (!array_key_exists('kid', $this->components)) { @@ -20,64 +23,77 @@ function __construct($components = array()) { } } - function toKey() { + private function keyParamToBigInteger($param) + { + return new BigInteger('0x' . bin2hex(URLSafeBase64::decode($param)), 16); + } + + function toKey() + { switch ($this->components['kty']) { case 'RSA': - $rsa = new RSA(); - $n = new BigInteger('0x' . bin2hex(JOSE_URLSafeBase64::decode($this->components['n'])), 16); - $e = new BigInteger('0x' . bin2hex(JOSE_URLSafeBase64::decode($this->components['e'])), 16); + $pemData = RSA::load([ + 'e' => $this->keyParamToBigInteger($this->components['e']), + 'n' => $this->keyParamToBigInteger($this->components['n']), + ]); + if (array_key_exists('d', $this->components)) { throw new UnexpectedAlgorithm('RSA private key isn\'t supported'); } else { - $pem_string = $rsa->_convertPublicKey($n, $e); + $pem_string = RSA::loadPublicKey($pemData->toString('PKCS1')); } - $rsa->loadKey($pem_string); - return $rsa; + return RSA::load($pem_string); default: throw new UnexpectedAlgorithm('Unknown key type'); } } - function thumbprint($hash_algorithm = 'sha256') { + function thumbprint($hash_algorithm = 'sha256') + { $hash = new Hash($hash_algorithm); - return JOSE_URLSafeBase64::encode( + return URLSafeBase64::encode( $hash->hash( json_encode($this->normalized()) ) ); } - private function normalized() { + private function normalized() + { switch ($this->components['kty']) { case 'RSA': return array( - 'e' => $this->components['e'], + 'e' => $this->components['e'], 'kty' => $this->components['kty'], - 'n' => $this->components['n'] + 'n' => $this->components['n'] ); default: throw new UnexpectedAlgorithm('Unknown key type'); } } - function toString() { + function toString() + { return json_encode($this->components); } - function __toString() { + + function __toString() + { return $this->toString(); } - static function encode($key, $extra_components = array()) { - switch(get_class($key)) { + static function encode($key, $extra_components = array()) + { + switch (get_class($key)) { case 'phpseclib\Crypt\RSA': $components = array( 'kty' => 'RSA', - 'e' => JOSE_URLSafeBase64::encode($key->publicExponent->toBytes()), - 'n' => JOSE_URLSafeBase64::encode($key->modulus->toBytes()) + 'e' => URLSafeBase64::encode($key->publicExponent->toBytes()), + 'n' => URLSafeBase64::encode($key->modulus->toBytes()) ); if ($key->exponent != $key->publicExponent) { $components = array_merge($components, array( - 'd' => JOSE_URLSafeBase64::encode($key->exponent->toBytes()) + 'd' => URLSafeBase64::encode($key->exponent->toBytes()) )); } return new self(array_merge($components, $extra_components)); @@ -86,7 +102,8 @@ static function encode($key, $extra_components = array()) { } } - static function decode($components) { + static function decode($components) + { $jwk = new self($components); return $jwk->toKey(); } diff --git a/src/Services/Jose/JOSE_JWS.php b/src/Services/Jose/JOSE_JWS.php index c77c2fc..401265f 100644 --- a/src/Services/Jose/JOSE_JWS.php +++ b/src/Services/Jose/JOSE_JWS.php @@ -63,12 +63,8 @@ private function rsa($public_or_private_key, $padding_mode) { } else if ($public_or_private_key instanceof RSA) { $rsa = $public_or_private_key; } else { - $rsa = new RSA(); - $rsa->loadKey($public_or_private_key); + $rsa = RSA::loadPrivateKey($public_or_private_key); } - $rsa->setHash($this->digest()); - $rsa->setMGFHash($this->digest()); - $rsa->setSignatureMode($padding_mode); return $rsa; } diff --git a/src/Services/Jose/JOSE_JWT.php b/src/Services/Jose/JOSE_JWT.php index 9a3acb6..3a21eef 100644 --- a/src/Services/Jose/JOSE_JWT.php +++ b/src/Services/Jose/JOSE_JWT.php @@ -53,8 +53,6 @@ static function encode($claims) { static function decode($jwt_string) { $segments = explode('.', $jwt_string); - var_dump($jwt_string); - exit; switch (count($segments)) { case 3: $jwt = new self(); diff --git a/src/Services/Jose/URLSafeBase64.php b/src/Services/Jose/URLSafeBase64.php index aef6237..8c365a6 100644 --- a/src/Services/Jose/URLSafeBase64.php +++ b/src/Services/Jose/URLSafeBase64.php @@ -2,157 +2,17 @@ namespace Services\Jose; -use phpseclib3\Crypt\RSA; -use Services\Jose\Exception\UnexpectedAlgorithm; -use Services\Jose\Exception\VerificationFailed; - -class URLSafeBase64 extends JOSE_JWT { - function __construct($jwt) { - $this->header = $jwt->header; - $this->claims = $jwt->claims; - $this->signature = $jwt->signature; - $this->raw = $jwt->raw; - } - - function toJson($syntax = 'flattened') { - if ($syntax == 'flattened') { - $components = array( - 'protected' => $this->compact((object) $this->header), - 'payload' => $this->compact((object) $this->claims), - 'signature' => $this->compact($this->signature) - ); - } else { - $components = array( - 'payload' => $this->compact((object) $this->claims), - 'signatures' => array( - 'protected' => $this->compact((object) $this->header), - 'signature' => $this->compact($this->signature) - ) - ); - } - return json_encode($components); - } - - function sign($private_key_or_secret, $algorithm = 'HS256') { - $this->header['alg'] = $algorithm; - if ( - $private_key_or_secret instanceof JOSE_JWK && - !array_key_exists('kid', $this->header) && - array_key_exists('kid', $private_key_or_secret->components) - ) { - $this->header['kid'] = $private_key_or_secret->components['kid']; - } - $this->signature = $this->_sign($private_key_or_secret); - if (!$this->signature) { - throw new Exception('Signing failed because of unknown reason'); - } - return $this; - } - - function verify($public_key_or_secret, $alg = null) { - if ($this->_verify($public_key_or_secret, $alg)) { - return $this; - } else { - throw new VerificationFailed('Signature verification failed'); - } +class URLSafeBase64 { + static function encode($input) { + return str_replace('=', '', strtr(base64_encode($input), '+/', '-_')); } - private function rsa($public_or_private_key, $padding_mode) { - if ($public_or_private_key instanceof JOSE_JWK) { - $rsa = $public_or_private_key->toKey(); - } else if ($public_or_private_key instanceof RSA) { - $rsa = $public_or_private_key; - } else { - $rsa = new RSA(); - $rsa->loadKey($public_or_private_key); - } - $rsa->setHash($this->digest()); - $rsa->setMGFHash($this->digest()); - $rsa->setSignatureMode($padding_mode); - return $rsa; - } - - private function digest() { - switch ($this->header['alg']) { - case 'HS256': - case 'RS256': - case 'ES256': - case 'PS256': - return 'sha256'; - case 'HS384': - case 'RS384': - case 'ES384': - case 'PS384': - return 'sha384'; - case 'HS512': - case 'RS512': - case 'ES512': - case 'PS512': - return 'sha512'; - default: - throw new UnexpectedAlgorithm('Unknown algorithm'); - } - } - - private function _sign($private_key_or_secret) { - $signature_base_string = implode('.', array( - $this->compact((object) $this->header), - $this->compact((object) $this->claims) - )); - switch ($this->header['alg']) { - case 'HS256': - case 'HS384': - case 'HS512': - return hash_hmac($this->digest(), $signature_base_string, $private_key_or_secret, true); - case 'RS256': - case 'RS384': - case 'RS512': - return $this->rsa($private_key_or_secret, RSA::SIGNATURE_PKCS1)->sign($signature_base_string); - case 'ES256': - case 'ES384': - case 'ES512': - throw new UnexpectedAlgorithm('Algorithm not supported'); - case 'PS256': - case 'PS384': - case 'PS512': - return $this->rsa($private_key_or_secret, RSA::SIGNATURE_PSS)->sign($signature_base_string); - default: - throw new UnexpectedAlgorithm('Unknown algorithm'); - } - } - - private function _verify($public_key_or_secret, $expected_alg = null) { - $segments = explode('.', $this->raw); - $signature_base_string = implode('.', array($segments[0], $segments[1])); - if (!$expected_alg) { - $expected_alg = $this->header['alg']; - $using_autodetected_alg = true; - } - switch ($expected_alg) { - case 'HS256': - case 'HS384': - case 'HS512': - if (isset($using_autodetected_alg)) { - throw new UnexpectedAlgorithm( - 'HMAC algs MUST be explicitly specified as $expected_alg' - ); - } - $hmac_hash = hash_hmac($this->digest(), $signature_base_string, $public_key_or_secret, true); - return hash_equals($this->signature, $hmac_hash); - case 'RS256': - case 'RS384': - case 'RS512': - return $this->rsa($public_key_or_secret, RSA::SIGNATURE_PKCS1)->verify($signature_base_string, $this->signature); - case 'ES256': - case 'ES384': - case 'ES512': - throw new UnexpectedAlgorithm('Algorithm not supported'); - case 'PS256': - case 'PS384': - case 'PS512': - return $this->rsa($public_key_or_secret, RSA::SIGNATURE_PSS)->verify($signature_base_string, $this->signature); - default: - throw new UnexpectedAlgorithm('Unknown algorithm'); + static function decode($input) { + $remainder = strlen($input) % 4; + if ($remainder) { + $padlen = 4 - $remainder; + $input .= str_repeat('=', $padlen); } + return base64_decode(strtr($input, '-_', '+/')); } }