美文网首页
06-密码学(2)

06-密码学(2)

作者: 深圳_你要的昵称 | 来源:发表于2021-04-18 14:19 被阅读0次

    前言

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

    一、证书

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

    1.1证书生成

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

    1. 钥匙串生成csr文件
    2. 命令行生成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格式文件,怎么生成呢?

    1. 从钥匙串中导出👇
    1. 命令行操作

    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

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

    再运行一次👇

    可以发现,每次加密后的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的安全系数非常高(因为整个业务逻辑非常安全)
      • 加密效率低(不能用于大数据加密)
      • 用来加密关键数据

    相关文章

      网友评论

          本文标题:06-密码学(2)

          本文链接:https://www.haomeiwen.com/subject/ewkrlltx.html