<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          iOS逆向--加密算法

          共 10221字,需瀏覽 21分鐘

           ·

          2021-09-30 14:02

          ????關(guān)注后回復(fù) “進(jìn)群” ,拉你進(jìn)程序員交流群????


          作者 | iOS_大書
          來(lái)源 | 掘金
          https://juejin.cn/post/7010665487809904647

          一、加密算法分類

          哈希(散列)函數(shù):不屬于加密算法。例如MD5、SHA1/256/512
          對(duì)稱加密算法:DES、3DES、AES(高級(jí)密碼標(biāo)準(zhǔn),mac電腦的鑰匙串就是用AES)
          非對(duì)稱加密算法:RAS

          1、Hash

          Hash,一般翻譯做“散列”,也有直接譯為“哈?!钡?,就是把任意長(zhǎng)度的輸入通過(guò)散列算法變換成固定長(zhǎng)度的輸出,該輸出就是散列值。
          這種轉(zhuǎn)換是一種壓縮映射,也就是散列值的空間通常遠(yuǎn)小于輸入的空間,不同的輸入可能會(huì)散列成相同的輸出,所以不可能從散列值來(lái)確定唯一的輸入值,簡(jiǎn)單的說(shuō)就是一種將任意長(zhǎng)度的消息壓縮到某一固定長(zhǎng)度的消息摘要的函數(shù),最著名的一個(gè)hash算法就是MD5
          Hash的特點(diǎn):
          • 算法是公開(kāi)的

          • 對(duì)相同數(shù)據(jù)運(yùn)算,得到的結(jié)果是一樣的

          • 對(duì)不同數(shù)據(jù)運(yùn)算,如MD5得到的結(jié)果默認(rèn)是128位,也就是32個(gè)字符(16進(jìn)制標(biāo)識(shí))

          • 無(wú)法逆運(yùn)算

          • 主要作為信息摘要,信息指紋,用來(lái)做數(shù)據(jù)識(shí)別的

          用途:
          • 用戶密碼的加密:因?yàn)闊o(wú)法還原,所以加密性很好,哪怕泄露了,也午飯逆向出用戶的真實(shí)密碼

          • 搜索引擎

          • 版權(quán)

          • 數(shù)字簽名

          密碼加密的方式:
          • 直接使用MD5

          • MD5加鹽

          • HMAC加密方案

          • 添點(diǎn)東西

          當(dāng)我們需要把密碼發(fā)送給服務(wù)器的時(shí)候我們要對(duì)密碼進(jìn)行加密,假如我們用RSA非對(duì)稱加密的話,效率會(huì)很低,并且有安全隱患,因?yàn)楫?dāng)通過(guò)RSA加密后會(huì)對(duì)密碼進(jìn)行解密,然后匹配,但是這樣的話服務(wù)器就需要明文存儲(chǔ)密碼,這是很不安全的:
          對(duì)于密碼在網(wǎng)絡(luò)上傳輸有了兩個(gè)原則:
          • 網(wǎng)絡(luò)上不允許明文傳遞用戶的隱私信息

          • 本地不允許明文保存用戶隱私信息

          所以可以用MD5轉(zhuǎn)換,這樣即使密文丟失了但是用戶的原始密碼是是無(wú)法破解的,我們來(lái)看一下MD5轉(zhuǎn)換代碼:
             
          - (NSString *)md5String {
          const char *str = self.UTF8String;
          uint8_t buffer[CC_MD5_DIGEST_LENGTH];
          //將字符串指針、字符串的長(zhǎng)度、以及密文存儲(chǔ)的空間傳進(jìn)去,空間一般是16位,加密后會(huì)把密文以16進(jìn)制形式放在待存儲(chǔ)的空間中,
          CC_MD5(str, (CC_LONG)strlen(str), buffer);
          //拿到密文后,我們將密文拼接起來(lái)就得到一個(gè)密文字符串
          return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
          }

          - (NSString *)stringFromBytes:(uint8_t *)bytes length:(int)length {
          NSMutableString *strM = [NSMutableString string];

          for (int i = 0; i < length; i++) {
          [strM appendFormat:@"%02x", bytes[i]];
          }
          return [strM copy];
          }

          我們對(duì)123456進(jìn)行加密:就得到這樣一個(gè)十六進(jìn)制的字符串
          e10adc3949ba59abbe56e057f20f883e
          但是現(xiàn)在MD5雖然無(wú)法破解,但是因?yàn)橥蛔址畬?duì)應(yīng)的密文是不變的,這樣我們就可以通過(guò)密文匹配到相應(yīng)的字符串,例如在CMD5上,我們就能通過(guò)密碼匹配到常見(jiàn)的字符串
          這個(gè)時(shí)候我們就需要對(duì)字符串加鹽后在進(jìn)行MD5轉(zhuǎn)換,所謂加鹽就是在字符串后拼接一個(gè)復(fù)雜字符串后再進(jìn)行MD5轉(zhuǎn)換,但是也有個(gè)弊端,就是這個(gè)鹽是固定的必須要寫到程序里面,一樣可以通過(guò)暴力破解,所以我們可以通過(guò)HMAC方式進(jìn)行加密:

          HMAC:

          • 使用一個(gè)密鑰加密,并且做兩次散列

          • 實(shí)際開(kāi)發(fā)中,密鑰來(lái)自于服務(wù)器,動(dòng)態(tài)的

          • 一個(gè)賬號(hào)對(duì)應(yīng)一個(gè)key,而且還可以更新 我們?cè)谧?cè)或者換設(shè)備時(shí)候?qū)ey下發(fā)給客戶端,然后在本地緩存起來(lái),然后以后每次登陸時(shí)候從本地取出來(lái)對(duì)密碼進(jìn)行加密,這樣我們就可以加上一個(gè)設(shè)備鎖,當(dāng)換設(shè)備時(shí)候需要原來(lái)設(shè)備同意才能在新設(shè)備上登陸

          蘋果也提供了CCHmac的方式:
             
          #pragma mark - HMAC 散列函數(shù)
          - (NSString *)hmacMD5StringWithKey:(NSString *)key {
          const char *keyData = key.UTF8String;
          const char *strData = self.UTF8String;
          uint8_t buffer[CC_MD5_DIGEST_LENGTH];

          CCHmac(kCCHmacAlgMD5, keyData, strlen(keyData), strData, strlen(strData), buffer);

          return [self stringFromBytes:buffer length:CC_MD5_DIGEST_LENGTH];
          }
          因?yàn)槊看蔚顷懠偃缥覀冎挥肕D5密文的話,就會(huì)導(dǎo)致每次登陸傳給服務(wù)器的信息都是一樣的,這樣就比較危險(xiǎn),如果被黑客劫持了,就會(huì)在后面時(shí)間用請(qǐng)求數(shù)據(jù)去破解,
          那我們可以加一個(gè)時(shí)間戳(服務(wù)器時(shí)間),這樣每次請(qǐng)求都不一樣,即使黑客劫持了也無(wú)所謂,因?yàn)橛醒舆t問(wèn)題,所以時(shí)間戳只精確到分鐘,加時(shí)間戳方式:
          • 1、登錄之前先從服務(wù)器請(qǐng)求到服務(wù)器的時(shí)間戳time

          • 2、然后在客戶端通過(guò)HMAC和key對(duì)密碼進(jìn)行加密得到密文1

          • 3、將密文1拼接上時(shí)間戳再進(jìn)行一次HMAC和key的加密得到密文2

          • 4、將密文2傳給服務(wù)器進(jìn)行校驗(yàn),服務(wù)器從本地取出用戶的密碼密文也就是密文1拼接上當(dāng)前時(shí)間戳后再進(jìn)行HMAC和key的加密跟客戶端傳過(guò)來(lái)的進(jìn)行匹配,相同則校驗(yàn)通過(guò)

          • 如果不同,則將密文1和服務(wù)器時(shí)間戳的前一分鐘的時(shí)間戳拼接后在進(jìn)行匹配,相同則通過(guò),不同則返回密碼不正確

          搜索引擎:

          對(duì)每個(gè)詞都拿到Hash值,然后將這些Hash值進(jìn)行相加,然后進(jìn)行查找,這樣不管你輸入的詞順序是如何的,那么查找到內(nèi)容都是整句話的,例如 張三 李四 王五,這三個(gè)詞的hash值都是一樣的,并且都是32位的16進(jìn)制數(shù)字,不管他們哪個(gè)在前,加起來(lái)的和都是一樣的

          版權(quán):

          對(duì)原文件通過(guò)Hash運(yùn)算得到一個(gè)Hash值,源文件里面有一個(gè)Hash值,假如有盜版文件上傳到百度云盤上會(huì)因?yàn)镠ash值不對(duì),并且有百度云盤有存在秒傳情況,這是因?yàn)樵票P已經(jīng)有了該文件。通過(guò)匹配Hash發(fā)現(xiàn)該文件已經(jīng)有了,所以就不用再次上傳

          數(shù)字簽名:

          為啥用簽名這個(gè)詞呢,因?yàn)槔贤庀矚g用支票,支票上的簽名能夠證明這玩意是你的,那么數(shù)字簽名就是用于鑒別數(shù)字信息的方法
          客戶端有個(gè)支付信息,三方可能從中間攻擊,篡改支付信息,這樣就可能讓客戶多支付錢,怎么防止呢?
          • 可以對(duì)支付的信息轉(zhuǎn)成MD5

          • 在對(duì)MD5密文進(jìn)行RSA加密得到一個(gè)密文,這個(gè)就是數(shù)字簽名

          • 傳遞給服務(wù)器后,服務(wù)器對(duì)密文進(jìn)行RSA解密得到MD5密文1,再對(duì)支付信息轉(zhuǎn)成MD5得到密文2,然后密文1和密文2進(jìn)行匹配,如果一樣,說(shuō)明支付信息沒(méi)有被修改

          因?yàn)閔ash是無(wú)論多大的數(shù)得到的都是128位的數(shù),所有肯定有些數(shù)據(jù)得到的hash值是一樣的,這個(gè)就叫做散列碰撞

          2、對(duì)稱加密:

          對(duì)稱加密就是明文通過(guò)密鑰能得到密文,密文通過(guò)密鑰解密能得到明文
          常見(jiàn)算法:
          • DES:數(shù)據(jù)加密標(biāo)準(zhǔn)(用得少,因?yàn)閺?qiáng)度不夠)

          • 3DES:用三個(gè)密鑰對(duì)相同數(shù)據(jù)執(zhí)行3次加密,強(qiáng)度增強(qiáng),但是有3個(gè)密鑰比較麻煩,所有用的比較少

          • AES:高級(jí)密碼標(biāo)準(zhǔn),鑰匙串訪問(wèn)就是使用這個(gè),F(xiàn)BI加密用的也是這個(gè)

          異或一般用于游戲數(shù)據(jù)的常規(guī)加密
          應(yīng)用模式:
          • ECB:電子密碼本模式,每一塊數(shù)據(jù)獨(dú)立加密。最基本的加密模式,也就是通常理解的加密,相同的明文將永遠(yuǎn)加密成相同的密文,無(wú)初始向量,因?yàn)槊恳粔K數(shù)據(jù)都是單獨(dú)的,所以容易受到密碼本重放攻擊,一般情況很少用

          • CBC:密碼分組鏈接模式,使用一個(gè)密鑰和一個(gè)初始化向量(IV)對(duì)數(shù)據(jù)執(zhí)行加密,明文被加密前要與前面的密文進(jìn)行異或或運(yùn)算后再加密,因此只要選擇不同的初始向量,相同的密碼加密后會(huì)形成不同的密文,這是目前應(yīng)用最廣泛的模式。CBC加密后的密文是上下文相關(guān)的,但明文的錯(cuò)誤不會(huì)傳遞到后續(xù)分組,但是如果一個(gè)分組丟失,后面的分組將全部作廢,也就是數(shù)據(jù)都是相關(guān)聯(lián)的,后面一塊數(shù)據(jù)的加解密依賴于前一塊數(shù)據(jù),如果其中一塊數(shù)據(jù)遭到破壞,那么整個(gè)數(shù)據(jù)都無(wú)法解析

          • CBC可以有效的保證密文的完整性,如果一個(gè)數(shù)據(jù)塊在傳遞時(shí)丟失或者改變了,后面的數(shù)據(jù)將無(wú)法正常解密

          通過(guò)終端命令加密,我們會(huì)發(fā)現(xiàn) 介紹下AES的終端加解密命令:
             
          /**
          * 終端測(cè)試指令
          *
          * DES(ECB)加密
          * $ echo -n hello | openssl enc -des-ecb -K 616263 -nosalt | base64
          *
          * DES(CBC)加密
          * $ echo -n hello | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
          *
          * AES(ECB)加密
          * $ echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
          *
          * AES(CBC)加密
          * $ echo -n hello | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
          *
          * DES(ECB)解密
          * $ echo -n HQr0Oij2kbo= | base64 -D | openssl enc -des-ecb -K 616263 -nosalt -d
          *
          * DES(CBC)解密
          * $ echo -n alvrvb3Gz88= | base64 -D | openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -d
          *
          * AES(ECB)解密
          * $ echo -n d1QG4T2tivoi0Kiu3NEmZQ== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
          *
          * AES(CBC)解密
          * $ echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
          *
          * 提示:
          * 1> 加密過(guò)程是先加密,再base64編碼
          * 2> 解密過(guò)程是先base64解碼,再解密
          */

          加密代碼:

          加解密其實(shí)用的都是CCCrypt函數(shù),只是傳入的類型不一樣
             
          /** AES - ECB */
          NSString * key = @"abc";
          NSString * encStr = [[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:key iv:nil];

          NSLog(@"加密的結(jié)果是:%@",encStr);

          NSLog(@"解密的結(jié)果是:%@",[[EncryptionTools sharedEncryptionTools] decryptString:encStr keyString:key iv:nil]);

          /** AES - CBC 加密 */
          uint8_t iv[8] = {1,2,3,4,5,6,7,8};
          NSData * ivData = [NSData dataWithBytes:iv length:sizeof(iv)];

          NSLog(@"CBC加密:%@",[[EncryptionTools sharedEncryptionTools] encryptString:@"hello" keyString:@"abc" iv:ivData]);

          NSLog(@"解密:%@",[[EncryptionTools sharedEncryptionTools] decryptString:@"u3W/N816uzFpcg6pZ+kbdg==" keyString:key iv:ivData]);

          - (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {

          // 設(shè)置秘鑰
          NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
          uint8_t cKey[self.keySize];
          bzero(cKey, sizeof(cKey));
          [keyData getBytes:cKey length:self.keySize];

          // 設(shè)置iv
          uint8_t cIv[self.blockSize];
          bzero(cIv, self.blockSize);
          int option = 0;
          if (iv) {
          [iv getBytes:cIv length:self.blockSize];
          option = kCCOptionPKCS7Padding;
          } else {
          option = kCCOptionPKCS7Padding | kCCOptionECBMode;
          }

          // 設(shè)置輸出緩沖區(qū)
          NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
          size_t bufferSize = [data length] + self.blockSize;
          void *buffer = malloc(bufferSize);

          // 開(kāi)始加密
          size_t encryptedSize = 0;
          //加密解密都是它 -- CCCrypt
          CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
          self.algorithm,
          option,
          cKey,
          self.keySize,
          cIv,
          [data bytes],
          [data length],
          buffer,
          bufferSize,
          &encryptedSize);

          NSData *result = nil;
          if (cryptStatus == kCCSuccess) {
          result = [NSData dataWithBytesNoCopy:buffer length:encryptedSize];
          } else {
          free(buffer);
          NSLog(@"[錯(cuò)誤] 加密失敗|狀態(tài)編碼: %d", cryptStatus);
          }

          return [result base64EncodedStringWithOptions:0];
          }

          - (NSString *)decryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {

          // 設(shè)置秘鑰
          NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
          uint8_t cKey[self.keySize];
          bzero(cKey, sizeof(cKey));
          [keyData getBytes:cKey length:self.keySize];

          // 設(shè)置iv
          uint8_t cIv[self.blockSize];
          bzero(cIv, self.blockSize);
          int option = 0;
          if (iv) {
          [iv getBytes:cIv length:self.blockSize];
          option = kCCOptionPKCS7Padding;//CBC 加密!
          } else {
          option = kCCOptionPKCS7Padding | kCCOptionECBMode;//ECB加密!
          }

          // 設(shè)置輸出緩沖區(qū)
          NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:0];
          size_t bufferSize = [data length] + self.blockSize;
          void *buffer = malloc(bufferSize);

          // 開(kāi)始解密
          size_t decryptedSize = 0;
          /**CCCrypt 對(duì)稱加密算法的核心函數(shù)(加密/解密)
          參數(shù):
          1、kCCEncrypt 加密/kCCDecrypt 解密
          2、加密算法、默認(rèn)的 AES/DES
          3、加密方式的選項(xiàng)
          kCCOptionPKCS7Padding | kCCOptionECBMode;//ECB加密!
          kCCOptionPKCS7Padding;//CBC 加密!
          4、加密密鑰
          5、密鑰長(zhǎng)度
          6、iv 初始化向量,ECB 不需要指定
          7、加密的數(shù)據(jù)
          8、加密的數(shù)據(jù)長(zhǎng)度
          9、緩沖區(qū)(地址),存放密文的
          10、緩沖區(qū)的大小
          11、加密結(jié)果大小
          */

          CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
          self.algorithm,
          option,
          cKey,
          self.keySize,
          cIv,
          [data bytes],
          [data length],
          buffer,
          bufferSize,
          &decryptedSize);

          NSData *result = nil;
          if (cryptStatus == kCCSuccess) {
          result = [NSData dataWithBytesNoCopy:buffer length:decryptedSize];
          } else {
          free(buffer);
          NSLog(@"[錯(cuò)誤] 解密失敗|狀態(tài)編碼: %d", cryptStatus);
          }

          return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
          }


          3、加密算法存在的問(wèn)題

          像我們加密會(huì)直接將要加密的字符串轉(zhuǎn)成NSData后丟給系統(tǒng)的加密函數(shù),但是對(duì)于黑客來(lái)說(shuō),因?yàn)榧用艿暮瘮?shù)是系統(tǒng)的函數(shù),所以黑客可以通過(guò)hook系統(tǒng)的函數(shù)來(lái)拿到將要加密的數(shù)據(jù),這樣很不安全
          我們可以通過(guò)符號(hào)斷點(diǎn)攔截到系統(tǒng)函數(shù)CCCrypt,因?yàn)榧用艿臄?shù)據(jù)在第七個(gè)參數(shù),所以我們可以看一下寄存器x6的數(shù)據(jù)


          作者 |  iOS_大書
          鏈接 | 點(diǎn)擊左下方的 ‘’閱讀原文’’ 可進(jìn)入作者主頁(yè)

          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來(lái),可以說(shuō)是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

          點(diǎn)擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

          在看點(diǎn)這里好文分享給更多人↓↓

          瀏覽 47
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲日韩一级精品片在线播放 | 午夜福利视频一区二区 | 日日夜夜抽麻豆 | 国家一级黄色视频 | 国产高清在线激情 |