You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS Swift中AES 128位密文解密问题及崩溃求助

解决Swift中AES-128解密崩溃及跨平台解密问题

首先,你遇到的Unexpectedly found nil while unwrapping an Optional value崩溃,根源是代码里滥用了强制解包!——如果密文是Base64编码,直接用.utf8转换肯定会失败,或者解密后decrypted为nil时,强制解包都会触发崩溃。这是第一个要紧急修复的点。

另外,你提到其他库只能解密同代码加密的内容,核心原因是AES解密必须和加密时使用完全一致的参数,这些参数包括:

  • 密钥派生方式(比如PBKDF2、HKDF,以及对应的哈希算法、迭代次数)
  • AES加密模式(CBC、GCM、ECB等,ECB不推荐但旧系统常用)
  • 填充规则(PKCS7、ZeroPadding等)
  • 初始化向量(IV)的长度和来源(是否和密文拼接传输,或是固定值)
  • 密文的编码格式(Base64或十六进制)

你的密文NilZ9gpu1M3KUnEyN9scllyV3aN7NSSPJXwbOy7qTOk=是Base64编码的,第一步应该先解码成Data,而不是直接转UTF8!

推荐方案:使用Apple原生CryptoKit框架

CryptoKit是Apple官方提供的加密库,稳定可靠,支持跨场景解密。下面是一个基于常见参数的示例(假设加密时用了PBKDF2派生密钥、CBC模式、PKCS7填充,且IV是密文的前16字节):

import CryptoKit

func decryptAES128(ciphertextBase64: String, password: String) throws -> String {
    // 1. 解码Base64密文为Data
    guard let ciphertextData = Data(base64Encoded: ciphertextBase64) else {
        throw NSError(domain: "DecryptError", code: 1, userInfo: [NSLocalizedDescriptionKey: "无效的Base64密文"])
    }
    
    // 2. 分离IV和实际密文(AES-128的IV通常为16字节,需和加密端一致)
    guard ciphertextData.count >= 16 else {
        throw NSError(domain: "DecryptError", code: 2, userInfo: [NSLocalizedDescriptionKey: "密文长度不足"])
    }
    let iv = ciphertextData.prefix(16)
    let actualCiphertext = ciphertextData.dropFirst(16)
    
    // 3. 从密码派生密钥(盐、迭代次数必须和加密端完全一致!)
    // 注意:这里的盐需要替换成加密时使用的真实值,不能随便填写
    guard let salt = "your-encryption-salt".data(using: .utf8) else {
        throw NSError(domain: "DecryptError", code: 3, userInfo: [NSLocalizedDescriptionKey: "盐转换失败"])
    }
    guard let passwordData = password.data(using: .utf8) else {
        throw NSError(domain: "DecryptError", code: 4, userInfo: [NSLocalizedDescriptionKey: "密码转换失败"])
    }
    let derivedKey = try PKCS5.PBKDF2SHA1(
        password: passwordData,
        salt: salt,
        iterations: 10000, // 替换为加密时的迭代次数
        keyLength: 16 // AES-128对应16字节密钥
    ).calculate()
    
    // 4. 执行AES-CBC解密
    let aesKey = SymmetricKey(data: derivedKey)
    let decryptedData = try AES.CBC.decrypt(
        actualCiphertext,
        using: aesKey,
        iv: iv,
        padding: .pkcs7
    )
    
    // 5. 转换为明文字符串
    guard let plaintext = String(data: decryptedData, encoding: .utf8) else {
        throw NSError(domain: "DecryptError", code: 5, userInfo: [NSLocalizedDescriptionKey: "解密数据转字符串失败"])
    }
    return plaintext
}

// 使用示例
do {
    let password = "Q@*Amn!"
    let encrypted = "NilZ9gpu1M3KUnEyN9scllyV3aN7NSSPJXwbOy7qTOk="
    let plaintext = try decryptAES128(ciphertextBase64: encrypted, password: password)
    print("解密结果:\(plaintext)")
} catch {
    print("解密失败:\(error.localizedDescription)")
}

关键注意事项

  1. 严格匹配加密参数:上面的示例是基于通用配置,你必须确认加密端的具体参数(比如盐、迭代次数、AES模式、IV的位置),参数不匹配的话解密必然失败。
  2. 杜绝强制解包:所有可选值都用guard let或if let处理,彻底避免nil解包崩溃。
  3. 如果是GCM模式:CryptoKit同样支持AES-GCM,这种模式会附带认证标签,需要把标签、IV、密文一起处理,代码逻辑会略有调整。

如果不确定加密参数,可以尝试询问提供密文的一方,或者用在线AES解密工具(输入密码和密文,尝试不同参数组合)验证,再将对应参数移植到Swift代码中。

内容的提问来源于stack exchange,提问作者Ashique

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:13:24