按處理順序說明:
1. 生成隨機數(shù)序列字符串函數(shù)
生成方法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) {//連續(xù)生產(chǎn)64個隨機數(shù)
unsigned long ranValue = rngCPluc2();
NSNumber *rngVal = [NSNumber numberWithUnsignedLong:ranValue];
[ranVlues addObject:rngVal];
}
NSString *ranSeriesStr = [ranVlues componentsJoinedByString:@""];
NSLog(@"隨機數(shù)值序列拼接字符串key1 = %@",ranSeriesStr);
return ranSeriesStr;
}
2. 對第一部中的隨機數(shù)序列字符串進行sha256加密,得到64字節(jié)的一個數(shù)據(jù)流函數(shù)。
#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加密模式,
如果不傳參數(shù),kCCOptionECBMode,則默認即使CBC模式加密。
ECB模式不是一種可靠安全的加密模式,推薦使用CBC模式。
另外也可以通過其他的庫或者方法實現(xiàn)GCM等方式的AES加密。在后面的代碼塊中翻入方法。
*/
NSData *aesCBCEncrypt(NSData *inputData, NSData *keyData, NSData *ivData) {
NSData *key = keyData;
// 準備一個初始化向量(IV),IV 的長度需要與 AES 加密模式匹配
// 在 AES-CBC 模式下,IV 的長度通常為 AES 塊大?。?6 字節(jié))
NSData *iv = ivData;
// 創(chuàng)建一個用于存儲加密后數(shù)據(jù)的 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 塊大?。?6 字節(jié))
NSData *iv = ivData;
// 創(chuàng)建一個用于存儲解密后數(shù)據(jù)的 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加密模式,
? ? 如果不傳參數(shù),kCCOptionECBMode,則默認即使CBC模式加密。
? ? ECB模式不是一種可靠安全的加密模式,推薦使用CBC模式。
? ? 另外也可以通過其他的庫或者方法實現(xiàn)GCM等方式的AES加密。在后面的代碼塊中翻入方法。
*/
4. 前三個步驟已經(jīng)完成了加密的基本算法代碼,接下來直接示例實現(xiàn)一個傳參加密:
- (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加密后的數(shù)據(jù)流,返回值作為start_service的參數(shù)
NSString *base64 = [aesData base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0];
NSString *encryptStr = base64;
NSLog(@"jsonContent:%@",muJson);
NSLog(@"start_service參數(shù)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向量數(shù)據(jù)。
- (void)loadAESKeyAndIVData {
// 設置隨機種子為 4728423
NSString *mt19937Str = JKJMT19937Seed(4728423);
NSString *sha256Str = sha256String(mt19937Str);
/*
密鑰,截取sha256的64個字節(jié)前面32個字節(jié)
IV:截取sha256的64個字節(jié)前面16個字節(jié)
*/
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庫,實現(xiàn)mt19937隨機數(shù);b.?CommonCrypto庫,實現(xiàn)AES-CBC對稱加密,實現(xiàn)SHA256加密。c. 另外Base64是OC中的NSData(NSDataBase64Encoding)分類方法提供。
#include <random>
#import <CommonCrypto/CommonCrypto.h>
?6. 補充, AES加密如果需要GCM或者其它(非CBC、非ECB)模式的,可能需要用到如下的方法去實現(xiàn):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 {
// 創(chuàng)建AES密鑰
let aesKey = SymmetricKey(data: keyData)
// 使用AES-256-GCM加密
let sealedBox = try AES.GCM.seal(contentData, using: aesKey, nonce: AES.GCM.Nonce(data: ivData))
// 返回加密后的數(shù)據(jù)
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 {
// 創(chuàng)建AES密鑰
let aesKey = SymmetricKey(data: keyData)
// 解密
let sealedBox = try AES.GCM.SealedBox(combined: encryptedData)
let decryptedData = try AES.GCM.open(sealedBox, using: aesKey)
// 將解密后的數(shù)據(jù)轉換為字符串
guard let decryptedString = String(data: decryptedData, encoding: .utf8) else {
print("解密后的數(shù)據(jù)無法轉換為字符串")
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 加密后的數(shù)據(jù): \(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];
// 將加密后的數(shù)據(jù)轉換為Base64字符串
NSString *encryptedString = [encryptedData base64EncodedStringWithOptions:0];
NSLog(@"加密后的字符串: %@", encryptedString);
} else {
// Fallback on earlier versions
}
}
- b. 使用第三方庫(libsodium-ios為例)
庫引用可以通過cocoa-pod方法,在Podfile文件中加入如下代碼,并在對應文件目錄下執(zhí)行【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文章來源:http://www.zghlxwxcb.cn/news/detail-845482.html
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
下面是庫引入之后得代碼示例:文章來源地址http://www.zghlxwxcb.cn/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];
// 獲取輸入數(shù)據(jù)的長度
NSUInteger inputLength = inputData.length;
// 準備輸出緩沖區(qū)
NSMutableData *encryptedData = [NSMutableData dataWithLength:inputLength];
// 產(chǎn)生AES-256-ESTREAM流密碼
unsigned char stream[inputLength];
crypto_stream_aes256estream(stream, inputLength, nonce, key);
// 對輸入數(shù)據(jù)進行異或運算,實現(xiàn)加密
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字節(jié)的nonce
unsigned char nonce[crypto_stream_aes256estream_NONCEBYTES];
randombytes_buf(nonce, sizeof(nonce));
// 長度為32字節(jié)的密鑰
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);
// 打印加密后的數(shù)據(jù)
NSLog(@"加密后的數(shù)據(jù):%@", encryptedData);
}
到了這里,關于iOS MT19937隨機數(shù)生成,結合AES-CBC加密算法實現(xiàn)。的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!