RSA 加密
我们在6、密码学 -- 初识RSA最后的时候生成了我们的公钥和私钥(两个.pem)文件,今天我们就要使用一下。
⚠️ 注意:我们的Xcode是不能使用.pem
文件进行加密和解密的
- 1、生成请求文件
openssl req -new -key private.pem -out rsacert.csr
*******
我们会得到一个 rsacert.csr 文件,该文件用于向签名机构,请求签名后的证书
-
2、请求签名后的证书
- 注意,这里我们用的是没有认证的证书。证书的认证需要去网上请求,需要一定的花费。
通过请求文件,对私钥进行签名,生成签名后的证书:
openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
*****
3650 代表有效期是 3650天
-
3、生成 der 文件
der
文件,就是我们在Xcode里面要用到的公钥。
openssl x509 -outform der -in rsacert.crt -out rsacert.der
-
4、生成p12文件
p12
文件就是我们在Xcode里面要用到的私钥。
openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
最终我们会得到这样一个结果:
-
5、实际应用
我们可以利用这样一个类来帮我进行加密 & 解密:RSACryptor
i
:首先我们要将我们上面生成的两个文件导入到我们的工程里面:
导入公钥和私钥
ii
:加载公钥 & 私钥:
//1\加载公钥
[[RSACryptor sharedRSACryptor] loadPublicKey:[[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil]];
//2.加载私钥
[[RSACryptor sharedRSACryptor] loadPrivateKey:[[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil] password:@"123456"];
******
注意:这里公钥和私钥的地址: ·不要写成绝对地址·
@"123456" 是生成 p12 文件的时候设置的,也可以设置成其他的密码。
iii
:加密 & 解密 的演练
加密后生成的是一个二进制文件。
//加密
NSData * encrypted_Files = [[RSACryptor sharedRSACryptor] encryptData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];
//解密
NSData * decrypt_Files = [[RSACryptor sharedRSACryptor] decryptData:encrypted_Files];
NSLog(@"解密:%@",[[NSString alloc] initWithData:decrypt_Files encoding:NSUTF8StringEncoding]);
- RSA内部的填充模式
⚠️ ⚠️ ⚠️ 注意:RSA加密,对于同一个加密内容,每次加密的结果是不一样的;但是解密的结果是一样的。我们来验证一下。虽然加密之后的结果是二进制数据,但是我们可以通过转Base64的格式来查看:
这是因为RSA内部的填充模式引起的:
RSACryptor.m
👇
// 填充模式
#define kTypeOfWrapPadding kSecPaddingPKCS1
**********
这个还有很多模式:
比如:设置成 `kSecPaddingNone` 那么每次加密的结果就不会有变化了。
Hash
- Hash,也叫做散列。就是把任意长度的输入,通过散列算法变成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入空间,不同的输入可能会散列成相同的输出,所以不可能从散列值来确定唯一的输入值。简单的说就是一种任意长度的消息压缩到某一个固定长度的消息摘要的函数。
基于Hash的加密算法有:MD5
/SHA1
/SHA256
/SHA512
等等。
- Hash的特点
- 算法是公开的
- 对相同数据运算,得到的结果是一样的
- 对不同数据运算,如
MD5
得到的结果默认是128位,32个字符(16进制标识符) - 信息摘要,信息,是用来做数据识别的。
- Hash用途
- 用户密码的加密
- 搜索引擎
- 版权
- 数字签名
用户密码加密
- 首先我们要知道,对于隐私数据,在网络传输和本地保存的过程中,有一个原则:。
那么就有以下几个问题:
i
:我们能否直接使用RSA对密码进行加密?
答案:不能!!!
原因:这样做对工程师的依赖过高,如果工程师离职的时候带走了public Key
和 private Key
。此时虽然服务器保存的密码是加密后的,此时也变的毫无意义。
ii
:能够使用Hash直接对密码进行加密?
答案:不能!!!
原因:虽然Hash加密后的密码不可逆,但是直接对密码进行加密也是不可取的,因为在md5在线解密中保存了大量的Hash值,一般情况下,用户设置的密码基本都可以在这里找到对应的结果。
iii
:加盐(使用本地的盐)在用户的密码中加上一串固定的复杂的字符?答案:不能!!!
原因:这个跟第一种情况一样,对工程师的依赖过高。
-
加密解决方案 --- HMAC
HMAC的加密同样需要一个KEY(盐)
,但是这个KEY
是由服务器提供的。并且,这种加密是对明文密码进行两次散列,得到一个密码。
1、在这个加密的过程中,
Key
可以通过RSA加密后进行传递。
2、每一个账号对应一个Key
。
-
这个时候就产生了一个问题,如果用户换手机了怎么办?
新的手机没有保存对应的Key
,无法对用户密码进行加密,此时无法登录账号。
这个时候,就需要向服务器重新请求Key
。这个时候,我们需要做的就是对用户进行验证,比如:手机验证码、人脸识别等等。这就与目前一些APP的手机的授权登录是一个道理。这个时候,也可以根据业务逻辑进行一系列的延展,比如通过手机的Mac地址要验证手机也是可以的。
⚠️
1、本地保存的Key
,要使用钥匙串访问,不要放在沙盒里面。因为钥匙串也是一层加密。
2、Key
如果丢失,也可以更换Key
。因为一个Key
对应一个用户,影响不大。还可以在用户根据业务逻辑,在用户再次输入密码登录的时候替换;这样对于用户来讲,影响基本为零。
-
再来思考另一个问题,虽然我们的密码的保护级别已经非常高了,但是登录一定需要密码吗?
我们要知道,登录不一定需要密码。我们只要在数据传输的过程中,拿到加密后的Hash值,就可以模仿客户端,向服务器请求登录。
这个时候我们就需要在Hash值里面再做一些事情。
i
:我们可以通过加时间的方式来限制登录超时时间。
数字签名
数字签名的目的是为了让接收端能够确认收到的信息是不是原始信息,有没有被篡改过。整个过程是这样的:
Tips:
- BAS64,这是一种编码格式,可以将二进制文件变成我们可以看的一些内容
- 版权,如果说你自己创作了一幅图画,上传到一些平台,那么平台就会保存原始的图片和Hash值。用户去下载的图片,只是肉眼看着一样,但是Hash值是不一样的。这样就可以区分哪个是正版,哪个是盗版。
网友评论