使用AES加密数据传输的iOS客户端实现方案

在现代应用开发中,确保数据传输的安全性是至关重要的。本文将介绍如何在iOS客户端中使用AES加密数据传输,并与服务器端保持加密解密的一致性。本文不会包含服务器端代码,但会解释其实现原理。

加密与解密的基本原理

AES(Advanced Encryption Standard)是一种对称加密算法,即加密和解密使用相同的密钥。为了增强安全性,AES通常与CBC(Cipher Block Chaining)模式和随机生成的初始化向量(IV)一起使用。

为什么IV明文传输不会影响安全性?
  1. 防止重复模式:IV确保相同的明文在每次加密时产生不同的密文,从而防止攻击者通过观察加密输出模式来推断输入模式。
  2. 随机性和唯一性:IV的唯一要求是随机性和唯一性,而不需要保密。因此,IV可以以明文形式与加密数据一起传输。
  3. 加密标准:大多数现代加密标准和协议(如AES-CBC、AES-GCM)都规定IV可以以明文形式传输。

客户端实现方案

在iOS客户端中,我们将使用以下步骤来实现AES加密数据传输:

  1. 生成和存储加密密钥:在用户登录成功后,从服务器获取并存储加密密钥。
  2. 加密请求数据:在每次发送请求时,使用AES和随机生成的IV对请求数据进行加密,并将IV与加密数据一起传输。
  3. 解密响应数据:在接收到服务器响应后,使用AES和IV对响应数据进行解密。

以下是实现这些步骤的详细代码。

AES加密解密类

swift 复制代码
import CommonCrypto

class AES {
    // 加密方法
    static func encrypt(data: Data, key: String) -> (Data, Data)? {
        return crypt(data: data, key: key, operation: CCOperation(kCCEncrypt))
    }

    // 解密方法
    static func decrypt(data: Data, key: String, iv: Data) -> Data? {
        return crypt(data: data, key: key, iv: iv, operation: CCOperation(kCCDecrypt)).map { $0.0 }
    }

    /**
     通用加密解密方法
     
     - Parameters:
       - data: 需要加密或解密的数据
       - key: 用于加密或解密的密钥
       - iv: 初始化向量。如果为空,则在加密时生成一个新的IV。在解密时需要传入之前生成的IV。
       - operation: 加密或解密操作(kCCEncrypt 或 kCCDecrypt)
     
     - Returns: 返回一个元组,包含加密或解密后的数据,以及用于加密的IV。如果操作失败,返回nil。
     */
    private static func crypt(data: Data, key: String, iv: Data? = nil, operation: CCOperation) -> (Data, Data)? {
        // 确定AES密钥长度为128位(16字节)
        let keyLength = kCCKeySizeAES128
        var keyBytes = [UInt8](repeating: 0, count: keyLength)
        // 将密钥字符串转换为字节数组,并确保其长度为16字节
        key.getCString(&keyBytes, maxLength: keyLength + 1, encoding: .utf8)
        
        // 初始化向量(IV)的字节数组
        var ivBytes: [UInt8]
        if let iv = iv {
            // 如果传入了IV,使用传入的IV
            ivBytes = [UInt8](iv)
        } else {
            // 如果没有传入IV,在加密时生成一个随机的IV
            let ivSize = kCCBlockSizeAES128
            ivBytes = [UInt8](repeating: 0, count: ivSize)
            _ = SecRandomCopyBytes(kSecRandomDefault, ivSize, &ivBytes)
        }

        // 输入数据的长度
        let dataLength = data.count
        // 输出缓冲区大小应为数据长度加上一个AES块的大小
        let bufferSize = dataLength + kCCBlockSizeAES128
        var buffer = [UInt8](repeating: 0, count: bufferSize)
        // 存储实际加密或解密后的字节数
        var numBytesCrypted: size_t = 0

        // 调用CCCrypt函数执行加密或解密操作
        let cryptStatus = CCCrypt(
            operation,                  // 指定加密或解密操作
            CCAlgorithm(kCCAlgorithmAES128),  // 使用AES-128加密算法
            CCOptions(kCCOptionPKCS7Padding), // 使用PKCS7填充
            keyBytes,                   // 密钥字节数组
            keyLength,                  // 密钥长度
            ivBytes,                    // 初始化向量(IV)
            [UInt8](data),              // 输入数据字节数组
            dataLength,                 // 输入数据长度
            &buffer,                    // 输出缓冲区
            bufferSize,                 // 输出缓冲区大小
            &numBytesCrypted            // 实际加密或解密后的字节数
        )
        
        // 检查加密或解密操作是否成功
        if cryptStatus == kCCSuccess {
            // 返回加密或解密后的数据,以及用于加密的IV
            let cryptData = Data(bytes: buffer, count: numBytesCrypted)
            return (cryptData, Data(ivBytes))
        }
        
        // 如果操作失败,返回nil
        return nil
    }
}

