iOS開發(fā)加解密算法-基礎(chǔ)篇(3)<大文件加解密>

一、 需求驅(qū)動(dòng)功能開發(fā),項(xiàng)目的需求是文件先經(jīng)過服務(wù)端加密,客戶端下載完成后再進(jìn)行解密后使用,最終確認(rèn)的方案是對(duì)文件分段加密,加密后再拼接成新的文件,最后在實(shí)現(xiàn)的時(shí)候遇到過一些坑<內(nèi)存問題>。該篇只是介紹我們項(xiàng)目中使用的文件加密方案,并不代表移動(dòng)端開發(fā)主流文件加密的方案

</br>

二、實(shí)現(xiàn):對(duì)大文件進(jìn)行分段切割

首先想到的就是OC自帶的文件處理類NSFileHandle,不過在使用的時(shí)候遇到了一個(gè)運(yùn)存無法消除的問題,雖然可以用NSFilehandlereadDataOfLengthseekToFileOffset的兩個(gè)方法達(dá)到分段讀取文件的功能,但是每次調(diào)用的時(shí)候程序的內(nèi)存是疊加的,文件多大需要消耗的內(nèi)存就有多大,當(dāng)需要的內(nèi)存大于程序的上限的時(shí)候,就會(huì)造成程序的閃退。


OC的方法雖然能實(shí)現(xiàn)功能,但是性能有不滿足要求,因?yàn)镃語言自帶標(biāo)準(zhǔn)I/O庫,就試著用C語言寫了個(gè)文件分段讀取的方法,并實(shí)現(xiàn)了內(nèi)存的即時(shí)的釋放,保證了App的性能需求。調(diào)用的方法解釋可以參考:C語言文件操作函數(shù)|c語言文件讀寫函數(shù),fopen方法參數(shù)說明參見百科,具體方法實(shí)現(xiàn)如下:

/**
 *  解密視文件,主要思路是先找到待解密的文件,將解密的文件存放與臨時(shí)文件下,
 *  解密完成將加密的文件刪除再將解密完成的文件替換成原文件的名字
 *
 *  @param mediaPath 文件路徑
 *  @param index     文件路徑下標(biāo)
 *
 *  @return 是否解密成功
 */
- (BOOL)addDecryptFileWithMediaPath:(NSString *)mediaPath index:(NSInteger)index  header:(NSInteger)header key:(NSInteger)key{
    NSFileManager *manager = [NSFileManager defaultManager];
    NSString *subPath = mediaPath;
    // 文件類型
    NSString *pathExtension = [subPath pathExtension];
    // 文件路徑的前路徑
    NSString *prePath = [subPath stringByDeletingLastPathComponent];
    // 當(dāng)前文件名 主要采用的是創(chuàng)建一個(gè)
    NSString *tempfilePath = [NSString stringWithFormat:@"%@/ios_temp_%ld.%@",prePath,index,pathExtension];
    [manager removeItemAtPath:tempfilePath error:nil];
    [manager createFileAtPath:tempfilePath contents:nil attributes:nil];
    // 創(chuàng)建讀寫FILE
    FILE *readFile;
    FILE *writeFile;
    //打開發(fā)文件
    readFile = fopen([subPath cStringUsingEncoding:NSUTF8StringEncoding], "rb+");
    writeFile = fopen([tempfilePath cStringUsingEncoding:NSUTF8StringEncoding], "a+");
   //獲取文件屬性信息
    NSDictionary *attributes = [manager attributesOfItemAtPath:subPath error:nil];
    //獲取文件字節(jié)總長(zhǎng)度
    self.fileLength = ((NSNumber *)[attributes objectForKey:@"NSFileSize"]).integerValue;
    int decodeKey = (int)key;
    //根據(jù)我們的加密頭和加密參數(shù)判斷是否需要解密
    if (self.fileLength > header) {
        //如果符合解密條件將當(dāng)前初始解密文件長(zhǎng)度設(shè)置成頭的長(zhǎng)度<header是加密的時(shí)候添加上的在解密的時(shí)候需要
先將header的長(zhǎng)度去除再進(jìn)行解密>
        self.currnentLength = header;
        //調(diào)用解密方法
        BOOL isSuc =  decodeFile(readFile, self.fileLength, self.currnentLength, writeFile,decodeKey);
        if (isSuc) {
            if([manager removeItemAtPath:mediaPath error:nil]){
                isSuc =  [manager moveItemAtPath:tempfilePath toPath:mediaPath error:nil];
            }else{
                isSuc = NO;
            }
        }
        return isSuc;
    }else{
        return NO;
    }
}

=============================我是分割線============================

