feat: 初始化项目

This commit is contained in:
richarjiang
2025-08-13 15:17:33 +08:00
commit 4f9d648a50
72 changed files with 29051 additions and 0 deletions

View File

@@ -0,0 +1,223 @@
# 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..<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. 使用示例
```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长度是否正确