iOS中常见的几种加密方式总结

前言

随着Internet网的广泛应用,信息安全问题日益突出,当今网络应用的数据不仅仅是强调对数据本身的保护,还有是在处理大量的并发请求时对Qos和服务器稳定的考虑。

如图加解密常用代名词
在这里插入图片描述

对称加密

对称加密简介

简介

他的加密和解密秘钥相同

优点

1.运算速度快,加密强度高,适合大批量的数据加密
2.加密解密的速度比较快,适合数据比较长时的使用

缺点

  1. 加密和解密使用相同的秘钥,秘钥的分发与保密比较困难
  2. 密钥传输的过程不安全,且容易被破解,密钥管理也比较麻烦

工作流程

在这里插入图片描述

AES加密算法

AES简介

AES又称高级加密标准,是下一代的加密算法标准,速度快,安全级别高,支持128、192、256、512位密钥的加密,其加密和解密的密钥都是同一个。

AES优点

比一般的非对称加密算法速度要快

AES缺点

由于加密与解密的密钥是相同的,如果前后端利用AES进行加密的话,如何保存密钥成了一个非常头疼的问题

注意

AES的秘钥是16字节的,待加密的内容必须是16的倍数,如果不是16的倍数通过补全内容方式进行避免

代码示例

+ (NSData *)aes256Encryption:(NSData *)originData
                  encryptKey:(NSString *)key
{
    if (!originData || !key) {
        return nil;
    }
     char keyPtr[kCCKeySizeAES256 + 1];
        bzero(keyPtr, sizeof(keyPtr));
        [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
        
        NSUInteger dataLength = [originData length];
        size_t bufferSize = dataLength + kCCBlockSizeAES128;
        void *buffer = malloc(bufferSize);
        size_t numBytesEncrypted = 0;
        CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode, keyPtr, kCCBlockSizeAES128, NULL, [originData bytes], dataLength, buffer, bufferSize, &numBytesEncrypted);
        
        if (cryptStatus == kCCSuccess) {
            
            return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        }
        
        free(buffer);
        return nil;
}

+ (NSData *)aes256Decryption:(NSData *)originData
                 decryptKey:(NSString *)key
{
    if (!originData || !key) {
        return nil;
    }
    char keyPtr[kCCKeySizeAES256+1];
    bzero(keyPtr, sizeof(keyPtr));
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [originData length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128,
                                          kCCOptionPKCS7Padding | kCCOptionECBMode,
                                          keyPtr, kCCBlockSizeAES128,
                                          NULL,
                                          [originData bytes], dataLength,
                                          buffer, bufferSize,
                                          &numBytesDecrypted);
    if (cryptStatus == kCCSuccess) {
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
        
    }
    free(buffer);
    return nil;
}

测试

//秘钥
        NSString *AESKeyString = [ZMMEncryptionModel getAES256EncryptKey];
        //手机号
        NSString *phone = [ZMMEncryptionModel getNeedEncryptedPhone];
        //手机号转化为NSData
        NSData *phoneData = [phone dataUsingEncoding:NSUTF8StringEncoding];
        //手机号加密过后的NSData
        NSData *AESPhEnAfterData = [NSData aes256Encryption:phoneData encryptKey:AESKeyString];
        //加密后得到的数据转换为16进制字符串,传给服务器
        NSString *passToServer = [NSData convertStringFromData:AESPhEnAfterData];
        //使用AES解密之后的数据
        NSData *AESPhDecAfterData = [NSData aes256Decryption:AESPhEnAfterData
                                                  decryptKey:AESKeyString];
        //解密之后转化为字符串
        NSString *result = [[NSString alloc] initWithData:AESPhDecAfterData
                                                 encoding:NSUTF8StringEncoding];

demo下载地址

非对称加密

非对称加密简介

加密和解密秘钥不同,一个是公钥一个是私钥

