当前位置: 首页 > news >正文

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

相关文章:

  • C语言从入门到实战————文件操作
  • 【头歌-Python】 函数自学引导
  • 探索IOT物联网接入数据中台架构的关键要素
  • Vue-B站学习笔记
  • 美国MDO4054B-3泰克混合域示波器
  • 【Redis】NoSQL之Redis的配置和优化
  • 本地MinIO存储服务通过Java程序结合cpolar实现远程连接上传文件
  • 深度优先搜索算法C实现
  • RFID智能绘本柜助力优化儿童阅读体验。
  • k8s部署efk
  • C#设计简单的WinForms多窗口应用程序[示例]
  • 对称排序(蓝桥杯)
  • springcloud第4季 使用resilience4j实现服务流量治理
  • LeetCode-热题100:300. 最长递增子序列
  • 论文阅读——MVDiffusion
  • Angular4 模板式表单用法以及验证
  • go语言学习初探(一)
  • iOS | NSProxy
  • js对象的深浅拷贝
  • JS题目及答案整理
  • Mac转Windows的拯救指南
  • nginx 负载服务器优化
  • Python 反序列化安全问题(二)
  • SpiderData 2019年2月13日 DApp数据排行榜
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • vue数据传递--我有特殊的实现技巧
  • 创建一个Struts2项目maven 方式
  • 从0搭建SpringBoot的HelloWorld -- Java版本
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 构建工具 - 收藏集 - 掘金
  • 聚簇索引和非聚簇索引
  • 看图轻松理解数据结构与算法系列(基于数组的栈)
  • 马上搞懂 GeoJSON
  • 人脸识别最新开发经验demo
  • 写给高年级小学生看的《Bash 指南》
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • 看到一个关于网页设计的文章分享过来!大家看看!
  • 大数据全解:定义、价值及挑战
  • ​​​​​​​​​​​​​​汽车网络信息安全分析方法论
  • !!Dom4j 学习笔记
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (笔记)Kotlin——Android封装ViewBinding之二 优化
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (附源码)计算机毕业设计SSM基于健身房管理系统
  • (离散数学)逻辑连接词
  • (六)库存超卖案例实战——使用mysql分布式锁解决“超卖”问题
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (数据结构)顺序表的定义
  • (原創) 系統分析和系統設計有什麼差別? (OO)
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复