iOS常用加密之RSA加密解密
前言:
iOS常用的加密有很多种,前两天在工作中遇到了RSA加密,现在把代吗分享出来。
RSA基本原理
RSA使用"秘匙对"对数据进行加密解密.在加密解密数据前,需要先生成公钥(public key)和私钥(private key).
- 公钥(public key): 用于加密数据. 用于公开, 一般存放在数据提供方, 例如iOS客户端.
- 私钥(private key): 用于解密数据. 必须保密, 私钥泄露会造成安全问题
第一步:公钥、私钥的生成
iOS开发者可直接在Mac终端生成,命令如下,生成公钥der文件的时候需要填写国家地区等基本信息,也可直接忽略不填。生成私p12文件的时候需要填写密码,这个必填而且要记住,后面会用得着。
// 生成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
// 为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.crt
第二步:加密相关的代码
在加密加密的时候需要定义公有变量公钥和私钥
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加密解密的应用
在加密活解密之前一定要闲加载证书,然后再调用加密方法,直接上代码
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 }
效果图