平時開發(fā)中不僅會遇到各種需要保護用戶隱私的情況饶辙,而且還有可能需要對公司核心數(shù)據(jù)進行保護捷绒,這時候加密隱私數(shù)據(jù)就成為了必要莺褒。然而市場上存在著各種各樣的抓包工具及解密算法挖炬,甚至一些公司有專門的逆向部門,這就加大了數(shù)據(jù)安全的風(fēng)險料仗,本文將通過以下幾個方面對各種加密算法進行分析對比:
- Base64編碼(基礎(chǔ))
- 單項散列函數(shù) MD5湾盗、SHA1、SHA256立轧、SHA512等
- 消息認證碼 HMAC-MD5格粪、HMAC-SHA1
- 對稱加密 DES|3DES|AES(高級加密標準)
- 非對稱加密 RSA
- 數(shù)字簽名
- 證書
通常我們對消息進行加解密有兩種處理方式:
- 只需要保存一個值躏吊,保證該值得機密性,不需要知道原文(用戶登錄)
- 除了保證機密性外還需要對加密后的值進行解密得到原文
Base64編碼
由于我們可能對各種各樣的數(shù)據(jù)進行加密帐萎,比如:視頻比伏、音頻唁影、文本文件等拓售,所以加密之前我們需要統(tǒng)一文件類型地熄,然后再進行加密處理。
- Base64編碼
// 要編碼的字符串
NSString *str = @"haha";
// 轉(zhuǎn)換成二進制文件
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
// 進行base64編碼
NSString *dataStr = [data base64EncodedStringWithOptions:kNilOptions];
NSLog(@"%@", dataStr);
- Base64解碼
// 先對數(shù)據(jù)進行解碼
NSData *encData = [[NSData alloc]initWithBase64EncodedString:dataStr options:kNilOptions];
// 將二進制數(shù)據(jù)轉(zhuǎn)換成字符串
NSString *encStr = [[NSString alloc]initWithData:encData encoding:NSUTF8StringEncoding];
NSLog(@"%@", encStr);
接下來分析一下Base64的編碼過程是鬼,參考維基百科:
如果要編碼的字節(jié)數(shù)不能被3整除,最后會多出1個或2個字節(jié)紫新,那么可以使用下面的方法進行處理:先使用0字節(jié)值在末尾補足均蜜,使其能夠被3整除,然后再進行Base64的編碼芒率。在編碼后的Base64文本后加上一個或兩個=號囤耳,代表補足的字節(jié)數(shù)。也就是說偶芍,當最后剩余兩個八位字節(jié)(2個byte)時充择,最后一個6位的Base64字節(jié)塊有四位是0值,最后附加上兩個等號匪蟀;如果最后剩余一個八位字節(jié)(1個byte)時椎麦,最后一個6位的base字節(jié)塊有兩位是0值,最后附加一個等號材彪。 參考下表:
- Base64編碼原理
- 將所有字符串轉(zhuǎn)換成ASCII碼
- 將ASCII碼轉(zhuǎn)換成8位二進制
- 將二進制三位歸成一組(不足三位在后邊補0)观挎,再按每組6位,拆成若干組
- 統(tǒng)一在6位二進制后不足8位的補0
- 將補0后的二進制轉(zhuǎn)換成十進制
- 從Base64編碼表取出十進制對應(yīng)的Base64編碼
若原數(shù)據(jù)長度不是3的倍數(shù)時且剩下1個輸入數(shù)據(jù)段化,則在編碼結(jié)果后加2個=嘁捷;若剩下2個輸入數(shù)據(jù),則在編碼結(jié)果后加1個=
如上面的例子:
原數(shù)據(jù)為A
显熏,數(shù)據(jù)長度為1雄嚣,1 % 3 = 1 后面加兩個==
原數(shù)據(jù)為bc
,數(shù)據(jù)長度為2喘蟆,2 % 3 = 2 后面加一個=
- Base64編碼的特點
- 可以將任意的二進制數(shù)據(jù)進行Base64編碼现诀。
- 所有的數(shù)據(jù)都能被編碼為并只用65個字符就能表示的文本文件。
- 編碼后的65個字符包括AZ,az,0~9,+,/,=
- 對文件或字符串進行Base64編碼后將比原始大小增加33%履肃。
- 能夠逆運算
- 不夠安全仔沿,但卻被很多加密算法作為編碼方式
單項散列函數(shù)
單向散列函數(shù)也稱為消息摘要函數(shù)、哈希函數(shù)或者雜湊函數(shù)尺棋。
單向散列函數(shù)輸出的散列值又稱為消息摘要或者指紋
特點:
- 對任意長度的消息散列得到散列值是定長的
- 散列計算速度快封锉,非常高效
- 消息不同绵跷,則散列值一定不同
- 消息相同,則散列值一定相同
- 具備單向性成福,無法逆推計算
經(jīng)典算法:
- MD4碾局、MD5、SHA1奴艾、SHA256净当、SHA512等
安全性:
- md5解密網(wǎng)站:http://www.cmd5.com
- MD5的強抗碰撞性已經(jīng)被證實攻破,即對于重要數(shù)據(jù)不應(yīng)該再繼續(xù)使用MD5加密蕴潦。
疑問一:單項散列函數(shù)為什么不可逆像啼??
原來好多同學(xué)知識知道m(xù)d5加密是不可逆的潭苞,卻不知道是為什么忽冻,其實散列函數(shù)可以將任意長度的輸入經(jīng)過變化得到不同的輸出,如果存在兩個不同的輸入得到了相同的散列值此疹,我們稱之為這是一個碰撞僧诚,因為使用的hash
算法,在計算過程中原文的部分信息是丟失了的蝗碎,一個MD5理論上可以對應(yīng)多個原文湖笨,因為MD5是有限多個,而原文是無限多個的蹦骑。
網(wǎng)上看到一個形象的例子:2 + 5 = 7赶么,但是根據(jù) 7 的結(jié)果,卻并不能推算出是由 2 + 5計算得來的
疑問二:為什么有些網(wǎng)站可以解密MD5后的數(shù)據(jù)脊串?辫呻?
MD5解密網(wǎng)站,并不是對加密后的數(shù)據(jù)進行解密琼锋,而是數(shù)據(jù)庫中存在大量的加密后的數(shù)據(jù)放闺,對用戶輸入的數(shù)據(jù)進行匹配(也叫暴力碰撞),匹配到與之對應(yīng)的數(shù)據(jù)就會輸出缕坎,并沒有對應(yīng)的解密算法怖侦。
MD5改進
由以上信息可以知道,MD5加密后的數(shù)據(jù)也并不是特別安全的谜叹,其實并沒有絕對的安全策略匾寝,我們可以對MD5進行改進,加大破解的難度荷腊,典型的加大解密難度的方式有一下幾種:
- 加鹽(Salt):在明文的固定位置插入隨機串艳悔,然后再進行MD5
- 先加密,后亂序:先對明文進行MD5女仰,然后對加密得到的MD5串的字符進行亂序
- 先亂序猜年,后加密:先對明文字符串進行亂序處理抡锈,然后對得到的串進行加密
- 先亂序,再加鹽乔外,再MD5等
- HMac消息認證碼
也可以進行多次的md5運算床三,總之就是要加大破解的難度。
Hmac消息認證碼(對MD5的改進)
原理:
- 消息的發(fā)送者和接收者有一個共享密鑰
- 發(fā)送者使用共享密鑰對消息加密計算得到MAC值(消息認證碼)
- 消息接收者使用共享密鑰對消息加密計算得到MAC值
- 比較兩個MAC值是否一致
使用:
- 客戶端需要在發(fā)送的時候把(消息)+(消息·HMAC)一起發(fā)送給服務(wù)器
- 服務(wù)器接收到數(shù)據(jù)后杨幼,對拿到的消息用共享的KEY進行HMAC撇簿,比較是否一致,如果一致則信任
對稱加密算法
對稱加密的特點:
- 加密/解密使用相同的密鑰
- 是可逆的
經(jīng)典算法:
- DES 數(shù)據(jù)加密標準
- 3DES 使用3個密鑰差购,對消息進行(密鑰1·加密)+(密鑰2·解密)+(密鑰3·加密)
- AES 高級加密標準
密碼算法可以分為分組密碼和流密碼兩種:
- 分組密碼:每次只能處理特定長度的一zu數(shù)據(jù)的一類密碼算法四瘫。一個分組的比特數(shù)量就稱之為分組長度。
- 流密碼:對數(shù)據(jù)流進行連續(xù)處理的一類算法歹撒。流密碼中一般以1比特莲组、8比特或者是32比特等作為單位倆進行加密和解密诊胞。
分組模式:主要有兩種
- ECB模式(又稱電子密碼本模式)
- 使用ECB模式加密的時候暖夭,相同的明文分組會被轉(zhuǎn)換為相同的密文分組。
- 類似于一個巨大的明文分組 -> 密文分組的對照表撵孤。
某一塊分組被修改迈着,不影響后面的加密結(jié)果
-
CBC模式(又稱電子密碼鏈條)
- 在CBC模式中,首先將明文分組與前一個密文分組進行XOR(異或)運算邪码,然后再進行加密裕菠。
- 每一個分組的加密結(jié)果依賴需要與前一個進行異或運算,由于第一個分組沒有前一個分組闭专,所以需要提供一個初始向量
iv
某一塊分組被修改奴潘,影響后面的加密結(jié)果
代碼演示兩種分組模式
- AES - ECB模式
加密:
/**
* 加密字符串并返回base64編碼字符串
*
* @param string 要加密的字符串
* @param keyString 加密密鑰
* @param iv 初始化向量(8個字節(jié))
*
* @return 返回加密后的base64編碼字符串
*/
NSLog(@"%@", [[EncryptionTools sharedEncryptionTools] encryptString:@"haha" keyString:@"abc" iv:nil]);
// 輸出 MIoAu+xUEpQZSUmkZUW6JQ==
解密:
NSLog(@"%@", [[EncryptionTools sharedEncryptionTools] decryptString:@"MIoAu+xUEpQZSUmkZUW6JQ==" keyString:@"abc" iv:nil]);
// 輸出 haha
- AES - CBC模式
加密:
uint8_t iv[8] = {1,2,3,4,5,6,7,8};
NSData *data = [[NSData alloc] initWithBytes:iv length:sizeof(iv)];
NSLog(@"%@", [[EncryptionTools sharedEncryptionTools] encryptString:@"haha" keyString:@"abc" iv:data]);
// 輸出 E/wWqUTiw/E+1DThAzV39A==
解密:
NSLog(@"%@", [[EncryptionTools sharedEncryptionTools] decryptString:@"E/wWqUTiw/E+1DThAzV39A==" keyString:@"abc" iv:data]);
// 輸出 haha
對稱加密存在的問題?影钉?
很明顯画髓,對稱加密主要取決于秘鑰的安全性,數(shù)據(jù)傳輸?shù)倪^程中平委,如果秘鑰被別人破解的話奈虾,以后的加解密就將失去意義
其實有點兒類似于我們平常看的諜戰(zhàn)類的電視劇廉赔,地下黨將情報發(fā)送給后方肉微,通常需要一個中間人將密碼本傳輸給后方,如果中間人被抓交出密碼本蜡塌,那么將來所有的情報都將失去意義碉纳,由此可見情報工作多么的重要!A蟀村象!
對稱密碼體制中只有一種密鑰笆环,并且是非公開的,如果要解密就得讓對方知道密鑰厚者。所以保證其安全性就是保證密鑰的安全躁劣,而非對稱密鑰體制有兩種密鑰,其中一個是公開的库菲,這樣就可以不需要像對稱密碼那樣傳輸對方的密鑰了
非對稱加密
鑒于對稱加密存在的風(fēng)險账忘,非對稱加密應(yīng)運而生
特點:
- 使用公鑰加密,使用私鑰解密
- 公鑰是公開的熙宇,私鑰保密
- 加密處理安全鳖擒,但是性能極差
非對稱密碼體制的特點:算法強度復(fù)雜、安全性依賴于算法與密鑰烫止,但是由于其算法復(fù)雜蒋荚,而使得加密解密速度沒有對稱加密解密的速度快
經(jīng)典算法:
- RSA
RSA算法原理
* 求N,準備兩個質(zhì)數(shù)p和q,N = p x q
* 求L,L是p-1和q-1的最小公倍數(shù)馆蠕。L = lcm(p-1,q-1)
* 求E期升,E和L的最大公約數(shù)為1(E和L互質(zhì))
* 求D,E x D mode L = 1
RSA加密實踐
* p = 17,q = 19 =>N = 323
* lcm(p-1,q-1)=>lcm(16互躬,18)=>L= 144
* gcd(E,L)=1 =>E=5
* E乘以幾可以mode L =1? D=29可以滿足
* 得到公鑰為:E=5,N=323
* 得到私鑰為:D=29,N=323
* 加密 明文的E次方 mod N = 123的5次方 mod 323 = 225(密文)
* 解密 密文的D次方 mod N = 225的29次方 mod 323 = 123(明文)
openssl生成密鑰命令
- 生成強度是 512 的 RSA 私鑰:$ openssl genrsa -out private.pem 512
- 以明文輸出私鑰內(nèi)容:$ openssl rsa -in private.pem -text -out private.txt
- 校驗私鑰文件:$ openssl rsa -in private.pem -check
- 從私鑰中提取公鑰:$ openssl rsa -in private.pem -out public.pem -outform PEM -pubout
- 以明文輸出公鑰內(nèi)容:$ openssl rsa -in public.pem -out public.txt -pubin -pubout -text
- 使用公鑰加密小文件:$ openssl rsautl -encrypt -pubin -inkey public.pem -in msg.txt -out msg.bin
- 使用私鑰解密小文件:$ openssl rsautl -decrypt -inkey private.pem -in msg.bin -out a.txt
- 將私鑰轉(zhuǎn)換成 DER 格式:$ openssl rsa -in private.pem -out private.der -outform der
- 將公鑰轉(zhuǎn)換成 DER 格式:$ openssl rsa -in public.pem -out public.der -pubin -outform der
非對稱加密存在的安全問題
原理上看非對稱加密非常安全播赁,客戶端用公鑰進行加密,服務(wù)端用私鑰進行解密吼渡,數(shù)據(jù)傳輸?shù)闹皇枪€容为,原則上看,就算公鑰被人截獲寺酪,也沒有什么用坎背,因為公鑰只是用來加密的,那還存在什么問題呢寄雀?得滤?那就是經(jīng)典的中間人攻擊
廢了半天勁畫的圖,太low了咙俩,我還是自己總結(jié)一遍吧9⑵荨!阿趁!
中間人攻擊詳細步驟:
- 客戶端向服務(wù)器請求公鑰信息
- 服務(wù)端返回給客戶端公鑰被中間人截獲
- 中間人將截獲的公鑰存起來
- 中間人自己偽造一套自己的公鑰和私鑰
- 中間人將自己偽造的公鑰發(fā)送給客戶端
- 客戶端將重要信息利用偽造的公鑰進行加密
- 中間人獲取到自己公鑰加密的重要信息
- 中間人利用自己的私鑰對重要信息進行解密
- 中間人篡改重要信息(將給客戶端轉(zhuǎn)賬改為向自己轉(zhuǎn)賬)
- 中間人將篡改后的重要信息利用原來截獲的公鑰進行加密膜蛔,發(fā)送給服務(wù)器
- 服務(wù)器收到錯誤的重要信息(給中間人轉(zhuǎn)賬)
疑問一:為什么會造成中間人攻擊?脖阵?
造成中間人攻擊的直接原因就是客戶端沒辦法判斷公鑰信息的正確性皂股。
疑問二:怎么解決中間人攻擊?命黔?
需要對公鑰進行數(shù)字簽名呜呐。就像古代書信傳遞就斤,家人之所以知道這封信是你寫的,是因為信上有你的簽名蘑辑、印章等證明你身份的信息洋机。
數(shù)字簽名需要嚴格驗證發(fā)送發(fā)的身份信息!Q蠡辍绷旗!
數(shù)字證書
數(shù)字證書包含:
- 公鑰
- 認證機構(gòu)的數(shù)字簽名(權(quán)威機構(gòu)CA)
數(shù)字證書可以自己生成,也可以從權(quán)威機構(gòu)購買副砍,但是注意衔肢,自己生成的證書,只能自己認可豁翎,別人都不認可.
權(quán)威機構(gòu)簽名的證書:
以GitHub官網(wǎng)為例角骤,Chrome瀏覽器打開網(wǎng)址,地址欄有一個小綠鎖心剥,點擊邦尊,內(nèi)容如下:
權(quán)威機構(gòu)認證的證書:
可以看到連接是安全的,點擊證書可以看到詳細信息
這是由權(quán)威機構(gòu)認證的證書刘陶,但是是需要花錢的胳赌,一年至少得一兩千牢撼,所以也有些公司用自己簽名的證書匙隔,自己簽名的證書不被信任,可能會提示用戶有風(fēng)險熏版,比如原來的12306網(wǎng)站纷责,現(xiàn)在大多數(shù)網(wǎng)站也都采用了CA簽名數(shù)字證書進行簽名,自己做簽名的也不好找了:扯獭T偕拧!12306都改成CA認證的了曲横。喂柒。。
自己生成一個證書
- 生成私鑰
openssl genrsa -out private.pem 1024
- 創(chuàng)建證書請求
openssl req -new -key private.pem -out rsacert.csr
- 生成證書并簽名禾嫉,有效期10年
openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
- 將 PEM 格式文件轉(zhuǎn)換成 DER 格式
openssl x509 -outform der -in rsacert.crt -out rsacert.der
- 導(dǎo)出P12文件
openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
注意:
- 在iOS開發(fā)中灾杰,不能直接使用 PEM 格式的證書,因為其內(nèi)部進行了Base64編碼熙参,應(yīng)該使用的是DER的證書艳吠,是二進制格式的
- OpenSSL默認生成的都是PEM格式的證書
代碼演示:
// p12 是私鑰
// .der 是公鑰
// 非對稱加密,使用公鑰加密孽椰,私鑰解密
// 加載公鑰
[[RSACryptor sharedRSACryptor] loadPublicKey:[[NSBundle mainBundle] pathForResource:@"rsacert.der" ofType:nil]];
// 對數(shù)據(jù)加密
NSData *data = [[RSACryptor sharedRSACryptor] encryptData:[@"hahaha" dataUsingEncoding:NSUTF8StringEncoding]];
// 對加密得到的密文進行base64編碼打印
NSLog(@"%@", [data base64EncodedStringWithOptions:kNilOptions]);
// 輸出結(jié)果:PflhCgTVNegcQXrb39RJOoxCRRIHuZ3LN0/hoxTDFBbC+8yKjp0m+/hxVUWBVsTo28WnNFCAFfrQ2of5SkqttD51a5eLb21R7bQSQRxg/gVZ5hePcE3vh7Slfcxm2qJM+J8hRWDP/MF4BiDLXI9ZqTpLCSS5mjJtmUBf2wNvI1Y=
// 私鑰解密
// 加載私鑰
[[RSACryptor sharedRSACryptor] loadPrivateKey:[[NSBundle mainBundle] pathForResource:@"p.p12" ofType:nil] password:@"123456"];
// 解密
NSData *decryDeta = [[RSACryptor sharedRSACryptor] decryptData:data];
NSLog(@"%@", [[NSString alloc] initWithData:decryDeta encoding:NSUTF8StringEncoding]);
// 輸出:hahaha
代碼地址
總結(jié)
至此數(shù)據(jù)安全和加解密相關(guān)結(jié)算完畢昭娩,寫博客的過程凛篙,也是學(xué)習(xí)的過程,斷斷續(xù)續(xù)的寫了三四天栏渺,總算寫完了呛梆,同時也對原來一些模糊的概念有了更清晰的認識,寫的這篇文章看了文頂頂老師的視頻磕诊,受益匪淺削彬,十分感謝,最近學(xué)習(xí)發(fā)現(xiàn)秀仲,學(xué)的越多融痛,感覺會的越少,時間十分的不夠用神僵。同時渴望遇到一些希望進步雁刷、不甘平凡的同行!1@瘛沛励!共勉!E谡稀目派!