iOS經常使用加密之RSA加密解密

前言:

iOS經常使用的加密有不少種,前兩天在工做中遇到了RSA加密,如今把代嗎分享出來。安全

RSA基本原理

RSA使用"祕匙對"對數據進行加密解密.在加密解密數據前,須要先生成公鑰(public key)和私鑰(private key).app

  • 公鑰(public key): 用於加密數據. 用於公開, 通常存放在數據提供方, 例如iOS客戶端.
  • 私鑰(private key): 用於解密數據. 必須保密, 私鑰泄露會形成安全問題

第一步:公鑰、私鑰的生成

iOS開發者可直接在Mac終端生成,命令以下,生成公鑰der文件的時候須要填寫國家地區等基本信息,也可直接忽略不填。生成私p12文件的時候須要填寫密碼,這個必填並且要記住,後面會用得着。ide

// 生成1024位私鑰
openssl genrsa -out private_key.pem 1024
// 根據私鑰生成CSR文件
openssl req -new -key private_key.pem -out rsaCertReq.csr
// 根據私鑰和CSR文件生成crt文件
openssl x509 -req -days 3650 -in rsaCertReq.csr -signkey private_key.pem -out rsaCert.crt ui

// 爲IOS端生成公鑰der文件
openssl x509 -outform der -in rsaCert.crt -out public_key.der加密

// 將私鑰導出爲這p12文件
openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crtlua

第二步:加密相關的代碼

在加密加密的時候須要定義公有變量公鑰和私鑰spa

    SecKeyRef _publicKey;
    SecKeyRef _privateKey;

加密相關的代碼

 1 #pragma mark - 加密相關
 2 //用本地證書加載公鑰
 3 - (void)loadPublicKeyWithPath:(NSString *)derFilePath
 4 {
 5     NSData *derData = [[NSData alloc] initWithContentsOfFile:derFilePath];
 6     if (derData.length > 0)
 7     {
 8         [self loadPublicKeyWithData:derData];
 9     }
10     else
11     {
12         NSLog(@"load public key fail with path: %@", derFilePath);
13     }
14 }
15 //加載公鑰方法
16 - (void)loadPublicKeyWithData:(NSData *)derData
17 {
18     SecCertificateRef myCertificate = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef)derData);
19     SecPolicyRef myPolicy = SecPolicyCreateBasicX509();
20     SecTrustRef myTrust;
21     OSStatus status = SecTrustCreateWithCertificates(myCertificate,myPolicy,&myTrust);
22     SecTrustResultType trustResult;
23     if (status == noErr) {
24         status = SecTrustEvaluate(myTrust, &trustResult);
25     }
26     
27     SecKeyRef securityKey = SecTrustCopyPublicKey(myTrust);  CFRelease(myCertificate);  CFRelease(myPolicy);  CFRelease(myTrust);
28     
29     _publicKey = securityKey;
30 }
31 
32 
33 //將文本內容加密
34 - (NSString *)rsaEncryptText:(NSString *)text
35 {
36     NSData *encryptedData = [self rsaEncryptData:[text dataUsingEncoding:NSUTF8StringEncoding]];
37     NSString *base64EncryptedString = [encryptedData base64EncodedStringWithOptions:0];
38     return base64EncryptedString;
39 }
40 
41 
42 //分段再加密數據
43 - (NSData *)rsaEncryptData:(NSData *)data
44 {
45     SecKeyRef key = _publicKey;
46     
47     size_t cipherBufferSize = SecKeyGetBlockSize(key);
48     uint8_t *cipherBuffer = malloc(cipherBufferSize * sizeof(uint8_t));
49     size_t blockSize = cipherBufferSize - 11;
50     size_t blockCount = (size_t)ceil([data length] / (double)blockSize);
51     NSMutableData *encryptedData = [[NSMutableData alloc] init] ;
52     for (int i = 0; i < blockCount; i++)
53     {
54         size_t bufferSize = MIN(blockSize,[data length] - i * blockSize);
55         NSData *buffer = [data subdataWithRange:NSMakeRange(i * blockSize, bufferSize)];
56         OSStatus status = SecKeyEncrypt(key, kSecPaddingPKCS1,(const uint8_t *)[buffer bytes],[buffer length],cipherBuffer,&cipherBufferSize);
57         if (status == noErr)
58         {
59             NSData *encryptedBytes = [[NSData alloc] initWithBytes:(const void *)cipherBuffer length: cipherBufferSize];
60             [encryptedData appendData:encryptedBytes];
61         }
62         else
63         {
64             if (cipherBuffer) {
65                 free(cipherBuffer);
66             }      return nil;
67         }
68         
69     }
70     if (cipherBuffer)
71     {
72         free(cipherBuffer);
73         
74     }
75     return encryptedData;
76 }

