2025年3月

在 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. 盐值生成‌

- 阅读剩余部分 -