orgNo = $partners['orgNo']; $this->appKey = $partners['appKey']; $this->publicKey = $this->loadPublicKey($partners['publicKey']); $this->platformPrivateKey = $this->loadPlatformPrivateKey(); } protected function loadPlatformPrivateKey() { $config = config('rsa'); $privateKey = file_get_contents($config['private_key_path']); $key = openssl_pkey_get_private($privateKey); if ($key === false) { throw new \Exception('Invalid private key: ' . openssl_error_string()); } return $key; } protected function loadPublicKey($publicKey) { $key = openssl_pkey_get_public($publicKey); if ($key === false) { throw new \Exception('Invalid public key: ' . openssl_error_string()); } return $key; } public function sign($data) { openssl_sign($data, $signature, $this->platformPrivateKey, OPENSSL_ALGO_SHA256); return base64_encode($signature); } public function verifySign($data, $signature) { $decodedSignature = base64_decode($signature); return openssl_verify($data, $decodedSignature, $this->publicKey, OPENSSL_ALGO_SHA256); } public function encryptData($data, $key) { $encryptedData = openssl_encrypt($data, 'AES-256-ECB', $key, OPENSSL_PKCS1_PADDING); return base64_encode($encryptedData); } public function decryptData($data, $key) { $decodedData = base64_decode($data); return openssl_decrypt($decodedData, 'AES-256-ECB', $key, OPENSSL_PKCS1_PADDING); } public function encryptKey($key) { openssl_public_encrypt($key, $encryptedKey, $this->publicKey, OPENSSL_PKCS1_PADDING); return base64_encode($encryptedKey); } public function decryptKey($encryptedKey) { $decodedKey = base64_decode($encryptedKey); if ($decodedKey === false) { throw new \Exception('Base64 decoding failed.'); } $decrypted = ''; $result = openssl_private_decrypt($decodedKey, $decrypted, $this->platformPrivateKey, OPENSSL_PKCS1_PADDING); if ($result === false) { throw new \Exception('Decryption failed: ' . openssl_error_string()); } return $decrypted; } public function generateKey() { return openssl_random_pseudo_bytes(32); } public function prepareRequest($header, $body) { $header = [ 'version' => config('rsa.app_version'), 'appKey' => $this->appKey, 'method' => $header['method'] ?? '', 'requestId' => $this->appKey.$this->generateUniqueString(30), ]; $bodyJson = json_encode($body); $signData = "version={$header['version']}&appKey={$header['appKey']}&method={$header['method']}&requestId={$header['requestId']}&body={$bodyJson}"; $signature = $this->sign($signData); $header['sign'] = $signature; $key = $this->generateKey(); $encryptedBody = $this->encryptData($bodyJson, $key); $encryptedKey = $this->encryptKey($key); return [ 'header' => $header, 'encryptData' => [ 'key' => $encryptedKey, 'data' => $encryptedBody, ], ]; } public function processResponse(array $response, bool $checkSign = true): array { // 1. 检查加密数据是否存在 if (empty($response['encryptData']['key'] ?? '') || empty($response['encryptData']['data'] ?? '')) { return [ 'code' => '04', 'errCode' => '0002', ]; } try { // 2. 解密密钥和数据 $encryptedKey = $response['encryptData']['key']; $encryptedData = $response['encryptData']['data']; $key = $this->decryptKey($encryptedKey); $data = $this->decryptData($encryptedData, $key); $body = json_decode($data, true); if ($body === null) { return [ 'code' => '03', 'errCode' => '0011', ]; } // 3. 验签(可选) if ($checkSign) { $header = $response['header'] ?? []; // 请求头version参数不正确 if(empty($header['version'] ?? '') || $header['version'] != '1.0.0'){ return [ 'code' => '12', 'errCode' => '0003', ]; } // 请求头APPKEY参数不正确 if(empty($header['appkey'] ?? $header['appKey'])){ return [ 'code' => '02', 'errCode' => '0004', ]; } // 请求参数不正确 if(empty($header['method'] ?? '') || empty($header['requestid'] ?? $header['requestId'])){ return [ 'code' => '12', 'errCode' => '0013', ]; } $signData = http_build_query([ 'version' => $header['version'], 'appKey' => $header['appkey'] ?? $header['appKey'], 'method' => $header['method'], 'requestId' => $header['requestid'] ?? $header['requestId'], 'body' => json_encode($body, JSON_UNESCAPED_UNICODE) ]); if (empty($header['sign']) || !$this->verifySign($signData, $header['sign'])) { return [ 'code' => '05', 'errCode' => '0006', ]; } } // 4. 成功返回 return [ 'code' => '00', 'data' => $body ]; } catch (\Throwable $e) { return [ 'code' => '99', 'errCode' => '0007', 'errMessage' => $e->getMessage() ?: '', ]; } } /** * 生成唯一字符串 * * @param int $length 字符串长度,不能超过128 * @return string 生成的唯一字符串 */ public function generateUniqueString($length = 100) { // 确保长度不超过100 if ($length > 100) { $length = 100; } // 生成基于时间的唯一ID $uniqueId = uniqid('', true); // 可选字符集,可以根据需要修改 $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; // 使用时间戳的微秒部分增加随机性 $microtime = microtime(); $randomSeed = substr($microtime, strpos($microtime, ' ') + 1); // 将随机种子转换为整数 $seed = crc32($randomSeed); // 设置随机种子 srand($seed); // 生成随机字符串 for ($i = 0; $i < $length - strlen($uniqueId); $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } // 结合唯一ID和随机字符串 $result = substr($uniqueId, 0, $length - strlen($randomString)) . $randomString; return $result; } }