# iOS端加密对接指南 ## 概述 本文档描述了如何在iOS端实现与服务端兼容的AES-256-GCM加解密功能。 ## 加密规格 - **算法**: AES-256-GCM - **密钥长度**: 256位 (32字节) - **IV长度**: 96位 (12字节) - **认证标签长度**: 128位 (16字节) - **数据格式**: Base64编码的 `IV + AuthTag + Ciphertext` ## 环境变量配置 在服务端设置环境变量 `ENCRYPTION_KEY`,确保密钥安全: ```bash export ENCRYPTION_KEY="your-32-character-secret-key-here" ``` ## iOS Swift 实现 ### 1. 创建加密工具类 ```swift import Foundation import CryptoKit class EncryptionHelper { private static let keyLength = 32 private static let ivLength = 12 private static let tagLength = 16 private static let additionalData = "additional-data".data(using: .utf8)! // 从配置或钥匙串获取密钥 private static let encryptionKey: SymmetricKey = { let keyString = "your-32-character-secret-key-here" // 应从安全存储获取 let keyData = keyString.prefix(keyLength).padding(toLength: keyLength, withPad: "0", startingAt: 0).data(using: .utf8)! return SymmetricKey(data: keyData) }() /// 加密数据 /// - Parameter plaintext: 要加密的明文字符串 /// - Returns: Base64编码的加密数据,格式:iv + tag + ciphertext static func encrypt(_ plaintext: String) throws -> String { guard let data = plaintext.data(using: .utf8) else { throw EncryptionError.invalidInput } // 生成随机IV let iv = Data((0.. String { guard let combined = Data(base64Encoded: encryptedData) else { throw EncryptionError.invalidInput } guard combined.count >= ivLength + tagLength else { throw EncryptionError.invalidDataLength } // 提取各部分 let iv = combined.prefix(ivLength) let tag = combined.dropFirst(ivLength).prefix(tagLength) let ciphertext = combined.dropFirst(ivLength + tagLength) // 创建密封盒进行解密 let sealedBox = try AES.GCM.SealedBox(nonce: AES.GCM.Nonce(data: iv), ciphertext: ciphertext, tag: tag) let decryptedData = try AES.GCM.open(sealedBox, using: encryptionKey, authenticating: additionalData) guard let plaintext = String(data: decryptedData, encoding: .utf8) else { throw EncryptionError.decodingFailed } return plaintext } } enum EncryptionError: Error { case invalidInput case invalidDataLength case decodingFailed } ``` ### 2. 使用示例 ```swift // 创建用户数据 struct CreateUserRequest: Codable { let id: String let name: String let mail: String } // 加密请求体 struct EncryptedRequest: Codable { let encryptedData: String } // 加密响应体 struct EncryptedResponse: Codable { let success: Bool let message: String let encryptedData: String? } // 使用示例 func createUserWithEncryption() async { do { // 1. 准备用户数据 let userData = CreateUserRequest( id: "1234567890", name: "张三", mail: "zhangsan@example.com" ) // 2. 序列化为JSON let jsonData = try JSONEncoder().encode(userData) let jsonString = String(data: jsonData, encoding: .utf8)! // 3. 加密数据 let encryptedData = try EncryptionHelper.encrypt(jsonString) // 4. 创建请求体 let request = EncryptedRequest(encryptedData: encryptedData) // 5. 发送请求 let response = try await sendEncryptedRequest(request) // 6. 解密响应(如果有加密数据) if let encryptedResponseData = response.encryptedData { let decryptedResponse = try EncryptionHelper.decrypt(encryptedResponseData) print("解密后的响应: \(decryptedResponse)") } } catch { print("加密通信失败: \(error)") } } func sendEncryptedRequest(_ request: EncryptedRequest) async throws -> EncryptedResponse { let url = URL(string: "https://your-server.com/users/encrypted")! var urlRequest = URLRequest(url: url) urlRequest.httpMethod = "POST" urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type") let requestData = try JSONEncoder().encode(request) urlRequest.httpBody = requestData let (data, _) = try await URLSession.shared.data(for: urlRequest) return try JSONDecoder().decode(EncryptedResponse.self, from: data) } ``` ## API 接口 ### 加密版创建用户接口 **端点**: `POST /users/encrypted` **请求体**: ```json { "encryptedData": "base64编码的加密数据" } ``` **响应体**: ```json { "success": true, "message": "用户创建成功", "encryptedData": "base64编码的加密响应数据" } ``` ## 安全建议 1. **密钥管理**: - 生产环境必须使用环境变量或安全密钥管理服务 - iOS端应将密钥存储在钥匙串中 - 定期轮换密钥 2. **传输安全**: - 始终使用HTTPS - 考虑添加请求签名验证 3. **错误处理**: - 不要在错误信息中暴露加密细节 - 记录加密失败日志用于监控 4. **测试**: - 确保iOS端和服务端使用相同的密钥 - 测试各种边界情况和错误场景 ## 故障排除 1. **解密失败**: 检查密钥是否一致 2. **格式错误**: 确认Base64编码格式正确 3. **数据长度错误**: 验证IV和Tag长度是否正确