iOS MT19937随机数生成,结合AES-CBC加密算法实现。

这篇具有很好参考价值的文章主要介绍了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, // 无需传入 IV
                                          inputData.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, // 传入 IV
                                          encryptedData.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:muJson
                                                         options:NSJSONWritingPrettyPrinted
                                                           error:&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 {
    // 设置随机种子为 4728423
    NSString *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 + kCCBlockSizeAES128
        var buffer = [UInt8](repeating: 0, count: bufferSize)
        var numBytesEncrypted: size_t = 0
        
        let cryptStatus = data.withUnsafeBytes { dataBytes in
            key.withUnsafeBytes { keyBytes in
                iv.withUnsafeBytes { ivBytes in
                    CCCrypt(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 = hexString
        var 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和iv
    NSString *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

下面是库引入之后得代码示例:文章来源地址https://www.toymoban.com/news/detail-845482.html

#include <sodium.h>


NSData *encryptStringWithAES256EStream(NSString *inputString, const unsigned char *nonce, const unsigned char *key) {
    // 转换输入字符串为NSData
    NSData *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字节的nonce
    unsigned 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加密算法实现。的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter 生成随机数

    如何让随机数变化? 我们尝试过的都知道,当你创建出来一个随机数后,调用他他的值是随机的,但是,这时候他的值就会固定住,不管怎么样都是随机出来的那个数,如果想要他每次都不一样的话,我们就想要使用刷新来让他变化了。 我们可以使用这样的方法来使他每次不一

    2024年02月13日
    浏览(47)
  • haiku生成随机数

    Haiku 遵循 JAX 的设计,生成的随机数是两个元素组成的列表。其中第一个元素是用于生成伪随机数的状态,第二个元素是用于分发密钥的子键。两个元素分别用于状态和子键,确保在分布式计算或并行计算中,多个随机数生成器的状态可以在一定程度上相互影响,从而提高随

    2024年01月20日
    浏览(64)
  • 生成随机数

    用于产生随机数 boolean nextBoolean() : 返回下一个伪随机数,它是取自此随机数生成器序列的均匀分布的 boolean 值。 void nextBytes(byte[] bytes) : 生成随机字节并将其置于用户提供的 byte 数组中。 double nextDouble() : 返回下一个伪随机数,它是取自此随机数生成器序列的、在 0.0 和 1.0 之

    2024年02月03日
    浏览(55)
  • Hutool 生成随机数和随机字符串

    官方文档: https://www.hutool.cn/docs/#/core/工具类/随机工具-RandomUtil 整理完毕,完结撒花~

    2024年02月16日
    浏览(57)
  • 生成随机数——C语言

    在C语言中,可以使用标准库函数 rand() 来生成随机数。需要注意的是, rand() 函数生成的是伪随机数,具体的随机序列取决于种子(seed)的值。 下面是一个简单的示例代码,展示如何在C语言中生成随机数: 在上述代码中,首先包含了 stdio.h 、 stdlib.h 和 time.h 头文件来使用相

    2024年02月12日
    浏览(55)
  • rust怎么生成随机数?

    在 Rust 中,有几种不同的方法可以实现随机数生成。以下是其中几种常见的方法,以及它们的优缺点: 优点: rand crate 是 Rust 中最常用的随机数库,提供了多种随机数生成器和功能。它易于使用,并且具有广泛的社区支持。 缺点: rand crate 生成的随机数是伪随机数,可能不

    2024年02月14日
    浏览(46)
  • 【Linux】随机数的生成

    /dev/random是一个随机数生成器设备文件,用于生成高质量的随机数。它通过收集系统上的环境噪声(例如硬件噪声,磁盘活动等)来产生随机数。由于它只在系统上有足够的环境噪声时才能生成随机数,因此/dev/random生成的随机数是高质量的。 但是,/dev/random的主要缺点是,如

    2024年02月11日
    浏览(47)
  • MySQL、Oracle 生成随机ID、随机数、随机字符串

    UUID():是由128位的数字组成的全局唯一标识符。每次都生成一个新的随机数。 它通常以32个十六进制数的形式表示,分为5个部分,以连字符分隔。 UUID的长度是36个字符,包括32个十六进制数字和4个连字符。 UUID的标准格式是由 8-4-4-4-12 个十六进制数字组成的,其中每个部分的

    2024年01月16日
    浏览(57)
  • 【数电实验】随机数生成电路

    1. 设计并实现一个随机数生成电路,每 2 秒 随机生成一个 0~999 之间的数 字,并在数码管上显示生成的随机数。 2. 为系统设置一个复位键,复位后数码管显示“000”,2 秒后再开始每 2 秒 生成并显示随机数,要求使用按键复位。 3. 实验板上输入时钟选择 1kHz 或更高的频率。

    2024年02月08日
    浏览(47)
  • 如何使用Verilog生成随机数

    输入:时钟信号,复位信号,重新加载信号,种子 输出:随机数 输入一个种子32位,输出16位随机数;选取时钟,复位,重新加载种子。 // 使用32个逻辑单元用于D触发器/加法器和8个DSP块用于32x18=32位乘法 module c_rand (   input clk,         // 时钟输入   input rst,        

    2024年02月03日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包