如何用PHP解密SQL Server加密数据?解密返回bool(false)求助
问题分析与解决方案
你遇到的openssl_decrypt返回bool(false)的问题,核心原因是SQL Server的EncryptByKey加密逻辑与PHP openssl扩展的标准AES加密不兼容,具体问题点如下:
EncryptByKey生成的加密数据包含额外元数据(密钥GUID、版本号等),并非纯AES加密字节流;- 你错误地将对称密钥名称
MySymmetricKey作为加密密钥使用,实际加密的是SQL Server内部生成的对称密钥值,该值无法直接获取; - 随机生成IV不符合SQL Server的加密逻辑,
EncryptByKey的IV已自动嵌入加密数据中,无需手动指定。
以下提供两种可行解决方案:
方案一:SQL Server端解密后返回数据(最简单安全)
直接在SQL查询中完成解密,避免客户端处理复杂的加密格式:
<?php $serverName = "LAPTOP-7A7MOGOK\MSSQLSERVER2"; $connectionInfo = array("Database" => "testen", "UID" => "sa", "PWD" => "04052002"); $conn = sqlsrv_connect($serverName, $connectionInfo); // 先打开对称密钥,再解密数据 $query = " OPEN SYMMETRIC KEY MySymmetricKey DECRYPTION BY PASSWORD = 'MyPassword'; SELECT CAST(DecryptByKey(Sensitive) AS VARCHAR(MAX)) AS DecryptedData FROM MyTable; CLOSE SYMMETRIC KEY MySymmetricKey; "; $result = sqlsrv_prepare($conn, $query); sqlsrv_execute($result); while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) { var_dump($row['DecryptedData']); } sqlsrv_free_stmt($result); sqlsrv_close($conn); ?>
方案二:改用EncryptByPassphrase实现客户端解密
若必须在客户端解密,建议使用EncryptByPassphrase(直接用密码加密,无需对称密钥),其加密格式可在PHP中模拟解析:
修改后的SQL脚本
CREATE DATABASE testen go USE testen go CREATE TABLE MyTable ( Ma INT IDENTITY(1,1) PRIMARY KEY, Sensitive VARBINARY(256) ) -- 使用密码直接加密数据 INSERT INTO MyTable (Sensitive) VALUES (EncryptByPassphrase('MyPassword', 'Sensitive Data')); SELECT * FROM MyTable
PHP解密代码
<?php $serverName = "LAPTOP-7A7MOGOK\MSSQLSERVER2"; $connectionInfo = array("Database" => "testen", "UID" => "sa", "PWD" => "04052002"); $conn = sqlsrv_connect($serverName, $connectionInfo); $query = "SELECT Sensitive FROM MyTable"; $result = sqlsrv_prepare($conn, $query); sqlsrv_execute($result); $password = 'MyPassword'; while ($row = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC)) { $encryptedData = $row['Sensitive']; // 拆分EncryptByPassphrase的加密结构:前16字节是密码SHA-1哈希前缀,中间16字节是IV,剩余是密文 $iv = substr($encryptedData, 16, 16); $ciphertext = substr($encryptedData, 32); // 生成AES-256密钥:对密码做SHA-1哈希后取前32字节 $key = substr(hash('sha1', $password, true), 0, 32); // AES-256-CBC模式解密,去除PKCS7填充 $decryptedData = openssl_decrypt($ciphertext, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv); $padding = ord(substr($decryptedData, -1)); $decryptedData = substr($decryptedData, 0, -$padding); var_dump($decryptedData); } sqlsrv_free_stmt($result); sqlsrv_close($conn); ?>
注:若坚持使用
EncryptByKey实现客户端解密,需先导出SQL Server内部对称密钥的明文(需通过证书等方式,存在安全风险),同时手动解析加密数据中的元数据,步骤复杂且不推荐。
内容的提问来源于stack exchange,提问作者Anh Kiệt Nguyễn
相关产品推荐
相关产品推荐