优点

  1. 加密强度小,加密时间长,常用于数字签名和加密秘钥
  2. 非对称加密算法有两种密钥,其中一个是公开的,所以在密钥传输上不存在安全性问题,使得其在传输加密数据的安全性上又高于对称加密算法。

缺点:

1.加密解密的速度远远低于对称加密算法,因此不适用于数据量较大的情况

工作流程
在这里插入图片描述

RSA加密算法

RSA简介

RSA加密算法是一种非对称加密算法,密钥为一对公钥和私钥组成。通常把公钥发送给使用方,私钥由接收方自己保存

RSA优点

解决了对称加密算法如何保存密钥的问题

RSA缺点

由于RSA算法的原理都是大数计算,使得RSA最快的情况也比对称加密算法慢上好几倍。速度一直是RSA的缺陷,一般来说RSA只用于小数据的加密.RSA的速度是对应同样安全级别的对称加密算法的1/1000左右。

RSA的长度

**秘钥长度:**秘钥长度一般是96bits~1024bits
**明文长度:**明文的长度(bytes) <= 秘钥长度(bytes) - 11(bytes)这样 128字节(1024bits)-减去11字节正好是117字节 。所以明文长度的最大值决定了RSA的最大瓶颈也就是一次加密的数量有限,可以用分片来解决,但分片的方法某些情况下给服务器解密带来一定的问题。
最佳解决方案: AES+RSA混合加密
密文长度:
不分片:密文长度 = 明文长度
分片: 密文长度 = 秘钥长度 * 片数

RSA特点
公钥加密,私钥解密。加密的系统和解密系统分开部署。加密的系统不应该同时具备解密的功能,

注意

RSA加密的明文最大长度117字节,如果超过117字节则程序会报错

使用openssl 生成所需要的密钥文件

代码示例

#import "ZMMSecurityUtil.h"
#import "ZMMBase64.h"

#define RSAPublicFileName @"公钥文件名"
#define RSAPublicFileType @"公钥文件类型"

static NSString *RSAEncryptString(NSString *str)
{
    SecKeyRef key = securityUtil.SecKeyRefCopyPublicKey();
    NSError *error = nil;
    NSString *result = nil;
    if (key!=NULL) {
        NSData *data = securityUtil.encryptString(str,key,&error);
        result = [ZMMBase64 encodeStringWithData:data];
        CFRelease(key);
    }
    if (!result) {
        return nil;
    }
    return result;
}

static NSData *RSAEncryptStringResultsData(NSString *str)
{
    SecKeyRef key = securityUtil.SecKeyRefCopyPublicKey();
    NSError *error = nil;
    NSData *reslut = nil;
    if (key!=NULL) {
        reslut = securityUtil.encryptString(str,key,&error);
        CFRelease(key);
    }
    if (!reslut) {
        return nil;
    }
    return reslut;
}

static SecKeyRef SecKeyRefCopyPublicKey()
{
    NSString *certPath = [[NSBundle mainBundle] pathForResource:RSAPublicFileName ofType:RSAPublicFileType];
    NSData *certData = [[NSData alloc] initWithContentsOfFile:certPath];
    if (!certData) {
        return nil;
    }
    SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)certData);
    CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, (const void **)&cert, 1, NULL);
    SecTrustRef trust = NULL;
    SecKeyRef pub_key_leaf = NULL;
    SecPolicyRef policy = NULL;
    if (certs != NULL) {
        policy = SecPolicyCreateBasicX509();
        SecTrustCreateWithCertificates(certs, policy, &trust);
        CFErrorRef *trustResult = NULL;
        if (SecTrustEvaluateWithError(trust, trustResult) == noErr) {
            pub_key_leaf = SecTrustCopyPublicKey(trust);
        }
    }
    
    if (cert != NULL) {
        CFRelease(cert);
    }
    if (certs != NULL) {
        CFRelease(certs);
    }
    if (trust != NULL) {
        CFRelease(trust);
    }
    if (policy != NULL) {
        CFRelease(policy);
    }
    return pub_key_leaf;
}


