06-密码学(2)

714 阅读7分钟

前言

接着上篇05-密码学(1)的RSA算法,最后我们介绍了下签名验证,也就是私钥加密,公钥解密,对应的实际运用场景,就是我们熟知的iOS系统证书的申请流程。本篇文章会结合RSA算法分析下证书的整个申请流程,以及RSA代码演示

一、证书

上篇05-密码学(1)中,我们介绍了Mac系统内置OpenSSL(开源加密库)可以帮助我们生成公钥私钥完成加解密,但是我们在实际的开发中,是没有办法直接使用.pem文件进行加解密,而是Xcode帮我们去钥匙串访问申请的证书,我们通过这个证书与苹果的服务器进行验签等交互。

1.1证书生成

证书生成之前,我们需要生成一个请求文件 👉 CertificateSigningRequest.certSigningRequest(简称csr文件),有2种方式👇

  1. 钥匙串生成csr文件
  2. 命令行生成csr文件
钥匙串生成

操作路径 👉 钥匙串 ->钥匙串访问->证书助理->从证书颁发机构请求证书,如下图👇

image.png

接着填入基本信息, 然后创建👇

image.png

这个时候就生成了一个请求csr文件

命令行生成

再看看命令行是如何操作的。

  • 通过私钥生成csr文件

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

利用上篇文章中生成的密钥.pem文件,生成csr请求文件👇

image.png

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

自己通过csr生成签名证书

当然,我们也可以不通过签名机构进行签名,直接自己签名生成crt证书

⚠️注意:通过私钥自己签名生成证书(crt)(这里是没有认证的)。

命令行👇

openssl x509 -req -days 3650 -in rsacer.csr -signkey private.pem -out rsacert.crt

image.png

这个crt证书就类似公司服务器上的证书,给别人接收的。但是这个时候crt证书仍然用不了,需要转换为der👇

openssl x509 -outform der -in rsacert.crt -out rsacert.der

image.png

因为从苹果申请的证书就是der证书

p12

还有一个我们熟悉的,p12格式文件,怎么生成呢?

  1. 从钥匙串中导出👇

image.png

image.png

  1. 命令行操作

crt获取p12文件👇

openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt

image.png

⚠️注意:p12(私钥)der(证书)一对。iOS开发中就是使用这两个进行加密和解密,是不是和RSA的公私钥原理一模一样。。。

二、RSA代码演示

接下来,我们接着之前的RSA算法,用代码演示一下加解密的过程。

2.1 Base64编解码

在演示之前,我们先来看看什么是Base64?代码加解密的过程中经常会用到Base64,为什么要Base64编解码呢?因为加密解密完数据都是二进制格式,一般情况下转换为base64是为了方便查看。

  • base64编码
base64 message.txt -o test.txt

编码前,message.txt的内容👇

image.png

编码后,test.txt的内容👇

image.png

编码后变成了5a+G56CBOkxHUGVyc29uCg==

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

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];
}

运行👇

image.png

base64是以查表的形式二进制进行编码,只适用于二进制文件。编码后文件会变大,会增加原来的1/3

base64参考文档

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]);

image.png

再运行一次👇

image.png

可以发现,每次加密后的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

XFCryptor

总结

  • 证书

    • csr请求文件,2种方式申请
      1. 钥匙串 ->钥匙串访问->证书助理->从证书颁发机构请求证书
      2. 终端命令行 openssl req -new -key private.pem -out rsacer.csr
    • crt证书生成
      1. csr请求文件发送到签名机构进行签名(⚠️需要收费
      2. 自己签名生成证书(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
    • 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
  1. 编码 👉 NSData的方法👇 - (NSString *)base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)options API_AVAILABLE(macos(10.9), ios(7.0), watchos(2.0), tvos(9.0));
  1. 解码 👉 NSString的方法👇 - (nullable instancetype)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding;
  • RSA代码
    • iOS本身支持RSA,系统提供了SecKeyEncryptSecKeyDecrypt加密和解密函数

    • RSA的安全系数非常高(因为整个业务逻辑非常安全)

    • 加密效率低(不能用于大数据加密)

    • 用来加密关键数据