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;
}

 

posted @ 2017-12-03 13:16  残梦未醒  阅读(185)  评论(0编辑  收藏  举报