static NSData *encryptString(NSString *inString,SecKeyRef keyRef,NSError **err)
{
    size_t cipherBufferSize = SecKeyGetBlockSize(keyRef);
    uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
    NSData *stringBytes = [inString dataUsingEncoding:NSUTF8StringEncoding];
    NSInteger blockSize = cipherBufferSize - 11;
    NSInteger blockCount = (NSInteger)ceil([stringBytes length] / (double)blockSize);
    NSMutableData *encryptedData = [[NSMutableData alloc] init];
    for (NSInteger i=0; i<blockCount; i++) {
        NSInteger bufferSize = MIN(blockSize,[stringBytes length]-i * blockSize);
        NSData *buffer = [stringBytes subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
        OSStatus status = SecKeyEncrypt(keyRef,
                                        kSecPaddingPKCS1,
                                        (const uint8_t *)[buffer bytes],
                                        [buffer length],
                                        cipherBuffer,
                                        &cipherBufferSize);
        if (status == noErr)
        {
            NSData *encryptedBytes = [[NSData alloc]
                                      initWithBytes:(const void *)cipherBuffer
                                      length:cipherBufferSize];
            [encryptedData appendData:encryptedBytes];
        }
        else
        {
            if (err) {
                *err = [NSError errorWithDomain:@"fail" code:status userInfo:nil];
            }
            
            (void)(free(cipherBuffer));
            if (keyRef) {
                CFRelease(keyRef);
            }
            return nil;
        }
    }
    (void)(free(cipherBuffer));
    if (keyRef) {
        CFRelease(keyRef);
    }
    return encryptedData;
}



const struct ZMMSecurityUtil securityUtil = {
    
    .SecKeyRefCopyPublicKey = SecKeyRefCopyPublicKey,
    .RSAEncryptString = RSAEncryptString,
    .encryptString = encryptString,
    .RSAEncryptStringResultsData = RSAEncryptStringResultsData,

};

测试

NSString *str = @"3431410491094017401249017410041";
        NSString *encrptionString = securityUtil.RSAEncryptString(str);
        NSLog(@"RSA加密后的字符串%@",encrptionString);

demo下载地址

AES+RSA混合加密

场景
打开应用的第一次登陆大概需要发送1000个字节,用RSA全部加密,由于RSA加密的特性,秘钥长度最大128字节,也就是一次加密的明文是117字节,超出的部分使用分片多次加密,那我们需要分9次,服务端在解密的时候也是耗时的,对性能造成了很大的影响。如果使用AES加密,可以做到一次性加密,但是秘钥的传输成了最大的问题,接收方独自拥有秘钥才安全,

方案

RSA先对AES的秘钥加密,在接收方对RSA解密得到秘钥,用该秘钥对AES进行解密得到所有明文。

流程

1.服务器端(server)分别生成自己的RSA密钥对,并提供接口给客户端获取RSA公钥(RSAPublicKey)
2.客户端拿到RSA公钥,随机生成AES的秘钥(AESKey),
3.用RSA公钥(RSAPublicKey)使用RSA加密方式对AES的秘钥(AESKey)加密得到= RSA加密过后的AES秘钥(AESKeyAfertRSA)
4.传输数据(Data)用RSA加密过后的AES秘钥(AESKeyAfertRSA) 使用AES加密的方式进行加密得到数据(AESData)
5.将 RSA加密过后的AES秘钥(AESKeyAfertRSA) 和 使用AES加密的方式进行加密得到数据(AESData) 拼接起来传输给服务端(server)
6.服务端用之前RSA生成的私钥解密 将 RSA加密过后的AES秘钥(AESKeyAfertRSA)拿到AES的秘钥(AESKey)在通过AES的秘钥拿到明文数据

代码示例

 //1.获取AES的秘钥
        NSString *AESKeyString = [ZMMEncryptionModel getAES256EncryptKey];
        //2.把AES的秘钥使用RSA加密
        NSData *encrptionData = securityUtil.RSAEncryptStringResultsData(AESKeyString);
        //3.把RSA加密过的AES的秘钥转化16进制字符串
        NSString *encryptKey = [NSData convertStringFromData:encrptionData];
        //4.需要加密的数据
        NSData *needEncrptionData = [ZMMEncryptionModel getNeedAES256Data];
        //5.AES加密过的数据
        NSData *AESPhEnAfterData = [NSData aes256Encryption:needEncrptionData encryptKey:encryptKey];
        //6.把AES加密过的数据 和秘钥 拼接字符串传给服务端
        NSString *reslut = [NSString stringWithFormat:@"%@,%@",AESPhEnAfterData,encryptKey];
        NSLog(@"传给服务端的数据%@",reslut);

demo下载地址

base64加密

定义

Base64编码,是我们程序开发中经常使用到的编码方法。它是一种基于用64个可打印字符来表示二进制数据的表示方法

base64编解码工具

工具

如图
在这里插入图片描述

Base64简单说明

特点:可以将任意的二进制数据进行Base64编码

结果:所有的数据都能被编码为并只用65个字符就能表示的文本文件。

65字符:A~Z a~z 0~9 + / =

对文件进行base64编码后文件数据的变化:编码后的数据~=编码前数据的4/3,会大1/3左右。

Base64编码原理
1)将所有字符转化为ASCII码;

