一、突然發現少寫了一個RSA - -#...,加解密原理參照RSA算法原理,常規的加解算法一般都是對稱加密:
(1)甲方選擇某一種加密規則,對信息進行加密
(2)乙方使用同一種規則,對信息進行解密。
由于加密和解密使用同樣規則(簡稱"密鑰"),這被稱為"對稱加密算法"(Symmetric-key algorithm)。
這種加密模式有一個最大弱點:甲方必須把加密規則告訴乙方,否則無法解密。保存和傳遞密鑰,就成了最頭疼的問題。
常用的是AES如:iOS開發加解密算法-基礎篇(2)<AES加密算法>
而RSA是非對稱加密:
(1)乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
(2)甲方獲取乙方的公鑰,然后用它對信息加密。
(3)乙方得到加密后的信息,用私鑰解密。
如果公鑰加密的信息只有私鑰解得開,那么只要私鑰不泄漏,通信就是安全的。
特點
A.便于理解,使用廣泛
RSA算法是第一個能同時用于加密和數字簽名的算法,也易于理解和操作。RSA是被研究得最廣泛的公鑰算法,從提出到現今的三十多年里,經歷了各種攻擊的考驗,逐漸為人們接受,普遍認為是目前最優秀的公鑰方案之一。
B.缺點與不足:加密和解密花費時間長、速度慢,只適合對少量數據進行加密。
為提高保密強度,RSA密鑰至少為500位長,一般推薦使用1024位。這就使加密的計算量很大。為減少計算量,在傳送信息時,常采用傳統加密方法與公開密鑰加密方法相結合的方式,即信息采用改進的DES或IDEA對話密鑰加密,然后使用RSA密鑰加密對話密鑰和信息摘要。對方收到信息后,用不同的密鑰解密并可核對信息摘要。
二、RSA的方法實現:
1.一般移動端的RSA加解密的公私鑰都是由服務端生成的,我們要做的其實是拿著公私鑰去做加解密的操作。
2.我們公司的項目使用的加解密流程是
雖然RSA加密后基本無解,但是RSA不適合對大文本進行加密,所以我們采用的是對文件采用AES加密,對AES的秘鑰進行RSA的加密,AES秘鑰是動態的每一個文件的秘鑰都是唯一的,RSA的私鑰在傳輸的時候再用一層AES加密.解密的流程就是再倒著來一遍...
3.RSA解密,使用第三方加解密庫openssl
- 一般公私鑰都是由我們服務端提供的的(java后臺),這里遇到過坑,我們當時雙方都沒做過RSA的加解密,格子調研在自己的平臺上自己加密和解密是沒有問題的,但是用服務端傳給我們的私鑰解密他們的加密文本卻不能解密。最后發現原來生成的跨平臺的私鑰不能直接使用,需要進行統一的編碼處理后才能使用,我們采用的是統一的PKCS#8編碼處理后生成的.pem格式。可以參考:Java中使用OpenSSL生成的RSA公私鑰進行數據加解密
2.秘鑰文本
AES秘鑰經過RSA加密后的Base64字符串<code>
key = eY4bZZsiqDCsNgHVaT5OJfDkGp5pNlJbYUUPOTauXO5Yz9szXgz1XOmjTq8aoPnHTkuh1GCSF/hj0g182U2iUTZFIwRoL7MZ/LtuTpwDMaa3XHAOjvTqxfHKy3htd9gpR/2/w9+l9urm2MPS31GD/ZalX8GGBltDVNZWXj0zyX4=;</code>
RSA私鑰經過PKCS#8編碼處理后獲取的私鑰字符串:
<code>
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQCWWQqoCxHmu9yklZ7DAME9lvw0t37SqBhIcvnma7Rl3kTn4lfJ
WEoycvNmduhf59g193c8/4tQKs/B71OUIDWfASNhnaBVzyHXTupeUSo5yaXYdSja
VIhc/HmSms1SqlsDWBzJldi0JVaN5MqNnitHpxPOBHEu6J3Xr+Cobkd1XwIDAQAB
AoGAVHmtQiQOJ92QKK2kqZ6H9SobhSdAy+4EzthDT1Ne5gnQH5YOiyPfdJ8f4YeY
IyLqWdA0oAJZbW7Qkv/8rvK2DUbH97LkeGOuJtY5SxmbWI0w7fGvefg9TPrDSyRq
PWvohEZSM2w7slhHTiPFeiRFIEmuWGTJAcnmPLAraxn5QTkCQQDWfX4ybSk5mX9y
iSt952C78c80bX54XW9VMCnDIFGDkSsG3zyXlI4i3PJAXYHFwzcysD0irxQPVjTA
7k6b1eflAkEAs3G8mxCAbuqbzw7zuJUgMshns2tD5BIH8/7DwhRl/ecz6Az6SQ6Q
ZF02XpDyqpNtllwc2WDIyTE7go33bNeL8wJBALYb6Hix/A1+iRna4sVMHPKV1QJD
cNyLIAqpENwt5Weaani0MwLTy3ZIN5p0ick5/PSZc96t3Y9D9xhTfQSMsg0CQFlC
wmcAFmMWINsmvOWciJ+6QJtnSCYzMfGVURtBulpKn+9WRUoCDKFgHKN9xrhDDcg1
mcQn+Ljb3JZcuC9UKTECQQCRCHnaY7sp3hIizdIRN5lI0vhyipVVIymTTgmtu7rV
LrnmEEas1RhUVOyVJaw08mON/eH17//9X29cA9ntFSLh
-----END RSA PRIVATE KEY-----
</code>
4.代碼實現
a.將私鑰寫入到本地后綴名不限制
NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@".private_key.rce"];
NSFileManager *manger = [NSFileManager defaultManager];
[manger removeItemAtPath:path error:nil];
NSError *error = nil;
BOOL success = [str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:&error];
b.將私鑰導入
//根據鑰匙類型導入公鑰私鑰
- (BOOL)importRSAKeyWithType:(KeyType)type {
FILE *file;
if (type == KeyTypePublic) {
file = fopen([OpenSSLRSAPublicKeyFile cStringUsingEncoding:NSASCIIStringEncoding],"rb");
}else{
file = fopen([OpenSSLRSAPrivateKeyFile1 cStringUsingEncoding:NSASCIIStringEncoding],"rb");
}
if (NULL != file) {
if (type == KeyTypePublic) {
_rsa = PEM_read_RSAPublicKey(file,NULL, NULL, NULL);
assert(_rsa != NULL);
// PEM_write_RSAPublicKey(stdout, _rsa);
}else{
_rsa = PEM_read_RSAPrivateKey(file, NULL, NULL, NULL);
assert(_rsa != NULL);
PEM_write_RSAPrivateKey(stdout, _rsa, NULL, NULL, 0, NULL, NULL);
}
fclose(file);
return (_rsa != NULL)?YES:NO;
} return NO;
}
c.導入完成后對加密二進制流進行解密
- (NSData*)decryptRSAKeyWithType:(KeyType)keyType paddingType:(RSA_PADDING_TYPE)padding encryptedData:(NSData*)data {
if (data && [data length]) {
NSUInteger flen = [data length];
unsigned char from[flen];
bzero(from, sizeof(from));
memcpy(from, [data bytes], [data length]);
// 這里可以更改解密密文長度
unsigned char to[32];
bzero(to, sizeof(to));
[self decryptRSAKeyWithType:keyType :from :flen :to :padding];
NSData *data = [NSData dataWithBytes:to length:sizeof(to)];
[[NSFileManager defaultManager] removeItemAtPath:OpenSSLRSAPrivateKeyFile1 error:nil];
return data;
}
return nil;
}
- (NSData *)decryptRSAKeyWithType:(KeyType)keyType paddingType:(RSA_PADDING_TYPE)padding encryptedData:(NSData *)data andKeyName:(NSString *)name {
[self importRSAKeyWithType:KeyTypePrivate keyName:name];
if (data && [data length])
{
NSUInteger flen = [data length];
unsigned char from[flen];
bzero(from, sizeof(from));
memcpy(from, [data bytes], [data length]);
unsigned char to[32];
bzero(to, sizeof(to));
[self decryptRSAKeyWithType:keyType :from :flen :to :padding];
return [NSData dataWithBytes:to length:sizeof(to)];
}
return nil;
}