密码学:RSA(二)

2021-04-15  本文已影响0人  HotPotCat

一、证书生成

iOS中没有办法直接使用.pem文件进行加解密。是Xcode帮我们去钥匙串访问申请的证书。

钥匙串生成csr文件

钥匙串->钥匙串访问->证书助理->从证书颁发机构请求证书

image.png

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

image.png
这个时候就生成了一个请求文件CertificateSigningRequest.certSigningRequest

命令行生成csr文件

通过私钥生成csr文件

openssl req -new -key private.pem -out rsacer.csr

填入基本信息就生成了csr文件

image.png
在这里通过自己创建的私钥生成了请求文件。将请求文件发送到签名机构进行签名(收费)。

自己通过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的编码对应如下:

image.png

base64按照6个二进制编码,通过查表编码:

image.png
相当于密码本。由于通过6个二进制位来编码一个结果,如果要编码的字节数不能被3整除,最后会多出1个或2个字节(补0)。
image.png
补的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。

base64

三、RSA代码

iOS本身支持RSA,系统提供了SecKeyEncryptSecKeyDecrypt加密和解密函数。具体的定义在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.用来加密关键数据。

上一篇 下一篇

猜你喜欢

热点阅读