使用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加密解密类

import CommonCryptoclass 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 = kCCKeySizeAES128var keyBytes = [UInt8](repeating: 0, count: keyLength)// 将密钥字符串转换为字节数组,并确保其长度为16字节key.getCString(&keyBytes, maxLength: keyLength + 1, encoding: .utf8)// 初始化向量(IV)的字节数组var ivBytes: [UInt8]if let iv = iv {// 如果传入了IV,使用传入的IVivBytes = [UInt8](iv)} else {// 如果没有传入IV,在加密时生成一个随机的IVlet ivSize = kCCBlockSizeAES128ivBytes = [UInt8](repeating: 0, count: ivSize)_ = SecRandomCopyBytes(kSecRandomDefault, ivSize, &ivBytes)}// 输入数据的长度let dataLength = data.count// 输出缓冲区大小应为数据长度加上一个AES块的大小let bufferSize = dataLength + kCCBlockSizeAES128var 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 {// 返回加密或解密后的数据,以及用于加密的IVlet cryptData = Data(bytes: buffer, count: numBytesCrypted)return (cryptData, Data(ivBytes))}// 如果操作失败,返回nilreturn nil}
}

自定义Request和Response Serializer

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

import AFNetworking// 自定义Request Serializer
class EncryptedJSONRequestSerializer: AFJSONRequestSerializer {var encryptionKey: String?override func request(bySerializingRequest request: URLRequest, withParameters parameters: Any?, error: NSErrorPointer) -> URLRequest {var mutableRequest = requestif 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}
}

网络管理类

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

import AFNetworkingclass 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) inif let response = responseObject as? [String: Any], let token = response["token"] as? String, let encryptionKey = response["encryptionKey"] as? String {// 保存token和加密密钥self?.token = tokenself?.encryptionKey = encryptionKeycompletion(true)} else {completion(false)}}) { (task, error) inprint("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 = encryptionKeymanager.requestSerializer = requestSerializerlet responseSerializer = EncryptedJSONResponseSerializer()responseSerializer.encryptionKey = encryptionKeymanager.responseSerializer = responseSerializerlet headers: HTTPHeaders = ["Authorization": token]// 发起POST请求发送加密数据manager.post("\(baseURL)/secure-data", parameters: parameters, headers: headers, progress: nil, success: { (task, responseObject) inif let response = responseObject as? [String: Any] {completion(.success(response))} else {completion(.failure(NSError(domain: "Invalid response", code: 0, userInfo: nil)))}}) { (task, error) incompletion(.failure(error))}}
}

使用示例

