使用CryptoSwift将AES-256-CBC的PHP代码转Swift后结果不匹配
解决CryptoSwift与PHP AES-256-CBC加密结果不匹配的问题
你的问题核心在于Swift代码没有完全复刻PHP的加密流程,尤其是密钥和IV的生成逻辑——PHP中使用的是哈希结果的十六进制字符串,而你在Swift中直接用了哈希的二进制数据转UTF-8字符串,这导致两者的密钥/IV字节完全不一致。以下是修正后的代码和详细解释:
修正后的Swift代码
首先需要添加几个工具方法来处理哈希和十六进制转换,然后严格按照PHP的流程实现:
import CryptoSwift extension String { // 计算字符串的SHA1小写十六进制结果(和PHP sha1()行为一致) func sha1Hex() -> String { guard let data = self.data(using: .utf8) else { return "" } let digest = SHA1.hash(data: data) return digest.map { String(format: "%02x", $0) }.joined() } // 计算字符串的SHA256小写十六进制结果(和PHP hash('sha256', ...)行为一致) func sha256Hex() -> String { guard let data = self.data(using: .utf8) else { return "" } let digest = SHA256.hash(data: data) return digest.map { String(format: "%02x", $0) }.joined() } } func encryptString() -> String? { let plaintext = "MyStringToEncrypt" let originalSecretKey = "MySecretKey" let originalSecretIV = "MySecretIV" // 1. 复刻PHP的密钥生成流程 let secretKeyHex = originalSecretKey.sha1Hex() let keyHex = secretKeyHex.sha256Hex() // 将64位十六进制字符串转成UTF-8字节,取前32字节(AES-256需要32字节密钥,和openssl截断逻辑一致) guard let keyData = keyHex.data(using: .utf8), keyData.count >= 32 else { print("密钥生成失败") return nil } let key = Array(keyData.prefix(32)) // 2. 复刻PHP的IV生成流程 let secretIVHex = originalSecretIV.sha1Hex() let ivFullHex = secretIVHex.sha256Hex() // 取十六进制字符串前16个字符,转成UTF-8字节(正好16字节,符合CBC要求) let ivHexPrefix = String(ivFullHex.prefix(16)) guard let ivData = ivHexPrefix.data(using: .utf8), ivData.count == 16 else { print("IV生成失败") return nil } let iv = Array(ivData) // 3. 处理明文 guard let plaintextData = plaintext.data(using: .utf8) else { print("明文转Data失败") return nil } let plaintextBytes = Array(plaintextData) // 4. AES-256-CBC加密(使用PKCS7填充,和PHP默认行为一致) do { let aes = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7) let encryptedBytes = try aes.encrypt(plaintextBytes) // 转成Base64字符串 let encryptedData = Data(encryptedBytes) return encryptedData.base64EncodedString() } catch { print("加密错误: \(error)") return nil } } // 调用测试 if let result = encryptString() { print("加密结果: \(result)") }
错误原因分析
对比你的原始Swift代码和PHP流程,核心差异点:
- 哈希结果的处理:PHP的
sha1()和hash('sha256', ...)返回的是小写十六进制字符串,而你之前的Swift代码直接使用了哈希的二进制Data转UTF-8字符串,这导致两者的中间值完全不同。 - 密钥截断逻辑:PHP中
$key是64位十六进制字符串(UTF-8转成64字节),openssl会自动截断前32字节作为AES-256密钥;你之前的Swift代码错误地截取了SHA256二进制Data的前32字节转字符串,和PHP的密钥字节完全不匹配。 - IV生成逻辑:PHP是取SHA256十六进制字符串的前16个字符转UTF-8字节作为IV,而你之前的Swift代码取的是SHA256二进制Data的前16字节转字符串,两者的IV字节不一致。
- 填充方式:CryptoSwift默认的填充方式可能和PHP默认的PKCS7不一致,需要显式指定。
内容的提问来源于stack exchange,提问作者user4296481
相关产品推荐
相关产品推荐

