zoukankan      html  css  js  c++  java
  • iOS学习——数据加密

      在加密使用中,一种是散列函数(HASH),它最著名的特点就是不可逆性,我们无法通过加密出来的结果反向解密出内容,其最突出的代表就是MD5加密。MD5加密会无视内容大小,加密成一串32位字符串。面对其不可逆和无视内容大小特性,我们可以用它来做很多事情。

      1.使用MD5做传统的登陆密码加密,服务器保留的并不是用户的密码明文,而是一串MD5加密过后的数据,仅仅用来做登陆验证。当然,由于MD5加密后类似指纹的特性,即不同的数据加密结果不一样,但是相同数据加密结果一直是相同的。一些网站可以通过保存加密后的数据与对应明文,来对照获取到与加密数据相对应的明文输入。面对这种情况,加密需要做一些改变,首先一种是,每个用户注册的时候为其生成相对应的盐,这样采用MD5+盐的方式加密或者其它方式MD5(MD5)+盐等其它方式,其内容就极其难以破解,并且也不会因为使用统一加盐的方式导致人为泄漏。另外,针对抓包工具的横行,防止被抓包后,黑客采用直接使用加密后的数据登陆,MD5加密后的数据可以加上时间再次加密上传,一般可以采用分钟作为单位,这样服务器采用相同的加时间,当前时间和前后一分钟进行验证,这样让登陆账号密文时效性足以验证登陆而抓包者又难以使用。ps:再多的加密仍旧难以100%阻止登陆信息泄漏,因此在登陆就诞生了qq登陆这种验证方式。当用户设定好一台手机作为本机,服务器会记录对应的id,当在别处登陆的时候,首先会上传账号名,服务器根据账号找到对应本机,并发出询问信息,是否允许登陆,如果拒绝,登陆将无法执行,同意后,服务器才向登陆者发送允许登陆,然后再执行登陆操作。

      2.使用MD5可以进行搜索功能,例如百度搜索引擎等,上面的数据无以计数,如何准确搜索到想要的数据,就可以将数据加密,利用这种类似指纹的特性,快速找到用户想要的内容并展示。

      3.MD5可以做的另外一个特性就是版权。譬如视频,当作者发布在网上后,别人下载了,然后改掉信息重新发布,我们如何识别到谁是真正的发布者,就可以通过MD5来识别。作者上传到网上后,原版并不会被发不出来,所有放出来给用户下载观看的都是网站处理过后的视频,MD5的特性保证,任何一点不同都会加密出不同的MD5字符串,因此,别人下载再次上传,对比下加密过后的MD5可以很明显识别版权所有。

      有不可逆加密,肯定也是有可逆加密的使用。对称加密——传统加密方式,都是采用明文——密钥——密文,密文——密钥——明文方式进行数据加解密。这种加密方式对密钥的要求很高,而且要保证不会泄漏,一旦泄漏就会被破解加密,而且需要定期更换,密钥使用得越旧越不安全。其最常用的加密算法是:DES、3DES、AES等,当然还有其它的方式,但就不一一赘述了。DES和3DES算法都是类似的,只不过DES加密强度太低,所以出现了使用三个密钥进行三次DES算法这种方式,泄漏一个两个密钥毫无影响。而AES则是苹果这边最常见的加密方式,例如钥匙串就是使用的AES进行加密。对称加密算法有两种加密方式:ECB和CBC,一个视频数据可能非常大,一次加密不太现实,因此会将数据拆分开来,一块一块的单独加密,这就是ECB的加密形式。而CBC,则是在ECB的基础上加上一个向量,进行链式加密,只有加密完了第一个数据才加密第二个数据,并且,第一个数据的加密结果会成为第二个数据的加密密钥,及时部分数据泄漏或被破解,仍然破解所有数据,因为不知道其处于链条的哪一部分。

      

    - (NSString *)encryptString:(NSString *)string keyString:(NSString *)keyString iv:(NSData *)iv {
        
        // 设置秘钥
        NSData *keyData = [keyString dataUsingEncoding:NSUTF8StringEncoding];
        uint8_t cKey[self.keySize];
        bzero(cKey, sizeof(cKey));
        [keyData getBytes:cKey length:self.keySize];
        
        // 设置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;
        }
        
        // 设置输出缓冲区
        NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
        size_t bufferSize = [data length] + self.blockSize;
        void *buffer = malloc(bufferSize);
        
        // 开始加密
        size_t encryptedSize = 0;
        
        
        //CCCrypt  苹果对称加密核心算法
        /**参数说明
         1.加密或者解密
            kCCEncrypt
            kCCDecrypt
         2.加密方式:AES,DES,blowfish等等所有的对称加密方式
         3.ECB 或者CBC
            ECB:kCCOptionPKCS7Padding | kCCOptionECBMode
            CBC:kCCOptionPKCS7Padding
         4.加密的密钥
         5.密钥长度
         6.向量
         7.加密的数据
         8.数据大小
         9.密文内存地址
         10.密文内存缓冲区大小
         11.加密结果大小
         */
        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(@"[错误] 加密失败|状态编码: %d", cryptStatus);
        }
        
        return [result base64EncodedStringWithOptions:0];
    }

      ECB加密终端测试命令,加密:$ openssl enc -des-ecb -K 616263 -nosalt -in msg1.txt -out msg1.bin;解密:$ openssl enc -des-ecb -K 616263 -nosalt -in msg1.bin -out msg1.txt -d。CBC终端测试命令,加密:$ openssl enc -des-cbc -K 616263 -iv 0000000000000000 -nosalt -in a.txt -out msg1.bin  解密:$ openssl enc -des-cbc -K 616263 -iv 0000000000000000 -nosalt -in msg1.bin -out msg4.txt -d,文件查看命令$ xxd msg1.bin

      对称加密的对应面肯定就是非对称加密(RSA)。这种加密方式采用了两种密钥,公钥/私钥。用公钥加密,私钥解密或者是私钥加密,公钥解密。其优点是非常之安全,就是采用大量的乘法运算得到一个加密结果,没有密钥用现在的手段基本无法解密。然后同样因为其安全的加密方式带来的后果是,加密非常缓慢,基本大数据不用想使用RSA加密。其加密原理就是:1.找到两个“很大”的质数,P&Q,然后N = P*Q,M=(P-1)*(N-1),公钥就是找到一个整数E与M互质,即除了1以外,没有其他公约数,这个数可以很简单,因为一般是对外公开使用。私钥:找到一个整数D,使得E*D除以M余1;然后就是进行加密:(明文 ^E)%N等到密文,解密:(密文^D)%N 得到明文。一般数字签名就可以用RSA,例如支付就需要使用RSA,其原理就是,将“支付金额”使用HASH得到“hash密文”,然后将“hash密文”使用RSA公钥加密得到“数字签名”,最后将数字签名和“支付金额”发送给服务器。服务器将“支付金额”加密得到“hash密文”,并同时使用私钥解密“数字签名”得到“hash密文”,将两个“hash密文”进行对比,正确就确认支付,这样可以防止金额被篡改。

    #pragma mark - 加密 & 解密数据
    - (NSData *)encryptData:(NSData *)plainData {
        OSStatus sanityCheck = noErr;
        size_t cipherBufferSize = 0;
        size_t keyBufferSize = 0;
        
        NSAssert(plainData != nil, @"明文数据为空");
        NSAssert(publicKeyRef != nil, @"公钥为空");
        
        NSData *cipher = nil;
        uint8_t *cipherBuffer = NULL;
        
        // 计算缓冲区大小
        cipherBufferSize = SecKeyGetBlockSize(publicKeyRef);
        keyBufferSize = [plainData length];
        
        if (kTypeOfWrapPadding == kSecPaddingNone) {
            NSAssert(keyBufferSize <= cipherBufferSize, @"加密内容太大");
        } else {
            NSAssert(keyBufferSize <= (cipherBufferSize - 11), @"加密内容太大");
        }
        
        // 分配缓冲区
        cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
        memset((void *)cipherBuffer, 0x0, cipherBufferSize);
        
        // 使用公钥加密
        sanityCheck = SecKeyEncrypt(publicKeyRef,
                                    kTypeOfWrapPadding,
                                    (const uint8_t *)[plainData bytes],
                                    keyBufferSize,
                                    cipherBuffer,
                                    &cipherBufferSize
                                    );
        
        NSAssert(sanityCheck == noErr, @"加密错误,OSStatus == %d", sanityCheck);
        
        // 生成密文数据
        cipher = [NSData dataWithBytes:(const void *)cipherBuffer length:(NSUInteger)cipherBufferSize];
        
        if (cipherBuffer) free(cipherBuffer);
        
        return cipher;
    }
  • 相关阅读:
    算法之二叉树各种遍历
    File类基本操作之OutputStream字节输出流
    W3C DOM 事件模型(简述)
    Linux多线程编程小结
    linux下getsockopt和setsockopt具体解释及測试
    MyBatis入门学习(一)
    [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use &#39;track by&#39; expression to specify uniq
    java中substring的使用方法
    Java Map遍历方式的选择
    E6全部刷机包
  • 原文地址:https://www.cnblogs.com/zhulilove/p/7965896.html
Copyright © 2011-2022 走看看