一、证书生成
iOS
中没有办法直接使用.pem
文件进行加解密。是Xcode
帮我们去钥匙串访问申请的证书。
钥匙串生成csr
文件
钥匙串->钥匙串访问->证书助理->从证书颁发机构请求证书

填入基本信息,然后创建:

这个时候就生成了一个请求文件
CertificateSigningRequest.certSigningRequest
命令行生成csr
文件
通过私钥生成csr
文件
openssl req -new -key private.pem -out rsacer.csr
填入基本信息就生成了csr
文件

在这里通过自己创建的私钥生成了请求文件。将请求文件发送到签名机构进行签名(收费)。
自己通过csr
生成签名证书
通过私钥自己签名生成证书(crt
)(这里是没有认证的)。
rsa openssl x509 -req -days 3650 -in rsacer.csr -signkey private.pem -out rsacert.crt
这个crt
证书就类似公司服务器上的证书,别人接收的。
➜ rsa cat rsacert.crt
-----BEGIN CERTIFICATE-----
MIICkTCCAfoCCQC/Rigkk81GFjANBgkqhkiG9w0BAQUFADCBjDELMAkGA1UEBhMC
Q04xETAPBgNVBAgMCFNoYW5nSGFpMREwDwYDVQQHDAhTaGFuZ0hhaTELMAkGA1UE
CgwCSFAxEjAQBgNVBAsMCWhvdHBvdC5jbjESMBAGA1UEAwwJSG90cG90Q2F0MSIw
IAYJKoZIhvcNAQkBFhNiaW54aWFvMDYwNEAxNjMuY29tMB4XDTIxMDQxNTA4MTYz
NFoXDTMxMDQxMzA4MTYzNFowgYwxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhTaGFu
Z0hhaTERMA8GA1UEBwwIU2hhbmdIYWkxCzAJBgNVBAoMAkhQMRIwEAYDVQQLDAlo
b3Rwb3QuY24xEjAQBgNVBAMMCUhvdHBvdENhdDEiMCAGCSqGSIb3DQEJARYTYmlu
eGlhbzA2MDRAMTYzLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuBAn
Mol9AauUt33FAzVR9iKknKlUWYGpfGtfdu2GAbGFS7jhX7M4Gg5ObVmnWh+4iNja
TujMxd83rS7LGK7le9oFhSxcgfWNTS7R0eR21OznGt0Op3kh3LOMPqCBjmaFb5x8
lvfmCTdFILlz9nruq4m/ejLHXO4jcTynREFPSCMCAwEAATANBgkqhkiG9w0BAQUF
AAOBgQBu0fmCBSS7G4K5ifO9Kh7oWOOR/gXu39G/pGGTDzgNGzTukulDzDbzHJFx
usVg1ZSOD0RikEZZnPxwpoy+MOxnEIu+STe2XuNgBaE0MPLx2PRP1kDJuQrQ9o3e
c+nPX5rO+D8QlGlBGfbTXib6uWtFMYqbdD9IpBpPsbyKCMwxlg==
-----END CERTIFICATE-----
这个时候crt
证书仍然用不了,需要转换为der
:
rsa openssl x509 -outform der -in rsacert.crt -out rsacert.der
从苹果申请的证书就是der
证书。
从crt
获取p12
文件
openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
p12
(私钥)和der
(证书)是一对。iOS开发中就是使用这两个进行加密和解密。
二、base64
加密解密完数据都是二进制,一般情况下转换为base64
查看。
比如有文本文件内容HotpotCat
,终端编码为base64
数据
base64编码
base64 message.txt -o test.txt
编码后变成了SG90cG90Q2F0Cg==
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的编解码:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"base64 encode:%@",[self base64Encode:@"HotpotCat"]);
NSLog(@"base64 decode:%@",[self base64Decode:@"SG90cG90Q2F0Cg=="]);
}
- (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 encode:SG90cG90Q2F0
base64 decode:HotpotCat
base64是以查表的形式对二进制进行编码,只适用于二进制文件。编码后文件会变大,大原来的1/3。
三、RSA代码
iOS
本身支持RSA
,系统提供了SecKeyEncrypt
和SecKeyDecrypt
加密和解密函数。具体的定义在Security
系统库中。
加载公钥&私钥
//加载公钥
[[HPRSACryptor sharedRSACryptor] loadPublicKey:[[NSBundle mainBundle] pathForResource:@"rsacert" ofType:@"der"]];
//加载私钥
[[HPRSACryptor sharedRSACryptor] loadPrivateKey:[[NSBundle mainBundle] pathForResource:@"p" ofType:@"p12"] password:@"123456"];
加密&解密
//加密
NSData *encryptData = [[HPRSACryptor sharedRSACryptor] encryptData:[@"HotpotCat" dataUsingEncoding:NSUTF8StringEncoding]];
NSString *encryptBase64Message = [encryptData base64EncodedStringWithOptions:0];
NSLog(@"rsa encrypt base64:%@",encryptBase64Message);
//解密
NSData *decryptData = [[HPRSACryptor sharedRSACryptor] decryptData:encryptData];
NSString *decryptStr = [[NSString alloc] initWithData:decryptData encoding:NSUTF8StringEncoding];
NSLog(@"rsa decrypt message:%@",decryptStr);
输出:
rsa encrypt base64:r8ljvoRIlIetwpYalstDDdj6n0ZDRzM+uKLRGcb+ZTH77Gx/XJQMie5e+CIBEGnb4v0h5XpvqxzskHhkQBxYbE6FB4/l9hHI+Z/OButC9gfNkYQJ7R8rd3I1YYX8vTwmgtmhlcJRqIItcDgEl/7DsaukIK24rAwhRLWb0lCYNrA=
rsa decrypt message:HotpotCat
rsa encrypt base64:IoqpK/WG8fA+MXODhelbboDOKwQwbubIA48+j34aRCz+URslrZ97cnHwZw50BZXRkrSLkMUfvMR3hz9gtIdRUbeTvkyZ9TWGRTKE1BWxElSJVQkY6WKSUO5WZ3rk+VPUBm87Gr3Kqe/wkD/tQE/XLbqZjIXZQJ1RMm41yz2tFwM=
rsa decrypt message:HotpotCat
rsa encrypt base64:HG7kUSqILZrp1lVDREzldcXAklECnqCQxBhWoOhzf8UOIv0XmJv2yDYr1C7T4bKJeRq+EsTKtY34q4XsHd+4djLc+YTtXRwS5dYQZOgMlhF7+kFohsowDmQEvHZc2I+fpHwN8rxvHTxwDaVrc0eB+4zCPoGyagG3Xe8qHNh5A5w=
rsa decrypt message:HotpotCat
可以看到每次加密后的base64
结果都不同,解密后相同。这个原因是rsa
内部实现的填充模式导致的。
具体定义在SecPadding
中,SecKeyEncrypt
函数第二个参数:
/*!
@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
则密文每次都一样了。
用途
客户端(公钥) 服务端(私钥)
一般情况下客户端保存公钥,服务端保存私钥。在通信时通过RSA
加密对称加密的key
然后客户端和服务端进行数据交换。
Demo
总结
1.RSA的安全系数非常高(因为整个业务逻辑非常安全)
2.加密效率低(不能丛大数据加密)
3.用来加密关键数据。
网友评论