2)将ASCII码转化为8位二进制;

3)将二进制3个归成一组(不足3个在后边补0)共24位,再拆分成4组,每组6位;

4)统一在6位二进制前补两个0凑足8位;

5)将补0后的二进制转为十进制;

6)从Base64编码表获取十进制对应的Base64编码;

处理过程说明

a.转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。

b.数据不足3byte的话,于缓冲区中剩下的bit用0补足。然后,每次取出6个bit,按照其值选择查表选择对应的字符作为编码后的输出。

c.不断进行,直到全部输入数据转换完成。

d.如果最后剩下两个输入数据,在编码结果后加1个“=”;

e.如果最后剩下一个输入数据,编码结果后加2个“=”;

f.如果没有剩下任何数据,就什么都不要加,这样才可以保证资料还原的正确性。

代码示例

代码

//base64解码
+ (nullable NSString *)decodeString:(NSString *)string {
    
    if (!string) {
        return nil;
    }
    NSData *data=[[NSData alloc]initWithBase64EncodedString:string options:0];
    if (data) {
        return [[NSString alloc]initWithData:data
                                    encoding:NSUTF8StringEncoding];;
    }
    
    return nil;
}
//base64编码
+ (nullable NSString *)encodeString:(NSString *)string
{
    if (!string) {
        return nil;
    }
    NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
    if (data) {
        return [data base64EncodedStringWithOptions:0];
    }
    return nil;
}

测试

 NSString *originString = [ZMMEncryptionModel getAES256EncryptKey];
        NSString *base64En = [ZMMBase64 encodeString:originString];
        NSString *base64Dec = [ZMMBase64 decodeString:base64En];

//原始数据=ZWCXQMeco6sdscQEF09
//编码后的数据=WldDWFFNZWNvNnNkc2NRRUYwOQ==
//解码后的数据=ZWCXQMeco6sdscQEF09
        

demo下载地址

信息摘要(Hash)

MD5

定义

MD5即Message-Digest Algorithm 5(消息-摘要算法5),为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4

MD5特点
1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4、弱抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
5、强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
6、MD5加密是不可解密的,但是网上有一些解析MD5的,那个相当于一个大型的数据库,通过匹配MD5去找到原密码。所以,只要在要加密的字符串前面加上一些字母数字符号或者多次MD5加密,这样出来的结果一般是解析不出来的。