/**
 *  C函數(shù)解密文件的方法
 *
 *  @param file         待解密的文件File
 *  @param fileLength   文件長(zhǎng)度
 *  @param currentLegth 當(dāng)前解密的文件長(zhǎng)度
 *  @param direcFile    目標(biāo)存儲(chǔ)目錄
 */
BOOL decodeFile(FILE *file,long fileLength,long currentLegth,FILE *direcFile,int key){
    BOOL isSucessed;
//分段最大讀取長(zhǎng)度 1MB
    NSInteger readLength = 1024 * 1024 * 1;
    // 如果文件長(zhǎng)度減去當(dāng)前解密到的文件長(zhǎng)度還大于分段最大讀取長(zhǎng)度則采用遞歸調(diào)用解密
    if (fileLength - currentLegth > readLength) {
        // 指針指向首字節(jié)
        //讀取文件
        // 成功,返回0,失敗返回-1
        int set = fseek(file, currentLegth, SEEK_SET);
        if (set == 0) {
            //設(shè)置buffer保存分段讀取文件的Data值
            Byte *buffer = malloc(sizeof(Byte) * readLength);
            fread(buffer, readLength, sizeof(Byte), file);
           //讀取成功后設(shè)置當(dāng)前解密長(zhǎng)度
            currentLegth += readLength;
            //設(shè)置讀取位置
            // 解密方法  可以在此基礎(chǔ)上采用其他的加解密<RSA/AES>
            for (int i = 0 ; i < readLength; i++) {
                *(buffer + i ) -= key;
            }
            // 將解密后的文件流寫入解密目標(biāo)文件
            size_t writedData =  fwrite(buffer, sizeof(Byte), readLength, direcFile);
            if (writedData == readLength) {
                isSucessed = YES;
            }else{
                isSucessed = NO;
            }
          // 釋放內(nèi)存  
            free(buffer);
            if (isSucessed) {
                // 遞歸調(diào)用
                return  decodeFile(file, fileLength, currentLegth,direcFile,key);
            }else{
                return isSucessed;
            }}}else{//如果文件長(zhǎng)度減去當(dāng)前長(zhǎng)度小于最小分段讀取長(zhǎng)度 則跳出遞歸完成解密
                // 大于0的話繼續(xù)解密
              if(fileLength - currentLegth  > 0){
            long length = fileLength - currentLegth;
            int set = fseek(file, currentLegth, SEEK_SET);
            if (set == 0) {
                Byte *buffer = malloc(sizeof(Byte) * length);
                fread(buffer, length, sizeof(Byte), file);
                currentLegth += length;
                //設(shè)置讀取位置
                for (int i = 0 ; i < length; i++) {
                    *(buffer + i ) -= key;
                }
                size_t writedData = fwrite(buffer, sizeof(Byte), length, direcFile);
                printf("最終-fseek--%d",set);
                if (writedData == length) {
                    isSucessed = YES;
                }else{
                    isSucessed = NO;
                }
                // 釋放內(nèi)存
                free(buffer);
                // 關(guān)閉文件
                fclose(file);
                fclose(direcFile);
            }
        }
    }
    return isSucessed;
}

Demo地址

如有不當(dāng)之處歡迎指正。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 項(xiàng)目也快兩年了,項(xiàng)目這么長(zhǎng)時(shí)間下來經(jīng)歷了各種加解密算法,坑也踩過不少.現(xiàn)在把項(xiàng)目中使用過一些常用的加解密算法總結(jié)一...
    踏遍青山閱讀 2,365評(píng)論 1 12
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,533評(píng)論 19 139
  • 首先羅列一些知識(shí)點(diǎn): 1.加密算法通常分為對(duì)稱性加密算法和非對(duì)稱性加密算法:對(duì)于對(duì)稱性加密算法,信息接收雙方都需事...
    JonesCxy閱讀 1,547評(píng)論 2 4
  • 嘟噥嘟噥:最近接到一個(gè)任務(wù):在客戶端動(dòng)態(tài)生成RSA密鑰對(duì),然后向服務(wù)器發(fā)送這個(gè)密鑰對(duì)中的公鑰字符串,由服務(wù)器進(jìn)行公...
    TimmyR閱讀 8,353評(píng)論 19 21
  • 忘掉今天犯的錯(cuò)誤,其實(shí)是對(duì)自己的一種寬恕。是人就會(huì)犯錯(cuò)誤,有時(shí)候就是當(dāng)時(shí)心念一轉(zhuǎn)的瞬間,于是犯下一些自己銘記的錯(cuò)誤...
    夏煙閱讀 207評(píng)論 0 0

友情鏈接更多精彩內(nèi)容