自定义Request和Response Serializer

为了处理请求和响应的加密解密,我们将创建自定义的AFJSONRequestSerializerAFHTTPResponseSerializer

swift 复制代码
import AFNetworking

// 自定义Request Serializer
class EncryptedJSONRequestSerializer: AFJSONRequestSerializer {
    var encryptionKey: String?
    
    override func request(bySerializingRequest request: URLRequest, withParameters parameters: Any?, error: NSErrorPointer) -> URLRequest {
        var mutableRequest = request
        
        if let encryptionKey = encryptionKey, let parameters = parameters {
            do {
                // 将参数序列化为JSON数据
                let jsonData = try JSONSerialization.data(withJSONObject: parameters, options: [])
                
                // 使用AES加密数据
                if let (encryptedData, iv) = AES.encrypt(data: jsonData, key: encryptionKey) {
                    let base64String = encryptedData.base64EncodedString()
                    let ivString = iv.base64EncodedString()
                    
                    // 将加密数据和IV一起传输
                    let encryptedParameters = ["data": base64String, "iv": ivString]
                    let encryptedJsonData = try JSONSerialization.data(withJSONObject: encryptedParameters, options: [])
                    mutableRequest.httpBody = encryptedJsonData
                }
            } catch {
                print("Error serializing or encrypting JSON: \(error)")
            }
        }
        
        return mutableRequest
    }
}

// 自定义Response Serializer
class EncryptedJSONResponseSerializer: AFHTTPResponseSerializer {
    var encryptionKey: String?
    
    override func responseObject(for response: URLResponse, data: Data?, error: NSErrorPointer) -> Any? {
        guard let encryptionKey = encryptionKey else {
            if error != nil {
                error?.pointee = NSError(domain: "Missing encryption key", code: -1, userInfo: nil)
            }
            return nil
        }
        
        guard let data = data else {
            if error != nil {
                error?.pointee = NSError(domain: "No data", code: -1, userInfo: nil)
            }
            return nil
        }
        
        do {
            // 解密响应数据
            if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any],
               let encryptedDataString = jsonResponse["data"] as? String,
               let ivString = jsonResponse["iv"] as? String,
               let encryptedData = Data(base64Encoded: encryptedDataString),
               let ivData = Data(base64Encoded: ivString) {
                
                if let decryptedData = AES.decrypt(data: encryptedData, key: encryptionKey, iv: ivData) {
                    return try JSONSerialization.jsonObject(with: decryptedData, options: [])
                }
            }
        } catch {
            if error != nil {
                error?.pointee = error as NSError
            }
        }
        
        return nil
    }
}

网络管理类

我们将创建一个网络管理类来处理登录和发送加密请求。

swift 复制代码
import AFNetworking

class NetworkManager {
    static let shared = NetworkManager()
    
    private let baseURL = "https://localhost:8443"
    private var token: String?
    private var encryptionKey: String?
    
    private init() {}