MD5好处
1、压缩到固定长度128bit,长度小适合互联网传输;
2、相同文件多次压缩的值不变,常用于对文件的是否被篡改的校验;
3、不同文件压缩后出现值冲突的几率很小;
4、md5算法比同类的sha-1计算速度快;

MD5应用

1、一致性验证:MD5的典型应用是对一段信息(Message)产生信息摘要(Message-Digest),以防止被篡改。MD5就可以为任何文件(不管其大小、格式、数量)产生一个同样独一无二的“数字指纹”,如果任何人对文件做了任何改动,其MD5值也就是对应的“数字指纹”都会发生变化。

2、数字签名:MD5的典型应用是对一段Message(字节串)产生fingerprint(指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫 readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现(两个MD5值不相同)。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。

 3、安全访问认证:MD5还广泛用于操作系统的登陆认证上,如Unix、各类BSD系统登录密码、数字签名等诸多方面。如在Unix系统中用户的密码是以MD5(或其它类似的算法)经Hash运算后存储在文件系统中。当用户登录的时候,系统把用户输入的密码进行MD5 Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这可以避免用户的密码被具有系统管理员权限的用户知道。

客户端应用
1、本地数据加密:对NSUserDefaults,qlite,存储文件数据加密,保护帐号和关键信息。
2、URL编码加密:对程序中出现的URL进行编码加密,防止URL被静态分析
3、网络传输数据加密:对客户端传输数据提供加密方案,有效防止通过网络接口的拦截获取
4、方法体,方法名高级混淆:对应用程序的方法名和方法体进行混淆,保证源码被逆向后无法解析代码
5、程序结构混排加密:对应用程序逻辑结构进行打乱混排,保证源码可读性降到最低

MD5虽然说是不可逆的,但是由于有网站的存在,专门用来查询MD5码,所以有的简单的MD5码是可以在这里搜到源码的。为了让MD5码更加安全 涌现了很多其他方法,如加盐。盐要足够长足够乱得到的MD5码就很难查到。

MD5字符串加密

- (NSString *)md5_32bit
{
    //MD5是基于C语言的,先转化为C字符串
    const char * str = [self UTF8String];
    //创建一个数组,接受MD5加密的值
    uint8_t outputBuffer[CC_MD5_DIGEST_LENGTH];
   //把str字符串转换成了32位的16进制数列(这个过程不可逆转) 存储到了result这个空间中
    CC_MD5(str, (CC_LONG)strlen(str), outputBuffer);
    NSMutableString *outputString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
    //把C字符串取出来,转化成NSString类型
       for(NSInteger count = 0; count < CC_MD5_DIGEST_LENGTH; count++){
           [outputString appendFormat:@"%02x",outputBuffer[count]];
       }
    NSString *result = [outputString copy];
    return result;
    
}

注意!!!!!

“CC_MD5”被弃用:第一次弃用是在iOS 13.0中。客户机应该迁移到SHA256(或更强)。

demo下载地址

SHA

定义

哈希算法主要适用于数字签名标准里面定义的数字签名算法

特性

不可以从消息摘要中复原信息;两个不同的消息不会产生同样的消息摘要。

SHA 校验大文件完整性

1.在文件超过1G的时候,不能一次性放入内存之中,但是我们还是需要将这个文件进行SHA256加密
2.一个系统的api——update系列的方法

一般大文件下载下来,为了确定这个文件是否下载有误,或者检查此文件在下载过程中有没有损坏,我们需要进行的一步安全性操作就是大文件的SHA256加密,用你加密的字符串,和源文件的md5字符串进行校验,看是否一样

  • 客户端上传文件

上传文件,在请求的body
里面添加该文件的SHA256值来告诉服务器,服务器接收文件完毕后通过检验文件的SHA256值与请求body里面的SHA256值来最终确定本次上否成功。

  • 客户端下载文件

下载文件,在响应头里收到了服务器附带的该文件的MD5值,文件下载结束后,通过获取下载后文件的SHA256值与本次请求服务器返回的响应头中的SHA256值做一个比较来最终判断本次下载是否成功。

代码

#define FileHashDefaultChunkSizeForReadingData 1024*8

+ (NSString *)getFileSHA256WithPath:(NSString* )path
{
     return (__bridge_transfer NSString *)FileSHA256HashCreateWithPath((__bridge CFStringRef)path, FileHashDefaultChunkSizeForReadingData);
}

CFStringRef FileSHA256HashCreateWithPath(CFStringRef filePath,size_t chunkSizeForReadingData) {
    // Declare needed variables
    CFStringRef result = NULL;
    CFReadStreamRef readStream = NULL;
    // Get the file URL
    CFURLRef fileURL =
    CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
                                  (CFStringRef)filePath,
                                  kCFURLPOSIXPathStyle,
                                  (Boolean)false);
    if (!fileURL) goto done;
    // Create and open the read stream
    readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault,
                                            (CFURLRef)fileURL);
    if (!readStream) goto done;
    bool didSucceed = (bool)CFReadStreamOpen(readStream);
    if (!didSucceed) goto done;
    // Initialize the hash object
    CC_SHA256_CTX hashObject;
    CC_SHA256_Init(&hashObject);
    // Make sure chunkSizeForReadingData is valid
    if (!chunkSizeForReadingData) {
        chunkSizeForReadingData = FileHashDefaultChunkSizeForReadingData;
    }
    // Feed the data to the hash object
    bool hasMoreData = true;
    while (hasMoreData) {
        uint8_t buffer[chunkSizeForReadingData];
        CFIndex readBytesCount = CFReadStreamRead(readStream,(UInt8 *)buffer,(CFIndex)sizeof(buffer));
        if (readBytesCount == -1) break;
        if (readBytesCount == 0) {
            hasMoreData = false;
            continue;
        }
        
        CC_SHA256_Update(&hashObject,(const void *)buffer,(CC_LONG)readBytesCount);
    }
    // Check if the read operation succeeded
    didSucceed = !hasMoreData;
    // Compute the hash digest
    unsigned char digest[CC_SHA224_DIGEST_LENGTH];
    CC_SHA256_Final(digest, &hashObject);
    // Abort if the read operation failed
    if (!didSucceed) goto done;
    // Compute the string result
    char hash[2 * sizeof(digest) + 1];
    for (size_t i = 0; i < sizeof(digest); ++i) {
        snprintf(hash + (2 * i), 3, "%02x", (int)(digest[i]));
    }
    result = CFStringCreateWithCString(kCFAllocatorDefault,(const char *)hash,kCFStringEncodingUTF8);
done:
    if (readStream) {
        CFReadStreamClose(readStream);
        CFRelease(readStream);
    }
    if (fileURL) {
        CFRelease(fileURL);
    }
    return result;
}

测试:

/*
1.本地文件
2.沙盒文件:把本地文件拷贝到沙盒文件
3.比较本地文件路径加密后字符串与沙盒文件路径加密后的字符串
4.查看文件是否被损坏

//本地文件
        NSString *filePath = [ZMMFileUtil getLocalFilePath];
        //本地文件加密SHA256
        NSString *localSHA256 = [NSString getFileSHA256WithPath:filePath];
        //沙盒文件的路径
        NSString *dirPath = [ZMMFileUtil getSandboxPath];
        //破坏文件
        BOOL damage = [ZMMFileUtil writeToFile:filePath data:@"破坏文件"];
        //把文件拷贝到沙盒
        BOOL copySuccess = [ZMMFileUtil fileCopy:filePath toPath:dirPath];
        NSString *dirSHA256 = [NSString getFileSHA256WithPath:dirPath];
        if (![dirSHA256 isEqualToString:localSHA256]) {
            NSLog(@"文件被损坏");
            
        }

*/

demo下载地址

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值