前言
接着上篇05-密码学(1)的RSA算法,最后我们介绍了下签名
与验证
,也就是私钥加密,公钥解密
,对应的实际运用场景,就是我们熟知的iOS系统证书
的申请流程。本篇文章会结合RSA算法
分析下证书的整个申请流程
,以及RSA代码演示
。
一、证书
上篇05-密码学(1)中,我们介绍了Mac系统内置OpenSSL(开源加密库)
可以帮助我们生成公钥私钥
完成加解密,但是我们在实际的开发中,是没有办法直接使用.pem文件
进行加解密,而是Xcode
帮我们去钥匙串访问
申请的证书
,我们通过这个证书
与苹果的服务器进行验签等交互。
1.1证书生成
在证书生成
之前,我们需要生成一个请求文件
👉 CertificateSigningRequest.certSigningRequest
(简称csr文件
),有2种方式👇
- 钥匙串生成
csr文件
- 命令行生成
csr文件
钥匙串生成
操作路径 👉 钥匙串 ->钥匙串访问->证书助理->从证书颁发机构请求证书
,如下图👇
接着填入基本信息, 然后创建👇
这个时候就生成了一个请求csr文件
。
命令行生成
再看看命令行
是如何操作的。
- 通过私钥生成csr文件
openssl req -new -key private.pem -out rsacer.csr
利用上篇文章中生成的密钥.pem
文件,生成csr请求文件
👇
在这里通过自己创建
的私钥
生成了请求文件
。将请求文件发送到签名机构
进行签名
(⚠️需要收费
)。
自己通过csr生成签名证书
当然,我们也可以不通过签名机构
进行签名
,直接自己签名
生成crt证书
。
⚠️注意:通过
私钥
自己签名生成证书(crt)
(这里是没有认证
的)。
命令行👇
openssl x509 -req -days 3650 -in rsacer.csr -signkey private.pem -out rsacert.crt
这个crt证书就类似公司服务器
上的证书
,给别人接收
的。但是这个时候crt证书
仍然用不了
,需要转换为der
👇
openssl x509 -outform der -in rsacert.crt -out rsacert.der
因为从苹果
申请的证书就是der证书
。
p12
还有一个我们熟悉的,p12格式文件,怎么生成呢?
- 从钥匙串中导出👇
- 命令行操作
从crt
获取p12文件
👇
openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
⚠️注意:
p12(私钥)
和der(证书)
是一对
。iOS开发中就是使用这两个进行加密和解密
,是不是和RSA的公私钥
原理一模一样。。。
二、RSA代码演示
接下来,我们接着之前的RSA算法
,用代码演示
一下加解密的过程。
2.1 Base64编解码
在演示之前,我们先来看看什么是Base64
?代码加解密的过程中经常会用到Base64
,为什么要Base64编解码呢?因为加密解密完数据都是二进制
格式,一般情况下转换为base64是为了方便查看。
- base64编码
base64 message.txt -o test.txt
编码前,message.txt
的内容👇
编码后,test.txt
的内容👇
编码后变成了5a+G56CBOkxHUGVyc29uCg==
base64编码由
0-9 a-z A-Z / =
64个字符组成。
- base64解码
base64 test.txt -o message2.txt -D
这里就不再示例演示了,和编码是一个道理,读者可自行敲一遍看看。
base64编码规则
例如:Man
的编码对应如下👇
上图中可看出👇
base64按照
6个二进制
编码
有表可查👇
该表相当于密码本
。由于通过6个二进制位
来编码一个结果
,如果要编码的字节数不能被3整除
,最后会多出
1个或2个字节(补0
)。例如👇
补的
0
变成了=
在还原
的时候通过查表
可以找到索引
,索引
能对应到二进制位数据
,就可以还原数据
了。
iOS中的Base64
iOS系统本身是支持base64的编解码的👇
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"base64 encode:%@",[self base64Encode:@"LGPerson"]);
NSLog(@"base64 decode:%@",[self base64Decode:@"TEdQZXJzb24="]);
}
- (NSString *)base64Encode:(NSString *)message {
NSData *messageData = [message dataUsingEncoding:NSUTF8StringEncoding];
return [messageData base64EncodedStringWithOptions:0];
}
- (NSString *)base64Decode:(NSString *)base64Message {
NSData *base64Data = [[NSData alloc] initWithBase64EncodedString:base64Message options:0];
return [[NSString alloc] initWithData:base64Data encoding:NSUTF8StringEncoding];
}
运行👇
base64
是以查表的形式
对二进制
进行编码,只适用于二进制文件
。编码后文件会变大
,会增加原来的1/3
。
2.2 RSA代码
iOS本身支持RSA
,系统提供了SecKeyEncrypt加密
和SecKeyDecrypt解密
函数。具体的定义在Security系统库
中。
- 加载公钥&私钥
//1.加载公钥
[[RSACryptor sharedRSACryptor] loadPublicKey:[[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil]];
//2.加载私钥
[[RSACryptor sharedRSACryptor] loadPrivateKey: [[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil] password:@"123456"];
- 加密&解密
// 加密
NSData * result = [[RSACryptor sharedRSACryptor] encryptData:[@"hello" dataUsingEncoding:NSUTF8StringEncoding]];
//base64编码
NSString * base64 = [result base64EncodedStringWithOptions:0];
NSLog(@"加密之后:%@\n",base64);
//解密
NSData * dcStr = [[RSACryptor sharedRSACryptor] decryptData:result];
NSLog(@"解密之后:%@",[[NSString alloc] initWithData:dcStr encoding:NSUTF8StringEncoding]);
再运行一次👇
可以发现,每次加密后的base64
结果都不同
,解密后相同
。这个原因是rsa
内部实现的填充模式
导致的。
具体SecKeyEncrypt函数
第二个参数SecPadding
中,👇
/*!
@typedef SecPadding
@abstract Supported padding types.
*/
typedef CF_OPTIONS(uint32_t, SecPadding)
{
kSecPaddingNone = 0,
kSecPaddingPKCS1 = 1,
kSecPaddingOAEP = 2, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0) __TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0),
/* For SecKeyRawSign/SecKeyRawVerify only,
ECDSA signature is raw byte format {r,s}, big endian.
First half is r, second half is s */
kSecPaddingSigRaw = 0x4000,
/* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is an MD2
hash; standard ASN.1 padding will be done, as well as PKCS1 padding
of the underlying RSA operation. */
kSecPaddingPKCS1MD2 = 0x8000, // __OSX_DEPRECATED(10.0, 10.12, "MD2 is deprecated") __IOS_DEPRECATED(2.0, 5.0, "MD2 is deprecated") __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE,
/* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is an MD5
hash; standard ASN.1 padding will be done, as well as PKCS1 padding
of the underlying RSA operation. */
kSecPaddingPKCS1MD5 = 0x8001, // __OSX_DEPRECATED(10.0, 10.12, "MD5 is deprecated") __IOS_DEPRECATED(2.0, 5.0, "MD5 is deprecated") __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE,
/* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA1
hash; standard ASN.1 padding will be done, as well as PKCS1 padding
of the underlying RSA operation. */
kSecPaddingPKCS1SHA1 = 0x8002,
/* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA224
hash; standard ASN.1 padding will be done, as well as PKCS1 padding
of the underlying RSA operation. */
kSecPaddingPKCS1SHA224 = 0x8003, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0),
/* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA256
hash; standard ASN.1 padding will be done, as well as PKCS1 padding
of the underlying RSA operation. */
kSecPaddingPKCS1SHA256 = 0x8004, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0),
/* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA384
hash; standard ASN.1 padding will be done, as well as PKCS1 padding
of the underlying RSA operation. */
kSecPaddingPKCS1SHA384 = 0x8005, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0),
/* For SecKeyRawSign/SecKeyRawVerify only, data to be signed is a SHA512
hash; standard ASN.1 padding will be done, as well as PKCS1 padding
of the underlying RSA operation. */
kSecPaddingPKCS1SHA512 = 0x8006, // __OSX_UNAVAILABLE __IOS_AVAILABLE(2.0),
};
SecPadding
改为kSecPaddingNone
则密文
每次都一样
了。
加解密Demo
总结
-
证书
-
csr
请求文件,2种方式申请钥匙串 ->钥匙串访问->证书助理->从证书颁发机构请求证书
- 终端命令行
openssl req -new -key private.pem -out rsacer.csr
-
crt
证书生成- 将
csr
请求文件发送到签名机构
进行签名
(⚠️需要收费
) - 自己签名生成
证书(crt)
(这里是没有认证
的)- 2.1
openssl x509 -req -days 3650 -in rsacer.csr -signkey private.pem -out rsacert.crt
- 2.2 从
crt
获取p12文件
👉openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
- 2.1
- 将
-
p12
- 从
钥匙串
导出 - 命令行操作 👉 openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
- 从
-
p12(私钥)
和der(证书)
是一对
。iOS开发中就是使用这两个进行加密和解密
。
-
-
RSA代码演示
- Base64
- 由
0-9 a-z A-Z / =
64个字符组成 - 按照
6个二进制
编码,位数多的补0
- iOS中的Base64
- 由
- Base64
- 编码 👉
NSData
的方法👇
- (NSString *)base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)options API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));
- 解码 👉
NSString
的方法👇
- (nullable instancetype)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding;
- RSA代码
- iOS本身支持RSA,系统提供了
SecKeyEncrypt
和SecKeyDecryp
t加密和解密函数 - RSA的
安全系数非常高
(因为整个业务逻辑非常安全) - 加密
效率低
(不能用于大数据加密) - 用来加密
关键数据
- iOS本身支持RSA,系统提供了
网友评论