    /**
     用户登录方法
     
     - Parameters:
       - username: 用户名
       - password: 密码
       - completion: 登录完成后的回调,传递登录是否成功的布尔值
     */
    func login(username: String, password: String, completion: @escaping (Bool) -> Void) {
        let parameters: [String: Any] = ["

username": username, "password": password]
        
        // 发起POST请求进行登录
        AFHTTPSessionManager().post("\(baseURL)/login", parameters: parameters, headers: nil, progress: nil, success: { [weak self] (task, responseObject) in
            if let response = responseObject as? [String: Any], let token = response["token"] as? String, let encryptionKey = response["encryptionKey"] as? String {
                // 保存token和加密密钥
                self?.token = token
                self?.encryptionKey = encryptionKey
                completion(true)
            } else {
                completion(false)
            }
        }) { (task, error) in
            print("Login failed: \(error)")
            completion(false)
        }
    }

    /**
     发送加密请求方法
     
     - Parameters:
       - parameters: 请求参数
       - completion: 请求完成后的回调,传递结果
     */
    func sendSecureRequest(parameters: [String: Any], completion: @escaping (Result<[String: Any], Error>) -> Void) {
        guard let token = token, let encryptionKey = encryptionKey else {
            completion(.failure(NSError(domain: "No token or encryption key", code: 0, userInfo: nil)))
            return
        }

        let manager = AFHTTPSessionManager()
        let requestSerializer = EncryptedJSONRequestSerializer()
        requestSerializer.encryptionKey = encryptionKey
        manager.requestSerializer = requestSerializer

        let responseSerializer = EncryptedJSONResponseSerializer()
        responseSerializer.encryptionKey = encryptionKey
        manager.responseSerializer = responseSerializer

        let headers: HTTPHeaders = ["Authorization": token]
        
        // 发起POST请求发送加密数据
        manager.post("\(baseURL)/secure-data", parameters: parameters, headers: headers, progress: nil, success: { (task, responseObject) in
            if let response = responseObject as? [String: Any] {
                completion(.success(response))
            } else {
                completion(.failure(NSError(domain: "Invalid response", code: 0, userInfo: nil)))
            }
        }) { (task, error) in
            completion(.failure(error))
        }
    }
}

使用示例

swift 复制代码
let username = "testuser"
let password = "testpassword"

// 用户登录
NetworkManager.shared.login(username: username, password: password) { success in
    if success {
        print("Login successful")
        
        // 发送加密请求
        let parameters: [String: Any] = ["example": "data"]
        NetworkManager.shared.sendSecureRequest(parameters: parameters) { result in
            switch result {
            case .success(let response):
                print("Secure data response: \(response)")
            case .failure(let error):
                print("Request failed: \(error)")
            }
        }
    } else {
        print("Login failed")
    }
}

总结

本文介绍了如何在iOS客户端中使用AES加密数据传输,并确保与服务器端的一致性。通过使用随机生成的IV并将其明文传输,我们可以有效地防止重复模式攻击,增强数据传输的安全性。希望这篇文章对你在应用开发中的数据安全保护有所帮助。

相关推荐
依旧风轻7 小时前
如何在应用运行时定期监控内存使用情况
ios·swift·内存优化
程序员老刘·8 小时前
如何评价Flutter?
android·flutter·ios
502胶水20511 小时前
腾讯地图异步调用
开发语言·ios·swift
刘小哈哈哈13 小时前
iOS UITableView自带滑动手势和父视图添加滑动手势冲突响应机制探索
macos·ios·cocoa
分享者花花13 小时前
恢复出厂设置后如何从 iPhone 恢复数据
windows·macos·ios·智能手机·excel·cocoa·iphone
1024小神14 小时前
SwiftUI中List的liststyle样式及使用详解添加、移动、删除、自定义滑动
ios·swiftui·swift
Lik102415 小时前
ReactNative如何实现沉浸式状态栏及渐变色Header【兼容Android和iOS】
android·react native·ios
Geeker5515 小时前
适用于 Windows的 5 个最佳 PDF 转 Word 转换器
ios·智能手机·pdf·电脑·word·手机·iphone
勤劳兔码农16 小时前
iOS开发新手教程:Swift语言与Xcode工具链
ios·xcode·swift
<花开花落>1 天前
iOS App 测试环境升级,遇到的问题以及解决方法
macos·ios·appium