首页 > 代码库 > iOS加密:RSA
iOS加密:RSA
RSA: 非对称加密算法(对称加密算法在加密和解密时使用的是同一个秘钥;而非对称加密算法需要两个密钥来进行加密和解密)
RSA作用:1,加密数据传输,
2,用于文件签名。
加密和加签有什么区别?
答:加密:公钥放在客户端,并使用公钥对数据进行加密,服务端拿到数据后用私钥进行解密;
加签:私钥放在客户端,并使用私钥对数据进行加签,服务端拿到数据后用公钥进行验签。
前者完全为了加密;后者主要是为了防恶意攻击,防止别人模拟我们的客户端对我们的服务器进行攻击,导致服务器瘫痪。
RSA加密方式:由已知加密密钥推导出解密密钥
RSA加密理论:1,大傻生成一对RSA 密钥,其中之一是私钥,自己保存,另一个为公钥,对外公开,
2,二傻的得到公钥,并对信息进行加密,
3,大傻收到信息后,用私钥解密。
- 公钥(public key): 用于加密数据. 用于公开, 一般存放在数据提供方, 例如iOS客户端.
- 私钥(private key): 用于解密数据. 必须保密, 私钥泄露会造成安全问题.
在iOS中使用RSA加密解密,需要用到.der
和.p12
后缀格式的文件,其中.der
格式的文件存放的是公钥(Public key)用于加密,.p12
格式的文件存放的是私钥(Private key)用于解密. 首先需要先生成这些文件,然后再将文件导入工程使用,不多说,开始做!
一、使用openssl生成所需秘钥文件
生成环境是在mac系统下,使用openssl进行生成,首先打开终端,按下面这些步骤依次来做:
1. 生成模长为1024bit的私钥文件private_key.pem
openssl genrsa -out private_key.pem 1024
2. 生成证书请求文件rsaCertReq.csr
openssl req -new -key private_key.pem -out rsaCerReq.csr
注意:这一步会提示输入国家、省份、mail等信息,可以根据实际情况填写,或者全部不用填写,直接全部敲回车.
3. 生成证书rsaCert.crt
,并设置有效时间为1年
openssl x509 -req -days 3650 -in rsaCerReq.csr -signkey private_key.pem -out rsaCert.crt
4. 生成供iOS使用的公钥文件public_key.der
openssl x509 -outform der -in rsaCert.crt -out public_key.der
5. 生成供iOS使用的私钥文件private_key.p12
openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt
注意:这一步会提示给私钥文件设置密码,直接输入想要设置密码即可,然后敲回车,然后再验证刚才设置的密码,再次输入密码,然后敲回车,完毕!
在解密时,private_key.p12
文件需要和这里设置的密码配合使用,因此需要牢记此密码.
6. 生成供Java使用的公钥rsa_public_key.pem
openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout
7. 生成供Java使用的私钥pkcs8_private_key.pem
openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt
全部执行成功后,会生成如下文件,其中public_key.der
和private_key.p12
就是iOS需要用到的文件,如下图:
二、将文件导入工程使用
1.新建工程, 并导入Security.framework
框架, 如下图:
2.导入秘钥文件
导入.der
和.p12
格式的秘钥文件, 如下图:
3.新建用于加密、解密的类RSAEncryptor
, 并实现相关方法
新建RSAEncryptor
类, 如下图:
下面开始上代码, 可以直接复制过去用:RSAEncryptor.h
代码如下:
#import <Foundation/Foundation.h>@interface RSAEncryptor : NSObject/** * 加密方法 * * @param str 需要加密的字符串 * @param path ‘.der‘格式的公钥文件路径 */+ (NSString *)encryptString:(NSString *)str publicKeyWithContentsOfFile:(NSString *)path;/** * 解密方法 * * @param str 需要解密的字符串 * @param path ‘.p12‘格式的私钥文件路径 * @param password 私钥文件密码 */+ (NSString *)decryptString:(NSString *)str privateKeyWithContentsOfFile:(NSString *)path password:(NSString *)password;/** * 加密方法 * * @param str 需要加密的字符串 * @param pubKey 公钥字符串 */+ (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey;/** * 解密方法 * * @param str 需要解密的字符串 * @param privKey 私钥字符串 */+ (NSString *)decryptString:(NSString *)str privateKey:(NSString *)privKey;@end
RSAEncryptor.m
代码如下:
#import "RSAEncryptor.h"#import <Security/Security.h>@implementation RSAEncryptorstatic NSString *base64_encode_data(NSData *data){ data = http://www.mamicode.com/[data base64EncodedDataWithOptions:0]; NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return ret;}static NSData *base64_decode(NSString *str){ NSData *data = http://www.mamicode.com/[[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters]; return data;}#pragma mark - 使用‘.der‘公钥文件加密//加密+ (NSString *)encryptString:(NSString *)str publicKeyWithContentsOfFile:(NSString *)path{ if (!str || !path) return nil; return [self encryptString:str publicKeyRef:[self getPublicKeyRefWithContentsOfFile:path]];}//获取公钥+ (SecKeyRef)getPublicKeyRefWithContentsOfFile:(NSString *)filePath{ NSData *certData = http://www.mamicode.com/[NSData dataWithContentsOfFile:filePath]; if (!certData) { return nil; } SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef)certData); SecKeyRef key = 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) { key = SecTrustCopyPublicKey(trust); } } } } if (policy) CFRelease(policy); if (trust) CFRelease(trust); if (cert) CFRelease(cert); return key;}+ (NSString *)encryptString:(NSString *)str publicKeyRef:(SecKeyRef)publicKeyRef{ if(![str dataUsingEncoding:NSUTF8StringEncoding]){ return nil; } if(!publicKeyRef){ return nil; } NSData *data = http://www.mamicode.com/[self encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] withKeyRef:publicKeyRef]; NSString *ret = base64_encode_data(data); return ret;}#pragma mark - 使用‘.12‘私钥文件解密//解密+ (NSString *)decryptString:(NSString *)str privateKeyWithContentsOfFile:(NSString *)path password:(NSString *)password{ if (!str || !path) return nil; if (!password) password = @""; return [self decryptString:str privateKeyRef:[self getPrivateKeyRefWithContentsOfFile:path password:password]];}//获取私钥+ (SecKeyRef)getPrivateKeyRefWithContentsOfFile:(NSString *)filePath password:(NSString*)password{ NSData *p12Data = http://www.mamicode.com/[NSData dataWithContentsOfFile:filePath]; if (!p12Data) { return nil; } SecKeyRef privateKeyRef = NULL; NSMutableDictionary * options = [[NSMutableDictionary alloc] init]; [options setObject: password 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); return privateKeyRef;}+ (NSString *)decryptString:(NSString *)str privateKeyRef:(SecKeyRef)privKeyRef{ NSData *data = http://www.mamicode.com/[[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters]; if (!privKeyRef) { return nil; } data = http://www.mamicode.com/[self decryptData:data withKeyRef:privKeyRef]; NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return ret;}#pragma mark - 使用公钥字符串加密/* START: Encryption with RSA public key *///使用公钥字符串加密+ (NSString *)encryptString:(NSString *)str publicKey:(NSString *)pubKey{ NSData *data = http://www.mamicode.com/[self encryptData:[str dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey]; NSString *ret = base64_encode_data(data); return ret;}+ (NSData *)encryptData:(NSData *)data publicKey:(NSString *)pubKey{ if(!data || !pubKey){ return nil; } SecKeyRef keyRef = [self addPublicKey:pubKey]; if(!keyRef){ return nil; } return [self encryptData:data withKeyRef:keyRef];}+ (SecKeyRef)addPublicKey:(NSString *)key{ NSRange spos = [key rangeOfString:@"-----BEGIN PUBLIC KEY-----"]; NSRange epos = [key rangeOfString:@"-----END PUBLIC KEY-----"]; if(spos.location != NSNotFound && epos.location != NSNotFound){ NSUInteger s = spos.location + spos.length; NSUInteger e = epos.location; NSRange range = NSMakeRange(s, e-s); key = [key substringWithRange:range]; } key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""]; key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""]; key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""]; key = [key stringByReplacingOccurrencesOfString:@" " withString:@""]; // This will be base64 encoded, decode it. NSData *data = base64_decode(key); data = http://www.mamicode.com/[self stripPublicKeyHeader:data]; if(!data){ return nil; } //a tag to read/write keychain storage NSString *tag = @"RSAUtil_PubKey"; NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; // Delete any old lingering key with the same tag NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init]; [publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass]; [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag]; SecItemDelete((__bridge CFDictionaryRef)publicKey); // Add persistent version of the key to system keychain [publicKey setObject:data forKey:(__bridge id)kSecValueData]; [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id) kSecAttrKeyClass]; [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) kSecReturnPersistentRef]; CFTypeRef persistKey = nil; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey); if (persistKey != nil){ CFRelease(persistKey); } if ((status != noErr) && (status != errSecDuplicateItem)) { return nil; } [publicKey removeObjectForKey:(__bridge id)kSecValueData]; [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef]; [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef]; [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; // Now fetch the SecKeyRef version of the key SecKeyRef keyRef = nil; status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef); if(status != noErr){ return nil; } return keyRef;}+ (NSData *)stripPublicKeyHeader:(NSData *)d_key{ // Skip ASN.1 public key header if (d_key == nil) return(nil); unsigned long len = [d_key length]; if (!len) return(nil); unsigned char *c_key = (unsigned char *)[d_key bytes]; unsigned