laowu 2 dienas atpakaļ
vecāks
revīzija
a37dabfbe9
3 mainītis faili ar 79 papildinājumiem un 12 dzēšanām
  1. 54 11
      app/Services/PayPlus.php
  2. 0 1
      composer.json
  3. 25 0
      tests/Unit/PayPlusServiceTest.php

+ 54 - 11
app/Services/PayPlus.php

@@ -280,22 +280,65 @@ class PayPlus
             throw new Exception('PayPlus public key is empty.');
         }
 
-        if (!class_exists('\phpseclib\Crypt\RSA')) {
-            throw new Exception('phpseclib is required for PayPlus RSA OAEP SHA-512.');
+        $details = $this->getPublicKeyDetails($publicKey);
+        $encoded = $this->oaepSha512Encode((string) $value, strlen($details['n']));
+        $encrypted = '';
+        $success = openssl_public_encrypt(
+            $encoded,
+            $encrypted,
+            $this->normalizePublicKey($publicKey),
+            OPENSSL_NO_PADDING
+        );
+        if (!$success) {
+            throw new Exception('PayPlus RSA encrypt failed.');
         }
 
-        $rsa = new \phpseclib\Crypt\RSA();
-        $rsa->setEncryptionMode(\phpseclib\Crypt\RSA::ENCRYPTION_OAEP);
-        $rsa->setHash('sha512');
-        $rsa->setMGFHash('sha512');
-        $rsa->loadKey($this->normalizePublicKey($publicKey));
+        return base64_encode($encrypted);
+    }
 
-        $encrypted = $rsa->encrypt($value);
-        if ($encrypted === false) {
-            throw new Exception('PayPlus RSA encrypt failed.');
+    protected function getPublicKeyDetails($publicKey)
+    {
+        $resource = openssl_pkey_get_public($this->normalizePublicKey($publicKey));
+        if ($resource === false) {
+            throw new Exception('PayPlus public key is invalid.');
         }
 
-        return base64_encode($encrypted);
+        $details = openssl_pkey_get_details($resource);
+        if (!isset($details['rsa']['n'], $details['rsa']['e'])) {
+            throw new Exception('PayPlus RSA public key details are invalid.');
+        }
+
+        return $details['rsa'];
+    }
+
+    protected function oaepSha512Encode($message, $keyLength)
+    {
+        $hashLength = 64;
+        $messageLength = strlen($message);
+        if ($messageLength > $keyLength - 2 * $hashLength - 2) {
+            throw new Exception('PayPlus RSA message is too long.');
+        }
+
+        $labelHash = hash('sha512', '', true);
+        $padding = str_repeat("\x00", $keyLength - $messageLength - 2 * $hashLength - 2);
+        $dataBlock = $labelHash . $padding . "\x01" . $message;
+        $seed = random_bytes($hashLength);
+        $maskedDataBlock = $dataBlock ^ $this->mgf1Sha512($seed, $keyLength - $hashLength - 1);
+        $maskedSeed = $seed ^ $this->mgf1Sha512($maskedDataBlock, $hashLength);
+
+        return "\x00" . $maskedSeed . $maskedDataBlock;
+    }
+
+    protected function mgf1Sha512($seed, $length)
+    {
+        $mask = '';
+        $counter = 0;
+        while (strlen($mask) < $length) {
+            $mask .= hash('sha512', $seed . pack('N', $counter), true);
+            $counter++;
+        }
+
+        return substr($mask, 0, $length);
     }
 
     protected function buildPayinHeaders()

+ 0 - 1
composer.json

@@ -12,7 +12,6 @@
         "laravel/tinker": "^1.0",
         "longman/telegram-bot": "^0.81.0",
         "maatwebsite/excel": "~2.1.0",
-        "phpseclib/phpseclib": "^2.0",
         "themsaid/laravel-langman": "*",
         "yansongda/laravel-pay": "^2.2"
     },

+ 25 - 0
tests/Unit/PayPlusServiceTest.php

@@ -73,6 +73,31 @@ class PayPlusServiceTest extends TestCase
         $this->assertSame($payload, $decrypted);
     }
 
+    /** @test */
+    public function it_encrypts_payin_payload_with_native_rsa_oaep_sha512()
+    {
+        $service = new PayPlus([
+            'publicKey' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnuDnY8u7a9EvUBAG7jJd'
+                . 'KNkPS2vPpHo/gp7f2TA62cHXRW0AmeqHoWkcW6s8mMyP9EC6zNOcaVbPZrh6o9q0'
+                . 'X06eZadexSK8bBY24c1j+uR1mivRcyB8bPiaNMGLaKKXpkbwttP+No7AOpAkWXx3'
+                . 'pemXJeO8CRZGGRT79gv4v8Sd9KXJvsV4tdOU/RObMBtjtyWnGbNWWkxyJfq/sU4e'
+                . 'DnFUr9J3jc1U6pPty/6ziukt6dMXth5qaod8kf7QMI0gXMlIi9znTLLSsQUzcZA0'
+                . 'pB4/QvEExJxq0mtCtrq80UWITeE0frgbS4djq9XFGU+YlEXEX9DWgby5E9uX05vV'
+                . 'UQIDAQAB',
+        ]);
+
+        $encrypted = $service->encryptPayinPayload([
+            'platform_order_id' => 'P100',
+            'amount' => '10.00',
+        ]);
+
+        $this->assertSame(64, strlen($encrypted['aes_key']));
+        $this->assertSame(24, strlen($encrypted['iv']));
+        $this->assertSame(344, strlen($encrypted['body']['componentX']));
+        $this->assertSame(344, strlen($encrypted['body']['componentY']));
+        $this->assertNotEmpty($encrypted['body']['componentDelta']);
+    }
+
     /** @test */
     public function it_builds_beneficiary_payload_with_safe_defaults()
     {