RSA: 非對稱加密算法(對稱加密算法在加密和解密時使用的是同一個祕鑰;而非對稱加密算法須要兩個密鑰來進行加密和解密)css
RSA做用:1,加密數據傳輸,算法
2,用於文件簽名。安全
加密和加簽有什麼區別?
答:加密:公鑰放在客戶端,並使用公鑰對數據進行加密,服務端拿到數據後用私鑰進行解密;
加簽:私鑰放在客戶端,並使用私鑰對數據進行加簽,服務端拿到數據後用公鑰進行驗籤。
前者徹底爲了加密;後者主要是爲了防惡意攻擊,防止別人模擬咱們的客戶端對咱們的服務器進行攻擊,致使服務器癱瘓。服務器
RSA加密方式:由已知加密密鑰推導出解密密鑰app
RSA加密理論:1,大傻生成一對RSA 密鑰,其中之一是私鑰,本身保存,另外一個爲公鑰,對外公開,框架
2,二傻的獲得公鑰,並對信息進行加密,ide
3,大傻收到信息後,用私鑰解密。測試
在iOS中使用RSA加密解密,須要用到.der
和.p12
後綴格式的文件,其中.der
格式的文件存放的是公鑰(Public key)用於加密,.p12
格式的文件存放的是私鑰(Private key)用於解密. 首先須要先生成這些文件,而後再將文件導入工程使用,很少說,開始作!fetch
生成環境是在mac系統下,使用openssl進行生成,首先打開終端,按下面這些步驟依次來作:ui
private_key.pem
openssl genrsa -out private_key.pem 1024
rsaCertReq.csr
openssl req -new -key private_key.pem -out rsaCerReq.csr
注意:這一步會提示輸入國家、省份、mail等信息,能夠根據實際狀況填寫,或者所有不用填寫,直接所有敲回車.
rsaCert.crt
,並設置有效時間爲1年openssl x509 -req -days 3650 -in rsaCerReq.csr -signkey private_key.pem -out rsaCert.crt
public_key.der
openssl x509 -outform der -in rsaCert.crt -out public_key.der
private_key.p12
openssl pkcs12 -export -out private_key.p12 -inkey private_key.pem -in rsaCert.crt
注意:這一步會提示給私鑰文件設置密碼,直接輸入想要設置密碼便可,而後敲回車,而後再驗證剛纔設置的密碼,再次輸入密碼,而後敲回車,完畢!
在解密時,private_key.p12
文件須要和這裏設置的密碼配合使用,所以須要牢記此密碼.
rsa_public_key.pem
openssl rsa -in private_key.pem -out rsa_public_key.pem -pubout
pkcs8_private_key.pem
openssl pkcs8 -topk8 -in private_key.pem -out pkcs8_private_key.pem -nocrypt
所有執行成功後,會生成以下文件,其中public_key.der
和private_key.p12
就是iOS須要用到的文件,以下圖:
Security.framework
框架, 以下圖:導入.der
和.p12
格式的祕鑰文件, 以下圖:
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 RSAEncryptor static NSString *base64_encode_data(NSData *data){ data = [data base64EncodedDataWithOptions:0]; NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; return ret; } static NSData *base64_decode(NSString *str){ NSData *data = [[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 = [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 = [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 = [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 = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters]; if (!privKeyRef) { return nil; } data = [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 = [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 = [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 int idx = 0; if (c_key[idx++] !=