iOS MT19937随机数生成,结合AES-CBC加密算法实现。
按处理顺序说明:
1. 生成随机数序列字符串函数
生成方法MT19937,初始种子seed,利用C++库方法,生成:
#include <random> //C++ 库头文件引入NSString * JKJMT19937Seed(uint32_t seed) {NSLog(@"MT19937Seed种子:%u",seed);NSMutableArray *ranVlues = [NSMutableArray array];std::mt19937 rngCPluc2(seed);for (int i = 0; i < 64; ++i) {//连续生产64个随机数unsigned long ranValue = rngCPluc2();NSNumber *rngVal = [NSNumber numberWithUnsignedLong:ranValue];[ranVlues addObject:rngVal];}NSString *ranSeriesStr = [ranVlues componentsJoinedByString:@""];NSLog(@"随机数值序列拼接字符串key1 = %@",ranSeriesStr);return ranSeriesStr;
}
2. 对第一部中的随机数序列字符串进行sha256加密,得到64字节的一个数据流函数。
#import <CommonCrypto/CommonCrypto.h>//加密头文件NSString * sha256String(NSString *inputString) {const char *str = inputString.UTF8String;uint8_t buffer[CC_SHA256_DIGEST_LENGTH];CC_SHA256(str, (CC_LONG)strlen(str), buffer);NSMutableString *strM = [NSMutableString string];for (int i = 0; i < CC_SHA256_DIGEST_LENGTH; i++) {[strM appendFormat:@"%02x", buffer[i]];}return [strM copy];
}
3. AES-CBC加密解密方法
/*CCCrypt方法提供了CBC 和 ECB 两种AES加密模式,如果不传参数,kCCOptionECBMode,则默认即使CBC模式加密。ECB模式不是一种可靠安全的加密模式,推荐使用CBC模式。另外也可以通过其他的库或者方法实现GCM等方式的AES加密。在后面的代码块中翻入方法。
*/
NSData *aesCBCEncrypt(NSData *inputData, NSData *keyData, NSData *ivData) {NSData *key = keyData;// 准备一个初始化向量(IV),IV 的长度需要与 AES 加密模式匹配// 在 AES-CBC 模式下,IV 的长度通常为 AES 块大小(16 字节)NSData *iv = ivData;// 创建一个用于存储加密后数据的 NSMutableData 对象NSMutableData *encryptedData = [NSMutableData dataWithLength:inputData.length + kCCBlockSizeAES128];size_t encryptedDataLength = 0;// 使用 AES-256 加密(CBC)CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES,kCCOptionPKCS7Padding,key.bytes, key.length,iv.bytes, // 无需传入 IVinputData.bytes, inputData.length,encryptedData.mutableBytes, encryptedData.length,&encryptedDataLength);if (cryptStatus == kCCSuccess) {encryptedData.length = encryptedDataLength;return encryptedData;} else {NSLog(@"AES-256 加密失败");return nil;}
}NSData *aesCBCDecrypt(NSData *encryptedData, NSData *keyData, NSData *ivData) {// 准备一个初始化向量(IV)// 在 AES-CBC 模式下,IV 的长度通常为 AES 块大小(16 字节)NSData *iv = ivData;// 创建一个用于存储解密后数据的 NSMutableData 对象NSMutableData *decryptedData = [NSMutableData dataWithLength:encryptedData.length];size_t decryptedDataLength = 0;// 进行 AES 解密CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES,kCCOptionPKCS7Padding,keyData.bytes, keyData.length,iv.bytes, // 传入 IVencryptedData.bytes, encryptedData.length,decryptedData.mutableBytes, decryptedData.length,&decryptedDataLength);if (cryptStatus == kCCSuccess) {decryptedData.length = decryptedDataLength;return decryptedData;} else {NSLog(@"AES 解密失败");return nil;}
}
/*
CCCrypt方法提供了CBC 和 ECB 两种AES加密模式,
如果不传参数,kCCOptionECBMode,则默认即使CBC模式加密。
ECB模式不是一种可靠安全的加密模式,推荐使用CBC模式。
另外也可以通过其他的库或者方法实现GCM等方式的AES加密。在后面的代码块中翻入方法。
*/
4. 前三个步骤已经完成了加密的基本算法代码,接下来直接示例实现一个传参加密:
- (NSString *)EncryptStringFromtServiceStartMap:(NSDictionary *)json {//补充ts字段。NSMutableDictionary *muJson = [NSMutableDictionary dictionaryWithDictionary:json];NSTimeInterval tsVal = [[NSDate date] timeIntervalSince1970];[muJson setObject:[NSNumber numberWithInteger:(NSUInteger)(1000* tsVal)] forKey:@"ts"];NSString *jsonString = nil;NSError *error;NSData *jsonData = [NSJSONSerialization dataWithJSONObject:muJsonoptions:NSJSONWritingPrettyPrintederror:&error];[self loadAESKeyAndIVData];//获取key和iv。//进行AES加密。NSData *aesData = aesCBCEncrypt(jsonData, self.aesSHA256keyData, self.aesIVData);//base64再次加密AES-CBC加密后的数据流,返回值作为start_service的参数NSString *base64 = [aesData base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0];NSString *encryptStr = base64;NSLog(@"jsonContent:%@",muJson);NSLog(@"start_service参数encryptStr = %@",encryptStr);NSData *uncodeAESData = aesCBCDecrypt(aesData, self.aesSHA256keyData, self.aesIVData);if(uncodeAESData){NSError *error = nil;NSDictionary *uncodeDict = [NSJSONSerialization JSONObjectWithData:uncodeAESData options:kNilOptions error:&error];if (error) {NSString *uncodeJSON = [[NSString alloc] initWithData:uncodeAESData encoding:NSUTF8StringEncoding];if(uncodeJSON){NSLog(@"验证解密ServiceMap:%@", uncodeJSON);}else{NSLog(@"验证解密ServiceMap: 解析失败:%@", error);}} else {NSLog(@"验证解密ServiceMap:%@",uncodeDict);}}return encryptStr;
}//初始化AES加密的Key和iv向量数据。
- (void)loadAESKeyAndIVData {// 设置随机种子为 4728423NSString *mt19937Str = JKJMT19937Seed(4728423);NSString *sha256Str = sha256String(mt19937Str);/*密钥,截取sha256的64个字节前面32个字节IV:截取sha256的64个字节前面16个字节*/NSString *keyString = substringWithLength(sha256Str, 32);NSString *ivString = substringWithLength(sha256Str, 16);//获取AES加密Key_aesSHA256keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];//获取AES加密的IV向量_aesIVData = [ivString dataUsingEncoding:NSUTF8StringEncoding];
}
5. 归纳,完成4的操作,用到了一下两个库,a. C++中的random库,实现mt19937随机数;b. CommonCrypto库,实现AES-CBC对称加密,实现SHA256加密。c. 另外Base64是OC中的NSData(NSDataBase64Encoding)分类方法提供。
#include <random>
#import <CommonCrypto/CommonCrypto.h>
6. 补充, AES加密如果需要GCM或者其它(非CBC、非ECB)模式的,可能需要用到如下的方法去实现:a. 使用iOS13之后的库, b. 使用第三方库(libsodium-ios为例)
- a.使用iOS13之后的库代码如下:
//
// AESEncryptor.swift
//
// Created by xw.long on 2024/4/7.
//import Foundation
import CryptoKit
import CommonCrypto@available(iOS 13.0, *)
@objc class AESEncryptor: NSObject {func encryptDataUsingCBCMode(data: Data, key: Data, iv: Data) -> Data? {let bufferSize = data.count + kCCBlockSizeAES128var buffer = [UInt8](repeating: 0, count: bufferSize)var numBytesEncrypted: size_t = 0let cryptStatus = data.withUnsafeBytes { dataBytes inkey.withUnsafeBytes { keyBytes iniv.withUnsafeBytes { ivBytes inCCCrypt(CCOperation(kCCEncrypt),CCAlgorithm(kCCAlgorithmAES),CCOptions(kCCOptionPKCS7Padding),keyBytes.baseAddress, key.count,ivBytes.baseAddress,dataBytes.baseAddress, data.count,&buffer, bufferSize,&numBytesEncrypted)}}}if cryptStatus == kCCSuccess {return Data(buffer.prefix(Int(numBytesEncrypted)))} else {print("Error: \(cryptStatus)")return nil}}// 加密方法@objc func encrypt(content: String, key: String, iv: String) -> Data? {guard let keyData = Data(hexString: key),let ivData = Data(hexString: iv),let contentData = content.data(using: .utf8) else {print("AESEncryptor 无法将输入转换为Data")return nil}do {// 创建AES密钥let aesKey = SymmetricKey(data: keyData)// 使用AES-256-GCM加密let sealedBox = try AES.GCM.seal(contentData, using: aesKey, nonce: AES.GCM.Nonce(data: ivData))// 返回加密后的数据return sealedBox.combined} catch {print("AESEncryptor 加密失败: \(error)")return nil}}// 解密方法@objc func decrypt(encryptedData: Data, key: String, iv: String) -> String? {guard let keyData = Data(hexString: key),let ivData = Data(hexString: iv) else {print("AESEncryptor 无法将输入转换为Data")return nil}do {// 创建AES密钥let aesKey = SymmetricKey(data: keyData)// 解密let sealedBox = try AES.GCM.SealedBox(combined: encryptedData)let decryptedData = try AES.GCM.open(sealedBox, using: aesKey)// 将解密后的数据转换为字符串guard let decryptedString = String(data: decryptedData, encoding: .utf8) else {print("解密后的数据无法转换为字符串")return nil}return decryptedString} catch {print("AESEncryptor 解密失败: \(error)")return nil}}// 测试方法@objc static func test() {let content = "hello world"let key = "3891346e92151849d58e70de02a05c596b48afe1ae2bdeedf3e69c661c2ea2ae"let iv = "3891346e9215"if let encryptedData = AESEncryptor().encrypt(content: content, key: key, iv: iv) {print("AESEncryptor 加密后的数据: \(encryptedData.base64EncodedString())")if let decryptedString = AESEncryptor().decrypt(encryptedData: encryptedData, key: key, iv: iv) {print("AESEncryptor 解密后的字符串: \(decryptedString)")}}}}// 十六进制字符串转换为Data扩展
extension Data {init?(hexString: String) {var hexString = hexStringvar data = Data()while hexString.count > 0 {let subIndex = hexString.index(hexString.startIndex, offsetBy: 2)let hexChar = String(hexString[..<subIndex])hexString = String(hexString[subIndex...])guard let byte = UInt8(hexChar, radix: 16) else {return nil}data.append(byte)}self = data}
}+ (void)swiftTest {NSString *originalString = @"3891346e92151849d89070de02a05c596b48a123ae2bdeedf3e69c661c2ea2ae";// 截取新的key和ivNSString *key = [originalString substringToIndex:32];NSString *iv = [originalString substringToIndex:12];// 待加密的内容NSString *content = @"hello world";// 调用加密方法if (@available(iOS 13.0, *)) {NSData *encryptedData = [[AESEncryptor new] encryptWithContent:content key:key iv:iv];// 将加密后的数据转换为Base64字符串NSString *encryptedString = [encryptedData base64EncodedStringWithOptions:0];NSLog(@"加密后的字符串: %@", encryptedString);} else {// Fallback on earlier versions}
}
- b. 使用第三方库(libsodium-ios为例)
库引用可以通过cocoa-pod方法,在Podfile文件中加入如下代码,并在对应文件目录下执行【pod install】。
platform :ios, '12.0'
也可以通过github 下载:https://github.com/mochtu/libsodium-ios
# Uncomment the next line to define a global platform for your project
platform :ios, '12.0'
target 'MYPROJECT' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for MYPROJECT
pod 'libsodium-ios'
end
post_install do |pi|
pi.pods_project.targets.each do |t|
t.build_configurations.each do |config|
config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '12.0'
end
end
end
下面是库引入之后得代码示例:
#include <sodium.h>NSData *encryptStringWithAES256EStream(NSString *inputString, const unsigned char *nonce, const unsigned char *key) {// 转换输入字符串为NSDataNSData *inputData = [inputString dataUsingEncoding:NSUTF8StringEncoding];// 获取输入数据的长度NSUInteger inputLength = inputData.length;// 准备输出缓冲区NSMutableData *encryptedData = [NSMutableData dataWithLength:inputLength];// 产生AES-256-ESTREAM流密码unsigned char stream[inputLength];crypto_stream_aes256estream(stream, inputLength, nonce, key);// 对输入数据进行异或运算,实现加密unsigned char *inputBytes = (unsigned char *)inputData.bytes;unsigned char *encryptedBytes = (unsigned char *)encryptedData.mutableBytes;for (NSUInteger i = 0; i < inputLength; i++) {encryptedBytes[i] = inputBytes[i] ^ stream[i];}return encryptedData;
}+ (void)cryptoTest {// 初始化libsodium库if (sodium_init() == -1) {NSLog(@"libsodium初始化失败");return;}// 长度为16字节的nonceunsigned char nonce[crypto_stream_aes256estream_NONCEBYTES];randombytes_buf(nonce, sizeof(nonce));// 长度为32字节的密钥unsigned char key[crypto_stream_aes256estream_KEYBYTES];randombytes_buf(key, sizeof(key));// 要加密的字符串NSString *inputString = @"hello world";// 使用AES-256-ESTREAM密钥流对字符串进行加密NSData *encryptedData = encryptStringWithAES256EStream(inputString, nonce, key);// 打印加密后的数据NSLog(@"加密后的数据:%@", encryptedData);}
相关文章:
iOS MT19937随机数生成,结合AES-CBC加密算法实现。
按处理顺序说明: 1. 生成随机数序列字符串函数 生成方法MT19937,初始种子seed,利用C库方法,生成: #include <random> //C 库头文件引入NSString * JKJMT19937Seed(uint32_t seed) {NSLog("MT19937Seed种…...

阿里云2024年优惠券获取方法及使用教程详解
阿里云是阿里巴巴集团旗下的云计算服务提供商,是全球领先的云计算及人工智能科技公司之一。提供免费试用、云服务器、云数据库、云安全、云企业应用等云计算服务,以及大数据、人工智能服务、精准定制基于场景的行业解决方案。 阿里云2024年优惠券的获取方…...
hadoop中hdfs的fsimage文件与edits文件
hadoop中hdfs的fsimage文件与edits文件的作用 首先,我们抛出fsimage和edits文件的功能描述。 Fsimage文件: HDFS文件系统元数据的一个永久性的检查点,其中包含HDFS文件系统的 所有目录和文件inode的序列化信息。 Edits文件:存放HDFS文件系统的所有更…...

最新版两款不同版SEO超级外链工具PHP源码
可根据个人感觉喜好自行任意选择不同版本使用(版V1或版V2) 请将zip文件全部解压缩即可访问! 源码全部开源,支持上传二级目录访问 已更新增加大量高质量外链(若需要增加修改其他外链请打开txt文件)修复优…...

.net框架和c#程序设计第二次测试
一、实验内容 1、设计一个用户登录页面webform1.aspx,效果如下图所示: 2、点击webform1.aspx中“还未注册”连接进入register.aspx,注册页面效果如下图所示:点击用户注册信息到usershow.aspx页面,并显示注册的用户信息…...

芒果YOLOv8改进组合157:动态标签分配ATSS+新颖高效AsDDet检测头组合改进,共同助力VisDrone涨点1.8%,小目标高效涨点
💡本篇内容:【芒果YOLOv8改进ATSS标签分配策略|第三集】芒果YOLOv8改进组合157:动态标签分配ATSS+新颖高效AsDDet检测头组合改进,共同助力VisDrone涨点1.8%,小目标高效涨点 💡🚀🚀🚀本博客 标签分配策略ATSS改进+ 新颖高效AsDDet检测头组合改进,适用于 YOLOv8 …...

自媒体内容创作助手:7款必备ai写作工具一览! #学习方法#科技#其他
这些工具不仅可以快速生成高质量的文本内容,还可以根据用户的需求进行个性化定制。它们可以帮助我们节省大量的时间和精力,让我们更加专注于创意和细节的打磨。本文将为大家详细介绍几个AI写作工具,让你在写作领域更上一层楼。 1.七燕写作 这…...
文心一言 vs GPT-4 -- 全面横向比较
文心一言和GPT-4都是当前非常先进的自然语言处理模型,它们在语言理解、生成和翻译等方面都展现出了出色的能力。以下是对这两个模型的全面横向比较: 核心技术基础: 文心一言:是基于BERT(Bidirectional Encoder Repre…...

Leetcode C语言习题
Leetcode习题27:移除元素 题目: 说明: 示例: 题解: 方法一:(开辟额外的数组空间) 我们可以创建一个新的数组,然后用循环来遍历原数组,将原数组中不为 val…...

比 Nest.js 更优雅的 TS 控制反转策略 - 依赖查找
一、Cabloy5.0 内测预告 Cabloy5.0 采用 TS 对整个全栈框架进行了脱胎换骨般的大重构,并且提供了更加优雅的 ts 控制反转策略,让我们的业务开发更加快捷顺畅 1. 新旧技术栈对比: 后端前端旧版js、egg2.0、mysqljs、vue2、framework7新版ts…...

java算法day43 | 动态规划part05 ● 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零
1049. 最后一块石头的重量 II 核心思想: 尽量让石头分成重量相同的两堆,相撞之后剩下的石头最小,这样就化解成01背包问题了。 是不是感觉和昨天讲解的416. 分割等和子集 (opens new window)非常像了。那么分成两堆石头,一堆石头的…...

STM32无刷电机全套开发资料(源码、原理图、PCB工程及说明文档)
目录 1、原理图、PCB、BOOM表 2、设计描述 2.1 前言 2.2 设计电路规范 3、代码 4、资料清单 资料下载地址:STM32无刷电机全套开发资料(源码、原理图、PCB工程及说明文档) 1、原理图、PCB、BOOM表 2、设计描述 2.1 前言 经过一个星期的画PCB,今…...

工地安全监测识别摄像机
工地安全监测识别摄像机是一种在建筑工地和施工现场广泛使用的智能监控设备,主要用于监测施工过程中可能出现的安全隐患和违规行为,以确保工地人员和设备的安全。通过高清摄像头、智能算法和远程监控系统的结合,该摄像机可以实时监测工地各个…...

【零基础学数据结构】顺序表实现书籍存储
目录 书籍存储的实现规划 编辑 前置准备: 书籍结构体: 书籍展示的初始化和文件加载 书籍展示的销毁和文件保存 书籍展示的容量检查 书籍展示的尾插实现 书籍展示的书籍增加 书籍展示的书籍打印 书籍删除展示数据 书籍展示修改数据 在指定位置之前…...

【智能算法】黑寡妇优化算法(BWO)原理及实现
目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2020年,V Hayyolalam等人受到自然界黑寡妇交配行为启发,提出了黑寡妇优化算法(Black Widow Optimization Agorithm, BWO)。 2.算法原理 2.1算法思想…...
C#-非托管代码
非托管代码是指不受.NET运行时(CLR)的管理和控制,而是直接由操作系统或其他本机执行环境(如C/C编译的代码)所执行的代码。以下是一些常见的非托管代码的例子: C/C代码:通过使用C或C等编程语言编…...

计算机视觉之三维重建(7)---多视图几何(下)
文章目录 一、透视结构恢复问题1.1 概述1.2 透视结构恢复歧义1.3 代数方法1.4 捆绑调整 二、P3P问题三、随机采样一致性 一、透视结构恢复问题 1.1 概述 1. 透视结构恢复问题:摄像机为透视相机,内外参数均未知。 2. 问题:已知 n n n 个三维…...

AUTOSAR配置工具开发教程 - 开篇
简介 本系列的教程,主要讲述如何自己开发一套简单的AUTOSAR ECU配置工具。适用于有C# WPF基础的人员。 简易介绍见:如何打造AUTOSAR工具_autosar_mod_ecuconfigurationparameters-CSDN博客 实现版本 AUTOSAR 4.0.3AUTOSAR 4.2.2AUTOSAR 4.4.0 效果 …...

配置VM开机自启动
1. 在此电脑-右键选择“管理”-服务和应用程序-服务中找到VMware Workstation Server服务(新版名称也可能是VMware自启动服务,自己找一下,服务属性里有描述信息的),将其启用并选择开机自动启动 新版参考官方文档&…...

工作的第四天
推荐一个软件分配软件 我们看一下如何使用 连接信息 AOC中国官方网站 发现打开 还是这个页面信息,发现最后出现了页面重新定向的问题 我服了 我的码 怎么解决 我想用这个软件 来看看这个软件下载就可以使用 一听到钱我使用的情绪不是很高了 算了不使用 使用…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...

【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...

(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...

在 Spring Boot 中使用 JSP
jsp? 好多年没用了。重新整一下 还费了点时间,记录一下。 项目结构: pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...

ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...