let username = "testuser"
let password = "testpassword"// 用户登录
NetworkManager.shared.login(username: username, password: password) { success inif success {print("Login successful")// 发送加密请求let parameters: [String: Any] = ["example": "data"]NetworkManager.shared.sendSecureRequest(parameters: parameters) { result inswitch 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并将其明文传输,我们可以有效地防止重复模式攻击,增强数据传输的安全性。希望这篇文章对你在应用开发中的数据安全保护有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/41080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言实现的冒泡排序算法的示例程序

冒泡排序是一种简单的排序算法&#xff0c;它重复地遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果它们的顺序错误就把它们交换过来。遍历数列的工作是重复地进行直到没有再需要交换&#xff0c;也就是说该数列已经排序完成。这个算法的名字由来是因为越小&…

Mysql8.0.36 Centos8环境安装

下载安装包 官网地址&#xff1a;MySQL :: Download MySQL Community Server (Archived Versions) 可以直接下载后再传到服务器&#xff0c;也可以在服务器采用wget下载。如下&#xff1a; wget https://downloads.mysql.com/archives/get/p/23/file/mysql-8.0.36-linux-glib…

SQL Server全文搜索揭秘:深度挖掘数据的隐藏价值

SQL Server全文搜索揭秘&#xff1a;深度挖掘数据的隐藏价值 SQL Server的全文搜索&#xff08;Full-Text Search&#xff09;功能是微软关系型数据库管理系统中的一个强大工具&#xff0c;它允许用户对非结构化文本数据执行复杂的查询。全文搜索功能不仅提高了数据检索的效率…

SpringBoot AOP切入点表达式

介绍 在AOP中可以通过注解来定义 切入点表达式来控制被监控的方法。 匹配所有 com.example.service 包下以 Service 结尾的方法&#xff1a; "execution(* com.example.service.*Service.*(..))"匹配任意类的 public 方法&#xff1a; "execution(public * …

【单片机毕业设计选题24047】-基于阿里云的工地环境监测系统

系统功能: 基于STM32完成 主机&#xff08;阿里云以及oled屏显示位置一&#xff09;&#xff1a;烟雾检测&#xff0c;温湿度检测&#xff0c;噪声检测&#xff0c;且用OLED屏显示&#xff0c;设置阈值&#xff0c;超过报警&#xff08;蜂鸣器&#xff09;。 从机&#xff0…

关于echarts中使用到的图例、颜色设置、设置tooltip换行显示等问题

最近使用echarts中用到图例随机生成&#xff0c;颜色多不好设置的问题&#xff0c;图例多展示出现不全&#xff0c;不能根据颜色判断图例和数据的问题等总结一下 原始代码&#xff1a; that_ge.charts echarts.init(document.getElementById(paramenterEcharts));that_ge.al…

(四)共享模型之内存

本章内容 上一章讲解的 Monitor 主要关注的是访问共享变量时&#xff0c;保证临界区代码的原子性 这一章我们进一步深入学习共享变量在多线程间的【可见性】问题与多条指令执行时的【有序性】问题 Java 内存模型 JMM 即 Java Memory Model&#xff0c;它定义了主存、工作内存…

firewalld(3)zone配置

简介 前面文章我们已经介绍了firewalld的安装&#xff0c;配置文件介绍、简单的规则查询&#xff0c;本篇文章主要介绍zone的配置。前面我们介绍了firewalld默认的zone和不同zone的功能&#xff0c;下面我们就直接进入zone的具体配置使用。 配置zone的方式 图形配置工具…

浅析基于量子成像的下一代甚高灵敏度图像传感器技术

高灵敏度探测成像是空间遥感应用中的一个重要技术领域&#xff0c;如全天时对地观测、空间暗弱目标跟踪识别等应用&#xff0c;对于甚高灵敏度图像传感器的需求日益强烈。随着固态图像传感器技术水平的不断提高&#xff0c;尤其背照式及埋沟道等工艺的突破&#xff0c;使得固态…

马拉松报名小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;赛事信息管理&#xff0c;赛事报名管理&#xff0c;活动商城管理&#xff0c;留言板管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;赛事信息&…

Python考前复习

选择题易错&#xff1a; python3不能完全兼容python2内置函数是python的内置对象之一&#xff0c;无需导入其他模块python中汉字变量合法&#xff0c;如“小李123”合法&#xff1b;但T-C不合法&#xff0c;因为有“-”集合无顺序&#xff0c;不能索引&#xff1b;range(5)[2]…

【python全栈系列】day09-python数据类型转换

在Python中&#xff0c;数据类型转换是一项非常常见的操作&#xff0c;它允许我们将一种类型的数据转换为另一种类型。这种转换在处理来自不同源的数据时尤其有用&#xff0c;例如用户输入、文件读取或网络数据等。下面&#xff0c;我将通过代码示例来展示如何将其他数据类型转…

ABAC模型

属性基访问控制&#xff08;Attribute-Based Access Control&#xff0c;ABAC&#xff09;是一种动态和细粒度的访问控制模型&#xff0c;通过评估用户属性、资源属性、环境属性和动作属性来决定访问权限。这种模型比传统的角色基访问控制&#xff08;RBAC&#xff09;更灵活&a…

json数据的解析

1. Json是什么&#xff1f; JavaScript Object Natation, 一种轻量级的数据交换格式, 与XML一样, 广泛被采用的客户端和服务端交互的解决方案&#xff01;具有良好的可读和便于快速编写的特性。 2. Json与XML的比较 JSON和XML的数据可读性基本相同; JSON和XML同样拥有丰富的…

手动访问mongo和ES插入和查询

1、手动访问mongo 1.1、mongo连接数据库 1.2、mongo插入和查询 db.hmf_test.insert( { "aoeId": "1", "aoeAes": "吴秀梅", "aoeSm4": "北京xx网络技术有限公司.", "aoeSm4_a": "…

构建可扩展的Java Web应用架构

构建可扩展的Java Web应用架构 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在现代软件开发中&#xff0c;可扩展性是一个至关重要的概念。构建一个可扩展的…

2pc 3pc

2pc&3pc问题 本质&#xff1a; 2pcTM超时机制 3pc加入事务询问机制RM超时机制 事务询问机制&#xff1a;减少阻塞 RM超时机制&#xff1a;避免死锁 2pc 3pc 参考&#xff1a; https://juejin.im/post/5aa3c7736fb9a028bb189bca#heading-1 https://blog.csdn.net/xj1…

Spring Boot 文件上传和下载指南:从基础到进阶

文章目录 引言1. 环境配置2. 文件上传2.1 配置文件上传路径2.2 创建上传服务2.3 创建上传控制器 3. 文件下载3.1 创建下载服务3.2 创建下载控制器 4. 前端页面4.1 文件上传页面4.2 文件下载页面 5. 技术分析结论 &#x1f389;欢迎来到SpringBoot框架学习专栏~ ☆* o(≧▽≦)o …

Java并发编程中的常见陷阱及解决方案

Java并发编程中的常见陷阱及解决方案 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在Java编程中&#xff0c;并发编程是一项高级技能&#xff0c;能够显著提…

iOS多target时怎么对InfoPlist进行国际化

由于不同target要显示不同的App名称、不同的权限提示语&#xff0c;国际化InfoPlist文件必须创建名称为InfoPlist.strings的文件&#xff0c;那么多个target时怎么进行国际化呢&#xff1f;步骤如下&#xff1a; 一、首先我们在项目根目录创建不同的文件夹对应多个不同的targe…