up. 双向数据加密

This commit is contained in:
u2nyakim 2025-08-29 15:49:20 +08:00
parent 7a072e4bec
commit bae500bd2c

View File

@ -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
);
if ($decrypted === false) {
throw new ValidateException('解密失败: ' . openssl_error_string());
return json_decode($decrypted, true);
}
// 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());
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;
}
return $data;
return [
'key' => substr($bytes, 0, 32),
'iv' => substr($bytes, 32, 16)
];
}
}