diff --git a/app/http/middleware/ContextMiddleware.php b/app/http/middleware/ContextMiddleware.php index dc92494..882342e 100644 --- a/app/http/middleware/ContextMiddleware.php +++ b/app/http/middleware/ContextMiddleware.php @@ -160,45 +160,48 @@ class ContextMiddleware extends middleware * @throws ValidateException 解密失败时抛出异常 */ private function decryptCryptoJSData(string $encryptedData): array - {// 1. Base64 解码加密数据 - $encrypted = base64_decode($encryptedData); + { + // Base64解码 + $data = base64_decode($encryptedData); - // 2. 提取初始化向量 (IV) - 前16字节 - if (strlen($encrypted) < 16) { - throw new ValidateException('加密数据太短,无法提取IV'); + // 检查Salted__头 + if (!str_starts_with($data, "Salted__")) { + throw new ValidateException('Invalid format: missing "Salted__" header'); } - $iv = substr($encrypted, 0, 16); - $ciphertext = substr($encrypted, 16); + // 提取Salt (8字节) + $salt = substr($data, 8, 8); + $ct = substr($data, 16); - // 3. 准备解密密钥 - // CryptoJS 使用密钥派生函数,这里使用简单的 SHA256 哈希 - $key = substr(hash('sha256', self::DATA_SECRET_KEY, true), 0, 32); + // 通过EVP_BytesToKey派生密钥和IV + $keyIv = $this->evpBytesToKey($salt); + $key = $keyIv['key']; + $iv = $keyIv['iv']; - // 4. 使用 AES-256-CBC 解密 + // AES-256-CBC解密 $decrypted = openssl_decrypt( - $ciphertext, - 'AES-256-CBC', + $ct, + 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv ); + return json_decode($decrypted, true); + } - if ($decrypted === false) { - throw new ValidateException('解密失败: ' . openssl_error_string()); + private function evpBytesToKey($salt): array + { + $password = self::DATA_SECRET_KEY; + $bytes = ''; + $last = ''; + // 生成48字节:32字节key + 16字节IV + while(strlen($bytes) < 48) { + $last = md5($last . $password . $salt, true); + $bytes .= $last; } - - // 5. 移除 PKCS#7 填充 - $padding = ord($decrypted[strlen($decrypted) - 1]); - $decrypted = substr($decrypted, 0, -$padding); - - // 6. 解析为 JSON - $data = json_decode($decrypted, true); - - if (json_last_error() !== JSON_ERROR_NONE) { - throw new ValidateException('JSON 解析失败: ' . json_last_error_msg()); - } - - return $data; + return [ + 'key' => substr($bytes, 0, 32), + 'iv' => substr($bytes, 32, 16) + ]; } } \ No newline at end of file