【原】iOS学习40网络之数据安全

在互联网发展趋势迅猛的今天,数据安全的重要性日趋凸显。也成为我们必须了解的互联网知识。

在移动互联网浪潮下,用户的资金安全、企业的信息安全都是我们实际开发中必须考虑的内容。

1. 数据安全

 1> 概述

  • 数据安全:是一种主动的包含措施,数据本身的安全必须基于可靠的加密算法与安全体系,主要是有对称算法与公开密钥密码体系两种(非对称算法),都包含了数据的加密和解密过程

  • 对称算法:对称密码算法有时又叫传统密码算法,是指加密密钥可以从解密密钥中推算出来,反过来也成立。

  • 非对称算法:对称密码算法有时又叫传统密码算法,就是加密密钥能够从解密密钥中推算出来,反过来也成立。

  • 加密算法有很多种,在iOS开发当中,MD5是我们常用的摘要算法。

 2> 术语

  • 密钥:密钥是一种参数,它是在明文转换为密文或将密文转换为明文的算法中输入的参数。密钥分为对称密钥与非对称密钥(也可以根据用途来分为加密密钥和解密密钥)

  • 明文:没有进行加密,能够直接代表原文含义的信息

  • 密文:经过加密处理处理之后,隐藏原文含义的信息

  • 加密:将明文转换成密文的实施过程

  • 解密:将密文转换成明文的实施过程

2. MD5加密

 1> 哈希算法

  • 哈希算法:哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值。

  • 哈希值是一段数据唯一且极其紧凑的数值表示形式。数据的哈希值可以检验数据的完整性。一般用于快速查找和加密算法。

  • 典型的的哈希算法有:MD2、MD4、MD5 和 SHA-1等。

 2> MD5

  MD5:Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。

 3> MD5算法具有以下特点:

  • 压缩性:任意长度的数据,算出的MD5值长度都是固定的(16进制的32位数,二进制128位)。

  • 容易计算:从原数据计算出MD5值很容易。

  • 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。

  • 强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

 3> 获取字符串MD5值

  • 引入<CommonCrypto/CommonCrypto.h>

  • 获取字符串的MD5值

 1 + (NSMutableString *)stringMD5:(NSString *)str
 2 {
 3     // 1. 因为MD5是基于C语言的,所以我们要将字符串进行编码
 4     const char *data = [str UTF8String];
 5     
 6     // 2. 使用字符串数组去存取加密后的相关内容(16进制,32位)
 7     // CC_MD5_DIGEST_LENGTH表示长度
 8     unsigned char result[CC_MD5_DIGEST_LENGTH];
 9     
10     // 3. 进行MD5加密
11     // 参数1:要加密的内容
12     // 参数2:要加密的data的一个长度
13     // 参数3:存储MD5加密后的结果数组
14     CC_MD5(data, (CC_LONG)strlen(data), result);
15     
16     // 4. 创建可变字符串,保存结果
17     NSMutableString *mutableStr = [NSMutableString string];
18     
19     // 5. 遍历结果数组,然后添加到可变字符串中
20     for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
21         
22         // 16进制需要大家知道格式修饰符(%x表示16进制,02表示当不足两位的时候,前面补0)
23         [mutableStr appendFormat:@"%02x", result[i]];
24     }
25     
26     return mutableStr;
27 } 

 在这里我将字符串使用MD5加密封装为NSString的类目,下载地址:https://github.com/AlonerOwl/MD5CommonCrypto

 4> 获取其他对象MD5值

  • 引入<CommonCrypto/CommonCrypto.h>

  • 将其它对象转化为NSData对象(可以将对象事先写入文件)

 1     // 1. 创建数组
 2     NSArray *array = @[@"小胖", @"Rose"];
 3     
 4     // 2. 找沙盒路径
 5     NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
 6     
 7     // 3. 拼接路径
 8     NSString *arrayPath = [documentPath stringByAppendingPathComponent:@"array.plist"];
 9     
