iOS加密学习
安全的原则
1、在网络上不允许传输用户隐私数据的明文
2、在本地不允许保存用户隐私数据的明文
数据安全
相对POST请求而言,GET请求的所有参数都直接暴露在URL中,请求的URL一般会记录在服务器的访问日志中,而服务器的访问日志是黑客攻击的重点对象之一。
然仅仅使用Post请求提交用户隐私数据,还是不能完全解决安全问题的,可以使用软件(比如Charles)设置代理服务器,拦截查看手机的请求数据,因此,提交用户的隐私数据时,一定不要明文提交,要加密处理后提交。
信息安全所面临的威胁
机密性(被窃听,秘密泄露)
完整性(篡改,信息被修改)
认证(伪装,伪装成通信双方)
不可否认性(否认,事后不承认是自己发送的)
常用的加密算法
MD5 \ SHA \ DES \ 3DES \ RC2和RC4 \ RSA \ IDEA \ DSA \ AES
加密算法的选择
一般公司都会有一套自己的加密方案,按照公司接口文档的规定去加密
一、Base64编码
描述:Base64可以成为密码学的基石,非常重要。
特点:可以将任意(图片、音频、视频、字符串)的二进制数据进行Base64编码;
能够逆运算,不够安全,但却被很多加密算法 作为编码方式;
结果:所有的数据(图片、音频、视频、字符串)都能被编码为并只用65个字符就能表示的文本文件。
65字符:A~Z a~z 0~9 + / =
对文件进行base64编码后文件数据的变化:编码后的数据~=编码前数据的4/3,会大1/3左右。
//字符串转base64字符串
-(NSString *)base64Encoding:(NSString *)string
{
//01 把字符串转换为二进制数据
NSData *data = [string dataUsingEncoding:NSUTF8StringEncoding];
//02 对二进制数据进行BASe64编码,返回字符串
return [data base64EncodedStringWithOptions:kNilOptions];
}
//base64字符串转字符串
-(NSString *)base64Decoding:(NSString *)string
{
//01 先对数据进行base64解码
NSData *data = [[NSData alloc]initWithBase64EncodedString:string options:kNilOptions];
//02 把二进制数据转换为字符串
return [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
}
//图片转base64字符串
- (NSString *)base64withimage:(UIImage *)image{
NSData *data=UIImagePNGRepresentation(image);
return [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength];
}
//base64字符串转图片
-(UIImage *)base64Encodingwithimagestring:(NSString *)imagestring{
NSData *decodedImageData = [[NSData alloc]
initWithBase64EncodedString:imagestring options:NSDataBase64DecodingIgnoreUnknownCharacters];
return [UIImage imageWithData:decodedImageData];
}
命令行进行Base64编码和解码
1.1、 字符串
编码: echo -n "我" | base64
解码:echo -n "YWFhCg=="| base64 -D
1.2、 文件
#pragma mark - 文件
编码:base64 123.png -o 123.txt
解码:base64 123.txt -o test.png -D
二、单向散列函数
单向[散列函数就是把任意长度的输入消息串变化成固定长的输出串且由输出串难以得到输入串的一种函数。
单向散列函数,又被称为消息摘要函数(message digest function),哈希函数。
输出的散列值,也被称为消息摘要(message digest)、指纹(fingerprint)
1、单向散列函数的特点:
- 1、加密后密文的长度是定长的
- 2、如果明文不一样,那么散列后的结果一定不一样
- 3、如果明文一样,那么加密后的密文一定一样(对相同数据加密,加密后的密文一样)
- 4、所有的加密算法是公开的
- 5、单向的,不可以逆推反算
2、常见的几种单向散列函数:
-
MD4、MD5
产生128bit的散列值,MD就是Message Digest的缩写,目前已经不安全
-
SHA-1
产生160bit的散列值,目前已经不安全
-
SHA-2
SHA-256、SHA-384、SHA-512,散列值长度分别是256bit、384bit、512bit
-
SHA-3
全新标准
3、单向散列函数应用领域
- 1、搜索 多个关键字,先对每个关键字进行散列,然后多个关键字进行或运算,如果值一致则搜索结果一致
- 2、版权。 对文件进行散列判断该文件是否是正版或原版的
- 3、文件完整性验证。 对整个文件进行散列,比较散列值判断文件是否完整或被篡改
- 4、密码加密。用户注册账号时,就把密码进行散列运算直接存到服务器上。下次用户登录输入密码,直接提交散列值值给服务器。
三、MD5加密算法
MD5加密算法简单说明:
1、对字符串进行MD5加密可以得到一个32个字符的密>文
2、加密之后不能根据密文逆推出明文
3、MD5已经被破解(暴力破解|碰撞检测)
3.1、md5加密
NSString *password=@“13663815139”;
NSString *md5string=[password md5String];
NSDictionary *parmers =@{
@"account”:password,
@"password”:md5string
};
3.2、md5加盐
现在的MD5已不再是绝对安全,对此,可以对MD5稍作改进,以增加解密的难度。加盐就是在明文的固定位置插入随机串,然后再进行MD5。
1、先加盐,然后再进行MD5
NSString *password=@“13663815139”;
NSString *salt = @“hlt”;
NSString *saltstr=[password stringByAppendingString:salt];
NSString *md5string=[saltstr md5String];
NSDictionary *parmers =@{
@"account”:password,
@"password”:md5string
};
2、先乱序,再进行MD5加密
NSString *str1 = [string substringFromIndex:3];
NSString *str2 = [string substringToIndex:3];
NSLog(@"%@-%@",str1,str2);
NSString *str = [str1 stringByAppendingString:str2];
NSLog(@"%@",[str md5String]);
3、乱序|加盐,多次MD5加密等
4、散列函数加密命令行
MD5加密-字符串 $ echo -n "520" |md5
MD5加密-文件1 $ md5 abc.png
SHA1加密: $ echo -n “520" |openssl sha -sha1
SHA256 $ echo -n "520" |openssl sha -sha256
SHA512 $ echo -n "520" |openssl sha -sha512
hmacMD5加密 $ echo -n "520it" |openssl dgst -md5 -hmac "123"
四、对称加密和非对称密码
4.1、非对称加密(公钥密码)
- 非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥(privatekey)
- 公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密.
特点:
- 非对称密码体制的特点:算法强度复杂、安全性依赖于算法与密钥但是由于其算法复杂,而使得加密解密速度没有对称加密解密的速度快
- 对称密码体制中只有一种密钥,并且是非公开的,如果要解密就得让对方知道密钥。所以保证其安全性就是保证密钥的安全,而非对称密钥体制有两种密钥,其中一个是公开的,这样就可以不需要像对称密码那样传输对方的密钥了
目前使用最广泛的非对称加密算法RSA。RSA的名字,由它的3位开发者,即Ron Rivest、Adi Shamir、Leonard Adleman的姓氏首字母组成。
- 1、生成强度是 2048 的 RSA 私钥:
openssl genrsa -out private.pem 2048
该命令生成一个模长2048位,名字为rsa_private_key.pem
、PKCS1
格式的RSA
私钥文件.
- genrsa:
指定生成算法使用RSA
-out:
后面参数是生成的私钥的文件名
2048:
生成私钥的模长,单位字节(bits)
- 2、 从私钥中提取公钥
openssl rsa -in private.pem -out public.pem
-outform PEM -pubout
截屏2021-12-15 下午12.30.21.png
至此就已经生成了密钥对,可以用文本编辑器直接打开pem查看
- 3、使用公钥加密小文件
openssl rsautl -encrypt -pubin -inkey public.pem
-in msg.txt -out msg.bin
- 4、使用私钥解密小文件
openssl rsautl -decrypt -inkey private.pem
-in msg.bin -out a.txt
4.2、RSA的实践应用
在实践项目中开发中,常用的是:1、直接使用公私钥字符串加解密,2、使用数字证书的公钥加密。
-
1、公私钥字符串加解密
截屏2021-12-16 下午1.57.48.png - 可以用文本编辑器直接打开pem文件直接获取公钥、私钥。
- 通过代码读取获取公钥、私钥。
NSString *publicpath = [[NSBundle mainBundle] pathForResource:@"public.pem" ofType:nil];
NSData *publicdata = [NSData dataWithContentsOfFile:publicpath];
NSString *publicdataString = [[NSString alloc]initWithData:publicdata encoding:NSUTF8StringEncoding];
NSString *privatepath = [[NSBundle mainBundle] pathForResource:@"private.pem" ofType:nil];
NSData *privatedata = [NSData dataWithContentsOfFile:privatepath];
NSString *privatedataString = [[NSString alloc]initWithData:privatedata encoding:NSUTF8StringEncoding];
获取到公私钥就可以使用,iosRSA算法工具:https://github.com/ideawu/Objective-C-RSA(注意:这里就需要PKCS8格式的私钥,要不然解密不出来一直是空。 如果你要直接使用PKCS1格式的私钥,注释掉添加私钥内:的data = [RSA stripPrivateKeyHeader:data];这个方法
)
补充:mac openssl 生成的私钥格式默认是PKCS1, java、php端一般用的是PKCS8格式的,网上一些ios RSA工具算法也是PKCS8格式。所以实际开发中很有必要将PKCS1转换成PKCS8
PKCS8和PKCS1的区别
- 将PKCS1格式的私钥转换成PKCS8格式:
openssl pkcs8 -topk8 -inform PEM -in private.pem
-outform PEM -nocrypt -out pkcs8private.pem
- 2、使用数字证书的公钥
证书和驾照很相似,里面记有姓名、组织、地址等个人信息,以及属于此人的公钥,并有认证机构施加数字签名,只要看到公钥证书,我们就可以知道认证机构认证该公钥的确属于此人。数字证书的内容包括:1、公钥 2、认证机构的数字签名。
数字证书本身就含有公钥,所以可以从证书内引用公钥。
- 证书的生成步骤
1)生成私钥 openssl genrsa -out private.pem 1024
2)创建证书请求 openssl req -new -key private.pem -out rsacert.csr
3)生成证书并签名,有效期10年 openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
4)将 PEM 格式文件转换成 DER 格式 openssl x509 -outform der -in rsacert.crt -out rsacert.der
5)导出P12文件 openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
iOS开发中的注意点:在iOS开发中,不能直接使用 PEM 格式的证书,因为其内部进行了Base64编码,应该使用的是DER的证书,是二进制格式的。
- p12文件(即私钥)
- DER文件(公钥)
RSA代码演示: https://www.jianshu.com/p/6c1340e116ca
4.3、对称加密
在对称密码中,加密、解密时使用的是同一个密钥
常见的对称密码算法有
- DES
- 3DES
- AES
对称加密的特点:
- 加密/解密使用相同的密钥
- 加密和解密的过程是可逆的(明文-》密文-》明文)
分组密码
密码算法可以分为分组密码和流密码两种。
分组密码:每次只能处理特定长度的一zu数据的一类密码算法。一个分组的比特数量就称之为分组长度。
ex:DES和3DES的分组长度都是64比特。即每次只能加密64比特的明文,并生成64比特的密文。AES的分组长度有128比特、192比特和256比特可以选择。
流密码:对数据流进行连续处理的一类算法。流密码中一般以1比特、8比特或者是32比特等作为单位俩进行加密和解密。
-
ECB分组模式
ECB模式的全称为Electronic CodeBook模式。又成为电子密码本模式。
特点:
1、使用ECB模式加密的时候,相同的明文分组会被转换为相同的密文分组。
2、类似于一个巨大的明文分组-》密文分组的对照表。 -
CBC分组模式
CBC模式全称为Cipher Block Chainning模式(密文分组链接模式|电子密码链条)
特点:在CBC模式中,首先将明文分组与前一个密文分组进行XOR运算,然后再进行加密。
AES
AES高级加密标准,其密钥长度有128、192、256bit三种,
目前AES,已经逐步取代DES、3DES,成为首选的对称密码算法
AES(ECB)加密
echo -n iostest| openssl enc -aes-128-ecb -K 616263 -nosalt | base64
AES(CBC)加密
echo -n iostest| openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt | base64
AES(ECB)解密
echo -n FqRpCOQG9IL2QrKBHhM+fA== | base64 -D | openssl enc -aes-128-ecb -K 616263 -nosalt -d
AES(CBC)解密
echo -n Kd9MN/rNEI40hdLhayPbUw== | base64 -D | openssl enc -aes-128-cbc -iv 0102030405060708 -K 616263 -nosalt -d
注abc == 616263,字符串abc的16进制就是616263
在实际开发中使用AES的ECB分组模式就可以了。
密钥配送问题
在使用对称密码时,双方是共用同一密钥的,所以一定要考虑密钥配送问题。
密钥配送方法:
- 密钥分配中心
- Diffie-Hellman密钥交换
- 事先共享密钥: 双方私底下一起共享,嘿嘿,实际开发中会经常这样。
- 公钥密码 :也就是消息的接收者生成一对RSA公钥、私钥,将公钥发送给消息的发送者,消息的发送者再将AES的密钥用RSA加密,消息接收者再用私钥进行解密就可以得到AES的密钥
总结
对称密码的缺点:不能很好地解决密钥配送问题
公钥密码的缺点:加密解密速度比较慢。
所以在开发中使用最多的是用AES加密信息,需要配送密钥或者信息量比较小的话可以用RSA加解密
五、数字签名
在网络传输过程中,A发送给B一条消息,信息有可能会被篡改或者有人伪装成A发送消息,或者说A可以否认是自己发的。为了解决篡改、伪装、否人就需要数字签名。
数字签名,其实就是将公钥密码反过来使用,使用私钥加密生成签名,公钥解密验签。
如果直接使用RSA的话,考虑到信息量比较大的话,RSA的效率会很低,所以通常会这样改进一下:消息发送者先使用单向散列函数对信息进行单向散列计算会得到定长的散列值,然后使用RSA的私钥对散列值进行签名之后发送签名和消息。消息接收者得到再使用公钥对签名验签,得到散列值之后,消息接收者使用同样的单向散列函数对消息进行运算也得到一个散列值,最后对比两个散列值是否一样,如果不一样说明消息被篡改过。
数字签名的作用:确认消息的完整性、识别消息是否被篡改、防止消息发送者发送,数字签名不能保证机密性。
六、数字证书
正确使用数字签名,前提是用于验证签名的公钥必须属于真正的发送者。如果遇到了中间人攻击,公钥被伪造,签名自然也将失效。所以在签名之前,必须先验证公钥的合法性。为了保证公钥的合法性,就需要证书了。
证书,联想的是驾驶证、毕业证、英语四六级证等等,都是由权威机构认证的。密码学中的证书,全称叫公钥证书(Public-key Certificate,PKC),跟驾驶证类似。
数字证书里面有姓名、邮箱等个人信息,以及个人的公钥。
- 自签名证书:自己生成的证书,生成见上面
- CA签名证书:由认证机构(Certificate Authority)施加数字签名。CA就是能够认定“公钥确实属于此人”并且能够生成数字签名的个人或者组织。