CryptoJS aes加密的数据包含Salted__ 如何使用php实现
在 PHP 中实现与 OpenSSL 兼容的 AES 加密(含 Salted__ 头),需手动处理盐值生成和密钥派生。以下是完整实现代码及分步说明:
一、加密实现代码
<?php
/**
* AES 加密(兼容 OpenSSL 的 "Salted__" 格式)
* @param string $data 明文数据
* @param string $password 加密密码
* @param string $method 加密算法,如 'AES-256-CBC'
* @return string Base64 编码的加密数据(含 Salted__ 头)
*/
function opensslEncryptWithSalt($data, $password, $method = 'AES-256-CBC') {
// 生成 8 字节随机盐
$salt = openssl_random_pseudo_bytes(8);
// 通过盐和密码派生密钥与 IV
$keyIv = deriveKeyAndIV($password, $salt, $method);
$key = $keyIv['key'];
$iv = $keyIv['iv'];
// 加密数据
$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
// 拼接 Salted__ 头 + 盐 + 密文
$result = "Salted__" . $salt . $encrypted;
// Base64 编码便于传输
return base64_encode($result);
}
/**
* 派生密钥和 IV(模拟 OpenSSL 的 EVP_BytesToKey)
*/
function deriveKeyAndIV($password, $salt, $method) {
$digest = 'md5'; // OpenSSL 默认使用 MD5
$keySize = 32; // AES-256 需要 32 字节密钥
$ivSize = 16; // CBC 模式需要 16 字节 IV
$derived = '';
$data = '';
$length = 0;
while ($length < $keySize + $ivSize) {
$data = $data . $password . $salt;
$md5 = hash($digest, $data, true);
$data = $md5;
$derived .= $md5;
$length += strlen($md5);
}
return [
'key' => substr($derived, 0, $keySize),
'iv' => substr($derived, $keySize, $ivSize)
];
}
二、解密实现代码
<?php
/**
* AES 解密(兼容 OpenSSL 的 "Salted__" 格式)
* @param string $encryptedData Base64 编码的加密数据
* @param string $password 解密密码
* @param string $method 加密算法,如 'AES-256-CBC'
* @return string 解密后的明文
*/
function opensslDecryptWithSalt($encryptedData, $password, $method = 'AES-256-CBC') {
// 解码 Base64
$data = base64_decode($encryptedData);
// 提取盐(前 8 字节,跳过 "Salted__" 头)
$salt = substr($data, 8, 8);
// 提取密文(去除头部的 16 字节:Salted__ + 盐)
$encrypted = substr($data, 16);
// 派生密钥和 IV
$keyIv = deriveKeyAndIV($password, $salt, $method);
$key = $keyIv['key'];
$iv = $keyIv['iv'];
// 解密数据
return openssl_decrypt($encrypted, $method, $key, OPENSSL_RAW_DATA, $iv);
}
三、使用示例
<?php
// 加密示例
$plaintext = "Hello, World!";
$password = "mySecretPassword";
$encrypted = opensslEncryptWithSalt($plaintext, $password);
echo "加密结果: " . $encrypted . "\n";
// 解密示例
$decrypted = opensslDecryptWithSalt($encrypted, $password);
echo "解密结果: " . $decrypted . "\n";
四、核心逻辑说明
1. 盐值生成
使用 openssl_random_pseudo_bytes(8) 生成 8 字节随机盐,确保每次加密结果不同。
2. 密钥派生
通过 EVP_BytesToKey 算法(模拟 OpenSSL 默认行为)派生密钥和 IV:
使用 MD5 哈希(出于兼容性考虑,尽管不够安全)
多次迭代拼接 $password + $salt 生成足够长度的密钥和 IV
3. 数据格式
加密结果格式为:
Base64编码( "Salted__" + 8字节盐 + 密文 )
- 算法兼容性
支持 AES-128-CBC、AES-256-CBC 等常见算法
与 OpenSSL 命令行加密结果互解:
# 加密
openssl enc -aes-256-cbc -pass pass:mySecretPassword -S $(echo -n "SALT_HEX" | xxd -r -p) -a -p
五、注意事项
1. 安全性建议
优先使用更安全的密钥派生方式(如 PBKDF2),但需放弃与 OpenSSL 的兼容性
避免使用弱密码或固定盐值
2. 错误处理
添加异常捕获:
<?php
try {
$encrypted = openssl_encrypt(...);
if ($encrypted === false) {
throw new Exception('加密失败: ' . openssl_error_string());
}
} catch (Exception $e) {
die("错误: " . $e->getMessage());
}
3. 编码格式
明文数据需为二进制格式(若含中文需统一编码,如 UTF-8)
密文通过 Base64 编码避免传输乱码
通过上述代码,可实现与 OpenSSL Salted__ 格式完全兼容的 AES 加密/解密,确保跨平台数据交换的可靠性。