iOS端RSA加密

RSA算法是最廣爲使用的「非對稱加密算法」,基本上只要有計算機網絡的地方,就有RSA算法。 這種算法很是可靠,密鑰越長,它就越難破解。根據報道,目前被破解的最長RSA密鑰是768個二進制位。也就是說,長度超過768位的密鑰,還沒法破解(至少沒人公開宣佈)。 所以能夠認爲,1024位的RSA密鑰基本安全,2048位的密鑰極其安全。RSA是由Rivest、Shamir 和 Adleman三位數學家1977年提出的加密算法,因此以他們首字母命名。html

理解RSA

理解RSA首先要理解非對稱加密:git

  • 公私鑰: 非對稱加密有公鑰私鑰組成,公鑰和私鑰是按照必定數學算法生成的。公鑰是公開的,任何人均可以獲取。私鑰是保密的,只有擁有者才能使用。
  • 加密和簽名: 他人使用你的公鑰加密信息,而後發送給你,你用私鑰解密,取出信息。反過來,你也能夠用私鑰加密信息,別人用你的公鑰解開,從而證實這個信息確實是你發出的,且未被篡改,這叫作數字簽名。
  • 理解: 至於公鑰和私鑰的關係,有人形象的把公鑰比喻爲保險箱,把私鑰比喻爲保險箱的鑰匙,保險箱我能夠給任何人,也能夠有多個保險箱,任何人均可以往保險箱裏面放東西(機密數據),但只有我有私鑰(保險箱的鑰匙),只有我能打開保險箱。

iOS使用RSA

RSA加密iOS中常常用到,常見場景是加密用戶輸入的密碼發送給後臺,固然爲了避免泄露用戶密碼,通常都是將密碼進行MD5加鹽編碼後再用RSA加密給後臺,這樣即便被破解,也不會泄露用戶輸入的密碼。github

基本流程

App->>Server: App請求「公鑰」
Server->> App: Server返回「公鑰」
App->> Server: App用公鑰加密「密碼」發送
Server->> App: Server解密正確返回數據
複製代碼

注意: 通常是後臺從密鑰池中選取一對公私鑰,把公鑰發送給客戶端,客戶端加密密碼等機密信息後發送給後臺,後臺使用私鑰解密獲取加密的內容。算法

iOS使用RSA注意點

  • 防反編譯: 密碼密鑰等信息通常不存在客戶端,防止被反編譯數據庫

  • 耗時操做: 生成公私鑰是耗時操做,後臺通常會提早生成多對公私鑰保存到數據庫中,使用的時候隨機取出一對,使用並記錄使用的那一對便可。安全

  • 文件格式: 後臺生成.der和.p12後綴格式的文件,其中der格式的文件存放的是公鑰(Public key)用於加密,p12格式的文件存放的是私鑰(Private key)用於解密。後臺能夠從.der文件中讀出公鑰,轉化爲JSON字符串格式發送給客戶端,也能夠直接發送後綴名爲.der格式公鑰文件,客戶端下載後使用。服務器

  • iOS生成公私鑰對: 至於iOS端生成RSA公私鑰,須要集成openssl庫,具體Google百度吧。網絡

  • 加解密失敗: 若是與後臺聯調的時候加解密失敗,注意一下密鑰格式(分爲pkcs8和pkcs1)。例如Mac下生成的給iOS使用公私鑰文件.der和.p12,密鑰編碼格式爲pkcs1;而Java後臺使用的.pem文件格式的公私鑰,編碼格式爲pkcs8,使用的時候須要轉換格式。函數

RSA可靠性

Wiki百科: 對極大整數作因數分解的難度決定了RSA算法的可靠性。換言之,對一極大整數作因數分解愈困難,RSA算法愈可靠。編碼

假若有人找到一種快速因數分解的算法,那麼RSA的可靠性就會極度降低。但找到這樣的算法的可能性是很是小的。今天只有短的RSA密鑰纔可能被暴力破解。到目前爲止,世界上尚未任何可靠的攻擊RSA算法的方式。

只要密鑰長度足夠長,用RSA加密的信息其實是不能被解破的。

RSA公私鑰生成步驟:

  1. 隨意選擇兩個大的質數p和q,p不等於q,計算N=pq,N的二進制位數就是密鑰長度。
  2. 根據歐拉函數(對正整數n,歐拉函數是小於n的正整數中與n互質的數的數目),求得r = (p-1)(q-1)
  3. 選擇一個小於r的整數e,條件是1< e < r,且e與r互質,求得 e 關於模 r 的模反元素,命名爲d。(模反元素存在,當且僅當e與r互質)
  4. 將 p 和 q 的記錄銷燬。
  5. (N,e)是公鑰,(N,d)是私鑰。