10     // 4. 写入
11     [array writeToFile:arrayPath atomically:YES];
12     
13     // 从沙盒中取出NSData数据
14     NSData *data = [NSData dataWithContentsOfFile:arrayPath];
  • 读取NSData对象的MD5值

 1 + (NSMutableString *)dataMD5:(NSData *)data
 2 {
 3     // 1. 创建MD5对象
 4     CC_MD5_CTX md5;
 5     
 6     // 2. 初始化MD5对象
 7     CC_MD5_Init(&md5);
 8     
 9     // 3. 准备开始数据加密
10     // 参数1:md5对象
11     // 参数2:要加密的data的字节长度
12     // 参数3:要加密内容的长度
13     CC_MD5_Update(&md5, data.bytes, (CC_LONG)data.length);
14     
15     // 4. 准备一个字符串数组用来存储结构
16     unsigned char result[CC_MD5_DIGEST_LENGTH];
17     
18     // 结束加密
19     CC_MD5_Final(result, &md5);
20     
21     // 5. 创建一个可变字符串存放加密结构
22     NSMutableString *mutableString = [NSMutableString string];
23     
24     // 6. 遍历数组,给可变字符串赋值
25     for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
26         [mutableString appendFormat:@"%02x", result[i]];
27     }
28     return mutableString;
29 }

  在这里我将字符串使用MD5加密封装为NSString的类目,下载地址:https://github.com/AlonerOwl/MD5CommonCrypto

 

3. 钥匙串加密

 1> 钥匙串概述

  钥匙串:(英文:Keychain)是苹果公司Mac OS中的密码管理系统。它在Mac OS 8.6中和iOS7之后被导入,并且包括在了所有后续的各版本中。一个钥匙串可以包含多种类型的数据:密码(包括网站,FTP服务器,SSH帐户,网络共享,无线网络,群组软件,加密磁盘镜像等),私钥,电子证书和加密笔记等。

 2> 钥匙串加密

  • 苹果 iOS 和 Mac OS X 系统自带了一套敏感信息保存方案:"钥匙串" (Keychain)。

  • 保存在钥匙串的内容相当于系统对其做了保护,在设备锁定时进行了加密处理。

  • 钥匙串中的条目称为SecItem,但它是存储在CFDictionary中的。SecItemRef类型并不存在。SecItem有五类:通用密码、互联网密码、证书、密钥和身份。在大多数情况下,我们用到的都是通用密码

  • 钥匙串的使用和字典非常的相似

  • 用原生的 Security.framework 就可以实现钥匙串的访问、读写。但是只能在真机上进行。通常我们使用KeychainItemWrapper来完成钥匙串的加密。

 3> 钥匙串的使用

  代码:

 1     // 1.创建钥匙串对象
 2     // 参数1:标识,用于识别加密的内容(回传标识符)
 3     // 参数2:分组,一般为nil
 4     KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"myItemWrapper" accessGroup:nil];
 5     
 6     // 常用于加密用户名和密码
 7     // 系统提供的键值对中的两个键,非系统的键,是无法添加到字典中的
 8     id kUserName = (__bridge id) kSecAttrAccount;
 9     id kUserPassword = (__bridge id) kSecValueData;
10     
11     [keychainItem setObject:@"MBBoy" forKey:kUserName];
12     [keychainItem setObject:@"123456" forKey:kUserPassword];
13     
14     // 从keychain中获取存储的数据
15     // 用户
16     NSString *userName = [keychainItem objectForKey:kUserName];
17     // 密码
18     NSString *userPassword = [keychainItem objectForKey:kUserPassword];
19     
20     NSLog(@"%@,%@", userName, userPassword);

 4> 注意

  • 引入的头文件是MRC模式的,需要进行混编

  • 获取对象的时候Identify必须一致

  • 非系统key值是无法添加到字典中的

