美文网首页
OC(十二):加密算法(一):RSA

OC(十二):加密算法(一):RSA

作者: IMSong | 来源:发表于2016-11-02 16:15 被阅读763次

    今天公司测试,还在等待 bug 降临,闲来无事捯饬一个小问题.
    首先絮叨一下 RSA 的前世今生, RSA 是三个作者名字的简称,具体内容请自行百度,加密机制如下:首先生成两个密钥,一个公钥,一个私钥,前者加密,后者解密,客户端和服务器各执一份.当客户端向服务器发送数据的时候,先用公钥加密,再有私钥加签,到了服务器一端,用公钥验签,用私钥解密,然后再往下走.加密是为了安全,加签是为了防止冒充APP 客户端进行请求,导致服务器的瘫痪.
    👉安装OpenSSL
    使用OpenSSL获取公钥和私钥, OpenSSL 的安装请自行百度.
    👉获取公钥,私钥步骤
    ①生成 pem 文件
    openssl:关键字
    genrsa:格式
    -out:输出到...
    privatekey.pem:文件名任意取
    1024:文件长度

    openssl genrsa -out privatekey.pem 1024

    ②通过第一步生成的 pem 请求 csr 文件,这里会让你填写一些基本信息,最后一下密码可以选填
    req:发出请求
    -new:新的
    privatekey.pem:👆生成的证书
    requestrsacert.csr:证书请求文件

    openssl req -new -key privatekey.pem -out requestCert.csr

    ③ 通过上面两步生成的文件,请求公钥
    x509:证书格式
    -days:有效时长
    3650:10年(随意设置)
    -in:放入哪个文件
    requestrsacert.csr:👆生成的证书
    -signkey:key
    private.pem:👆生成的证书
    publickey.crt:请求到的公钥

    openssl x509 -req -days 3650 -in requestCert.csr -signkey privatekey.pem -out publickey.crt

    ④ 转换格式将base64转换为 bitcode
    -outform:输出格式

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

    ⑤ 生成p12 私钥文件,会提示输入密码,这个密码是用来在加密是调用私钥的密码
    -export:导出

    openssl pkcs12 -export -out privatekey.p12 -inkey privatekey.pem -in publickey.crt

    👉将公钥和私钥添加到工程中,引入Security.framework,创建对应的类SRSA, 这是我自己命名,你自己也是可以去自己想用的名字.记得设置为 MRC 的模式(-fno-objc-arc)

    公钥密钥

    👉.h

    //
    //  SRSA.h
    //  RSA
    //
    //  Created by HMC on 2016/11/1.
    //  Copyright © 2016年 HMC. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface SRSA : NSObject
    
    /**
     *
     * 加密
     * originalString 原始字符串
     */
    +(NSString *)encryptString:(NSString *) originalString;
    
    /**
     *
     * 解密
     *
     * ciphertextString 加密字符串
     */
    +(NSString *)decryptString:(NSString *) ciphertextString;
    
    
    @end
    
    

    👉.m

    //
    //  SRSA.m
    //  RSA
    //
    //  Created by HMC on 2016/11/1.
    //  Copyright © 2016年 HMC. All rights reserved.
    //
    
    #import "SRSA.h"
    
    //私钥的密码
    static NSString * pwd = @"123456";
    
    @implementation SRSA
    
    +(NSString *)encryptString:(NSString *)originalString{
        
        if (!originalString)
            return nil;
        SecKeyRef publicKey = [self getPublicKeyRef];
        size_t cipherBufferSize = SecKeyGetBlockSize(publicKey);
        uint8_t *cipherBuffer = malloc(cipherBufferSize);
        uint8_t *nonce = (uint8_t *) [originalString UTF8String];
        
        SecKeyEncrypt(publicKey,
                      kSecPaddingPKCS1,
                      nonce,
                      strlen((char *) nonce),
                      &cipherBuffer[0],
                      &cipherBufferSize);
        NSData *encryptedData = [NSData dataWithBytes:cipherBuffer length:cipherBufferSize];
        free(cipherBuffer);
        
        return [encryptedData base64EncodedStringWithOptions:0];
        
    }
    
    +(NSString *)decryptString:(NSString *)ciphertextString{
        
        if (!ciphertextString)
            return nil;
        
        SecKeyRef privateKey = [self getPrivateKeyRef];
        size_t plainBufferSize = SecKeyGetBlockSize(privateKey);
        uint8_t *plainBuffer = malloc(plainBufferSize);
        
        
        NSData *incomingData = [[NSData alloc] initWithBase64EncodedString:ciphertextString options:NSDataBase64DecodingIgnoreUnknownCharacters];
        uint8_t *cipherBuffer = (uint8_t *) [incomingData bytes];
        size_t cipherBufferSize = SecKeyGetBlockSize(privateKey);
        SecKeyDecrypt(privateKey,
                      kSecPaddingPKCS1,
                      cipherBuffer,
                      cipherBufferSize,
                      plainBuffer,
                      &plainBufferSize);
        NSData *decryptedData = [NSData dataWithBytes:plainBuffer length:plainBufferSize];
        NSString *originalString = [[NSString alloc] initWithData:decryptedData encoding:NSUTF8StringEncoding];
        [incomingData release];
        free(plainBuffer);
        return originalString;
    ;
        
    }
    
    //获取公钥
    
    +(SecKeyRef)getPublicKeyRef{
        
        NSString * path = [[NSBundle mainBundle] pathForResource:@"publickey.der" ofType:nil];
        NSData *certData = [NSData dataWithContentsOfFile:path];
        
        if (!certData) {
            return nil;
        }
        
        SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef)certData);
        
        SecKeyRef publicKey = NULL;
        SecTrustRef trust = NULL;
        SecPolicyRef policy = NULL;
        
        if (cert != NULL) {
            policy = SecPolicyCreateBasicX509();
            if (policy) {
                if (SecTrustCreateWithCertificates((CFTypeRef)cert, policy, &trust) == noErr) {
                    SecTrustResultType result;
                    if (SecTrustEvaluate(trust, &result) == noErr) {
                        publicKey = SecTrustCopyPublicKey(trust);
                    }
                }
            }
        }
        
        if (policy) CFRelease(policy);
        if (trust) CFRelease(trust);
        if (cert) CFRelease(cert);
        
        return publicKey;
    }
    
    
    //获取私钥
    +(SecKeyRef)getPrivateKeyRef{
        
        NSString * path = [[NSBundle mainBundle] pathForResource:@"privatekey.p12" ofType:nil];
        NSData *p12Data = [NSData dataWithContentsOfFile:path];
        
        NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
        
        SecKeyRef privateKeyRef = NULL;
        
        //这里的密码改成实际私钥的密码
        [options setObject:pwd forKey:(__bridge id)kSecImportExportPassphrase];
        
        CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
        
        OSStatus securityError = SecPKCS12Import((__bridge CFDataRef) p12Data,
                                                 (__bridge CFDictionaryRef)options, &items);
        
        if (securityError == noErr && CFArrayGetCount(items) > 0) {
            CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
            SecIdentityRef identityApp =
            (SecIdentityRef)CFDictionaryGetValue(identityDict,
                                                 kSecImportItemIdentity);
            
            securityError = SecIdentityCopyPrivateKey(identityApp, &privateKeyRef);
            if (securityError != noErr) {
                privateKeyRef = NULL;
            }
        }
        CFRelease(items);
        [options release];
        return privateKeyRef;
    }
    
    
    @end
    
    

    👉调用

    //
    //  ViewController.m
    //  RSA
    //
    //  Created by HMC on 2016/11/1.
    //  Copyright © 2016年 HMC. All rights reserved.
    //
    
    #import "ViewController.h"
    
    #import "SRSA.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        NSString * str = [SRSA encryptString:@"I am a Chinese"];
        
        NSLog(@"加密后:%@",str);
        NSLog(@"%@ 解密后:%@",str,[SRSA decryptString:str]);
        
    }
    
    @end
    
    验证结果

    PS: 客户端的 RSA 是配合后台进行加密解密的,所以也要后台(本文是 Java 的后台)有同样的公钥和私钥,只是格式不同.命令如下:
    公钥:

    openssl rsa -in privatekey.pem -out publickeyForJava.pem -pubout

    私钥

    openssl pkcs8 -topk8 -in privatekey.pem -out privatekeyForJava.pem -nocrypt

    相关文章

      网友评论

          本文标题:OC(十二):加密算法(一):RSA

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