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

Swift中实现与Java兼容的AES文件加密方案问询

Swift 实现与 Android Java 兼容的 AES 加密(PBKDF2+HMAC-SHA1 密钥派生)

以下是完全匹配你提供的 Java 加密逻辑的 Swift 实现,确保两端加密结果一致,可在 Java 服务器端正常解密:

完整实现代码

首先需要在项目桥接文件(如YourProject-Bridging-Header.h)中添加 CommonCrypto 依赖:

#import <CommonCrypto/CommonCrypto.h>

密钥派生与加密核心函数

import Foundation

/// 基于 PBKDF2+HMAC-SHA1 派生 AES 密钥(对应 Java 的 PBKDF2WithHmacSHA1)
func deriveKey(from password: String, salt: String, iterations: UInt32, keyLength: Int) throws -> Data {
    guard let passwordData = password.data(using: .utf8),
          let saltData = salt.data(using: .utf8) else {
        throw NSError(domain: "EncryptionError", code: -1, userInfo: [NSLocalizedDescriptionKey: "字符串编码失败"])
    }
    
    var derivedKeyData = Data(repeating: 0, count: keyLength)
    
    let status = derivedKeyData.withUnsafeMutableBytes { derivedKeyBytes in
        saltData.withUnsafeBytes { saltBytes in
            passwordData.withUnsafeBytes { passwordBytes in
                CCKeyDerivationPBKDF(
                    CCPBKDFAlgorithm(kCCPBKDF2),
                    passwordBytes.baseAddress, passwordData.count,
                    saltBytes.baseAddress, saltData.count,
                    CCPseudoRandomAlgorithm(kCCPRFHmacAlgSHA1),
                    iterations,
                    derivedKeyBytes.baseAddress, derivedKeyData.count
                )
            }
        }
    }
    
    guard status == kCCSuccess else {
        throw NSError(domain: "EncryptionError", code: Int(status), userInfo: [NSLocalizedDescriptionKey: "密钥派生失败"])
    }
    
    return derivedKeyData
}

/// AES-CBC-PKCS7 加密(对应 Java 的 AES/CBC/PKCS5Padding)
func encryptData(_ data: Data, key: Data, iv: [UInt8]) throws -> Data {
    guard iv.count == kCCBlockSizeAES128 else {
        throw NSError(domain: "EncryptionError", code: -2, userInfo: [NSLocalizedDescriptionKey: "IV 长度必须为16字节"])
    }
    
    let ivData = Data(iv)
    var encryptedData = Data(repeating: 0, count: data.count + kCCBlockSizeAES128)
    var numBytesEncrypted = 0
    
    let status = CCCrypt(
        CCOperation(kCCEncrypt),
        CCAlgorithm(kCCAlgorithmAES),
        CCOptions(kCCOptionPKCS7Padding),
        key.bytes, key.count,
        ivData.bytes,
        data.bytes, data.count,
        encryptedData.mutableBytes, encryptedData.count,
        &numBytesEncrypted
    )
    
    guard status == kCCSuccess else {
        throw NSError(domain: "EncryptionError", code: Int(status), userInfo: [NSLocalizedDescriptionKey: "加密失败"])
    }
    
    encryptedData.removeSubrange(numBytesEncrypted..<encryptedData.count)
    return encryptedData
}

补全文件选择后的加密逻辑

func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
    guard let inputURL = urls.first else { return }
    
    // 输出文件路径:Documents 目录下的 temp.enc
    let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let outputURL = documentDirectory.appendingPathComponent("temp.enc")
    
    // 与 Java 端完全一致的配置参数
    let secretKeyString = "MY_SECRETE_KEY"
    let saltString = "MY_SALT_KEY"
    let iterations: UInt32 = 65536
    let keyLength = 32 // 256位密钥
    let iv: [UInt8] = Array(repeating: 0, count: 16) // 16字节全0 IV
    
    do {
        // 1. 读取选中的文件数据
        let fileData = try Data(contentsOf: inputURL)
        
        // 2. 派生 AES 密钥
        let aesKey = try deriveKey(from: secretKeyString, salt: saltString, iterations: iterations, keyLength: keyLength)
        
        // 3. 执行加密
        let encryptedData = try encryptData(fileData, key: aesKey, iv: iv)
        
        // 4. 写入加密后的文件
        try encryptedData.write(to: outputURL)
        print("加密完成,文件路径:\(outputURL.path)")
    } catch {
        print("加密出错:\(error.localizedDescription)")
    }
}

代码对应关系说明

  1. 密钥派生逻辑

    • Java 中的SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1")和PBEKeySpec,对应 Swift 的CCKeyDerivationPBKDF函数,参数完全匹配:
      • 伪随机算法:kCCPRFHmacAlgSHA1(对应 HmacSHA1)
      • 迭代次数:65536(与 Java 一致)
      • 密钥长度:32字节(256位,对应 Java 的256参数)
      • 编码:密码和盐均使用 UTF-8,与 Java 的getBytes()默认行为保持一致
  2. AES加密逻辑

    • Java 的AES/CBC/PKCS5Padding对应 Swift 配置:
      • 算法:kCCAlgorithmAES(AES)
      • 模式:CBC(CCCrypt 默认模式为 CBC,无需额外指定)
      • 填充:kCCOptionPKCS7Padding(AES 块大小为16字节,PKCS5与PKCS7填充在此场景下等价)
    • IV 使用16字节全0数组,与 Java 的IvParameterSpec完全一致
  3. 文件读写

    • Swift 的Data(contentsOf:)对应 Java 的Files.readAllBytes
    • Swift 的Data.write(to:)对应 Java 的FileOutputStream写入逻辑

注意事项

  • 确保 Android 端的SALT.getBytes()和SECRET_KEY.toCharArray()使用 UTF-8 编码,若 Java 端指定了其他编码,Swift 需同步调整(如.ascii)
  • 实际项目中建议优化错误处理逻辑,避免直接打印错误,可向用户展示友好提示
  • 密钥和盐不应硬编码在代码中,建议通过安全渠道传递

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 21:35:25