PHP如何实现带盐PBKDF2withHmacSHA1的AES/CBC/PKCS5Padding解密
PHP AES-256-CBC 基于PBKDF2派生密钥解密失败修复方案
已知加密规则
- 密钥长度:256位
- 加密模式:AES/CBC/PKCS5Padding
- 密钥派生算法:PBKDF2withHmacSHA1
- 密钥派生迭代次数:5000
- 返回数据格式:
iv(初始化向量)、salt(密钥派生盐)、encrypted_data(密文)三个字段均为base64编码
原有代码问题说明
- 填充参数配置错误:代码中使用
OPENSSL_ZERO_PADDING强制零填充,和加密方使用的PKCS5Padding规则不匹配,直接触发「data not multiple of block length」块长度不匹配错误。AES块大小固定为16字节,PKCS5Padding与OpenSSL默认支持的PKCS7Padding逻辑完全兼容,无需手动指定零填充。 - 密文格式参数缺失:代码中已手动将密文做base64解码传入,但未添加
OPENSSL_RAW_DATA参数,OpenSSL会默认将传入值再次做base64解码,导致密文格式损坏。 - 密钥使用逻辑错误:跳过PBKDF2密钥派生步骤、直接将原始密码作为密钥传入的方式完全不符合加密规则,原始密码长度为49字符,和256位(32字节)要求的密钥长度不匹配,必然输出乱码。
正确实现代码
// 持有的原始解密密码 $password = "supersecretkey"; // 所有base64字段解码为原始二进制 $salt = base64_decode($data['salt']); $iv = base64_decode($data['iv']); $ciphertext = base64_decode($data['encrypted_data']); // 按规则派生256位密钥:SHA1算法、5000次迭代、输出32字节原始二进制结果 $key = hash_pbkdf2( "sha1", $password, $salt, 5000, 32, true ); // 解密:传入原始二进制密文,使用默认PKCS填充处理 $plaintext = openssl_decrypt( $ciphertext, "AES-256-CBC", $key, OPENSSL_RAW_DATA, $iv ); // 结果校验 if ($plaintext === false) { echo "解密失败,错误:" . openssl_error_string(); } else { echo "解密结果:" . $plaintext; }
异常排查点
如果上述代码运行仍失败,逐一校验以下项:
- 校验
iv解码后长度:AES-CBC模式初始化向量固定为16字节,长度不符说明拿到的iv字段存在截断或编码错误 - 校验派生密钥长度:通过
strlen($key)输出长度,必须为32字节才能匹配256位密钥要求 - 确认密文完整性:
encrypted_data字段无截断、无转义导致的字符变更,base64解码后长度必须为16的整数倍
内容的提问来源于stack exchange,提问作者chingo81
相关产品推荐
相关产品推荐

