加密
A:数据为什么要加密呢?
B:废话,为了安全呗。
在互联网发展趋势迅猛的今天,用户的资金安全、企业的信息安全......安全!安全!安全!——数据安全的重要性日趋凸显。也成为我们必须了解的互联网知识。
数据安全:是一种主动的包含措施,数据本身的安全必须基于可靠的加密算法与安全体系,主要是有对称算法与公开密钥密码体系两种(非对称算法),都包含了数据的加密和解密过程。
今天就来介绍几种加密方式:
一,MD5:加密算法有很多种,在iOS开发当中,MD5是我们常用的摘要算法。
PS:哈希算法,哈希算法将任意长度的二进制值映射为较短的固定长度的二进制值,这个小的二进制值称为哈希值。 哈希值是一段数据唯一且极其紧凑的数值表示形式。数据的哈希值可以检验数据的完整性。一般用于快速查找和加密算法。 典型的哈希算法有:MD2、MD4、MD5 和 SHA-1等。
MD5:Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。
MD5算法具有以下特点:
1、 压缩性:任意长度的数据,算出的MD5值长度都是固定的(16进制,32位)。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
下面送上MD5加密的使用方式:
首先,引入<CommonCrypto/CommonCrypto.h>
1)针对于字符串对象:
//准备字符串
NSString * foo = @"I love my iOS teacher";
//1.获取C字符串(MD5加密基于C语言实现,Foundation框架字符串需要转化)
const char * fooData = [foo UTF8String];//__strong const char *UTF8String,C语言无法持有字符串,必须用__strong修饰来拷贝内容
//2.创建字符串数组接收MD5值
//一个字节是8位,两个字节是16位,两个字符可以表示一个16位进制的数,MD5结果为32位,实际上由16位16进制数组成。
unsigned char resut[CC_MD5_DIGEST_LENGTH];
//3.计算MD5值(结果存储在result数组中)
CC_MD5(fooData, (CC_LONG)strlen(fooData), resut);
//4.获取摘要值
NSMutableString *bar = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i ++) {
[bar appendFormat:@"%02X",resut[i]];
}
NSLog(@"%@",bar);
2)针对于非字符串的其他类型:
将其它对象转化为NSData对象(可以将对象事先写入文件),然后获取NSData对象的MD5值。
//1.NSData对象获取
//获取文件路径
NSString *path = [[NSBundle mainBundle] pathForResource:@"一双人" ofType:@“mp3"];
//根据文件路径获取NSData对象
NSData *data = [NSData dataWithContentsOfFile:path];
//2.创建MD5变量
CC_MD5_CTX md5;
//3.初始化MD5变量
CC_MD5_Init(&md5);
//4.准备MD5加密
CC_MD5_Update(&md5, data.bytes, (CC_LONG)data.length);
//5.结束MD5加密
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(result, &md5);
//6.获取结果
NSMutableString *resultString = [[NSMutableString alloc] initWithCapacity:CC_MD5_DIGEST_LENGTH];
for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i ++) {
[resultString appendFormat:@"%02X",result[i]];
}
NSLog(@"%@",resultString);
总的来说,哈希算法是一种摘要算法,主要作用是用来获取数据的摘要。严格意义上来说不属于加密算法(因为没有解密过程)。获取字符串的MD5值比较简单,其它对象可以先转化成NSData对象再进行操作。可以根据路径直接获取文件数据,也可以将对象写入文件件后获取为NSData对象。iOS同样支持SHA1、base64、AES、钥匙串等方式加密数据。
二,钥匙串加密
钥匙串:(英文:Keychain)是苹果公司Mac OS中的密码管理系统。它在Mac OS 8.6中和iOS7之后被导入,并且包括在了所有后续的各版本中。一个钥匙串可以包含多种类型的数据:密码(包括网站,FTP服务器,SSH帐户,网络共享,无线网络,群组软件,加密磁盘镜像等),私钥,电子证书和加密笔记等。
保存在钥匙串的内容相当于系统对其做了保护,在设备锁定时进行了加密处理。
钥匙串中的条目称为SecItem,但它是存储在CFDictionary中的。SecItemRef类型并不存在。SecItem有五类:通用密码、互联网密码、证书、密钥和身份。在大多数情况下,我们用到的都是通用密码
钥匙串的使用和字典非常的相似。
用原生的 Security.framework 就可以实现钥匙串的访问、读写。但是只能在真机上进行。通常我们使用KeychainItemWrapper来完成钥匙串的加密。
使用钥匙串加密的步骤:
步骤一:拷贝钥匙串类到工程中
步骤二:引入标准头文件
步骤三:生成钥匙串对象
步骤四:存储加密的数据
步骤五:获得钥匙串对象
步骤六:获取加密的数据
以下是代码演示:(要导入工程的文件是一对儿KeychainItemWrapper文件)
在要使用钥匙串加密的类中导入KeychainItemWrapper.h,然后按照上述步骤操作即可。
注意:引入的头文件是MRC模式的,需要进行混编。
代码送上:
//创建并初始化
KeychainItemWrapper *wrapperItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyKeychainItem" accessGroup:nil];
//现在可以对wrapperItem进行读取和写入了,就跟使用NSDictionary一样。它会自动跟钥匙串同步。__bridge强制转换用来将Core Foundation的常量传给一个使用ARC的Cocoa方法。
//系统提供的键值对中的两个键,非系统的键是没法添加到字典中的
id usernameKey = (__bridge id)kSecAttrAccount;
id passwordKey = (__bridge id)kSecValueData;
//注意,我使用的是个Core Foundation类型(kSecAttrAccount),这里它需要用到id(objectForKey:),不要用类型转换,也不要用__bridge。这是一个新特性。
//存值
[wrapperItem setObject:@"user" forKey:usernameKey];
[wrapperItem setObject:@"123" forKey:passwordKey];
//通过相同 的标记创建的钥匙串中具有相同的数据,可以看做是一个对象
KeychainItemWrapper *wrapperItemSec = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyKeychainItem" accessGroup:nil];
//取值
NSString *userName = [wrapperItemSec objectForKey:usernameKey];
NSLog(@"用户名为: %@",userName);
NSString *password = [wrapperItem objectForKey:passwordKey];
NSLog(@"密码为: %@", password);
//KeyChainItemWrapper会缓存读入数据,但不会缓存写出的数据。向钥匙串中写数据的成本很高,所以我们不会频繁写入。钥匙串不适合用来存储经常改变的敏感数据。那类数据应该保存到加密文件中
三,公钥加密
公钥加密也叫非对称加密,常用算法有RSA、ElGamal、背包算法、Rabin等等,iOS中用的最多的是RSA,iOS 使用 RSA 加密, 只需要公钥。
使用RSA,需要首先导入RSA.h和RSA.m文件。
实例代码:
//公钥和私钥都是使用证书生成的,并非我们自定义字符串就可以。我们使用的是生成好的公钥和私钥
//其中-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----不属于密钥部分
//公钥,用于加密数据. 用于公开, 一般存放在数据提供方, 例如iOS客户端.
NSString *publickey = @"-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEChqe80lJLTTkJD3X3Lyd7Fj+\nzuOhDZkjuLNPog3YR20e5JcrdqI9IFzNbACY/GQVhbnbvBqYgyql8DfPCGXpn0+X\nNSxELIUw9Vh32QuhGNr3/TBpechrVeVpFPLwyaYNEk1CawgHCeQqf5uaqiaoBDOT\nqeox88Lc1ld7MsfggQIDAQAB\n-----END PUBLIC KEY-----";
//私钥,用于解密数据. 必须保密, 私钥泄露会造成安全问题.
NSString *privatekey = @"-----BEGIN RSA PRIVATE KEY-----\nMIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMQKGp7zSUktNOQk\nPdfcvJ3sWP7O46ENmSO4s0+iDdhHbR7klyt2oj0gXM1sAJj8ZBWFudu8GpiDKqXw\nN88IZemfT5c1LEQshTD1WHfZC6EY2vf9MGl5yGtV5WkU8vDJpg0STUJrCAcJ5Cp/\nm5qqJqgEM5Op6jHzwtzWV3syx+CBAgMBAAECgYEApSzqPzE3d3uqi+tpXB71oY5J\ncfB55PIjLPDrzFX7mlacP6JVKN7dVemVp9OvMTe/UE8LSXRVaFlkLsqXC07FJjhu\nwFXHPdnUf5sanLLdnzt3Mc8vMgUamGJl+er0wdzxM1kPTh0Tmq+DSlu5TlopAHd5\nIqF3DYiORIen3xIwp0ECQQDj6GFaXWzWAu5oUq6j1msTRV3mRZnx8Amxt1ssYM0+\nJLf6QYmpkGFqiQOhHkMgVUwRFqJC8A9EVR1eqabcBXbpAkEA3DQfLVr94vsIWL6+\nVrFcPJW9Xk28CNY6Xnvkin815o2Q0JUHIIIod1eVKCiYDUzZAYAsW0gefJ49sJ4Y\niRJN2QJAKuxeQX2s/NWKfz1rRNIiUnvTBoZ/SvCxcrYcxsvoe9bAi7KCMdxObJkn\nhNXFQLav39wKbV73ESCSqnx7P58L2QJABmhR2+0A5EDvvj1WpokkqPKmfv7+ELfD\nHQq33LvU4q+N3jPn8C85ZDedNHzx57kru1pyb/mKQZANNX10M1DgCQJBAMKn0lEx\nQH2GrkjeWgGVpPZkp0YC+ztNjaUMJmY5g0INUlDgqTWFNftxe8ROvt7JtUvlgtKC\nXdXQrKaEnpebeUQ=\n-----END RSA PRIVATE KEY-----";
//创建字符串
NSString *originString = @"hello world!";
//打印原始字符串
NSLog(@"原始字符串: %@", originString);
//使用公钥对数据进行加密
NSString *encWithPublicKey = [RSA encryptString:originString publicKey:publickey];
NSLog(@"Enctypted with public key公钥加密: %@", encWithPublicKey);
//使用私钥对数据进行解密
NSString *decWithPrivateKey = [RSA decryptString:encWithPublicKey privateKey:privatekey];
NSLog(@"Decrypted with private key私钥解密: %@", decWithPrivateKey);
//服务器端
encWithPublicKey = @"p/hm1SvJm9SuuPy66rrf37+EhynkpVnCxbSCZfKznrAKVfpciX/TZM9GfLrAs+bXlND+GeOeZDz2zm+nZDtxpGV1pyQY03hOWn1MQ2+wBKKQdveEdYJ4TVXwGtC3PMaA3dwdRY+WqInQj9WX4JfuQfkYCqbmI0w86uydjFpenwE=";
//使用私钥对数据进行解密
decWithPrivateKey = [RSA decryptString:encWithPublicKey privateKey:privatekey];
NSLog(@"(PHP enc)Decrypted with private key私钥解密: %@", decWithPrivateKey);
//使用公钥对数据进行解密
NSString *encWithPrivKey = @"F+feHOH6807tUV/drvepAMzKlVKRsoDFRkFNfhS9kgVoBt2E6OnUIVw12l608yQGWiqtq8rgZgMY/VCQYZB+3r2rhDlyZ2fjo00sUFOp5BkNPFTs/NpQAolD6V3ifNgDmBQP92uVbxbod1pLRwLC0wLOhr5flQXvvobeg5KrDeE=";
NSString *decWithPublicKey = [RSA decryptString:encWithPrivKey publicKey:publickey];
NSLog(@"(PHP enc)Decrypted with public key公钥解密: %@", decWithPublicKey);
另外,后台和前端开发工程师可根据实际需要,决定谁来加密,谁来解密。