6.1 KiB
6.1 KiB
iOS端加密对接指南
概述
本文档描述了如何在iOS端实现与服务端兼容的AES-256-GCM加解密功能。
加密规格
- 算法: AES-256-GCM
- 密钥长度: 256位 (32字节)
- IV长度: 96位 (12字节)
- 认证标签长度: 128位 (16字节)
- 数据格式: Base64编码的
IV + AuthTag + Ciphertext
环境变量配置
在服务端设置环境变量 ENCRYPTION_KEY,确保密钥安全:
export ENCRYPTION_KEY="your-32-character-secret-key-here"
iOS Swift 实现
1. 创建加密工具类
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..<ivLength).map { _ in UInt8.random(in: 0...255) })
// 使用AES-GCM加密
let sealedBox = try AES.GCM.seal(data, using: encryptionKey, nonce: AES.GCM.Nonce(data: iv), authenticating: additionalData)
// 组合数据:IV + Tag + Ciphertext
var combined = Data()
combined.append(iv)
combined.append(sealedBox.tag)
combined.append(sealedBox.ciphertext)
return combined.base64EncodedString()
}
/// 解密数据
/// - Parameter encryptedData: Base64编码的加密数据
/// - Returns: 解密后的明文字符串
static func decrypt(_ encryptedData: String) throws -> 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. 使用示例
// 创建用户数据
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
请求体:
{
"encryptedData": "base64编码的加密数据"
}
响应体:
{
"success": true,
"message": "用户创建成功",
"encryptedData": "base64编码的加密响应数据"
}
安全建议
-
密钥管理:
- 生产环境必须使用环境变量或安全密钥管理服务
- iOS端应将密钥存储在钥匙串中
- 定期轮换密钥
-
传输安全:
- 始终使用HTTPS
- 考虑添加请求签名验证
-
错误处理:
- 不要在错误信息中暴露加密细节
- 记录加密失败日志用于监控
-
测试:
- 确保iOS端和服务端使用相同的密钥
- 测试各种边界情况和错误场景
故障排除
- 解密失败: 检查密钥是否一致
- 格式错误: 确认Base64编码格式正确
- 数据长度错误: 验证IV和Tag长度是否正确