第三步:解密相關代碼

#pragma mark - 解密相關
- (void)loadPrivateKeyWithPath:(NSString *)p12FilePath password:(NSString *)p12Password
{
    NSData *data = [NSData dataWithContentsOfFile:p12FilePath];
    if (data.length > 0)
    {
        [self loadPrivateKeyWithData:data password:p12Password];
}
    else
    {    NSLog(@"load private key fail with path: %@", p12FilePath);
}
}
//生成私鑰
- (void)loadPrivateKeyWithData:(NSData *)p12Data password:(NSString *)p12Password
{
    SecKeyRef privateKeyRef = NULL;
    NSMutableDictionary * options = [[NSMutableDictionary alloc] init];
    
    [options setObject:p12Password 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;
        }
    }
    
    _privateKey = privateKeyRef;
    CFRelease(items);
}


//調用下面方法進行解密,最後返回一個字符串
- (NSString *)rsaDecryptText:(NSString *)text
{
    NSData *data = [[NSData alloc] initWithBase64EncodedString:text options:0];
    NSData *decryptData = [self rsaDecryptData:data];
    NSString *result = [[NSString alloc] initWithData:decryptData encoding:NSUTF8StringEncoding];
    return result;
}


//用私鑰解密的方法,被上面方法調用
- (NSData *)rsaDecryptData:(NSData *)data
{
    SecKeyRef key = _privateKey;
    
    size_t cipherLen = [data length];
    void *cipher = malloc(cipherLen);
    
    [data getBytes:cipher length:cipherLen];
    size_t plainLen = SecKeyGetBlockSize(key) - 12;
    void *plain = malloc(plainLen);
    OSStatus status = SecKeyDecrypt(key, kSecPaddingPKCS1, cipher, cipherLen, plain, &plainLen);
    if (status != noErr)
    {
        return nil;
    }
    NSData *decryptedData = [[NSData alloc] initWithBytes:(const void *)plain length:plainLen];
    return decryptedData;
}

第四步:RSA加密解密的應用

在加密活解密以前必定要閒加載證書,而後再調用加密方法,直接上代碼code

 1 - (IBAction)decryptionBtnClick:(id)sender {
 2     
 3     NSString *path = [[NSBundle mainBundle] pathForResource:@"public_key" ofType:@"der"];
 4     [self loadPublicKeyWithPath:path];
 5     path = [[NSBundle mainBundle] pathForResource:@"private_key" ofType:@"p12"];
 6     [self loadPrivateKeyWithPath:path password:@"bestnet"];
 7     
 8     NSString *encryptStr = self.encryptTextFeild.text;
 9     if (encryptStr.length > 0)
10     {
11         NSString *miwen = [self rsaEncryptText:encryptStr];
12         self.miWenLabel.text = [NSString stringWithFormat:@"加密結果:%@", miwen];
13         if (miwen.length > 0)
14         {
15             self.decryptionTextFeild.text = [self rsaDecryptText:miwen];
16         }
17     }
18 }

效果圖

相關文章
相關標籤/搜索