利用BBRSACryptor實現iOS端的RSA加解密
背景
RSA這種非對稱加密被廣泛的運用于網絡數據的傳輸,但其在iOS上很那直接實現,BBRSACryptor框架通過移植openssl實現了iOS端的RSA,本文將介紹如何使用BBRSACryptor生成證書,加載公鑰,以及后端如何用php讀取證書,加載私鑰。
iOS加密
新建工程并集成BBRSACryptor
這個框架自帶的demo將工程文件與框架放在了同一目錄,因此在配置Header Search Paths時沒有包含工程文件夾,一定注意,下面新建的工程將框架放在了工程文件夾內,因此頭文件尋找路徑需要包含上工程目錄。詳細步驟如下。
1. 新建一個iOS工程,將BBRSACryptor、GTMBase64、OpenSSL三個文件夾拖入工程,目錄結構如下。
2.在Build Settings中配置Header Search Pathes。
注意最前面的文件夾名稱要和自己的工程名相同
3.打開BBRSACryptor.m文件,修改存儲證書的目錄和文件路徑,默認的是隱藏目錄(前加點),為了方便查看與復制證書,建議將路徑前面的點去掉,例如:
#define OpenSSLRSAKeyDir [DocumentsDir stringByAppendingPathComponent:@"openssl_rsa"] #define OpenSSLRSAPublicKeyFile [OpenSSLRSAKeyDir stringByAppendingPathComponent:@"publicKey.pem"] #define OpenSSLRSAPrivateKeyFile [OpenSSLRSAKeyDir stringByAppendingPathComponent:@"privateKey.pem"]
4.打開ViewController.m,導入BBRSACryptor.h和GTMBase64.h,使用下面的代碼生成證書。
BBRSACryptor *rsaCryptor = [[BBRSACryptor alloc] init]; [rsaCryptor generateRSAKeyPairWithKeySize:1024];
運行后,在控制臺會打印出證書路徑,進入路徑后,可以看到公鑰和私鑰證書。
5.使用TextEdit打開公鑰證書,將—–BEGIN PUBLIC KEY—–和—–END PUBLIC KEY—–之間的部分復制,然后在工程中新建一個宏,來保存這個公鑰,以便后續讀取。
#define PublicKey \ @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjYyZoASYgT+MIc/5YkSJngRbNYEQEI3UF7RVijF0STcMs93pH0qhjLJIQnsvUn2ghEVM4X+S+tQ0XhS+7tmL1UMEFgDgYwG/xr/ZjUozgQyvqeUejA08pbun0E0/Yx9WuBQfCpCc5vNka/ENDZEy/2PbEO5KD3hgsnH1JyNqNnwIDAQAB"
客戶端僅保存公鑰即可,私鑰放在服務器上。使用php可以直接讀取證書。
6.在客戶端加載公鑰與進行加密
前面已經創建了宏,以后通過宏即可加載公鑰。如下:
BBRSACryptor *rsaCryptor = [[BBRSACryptor alloc] init]; // PublicKey是從公鑰證書中復制的內容創建的宏,見上文。 [rsaCryptor importRSAPublicKeyBase64:PublicKey]; NSData *data = [rsaCryptor encryptWithPublicKeyUsingPadding:RSA_PADDING_TYPE_PKCS1 plainData:[@"客戶端加密的內容" dataUsingEncoding:NSUTF8StringEncoding]]; NSString *baseStr = [GTMBase64 stringByEncodingData:data]; NSLog(@"%@",baseStr);
先加載公鑰,然后把要加密的內容轉換成NSData,加密后的內容先進行base64編碼后再傳輸。為了驗證能夠解密,最后對base64編碼的加密內容進行了打印,將這個內容先復制到剪貼板,后面貼在php中進行解密。
php解密
為了方便,將按照上文方法生成的私鑰證書復制到服務器的某個目錄,并在這個目錄下創建一個php文件,并添加如下代碼:
<?php header("Content-type:text/html; charset=utf-8"); /** * 密鑰文件的路徑 */ $privateKeyFilePath = 'privateKey.pem'; /** * 公鑰文件的路徑 */ $publicKeyFilePath = 'publicKey.pem'; extension_loaded('openssl') or die('php需要openssl擴展支持'); (file_exists($privateKeyFilePath) && file_exists($publicKeyFilePath)) or die('密鑰或者公鑰的文件路徑不正確'); /** * 生成Resource類型的密鑰,如果密鑰文件內容被破壞,openssl_pkey_get_private函數返回false */ $privateKey = openssl_pkey_get_private(file_get_contents($privateKeyFilePath)); /** * 生成Resource類型的公鑰,如果公鑰文件內容被破壞,openssl_pkey_get_public函數返回false */ $publicKey = openssl_pkey_get_public(file_get_contents($publicKeyFilePath)); ($privateKey && $publicKey) or die('密鑰或者公鑰不可用'); // 這段內容來自上面iOS端打印的加密內容的base64編碼 $encryptData = 'J0oTqBCNbsJauVwRz+380y519sSa7ficUO1NvRKiMGKUGJF0pomOu20fHqC77NmsKle9/L4DyYNr3xDgDa4SpO0in39rA9EYXzmx3rlyI1c8iPjAkQ6XpwZk7BsThiCFB/6QmkTW5pMIo4b0axRv/4lq1Rqx/YtuIsGkXQTNntI='; $ee = base64_decode($encryptData); $decryptData =''; if (openssl_private_decrypt($ee, $decryptData, $privateKey)) { echo '解密成功,解密后數據為:', $decryptData, PHP_EOL; } else { die('解密成功'); } ?>
訪問這個腳本,如果前面做的沒有問題,會得到解密的結果:
php加密
使用私鑰加密后,可以在客戶端利用公鑰解密。使用下面的代碼進行加密。
<?php header("Content-type:text/html; charset=utf-8"); /** * 密鑰文件的路徑 */ $privateKeyFilePath = 'privateKey.pem'; /** * 公鑰文件的路徑 */ $publicKeyFilePath = 'publicKey.pem'; extension_loaded('openssl') or die('php需要openssl擴展支持'); (file_exists($privateKeyFilePath) && file_exists($publicKeyFilePath)) or die('密鑰或者公鑰的文件路徑不正確'); /** * 生成Resource類型的密鑰,如果密鑰文件內容被破壞,openssl_pkey_get_private函數返回false */ $privateKey = openssl_pkey_get_private(file_get_contents($privateKeyFilePath)); /** * 生成Resource類型的公鑰,如果公鑰文件內容被破壞,openssl_pkey_get_public函數返回false */ $publicKey = openssl_pkey_get_public(file_get_contents($publicKeyFilePath)); ($privateKey && $publicKey) or die('密鑰或者公鑰不可用'); $originalData = '服務器加密的內容'; /** * 加密以后的數據,用于在網路上傳輸 */ $encryptData = ''; echo '原數據為:', $originalData, PHP_EOL; ///////////////////////////////用私鑰加密//////////////////////// if (openssl_private_encrypt($originalData, $encryptData, $privateKey)) { echo '加密成功,加密后數據(base64_encode后)為:', base64_encode($encryptData), PHP_EOL; } else { die('加密失敗'); } ?>
訪問腳本后會打印出加密的base64編碼,將這個編碼復制到客戶端進行解密,來驗證可用性。
iOS解密
要在iOS端解密,和加密類似,先加載公鑰,然后把base64編碼的加密內容解碼,解密后轉為NSString即可。
BBRSACryptor *rsaCryptor = [[BBRSACryptor alloc] init]; [rsaCryptor importRSAPublicKeyBase64:PublicKey]; NSData *enCryptorDataBase64 = [@"aWdbPQHiQzU5CUOAIGQT3OD/MPqcqoXHXDFtYQPVRo9/Mb1S/aVcKQVHDjBpLgfzw+0mWxgHN6SuOfH8z9WobgQrTZh+pxhau3DnfukLmENGPWVMqquWMxTkEU7yCkx/RI7XEwv3jk9d4UgFOv35eqNUgYyWDq2gGatEpfnUg6U=" dataUsingEncoding:NSUTF8StringEncoding]; NSData *deCryptorData = [rsaCryptor decryptWithPublicKeyUsingPadding:RSA_PADDING_TYPE_PKCS1 cipherData:[GTMBase64 decodeData:enCryptorDataBase64]]; NSLog(@"%@",[[NSString alloc] initWithData:deCryptorData encoding:NSUTF8StringEncoding]);
不出意外的話,控制臺將會打印出解密后的內容。