4. 公钥加密

 1> 概述

  • 公钥加密也叫非对称加密

  • 常用算法有RSA、ElGamal、背包算法、Rabin等等,IOS中用的最多的是RSA

  • iOS 使用 RSA 加密, 只需要公钥

 2> RSA加密的基本原理

 RSA使用"秘匙对"对数据进行加密解密.在加密解密数据前,需要先生成公钥(public key)和私钥(private key).

 

  • 公钥(public key): 用于加密数据. 用于公开, 一般存放在数据提供方, 例如iOS客户端.
  • 私钥(private key): 用于解密数据. 必须保密, 私钥泄露会造成安全问题.

 3> 使用openssl生成密匙对

  Shell代码

 1 - #!/usr/bin/env bash
 2 - echo "Generating RSA key pair ..."
 3 - echo "1024 RSA key: private_key.pem"
 4 - openssl genrsa -out private_key.pem 1024
 5 -
 6 - echo "create certification require file: rsaCertReq.csr"
 7 - openssl req -new -key private_key.pem -out rsaCertReq.csr
 8 -
 9 - echo "create certification using x509: rsaCert.crt"
10 - openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt
11 -
12 - echo "create public_key.der For IOS"
13 - openssl x509 -outform der -in rsaCert.crt -out public_key.der
14 -
15 - echo "create private_key.p12 For IOS. Please remember your password. The password will be used in iOS."
16 - openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt
17 -
18 - echo "create rsa_public_key.pem For Java"
19 - openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout
20 - echo "create pkcs8_private_key.pem For Java"
21 - openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt
22 -
23 - echo "finished."

  在你所在的路径下会生成一下公钥文件:

 

  在这些文件中最重要的是:pkcs8_private_key.pem和rsa_public_key.pem

 4> 代码取得公钥和私钥的字符串

  公钥:

  

  私钥:

  

 5> 代码

    // 获取公钥的数据
    // 公钥:iOS客户端使用,我们拿到公钥后,只需要根据公钥处理数据就可以了
    NSString *publicKey = @"-----BEGIN PUBLIC KEY-----MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCfQC1ccd5U8Yz8GOh2eQiMRaJX0izpbmrNsJOGzbFhzU3GzFI3RB6VTV4zZG5zUuSBU+JNgVZLjDmAx4f7461Tb91R8ikBNOA18aze7FPKx1i+6q4hj+fK6/hCqivoHwq047XoDbjbZ+yw+zDhz1oezvQogNXyHEpsCf5YSr/nUwIDAQAB-----END PUBLIC KEY-----";
    
    // 私钥:用于解密数据千万不能泄露,否则数据不安全
    NSString *privateKey = @"-----BEGIN PRIVATE KEY-----MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ9ALVxx3lTxjPwY    6HZ5CIxFolfSLOluas2wk4bNsWHNTcbMUjdEHpVNXjNkbnNS5IFT4k2BVkuMOYDHh/vjrVNv3VHyKQE04DXxrN7sU8rHWL7qriGP58rr+EKqK+gfCrTjtegNuNtn7LD7MOHPWh7O9CiA1fIcSmwJ/lhKv+dTAgMBAAECgYBejvrgQ3Sit3LhVeDiR+e9crN8tf2Y9clRLSHMD2LeEcu22SeQTVBjkrb2iRHUREoOSMK9Bqk43qBeSRwDgyMs0g5v    WZnIOFshyrotqsuGpQw29Sph4363dq1iFqLFaZx+NVxAv9KOlh05EwRE42snPu8tR7ED1zCxF/byGCDVEQJBAM5mOFh/9ff+CsrdXnubhq5IKqlZ0Jdq05pWhkW8wjwrSvjwKDRry92apYFY4AJD1WbMSv8knN/RhrFFPyfefu8CQQDFhVpplu12Tksp/qrx47b/AgA6NzShfRdjEptNQjc88pkgSwFHeJGly0SCy4V+aBgNtdEsLpe+nrU2kQ91aN3dAkEAw2oSlO/qELcMvs9iYkN4+09GXPq1PHcfCvQ6wpIZkGAo5pJybldVOGXvpwxfYqWYyXBI3VJr2JkHHpWCWxwULwJALTksCzLoKYchhHrvbrSBaH9vx+Rt4299lExlTFoVxZmR36fsog2D417Xz86DQP7aSwFO4/vC+Hzj5ptt26bn7QJARTIH4/FQ7y7pg2tKqvrSMvzwwVtY40yT2DT15jnA5CunVgQJmxScCkcCaW9LXb8tjJjKJ2ync6IA8Su8mTQ8qg==-----END PRIVATE KEY-----";
    
    // 创建字符串
    NSString *testStr = @"小胖子";
    
    // 创建存储公钥的字符串
    NSString *encPublicKey;
    // 创建存储私钥的字符串
    NSString *encPrivateKey;
    
    // 使用RSA进行加密:
    // 参数1:需要加密的内容
    // 参数2:公钥字符串
    encPublicKey = [RSA encryptString:testStr publicKey:publicKey];
    
    NSLog(@"%@", encPublicKey);
    
    // 使用RSA进行解密:
    
    NSString *result = @""; // 经过加密后需要把加密的内容传送给后台,此时后台会给你返回一个字符串,大家如果感兴趣可以试一试
    
    // 参数1:由Java后台提供
    // 参数2:私钥
    encPrivateKey = [RSA decryptString:result privateKey:privateKey];
    
    NSLog(@"%@",encPrivateKey);

  RSA第三方文件下载地址:https://github.com/AlonerOwl/RSAEncrypt