RSA加解密公式

PS:假設m爲要傳遞的密文,mod爲求餘,N、e、d都是已知的

  • 加密公式: m^e ≡ c (mod N),m、e、N都爲已知,加密就是算出密文c。
  • 解密公式: c^d ≡ m (mod N),c、d、N爲已知,解密就是算出m。

RSA加密長度限制:

  • 理論可加密明文長度: RSA算法自己要求加密內容也就是明文長度m必須0<m<N,也就是說內容這個大整數不能超過N,不然就出錯。
  • 實際可加密明文長度: 實際可加密明文長度小於理論長度,由於加密須要遵循必定標準,須要用到padding,padding標準有NoPPadding、OAEPPadding、PKCS1Padding,其中PKCS#1建議的padding就佔用了11個字節。
  • 實際可加密明文長度計算: 目前主流的密鑰長度通常爲1024bits2048bits,若是是PKCS格式密鑰長度是1024位,則可加密字符長度爲1024/8=128個字節,實際可加密明文長度爲128-11=117個字節;同理,若是是PKCS格式2048位密鑰,可加密長度爲256-11=244個字節。

RSA加密長度超限制解決辦法:

若是要加密大於N的數據怎麼辦? 有兩種解決方法:

  • 一種是把長信息分割成若干段短消息,每段分別加密,由於RSA加解密效率比較低,因此這種方式效率很低;
  • 另外一種是先選擇一種"對稱性加密算法"(好比DES或AES),先用RSA加密傳遞DES或AES密鑰,而後用AES或DES的密鑰加密信息,對稱加密的效率很高。HTTPS就是採用這種方式,RSA傳遞對稱加密密鑰,對稱密鑰加密數據傳遞。

iOS端RSA加解密示例

場景:客戶端加密用戶密碼/交易密碼發送給服務器

客戶端向服務器請求RSA公鑰服務器 → 返給客戶端一個NSString格式的RSA公鑰 → 客戶端用RSA公鑰字符串加密密碼發送給服務器 → 服務器用RSA私鑰解密並覈對密碼 → 覈對密碼是否正確,並返回客戶數據給客戶端

RSA序列圖

例如:這是一串服務器生成的RSA公鑰

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDTbZ6cNH9 PgdF60aQKveLz3FTalyzHQwbp601y77SzmGHX3F5NoVUZbd K7UMdoCLK4FBziTewYD9DWvAErXZo9BFuI96bAop8wfl1Vk ZyyHTcznxNJFGSQd/B70/ExMgMBpEwkAAdyUqIjIdVGh1FQ K/4acwS39YXwbS+IlHsPSQIDAQAB

但因爲含有/+=\n等特殊字符串,網絡傳輸過程當中致使轉義,進而致使加密解密不成功,解決辦法是進行URL特殊符號編碼解碼(百分號轉義);具體示例,在Demo中有示例,文章最下方有Demo連接

RSA用NSString加密解密Demo,很是簡單

//----------------------RSA加密示例------------------------
//原始數據,要加密的字符串
NSString *originalString = @"這是一段將要使用'祕鑰字符串'進行加密的字符串!";

//使用字符串格式的公鑰私鑰加密解密, RSAPublickKey爲公鑰字符串(NSString格式)
NSString *encryptStr = [RSAEncryptor encryptString:originalString publicKey:RSAPublickKey];

NSLog(@"加密前:%@", originalString);
NSLog(@"加密後:%@", encryptStr);
//用私鑰解密,RSAPrivateKey爲私鑰字符串(NSString格式)
NSString *decryptString = [RSAEncryptor decryptString:encryptStr privateKey:RSAPrivateKey];

NSLog(@"解密後:%@",decryptString);
複製代碼

RSA用NSString加解密的示例頭文件

// RSA加密封裝類
//注意:若是使用,須要打開鑰匙串;由於iOS不支持直接使用字符串格式的公鑰進行加密,轉換爲文件後可以使用

#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
複製代碼

若是您以爲有所幫助,請在RSADemo上賞個Star ⭐️,您的鼓勵是我前進的動力

參考:

相關文章
相關標籤/搜索