使用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 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

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
    }
}

网络管理类

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

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))
        }
    }
}

使用示例

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并将其明文传输,我们可以有效地防止重复模式攻击,增强数据传输的安全性。希望这篇文章对你在应用开发中的数据安全保护有所帮助。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

java+springboot+Mysql“友书”综合书籍平台系统24489-计算机毕业设计项目选题推荐(附源码)

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;“友书”综合书籍平台当然也不能排除在外。“友书”综合书籍平台系统是以实际运用为开发背景&#xff0c;运用软件工程原…

AI产品经理能力模型的重点素质:人文素养和灵魂境界

在AI产品经理的能力模型中&#xff0c;我最想提的差异化关键点&#xff0c;就是“人文素养和灵魂境界”。 1 为什么“人文素养和灵魂境界”非常重要&#xff1f; 一、“人文素养和灵魂境界”如何影响AI产品设计&#xff1f; 例1&#xff1a;面对一个具体的AI场景&#xff0…

NLP入门——前馈词袋分类模型的搭建、训练与预测

模型的搭建 线性层 >>> import torch >>> from torch import nn >>> class DBG(nn.Module): ... def forward(self,x): ... print(x.size()) ... return x ... >>> tmod nn.Sequential(nn.Linear(3,4),DB…

30斤用什么快递便宜?大件物品怎么寄划算省钱?

大学生小李最近因为毕业要搬家&#xff0c;不得不把一堆书籍、衣服和一些生活用品寄回家。作为一个精打细算的“穷学生”&#xff0c;小李可是不愿意在快递费上花冤枉钱的。于是&#xff0c;他开始研究各种寄快递省钱的方法&#xff0c;今天我们就来看看小李是怎么操作的。一、…

基于Wireshark和TiWsPC(Wireshark Packet Converter)的Zigbee抓包

前言 介绍几种Zigbee抓包方式&#xff1a; 1. Ubiqua 使用教程网上非常多也非常清晰&#xff1b; 但是Ubiqua是收费软件&#xff0c;较贵&#xff1b; 我安装过了&#xff0c;费好多事&#xff0c;没安装成功。 2. Killerbee套件 https://github.com/riverloopsec/killerbe…

phpcms 升级php8.3.8

windows 2008 server 不支持php8.3.8,需升级为windows 2012 1.下载php8.3.8 PHP8.3.9 For Windows: Binaries and sources Releases 2.配置php.ini (1.)在php目录下找到php.ini-development文件&#xff0c;把它复制一份&#xff0c;改名为php.ini (2.)修改php安装目录 根…

【设计模式】装饰器模式(定义 | 特点 | Demo入门讲解)

文章目录 定义装饰模式的结构 快速入门 | Demo顶层抽象DataSource数据源接⼝具体实现类引入BASE**64**编码装饰器客户端Client 定义 所谓装饰器模式其实就是在原有的功能上做一个增强&#xff01;&#xff01; 换句话说&#xff1a;以前你妈妈揍你的时候用的巴掌&#xff0c;但…

Windows 安装hadoop 3.4

目录 安装 下载 设置环境变量 配置 修改&#xff1a;hadoop-env.cmd 修改&#xff1a;core-sit.xml 修改&#xff1a;hdfs-site.xml 修改&#xff1a;mapred-site.xml 修改&#xff1a;yarn-site.xml 运行 格式化HDFS文件系统 启动&#xff1a;hadoop 启动&#xf…

开源大模型和闭源大模型,打法有何区别?

现阶段&#xff0c;各个公司都有自己的大模型产品&#xff0c;有的甚至不止一个。除了小部分开源外&#xff0c;大部分都选择了闭源。那么&#xff0c;头部开源模型厂商选择开源是出于怎样的初衷和考虑&#xff1f;未来大模型将如何发展&#xff1f;我们来看看本文的分享。 在对…

多态的优点

多态的优点 1、多态的优点1.1 可替换性&#xff08;Substitutability&#xff09;2、可扩充性&#xff08;Extensibility&#xff09; 2、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 1、多态的优点 在面向对象编程&#xff08;OOP…

滤波算法学习笔记

目录 引言 一、定义 二、分类 三、常见滤波算法 四、应用与优势 五、发展趋势 例程 1. 均值滤波&#xff08;Moving Average Filter&#xff09; 2. 中值滤波&#xff08;Median Filter&#xff09; 3. 高斯滤波&#xff08;Gaussian Filter&#xff09; 4.指数移动…

【Python画图-seaborn驯化】一文学会seaborn画散点图scatterplot、swarmplot技巧

【Python画图-seaborn驯化】一文学会seaborn画散点图scatterplot、swarmplot 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 免费获取相关内…

【uni-app】基础

一、官网 网址&#xff1a;https://zh.uniapp.dcloud.io/tutorial/其他辅助网页讲解&#xff1a;https://www.wenjiangs.com/doc/7y94pldun2插件下载free&#xff1a;https://ext.dcloud.net.cn/ 二、提示框 用uni.showToast提醒的次数超过7个字的时候就会导致文字显示不全&…

【Arduino】XIAOFEIYU实验ESP32使用温湿度传感器测量温度(图文)

温度传感器在我们的日常生活中应用还是很普遍的&#xff0c;使用ESP32可以方便的使用温度传感器对文档进行测量&#xff0c;今天XIAOFEIYU就来实验一下DHT11温湿度传感器。 需要安装DHT温度传感器的库&#xff0c;可以先进行下载&#xff1a;GitHub - adidax/dht11: DHT11 lib…

ChatMoney:AI看病,私人医生不是梦想!

本文由 ChatMoney团队出品 在当今这个科技飞速发展的时代&#xff0c;人工智能技术正在以惊人的速度改变着我们的生活&#xff0c;人工智能已经深入到各个领域&#xff0c;医疗行业也不例外。 而今天我要和大家聊一聊利用ChatMoney全能知识库AI系统在求医问诊领域所发挥的巨大…

Cesium与Three相机同步(3)

Cesium与Three融合的案例demo <!DOCTYPE html> <html lang"en" class"dark"><head><meta charset"UTF-8"><link rel"icon" href"/favicon.ico"><meta name"viewport" content&q…

接口签名、日志、token校验优化

文章目录 引言I 整合接口签名校验、接口信息日志处理、token校验功能为一个注解1.1 获取注解信息,判断API校验功能配置II 签名优化2.1 签名随机数统一放在请求头2.2 校验签名接口的请求参数类型为自定义对象2.3 获取请求数据,并校验签名数据2.4 Knife4j全局添加鉴权参数III 签…

thinkadmin 新增和编辑页面多选关联表人员信息,并可按名称搜索查询

假如现在有一个窗口表和人员表,窗口表中的user_ids字段存储多个工作人员,人员表的id在窗口表的user_ids字段中存储为 “1,2,3”,代表3个工作人员,通过以下代码实现 form.html <div class="layui-col-xs12"><span class="help-label

自动驾驶理论新突破登Nature子刊!清华、密歇根联合提出三条技术路线,剑指「稀疏度灾难」

自动驾驶理论新突破登Nature子刊&#xff01;清华、密歇根联合提出三条技术路线&#xff0c;剑指「稀疏度灾难」 近日&#xff0c;清华大学与密歇根大学联合提出的自动驾驶汽车安全性「稀疏度灾难」问题&#xff0c;发表在了顶刊《Nature Communications》上。研究指出&#…

【12321骚扰电话举报受理中心-短信验证安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…