5. KVO

 1> 概述

  KVO:(Key-Value-Observer)键值观察者,是观察者设计模式的一种具体实现

  KVO触发机制:一个对象(观察者),监测另一对象(被观察者)的某属性是否发生变化,若被监测的属性发生的更改,会触发观察者的一个方法(方法名固定,类似代理方法)

 2> 使用步骤

  • 注册观察者(为被观察者指定观察者以及被观察属性)

 1 // KVO 键值观察,是观察者设计模式
 2 @interface ViewController ()
 3 
 4 // 观察可变数组的改变情况(苹果官方文档不建议对数组进行观察)
 5 @property (nonatomic, strong) NSMutableArray *array;
 6 
 7 @end
 8 
 9 - (void)viewDidLoad {
10     [super viewDidLoad];
11     // Do any additional setup after loading the view, typically from a nib.
12     
13     self.array = [NSMutableArray array];
14     
15     // 第一步:注册观察者
16     // 参数1:添加的观察者对象
17     // 参数2:字符串标识的key
18     // 参数3:触发添加观察者对象的时候
19     /*
20      NSKeyValueObservingOptionNew = 0x01 key或value只要有一个更新的时候就会触发
21      NSKeyValueObservingOptionOld = 0x02
22      NSKeyValueObservingOptionInitial = 0x04
23      NSKeyValueObservingOptionPrior = 0x08
24      */
25     // 参数4:文本内容 一般为nil
26     [self addObserver:self forKeyPath:@"array" options:NSKeyValueObservingOptionNew context:nil];
27 }
  • 
实现回调方法

 1 // 第二步:实现回调
 2 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
 3 {
 4     
 5     NSLog(@"keyPath = %@", keyPath);
 6     NSLog(@"object = %@", object);
 7     NSLog(@"change = %@", change);
 8     
 9     // 可以进行刷新UI的操作
10 }
  • 
触发回调方法(被观察属性发生更改)

 1 // 第二步:实现回调
 2 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
 3 {
 4     
 5     NSLog(@"keyPath = %@", keyPath);
 6     NSLog(@"object = %@", object);
 7     NSLog(@"change = %@", change);
 8     
 9     // 可以进行刷新UI的操作
10 }
  • 移除观察者

  在不需要观察者的时候需要把它删除,本人就只在视图将要消失时移除

1 // 视图将要消失的时候
2 - (void)viewWillDisappear:(BOOL)animated
3 {
4     // 在不需要观察者的时候需要把它删除
5     [self removeObserver:self forKeyPath:@"array"];
6 }

 

posted @ 2016-05-12 20:40  墨隐于非  阅读(284)  评论(0编辑  收藏  举报